changeset 7:8a302fdb4140

Jface some window and resource classes
author Frank Benoit <benoit@tionex.de>
date Fri, 28 Mar 2008 23:32:40 +0100
parents 1a6747be662d
children a3ff22a98bef
files dwtx/core/runtime/Assert.d dwtx/jface/resource/ArrayFontDescriptor.d dwtx/jface/resource/DataFormatException.d dwtx/jface/resource/FontDescriptor.d dwtx/jface/resource/FontRegistry.d dwtx/jface/resource/JFaceResources.d dwtx/jface/resource/ResourceRegistry.d dwtx/jface/resource/StringConverter.d dwtx/jface/window/DefaultToolTip.d dwtx/jface/window/IShellProvider.d dwtx/jface/window/SameShellProvider.d dwtx/jface/window/ToolTip.d dwtx/jface/window/Window.d dwtx/jface/window/WindowManager.d
diffstat 14 files changed, 5198 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/dwtx/core/runtime/Assert.d	Fri Mar 28 19:31:01 2008 +0100
+++ b/dwtx/core/runtime/Assert.d	Fri Mar 28 23:32:40 2008 +0100
@@ -77,6 +77,9 @@
     public static void isNotNull(Object object) {
         isNotNull(object, ""); //$NON-NLS-1$
     }
+    public static void isNotNull(String object) {
+        isTrue(object.ptr !is null); //$NON-NLS-1$
+    }
 
     /** Asserts that the given object is not <code>null</code>. If this
      * is not the case, some kind of unchecked exception is thrown.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/ArrayFontDescriptor.d	Fri Mar 28 23:32:40 2008 +0100
@@ -0,0 +1,145 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.resource.ArrayFontDescriptor;
+
+import dwtx.jface.resource.FontDescriptor;
+
+import dwt.graphics.Device;
+import dwt.graphics.Font;
+import dwt.graphics.FontData;
+
+/**
+ * Describes a Font using an array of FontData
+ *
+ * @since 3.1
+ */
+final class ArrayFontDescriptor : FontDescriptor {
+
+    private FontData[] data;
+    private Font originalFont = null;
+
+    /**
+     * Creates a font descriptor for a font with the given name, height,
+     * and style. These arguments are passed directly to the constructor
+     * of Font.
+     *
+     * @param data FontData describing the font to create
+     *
+     * @see dwt.graphics.Font#Font(dwt.graphics.Device, dwt.graphics.FontData)
+     * @since 3.1
+     */
+    public this(FontData[] data) {
+        this.data = data;
+    }
+
+    /**
+     * Creates a font descriptor that describes the given font.
+     *
+     * @param originalFont font to be described
+     *
+     * @see FontDescriptor#createFrom(dwt.graphics.Font)
+     * @since 3.1
+     */
+    public this(Font originalFont) {
+        this(originalFont.getFontData());
+        this.originalFont = originalFont;
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.FontDescriptor#getFontData()
+     */
+    public FontData[] getFontData() {
+        // Copy the original array to ensure that callers will not modify it
+        return copy(data);
+    }
+
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.FontDescriptor#createFont(dwt.graphics.Device)
+     */
+    public Font createFont(Device device) {
+
+        // If this descriptor is an existing font, then we can return the original font
+        // if this is the same device.
+        if (originalFont !is null) {
+            // If we're allocating on the same device as the original font, return the original.
+            if (originalFont.getDevice() is device) {
+                return originalFont;
+            }
+        }
+
+        return new Font(device, data);
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public override int opEquals(Object obj) {
+        if ((obj.classinfo is ArrayFontDescriptor.classinfo)) {
+            ArrayFontDescriptor descr = cast(ArrayFontDescriptor)obj;
+
+            if (descr.originalFont !is originalFont) {
+                return false;
+            }
+
+            if (originalFont !is null) {
+                return true;
+            }
+
+            if (data.length !is descr.data.length) {
+                return false;
+            }
+
+            for (int i = 0; i < data.length; i++) {
+                FontData fd = data[i];
+                FontData fd2 = descr.data[i];
+
+                if (!fd.opEquals(fd2)) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    public override hash_t toHash() {
+        if (originalFont !is null) {
+            return originalFont.toHash();
+        }
+
+        int code = 0;
+
+        for (int i = 0; i < data.length; i++) {
+            FontData fd = data[i];
+            code += fd.toHash();
+        }
+        return code;
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.FontDescriptor#destroyFont(dwt.graphics.Font)
+     */
+    public void destroyFont(Font previouslyCreatedFont) {
+        if (previouslyCreatedFont is originalFont) {
+            return;
+        }
+        previouslyCreatedFont.dispose();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/DataFormatException.d	Fri Mar 28 23:32:40 2008 +0100
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.resource.DataFormatException;
+
+import dwt.dwthelper.utils;
+
+/**
+ * An exception indicating that a string value could not be
+ * converted into the requested data type.
+ *
+ * @see StringConverter
+ */
+public class DataFormatException : IllegalArgumentException {
+
+    /**
+     * Generated serial version UID for this class.
+     * @since 3.1
+     */
+    private static const long serialVersionUID = 3544955467404031538L;
+
+    /**
+     * Creates a new exception.
+     */
+    public this() {
+        super("");
+    }
+
+    /**
+     * Creates a new exception.
+     *
+     * @param message the message
+     */
+    public this(String message) {
+        super(message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/FontDescriptor.d	Fri Mar 28 23:32:40 2008 +0100
@@ -0,0 +1,301 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.resource.FontDescriptor;
+
+import dwtx.jface.resource.DeviceResourceDescriptor;
+import dwtx.jface.resource.ArrayFontDescriptor;
+
+import dwt.graphics.Device;
+import dwt.graphics.Font;
+import dwt.graphics.FontData;
+import dwt.widgets.Display;
+
+import dwt.dwthelper.utils;
+
+/**
+ * Lightweight descriptor for a font. Creates the described font on demand.
+ * Subclasses can implement different ways of describing a font. These objects
+ * will be compared, so hashCode(...) and equals(...) must return something
+ * meaningful.
+ *
+ * @since 3.1
+ */
+public abstract class FontDescriptor : DeviceResourceDescriptor {
+
+    /**
+     * Creates a FontDescriptor that describes an existing font. The resulting
+     * descriptor depends on the Font. Disposing the Font while the descriptor
+     * is still in use may throw a graphic disposed exception.
+     *
+     * @since 3.1
+     *
+     * @deprecated use {@link FontDescriptor#createFrom(Font)}
+     *
+     * @param font a font to describe
+     * @param originalDevice must be the same Device that was passed into
+     * the font's constructor when it was first created.
+     * @return a newly created FontDescriptor.
+     */
+    public static FontDescriptor createFrom(Font font, Device originalDevice) {
+        return new ArrayFontDescriptor(font);
+    }
+
+    /**
+     * Creates a FontDescriptor that describes an existing font. The resulting
+     * descriptor depends on the original Font, and disposing the original Font
+     * while the descriptor is still in use may cause DWT to throw a graphic
+     * disposed exception.
+     *
+     * @since 3.1
+     *
+     * @param font font to create
+     * @return a newly created FontDescriptor that describes the given font
+     */
+    public static FontDescriptor createFrom(Font font) {
+        return new ArrayFontDescriptor(font);
+    }
+
+    /**
+     * Creates a new FontDescriptor given the an array of FontData that describes
+     * the font.
+     *
+     * @since 3.1
+     *
+     * @param data an array of FontData that describes the font (will be passed into
+     * the Font's constructor)
+     * @return a FontDescriptor that describes the given font
+     */
+    public static FontDescriptor createFrom(FontData[] data) {
+        return new ArrayFontDescriptor(data);
+    }
+
+    /**
+     * Creates a new FontDescriptor given the associated FontData
+     *
+     * @param data FontData describing the font to create
+     * @return a newly created FontDescriptor
+     */
+    public static FontDescriptor createFrom(FontData data) {
+        return new ArrayFontDescriptor( [data] );
+    }
+
+    /**
+     * Creates a new FontDescriptor given an OS-specific font name, height, and style.
+     *
+     * @see Font#Font(dwt.graphics.Device, java.lang.String, int, int)
+     *
+     * @param name os-specific font name
+     * @param height height (pixels)
+     * @param style a bitwise combination of NORMAL, BOLD, ITALIC
+     * @return a new FontDescriptor
+     */
+    public static FontDescriptor createFrom(String name, int height, int style) {
+        return createFrom(new FontData(name, height, style));
+    }
+
+    /**
+     * Returns the set of FontData associated with this font. Modifying the elements
+     * in the returned array has no effect on the original FontDescriptor.
+     *
+     * @return the set of FontData associated with this font
+     * @since 3.3
+     */
+    public FontData[] getFontData() {
+        Font tempFont = createFont(Display.getCurrent());
+        FontData[] result = tempFont.getFontData();
+        destroyFont(tempFont);
+        return result;
+    }
+
+    /**
+     * Returns an array of FontData containing copies of the FontData
+     * from the original.
+     *
+     * @param original array to copy
+     * @return a deep copy of the original array
+     * @since 3.3
+     */
+    public static FontData[] copy(FontData[] original) {
+        FontData[] result = new FontData[original.length];
+        for (int i = 0; i < original.length; i++) {
+            FontData next = original[i];
+
+            result[i] = copy(next);
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns a copy of the original FontData
+     *
+     * @param next FontData to copy
+     * @return a copy of the given FontData
+     * @since 3.3
+     */
+    public static FontData copy(FontData next) {
+        FontData result = new FontData(next.getName(), next.getHeight(), next.getStyle());
+        result.setLocale(next.getLocale());
+        return result;
+    }
+
+    /**
+     * Returns a FontDescriptor that is equivalent to the reciever, but uses
+     * the given style bits.
+     *
+     * <p>Does not modify the reciever.</p>
+     *
+     * @param style a bitwise combination of DWT.NORMAL, DWT.ITALIC and DWT.BOLD
+     * @return a new FontDescriptor with the given style
+     *
+     * @since 3.3
+     */
+    public final FontDescriptor setStyle(int style) {
+        FontData[] data = getFontData();
+
+        for (int i = 0; i < data.length; i++) {
+            FontData next = data[i];
+
+            next.setStyle(style);
+        }
+
+        // Optimization: avoid holding onto extra instances by returning the reciever if
+        // if it is exactly the same as the result
+        FontDescriptor result = new ArrayFontDescriptor(data);
+        if (result.opEquals(this)) {
+            return this;
+        }
+
+        return result;
+    }
+
+    /**
+     * <p>Returns a FontDescriptor that is equivalent to the reciever, but
+     * has the given style bits, in addition to any styles the reciever already has.</p>
+     *
+     * <p>Does not modify the reciever.</p>
+     *
+     * @param style a bitwise combination of DWT.NORMAL, DWT.ITALIC and DWT.BOLD
+     * @return a new FontDescriptor with the given additional style bits
+     * @since 3.3
+     */
+    public final FontDescriptor withStyle(int style) {
+        FontData[] data = getFontData();
+
+        for (int i = 0; i < data.length; i++) {
+            FontData next = data[i];
+
+            next.setStyle(next.getStyle() | style);
+        }
+
+        // Optimization: avoid allocating extra instances by returning the reciever if
+        // if it is exactly the same as the result
+        FontDescriptor result = new ArrayFontDescriptor(data);
+        if (result.opEquals(this)) {
+            return this;
+        }
+
+        return result;
+    }
+
+    /**
+     * <p>Returns a new FontDescriptor that is equivalent to the reciever, but
+     * has the given height.</p>
+     *
+     * <p>Does not modify the reciever.</p>
+     *
+     * @param height a height, in points
+     * @return a new FontDescriptor with the height, in points
+     * @since 3.3
+     */
+    public final FontDescriptor setHeight(int height) {
+        FontData[] data = getFontData();
+
+        for (int i = 0; i < data.length; i++) {
+            FontData next = data[i];
+
+            next.setHeight(height);
+        }
+
+        // Optimization: avoid holding onto extra instances by returning the reciever if
+        // if it is exactly the same as the result
+        FontDescriptor result = new ArrayFontDescriptor(data);
+        if (result.opEquals(this)) {
+            return this;
+        }
+
+        return result;
+    }
+
+    /**
+     * <p>Returns a FontDescriptor that is equivalent to the reciever, but whose height
+     * is larger by the given number of points.</p>
+     *
+     * <p>Does not modify the reciever.</p>
+     *
+     * @param heightDelta a change in height, in points. Negative values will return smaller
+     * fonts.
+     * @return a FontDescriptor whose height differs from the reciever by the given number
+     * of points.
+     * @since 3.3
+     */
+    public final FontDescriptor increaseHeight(int heightDelta) {
+        if (heightDelta is 0) {
+            return this;
+        }
+        FontData[] data = getFontData();
+
+        for (int i = 0; i < data.length; i++) {
+            FontData next = data[i];
+
+            next.setHeight(next.getHeight() + heightDelta);
+        }
+
+        return new ArrayFontDescriptor(data);
+    }
+
+    /**
+     * Creates the Font described by this descriptor.
+     *
+     * @since 3.1
+     *
+     * @param device device on which to allocate the font
+     * @return a newly allocated Font (never null)
+     * @throws DeviceResourceException if unable to allocate the Font
+     */
+    public abstract Font createFont(Device device);
+
+    /**
+     * Deallocates anything that was allocated by createFont, given a font
+     * that was allocated by an equal FontDescriptor.
+     *
+     * @since 3.1
+     *
+     * @param previouslyCreatedFont previously allocated font
+     */
+    public abstract void destroyFont(Font previouslyCreatedFont);
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.DeviceResourceDescriptor#create(dwt.graphics.Device)
+     */
+    public final Object createResource(Device device) {
+        return createFont(device);
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.DeviceResourceDescriptor#destroy(java.lang.Object)
+     */
+    public final void destroyResource(Object previouslyCreatedObject) {
+        destroyFont(cast(Font)previouslyCreatedObject);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/FontRegistry.d	Fri Mar 28 23:32:40 2008 +0100
@@ -0,0 +1,852 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.resource.FontRegistry;
+
+import dwtx.jface.resource.ResourceRegistry;
+import dwtx.jface.resource.FontDescriptor;
+import dwtx.jface.resource.StringConverter;
+import dwtx.jface.resource.JFaceResources;
+import dwtx.jface.resource.DataFormatException;
+
+import tango.util.collection.ArraySeq;
+import tango.util.collection.HashMap;
+import tango.util.collection.model.Map;
+import tango.util.collection.model.Seq;
+import tango.util.collection.model.Set;
+import tango.util.collection.model.SetView;
+import tango.util.collection.HashSet;
+// import java.util.Arrays;
+// import java.util.Collections;
+// import java.util.Enumeration;
+// import java.util.HashMap;
+// import java.util.Iterator;
+// import java.util.List;
+// import java.util.Map;
+// import java.util.MissingResourceException;
+// import java.util.Set;
+
+import dwt.DWT;
+import dwt.graphics.Font;
+import dwt.graphics.FontData;
+import dwt.widgets.Display;
+import dwt.widgets.Shell;
+import dwtx.core.runtime.Assert;
+
+import dwt.dwthelper.ResourceBundle;
+import dwt.dwthelper.utils;
+import dwt.dwthelper.Runnable;
+
+/**
+ * A font registry maintains a mapping between symbolic font names
+ * and DWT fonts.
+ * <p>
+ * A font registry owns all of the font objects registered
+ * with it, and automatically disposes of them when the DWT Display
+ * that creates the fonts is disposed. Because of this, clients do
+ * not need to (indeed, must not attempt to) dispose of font
+ * objects themselves.
+ * </p>
+ * <p>
+ * A special constructor is provided for populating a font registry
+ * from a property files using the standard Java resource bundle mechanism.
+ * </p>
+ * <p>
+ * Methods are provided for registering listeners that will be kept
+ * apprised of changes to list of registed fonts.
+ * </p>
+ * <p>
+ * Clients may instantiate this class (it was not designed to be subclassed).
+ * </p>
+ *
+ * Since 3.0 this class extends ResourceRegistry.
+ */
+public class FontRegistry : ResourceRegistry {
+
+    /**
+     * FontRecord is a private helper class that holds onto a font
+     * and can be used to generate its bold and italic version.
+     */
+    private class FontRecord {
+
+        Font baseFont;
+
+        Font boldFont;
+
+        Font italicFont;
+
+        FontData[] baseData;
+
+        /**
+         * Create a new instance of the receiver based on the
+         * plain font and the data for it.
+         * @param plainFont The base looked up font.
+         * @param data The data used to look it up.
+         */
+        this(Font plainFont, FontData[] data) {
+            baseFont = plainFont;
+            baseData = data;
+        }
+
+        /**
+         * Dispose any of the fonts created for this record.
+         */
+        void dispose() {
+            baseFont.dispose();
+            if (boldFont !is null) {
+                boldFont.dispose();
+            }
+            if (italicFont !is null) {
+                italicFont.dispose();
+            }
+        }
+
+        /**
+         * Return the base Font.
+         * @return Font
+         */
+        public Font getBaseFont() {
+            return baseFont;
+        }
+
+        /**
+         * Return the bold Font. Create a bold version
+         * of the base font to get it.
+         * @return Font
+         */
+        public Font getBoldFont() {
+            if (boldFont !is null) {
+                return boldFont;
+            }
+
+            FontData[] boldData = getModifiedFontData(DWT.BOLD);
+            boldFont = new Font(Display.getCurrent(), boldData);
+            return boldFont;
+        }
+
+        /**
+         * Get a version of the base font data with the specified
+         * style.
+         * @param style the new style
+         * @return the font data with the style {@link FontData#FontData(String, int, int)}
+         * @see DWT#ITALIC
+         * @see DWT#NORMAL
+         * @see DWT#BOLD
+         * @todo Generated comment
+         */
+        private FontData[] getModifiedFontData(int style) {
+            FontData[] styleData = new FontData[baseData.length];
+            for (int i = 0; i < styleData.length; i++) {
+                FontData base = baseData[i];
+                styleData[i] = new FontData(base.getName(), base.getHeight(),
+                        base.getStyle() | style);
+            }
+
+            return styleData;
+        }
+
+        /**
+         * Return the italic Font. Create an italic version of the
+         * base font to get it.
+         * @return Font
+         */
+        public Font getItalicFont() {
+            if (italicFont !is null) {
+                return italicFont;
+            }
+
+            FontData[] italicData = getModifiedFontData(DWT.ITALIC);
+            italicFont = new Font(Display.getCurrent(), italicData);
+            return italicFont;
+        }
+
+        /**
+         * Add any fonts that were allocated for this record to the
+         * stale fonts. Anything that matches the default font will
+         * be skipped.
+         * @param defaultFont The system default.
+         */
+        void addAllocatedFontsToStale(Font defaultFont) {
+            //Return all of the fonts allocated by the receiver.
+            //if any of them are the defaultFont then don't bother.
+            if (defaultFont !is baseFont && baseFont !is null) {
+                staleFonts.append(baseFont);
+            }
+            if (defaultFont !is boldFont && boldFont !is null) {
+                staleFonts.append(boldFont);
+            }
+            if (defaultFont !is italicFont && italicFont !is null) {
+                staleFonts.append(italicFont);
+            }
+        }
+    }
+
+    /**
+     * Table of known fonts, keyed by symbolic font name
+     * (key type: <code>String</code>,
+     *  value type: <code>FontRecord</code>.
+     */
+    private Map!(String,FontRecord) stringToFontRecord;
+
+    /**
+     * Table of known font data, keyed by symbolic font name
+     * (key type: <code>String</code>,
+     *  value type: <code>dwt.graphics.FontData[]</code>).
+     */
+    private Map!(String,FontData[]) stringToFontData;
+
+    /**
+     * Collection of Fonts that are now stale to be disposed
+     * when it is safe to do so (i.e. on shutdown).
+     * @see List
+     */
+    private Seq!(Font) staleFonts;
+
+    /**
+     * Runnable that cleans up the manager on disposal of the display.
+     */
+    protected Runnable displayRunnable;
+
+    /**
+     * Creates an empty font registry.
+     * <p>
+     * There must be an DWT Display created in the current
+     * thread before calling this method.
+     * </p>
+     */
+    public this() {
+        this(Display.getCurrent(), true);
+    }
+
+    /**
+     * Creates a font registry and initializes its content from
+     * a property file.
+     * <p>
+     * There must be an DWT Display created in the current
+     * thread before calling this method.
+     * </p>
+     * <p>
+     * The OS name (retrieved using <code>System.getProperty("os.name")</code>)
+     * is converted to lowercase, purged of whitespace, and appended
+     * as suffix (separated by an underscore <code>'_'</code>) to the given
+     * location string to yield the base name of a resource bundle
+     * acceptable to <code>ResourceBundle.getBundle</code>.
+     * The standard Java resource bundle mechanism is then used to locate
+     * and open the appropriate properties file, taking into account
+     * locale specific variations.
+     * </p>
+     * <p>
+     * For example, on the Windows 2000 operating system the location string
+     * <code>"com.example.myapp.Fonts"</code> yields the base name
+     * <code>"com.example.myapp.Fonts_windows2000"</code>. For the US English locale,
+     * this further elaborates to the resource bundle name
+     * <code>"com.example.myapp.Fonts_windows2000_en_us"</code>.
+     * </p>
+     * <p>
+     * If no appropriate OS-specific resource bundle is found, the
+     * process is repeated using the location as the base bundle name.
+     * </p>
+     * <p>
+     * The property file contains entries that look like this:
+     * <pre>
+     *  textfont.0=MS Sans Serif-regular-10
+     *  textfont.1=Times New Roman-regular-10
+     *
+     *  titlefont.0=MS Sans Serif-regular-12
+     *  titlefont.1=Times New Roman-regular-12
+     * </pre>
+     * Each entry maps a symbolic font names (the font registry keys) with
+     * a "<code>.<it>n</it></code> suffix to standard font names
+     * on the right. The suffix indicated order of preference:
+     * "<code>.0</code>" indicates the first choice,
+     * "<code>.1</code>" indicates the second choice, and so on.
+     * </p>
+     * The following example shows how to use the font registry:
+     * <pre>
+     *  FontRegistry registry = new FontRegistry("com.example.myapp.fonts");
+     *  Font font = registry.get("textfont");
+     *  control.setFont(font);
+     *  ...
+     * </pre>
+     *
+     * @param location the name of the resource bundle
+     * @param loader the ClassLoader to use to find the resource bundle
+     * @exception MissingResourceException if the resource bundle cannot be found
+     * @since 2.1
+     */
+    public this(String location, /+ClassLoader+/Object loader){
+        initInstance();
+        Display display = Display.getCurrent();
+        Assert.isNotNull(display);
+        // FIXE: need to respect loader
+        //readResourceBundle(location, loader);
+        readResourceBundle(location);
+
+        hookDisplayDispose(display);
+    }
+
+    private void initInstance(){
+        displayRunnable = new class Runnable {
+            public void run() {
+                clearCaches();
+            }
+        };
+        stringToFontRecord = new HashMap!(String,FontRecord);
+        //stringToFontRecord.capacity(7);
+
+        stringToFontData = new HashMap!(String,FontData[]);
+        //stringToFontData.capacity(7);
+
+        staleFonts = new ArraySeq!(Font);
+    }
+
+    /**
+     * Load the FontRegistry using the ClassLoader from the PlatformUI
+     * plug-in
+     * @param location the location to read the resource bundle from
+     * @throws MissingResourceException Thrown if a resource is missing
+     */
+    public this(String location) {
+        // FIXE:
+        //  this(location, WorkbenchPlugin.getDefault().getDescriptor().getPluginClassLoader());
+        this(location, null);
+    }
+
+    /**
+     * Read the resource bundle at location. Look for a file with the
+     * extension _os_ws first, then _os then just the name.
+     * @param location - String - the location of the file.
+     */
+
+    private void readResourceBundle(String location) {
+        String osname = System.getProperty("os.name").trim(); //$NON-NLS-1$
+        String wsname = DWT.getPlatform();
+        osname = StringConverter.removeWhiteSpaces(osname).toLowerCase();
+        wsname = StringConverter.removeWhiteSpaces(wsname).toLowerCase();
+        String OSLocation = location;
+        String WSLocation = location;
+        ResourceBundle bundle = null;
+        if (osname !is null) {
+            OSLocation = location ~ "_" ~ osname; //$NON-NLS-1$
+            if (wsname !is null) {
+                WSLocation = OSLocation ~ "_" ~ wsname; //$NON-NLS-1$
+            }
+        }
+
+        try {
+            bundle = ResourceBundle.getBundle(WSLocation);
+            readResourceBundle(bundle, WSLocation);
+        } catch (MissingResourceException wsException) {
+            try {
+                bundle = ResourceBundle.getBundle(OSLocation);
+                readResourceBundle(bundle, WSLocation);
+            } catch (MissingResourceException osException) {
+                if (location !is OSLocation) {
+                    bundle = ResourceBundle.getBundle(location);
+                    readResourceBundle(bundle, WSLocation);
+                } else {
+                    throw osException;
+                }
+            }
+        }
+    }
+
+    /**
+     * Creates an empty font registry.
+     *
+     * @param display the Display
+     */
+    public this(Display display) {
+        this(display, true);
+    }
+
+    /**
+     * Creates an empty font registry.
+     *
+     * @param display
+     *            the <code>Display</code>
+     * @param cleanOnDisplayDisposal
+     *            whether all fonts allocated by this <code>FontRegistry</code>
+     *            should be disposed when the display is disposed
+     * @since 3.1
+     */
+    public this(Display display, bool cleanOnDisplayDisposal) {
+        initInstance();
+        Assert.isNotNull(display);
+        if (cleanOnDisplayDisposal) {
+            hookDisplayDispose(display);
+        }
+    }
+
+    /**
+     * Find the first valid fontData in the provided list. If none are valid
+     * return the first one regardless. If the list is empty return null. Return
+     * <code>null</code> if one cannot be found.
+     *
+     * @param fonts the font list
+     * @param display the display used
+     * @return the font data of the like describe above
+     *
+     * @deprecated use bestDataArray in order to support Motif multiple entry
+     *             fonts.
+     */
+    public FontData bestData(FontData[] fonts, Display display) {
+        for (int i = 0; i < fonts.length; i++) {
+            FontData fd = fonts[i];
+
+            if (fd is null) {
+                break;
+            }
+
+            FontData[] fixedFonts = display.getFontList(fd.getName(), false);
+            if (isFixedFont(fixedFonts, fd)) {
+                return fd;
+            }
+
+            FontData[] scalableFonts = display.getFontList(fd.getName(), true);
+            if (scalableFonts.length > 0) {
+                return fd;
+            }
+        }
+
+        //None of the provided datas are valid. Return the
+        //first one as it is at least the first choice.
+        if (fonts.length > 0) {
+            return fonts[0];
+        }
+
+        //Nothing specified
+        return null;
+    }
+
+    /**
+     * Find the first valid fontData in the provided list.
+     * If none are valid return the first one regardless.
+     * If the list is empty return <code>null</code>.
+     *
+     * @param fonts list of fonts
+     * @param display the display
+     * @return font data like described above
+     * @deprecated use filterData in order to preserve
+     * multiple entry fonts on Motif
+     */
+    public FontData[] bestDataArray(FontData[] fonts, Display display) {
+
+        FontData bestData = bestData(fonts, display);
+        if (bestData is null) {
+            return null;
+        }
+
+        FontData[] datas = new FontData[1];
+        datas[0] = bestData;
+        return datas;
+    }
+
+    /**
+     * Removes from the list all fonts that do not exist in this system.
+     * If none are valid, return the first irregardless.  If the list is
+     * empty return <code>null</code>.
+     *
+     * @param fonts the fonts to check
+     * @param display the display to check against
+     * @return the list of fonts that have been found on this system
+     * @since 3.1
+     */
+    public FontData [] filterData(FontData [] fonts, Display display) {
+        ArraySeq!(FontData) good = new ArraySeq!(FontData);
+        good.capacity(fonts.length);
+        for (int i = 0; i < fonts.length; i++) {
+            FontData fd = fonts[i];
+
+            if (fd is null) {
+                continue;
+            }
+
+            FontData[] fixedFonts = display.getFontList(fd.getName(), false);
+            if (isFixedFont(fixedFonts, fd)) {
+                good.append(fd);
+            }
+
+            FontData[] scalableFonts = display.getFontList(fd.getName(), true);
+            if (scalableFonts.length > 0) {
+                good.append(fd);
+            }
+        }
+
+
+        //None of the provided datas are valid. Return the
+        //first one as it is at least the first choice.
+        if (good.drained() && fonts.length > 0) {
+            good.append(fonts[0]);
+        }
+        else if (fonts.length is 0) {
+            return null;
+        }
+
+        return good.toArray();
+    }
+
+
+    /**
+     * Creates a new font with the given font datas or <code>null</code>
+     * if there is no data.
+     * @return FontRecord for the new Font or <code>null</code>.
+     */
+    private FontRecord createFont(String symbolicName, FontData[] fonts) {
+        Display display = Display.getCurrent();
+        if (display is null) {
+            return null;
+        }
+
+        FontData[] validData = filterData(fonts, display);
+        if (validData.length is 0) {
+            //Nothing specified
+            return null;
+        }
+
+        //Do not fire the update from creation as it is not a property change
+        put(symbolicName, validData, false);
+        Font newFont = new Font(display, validData);
+        return new FontRecord(newFont, validData);
+    }
+
+    /**
+     * Calculates the default font and returns the result.
+     * This method creates a font that must be disposed.
+     */
+    Font calculateDefaultFont() {
+        Display current = Display.getCurrent();
+        if (current is null) {
+            Shell shell = new Shell();
+            Font font = new Font(null, shell.getFont().getFontData());
+            shell.dispose();
+            return font;
+        }
+        return new Font(current, current.getSystemFont().getFontData());
+    }
+
+    /**
+     * Returns the default font data.  Creates it if necessary.
+     * @return Font
+     */
+    public Font defaultFont() {
+        return defaultFontRecord().getBaseFont();
+    }
+
+    /**
+     * Returns the font descriptor for the font with the given symbolic
+     * font name. Returns the default font if there is no special value
+     * associated with that name
+     *
+     * @param symbolicName symbolic font name
+     * @return the font descriptor (never null)
+     *
+     * @since 3.3
+     */
+    public FontDescriptor getDescriptor(String symbolicName) {
+        Assert.isTrue(symbolicName.length > 0);
+        return FontDescriptor.createFrom(getFontData(symbolicName));
+    }
+
+
+
+    /**
+     * Returns the default font record.
+     */
+    private FontRecord defaultFontRecord() {
+
+        FontRecord record = cast(FontRecord) stringToFontRecord
+                .get(JFaceResources.DEFAULT_FONT);
+        if (record is null) {
+            Font defaultFont = calculateDefaultFont();
+            record = createFont(JFaceResources.DEFAULT_FONT, defaultFont
+                    .getFontData());
+            defaultFont.dispose();
+            stringToFontRecord.add(JFaceResources.DEFAULT_FONT, record);
+        }
+        return record;
+    }
+
+    /**
+     * Returns the default font data.  Creates it if necessary.
+     */
+    private FontData[] defaultFontData() {
+        return defaultFontRecord().baseData;
+    }
+
+    /**
+     * Returns the font data associated with the given symbolic font name.
+     * Returns the default font data if there is no special value associated
+     * with that name.
+     *
+     * @param symbolicName symbolic font name
+     * @return the font
+     */
+    public FontData[] getFontData(String symbolicName) {
+
+        Assert.isTrue(symbolicName.length > 0);
+        auto result = stringToFontData.get(symbolicName);
+        if (result.length is 0) {
+            return defaultFontData();
+        }
+
+        return result;
+    }
+
+    /**
+     * Returns the font associated with the given symbolic font name.
+     * Returns the default font if there is no special value associated
+     * with that name.
+     *
+     * @param symbolicName symbolic font name
+     * @return the font
+     */
+    public Font get(String symbolicName) {
+
+        return getFontRecord(symbolicName).getBaseFont();
+    }
+
+    /**
+     * Returns the bold font associated with the given symbolic font name.
+     * Returns the bolded default font if there is no special value associated
+     * with that name.
+     *
+     * @param symbolicName symbolic font name
+     * @return the font
+     * @since 3.0
+     */
+    public Font getBold(String symbolicName) {
+
+        return getFontRecord(symbolicName).getBoldFont();
+    }
+
+    /**
+     * Returns the italic font associated with the given symbolic font name.
+     * Returns the italic default font if there is no special value associated
+     * with that name.
+     *
+     * @param symbolicName symbolic font name
+     * @return the font
+     * @since 3.0
+     */
+    public Font getItalic(String symbolicName) {
+
+        return getFontRecord(symbolicName).getItalicFont();
+    }
+
+    /**
+     * Return the font record for the key.
+     * @param symbolicName The key for the record.
+     * @return FontRecird
+     */
+    private FontRecord getFontRecord(String symbolicName) {
+        Assert.isNotNull(symbolicName);
+        Object result1 = stringToFontRecord.get(symbolicName);
+        if (result1 !is null) {
+            return cast(FontRecord) result1;
+        }
+
+        auto result = stringToFontData.get(symbolicName);
+
+        FontRecord fontRecord;
+
+        if (result is null) {
+            fontRecord = defaultFontRecord();
+        } else {
+            fontRecord = createFont(symbolicName, result);
+        }
+
+        if (fontRecord is null) {
+            fontRecord = defaultFontRecord();
+        }
+
+        stringToFontRecord.add(symbolicName, fontRecord);
+        return fontRecord;
+
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.ResourceRegistry#getKeySet()
+     */
+    public SetView!(String) getKeySet() {
+        auto res = new HashSet!(String);
+        foreach( k, v; stringToFontData ){
+            res.add( k );
+        }
+        return res;
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.ResourceRegistry#hasValueFor(java.lang.String)
+     */
+    public bool hasValueFor(String fontKey) {
+        return stringToFontData.containsKey(fontKey);
+    }
+
+    /* (non-Javadoc)
+     * @see dwtx.jface.resource.ResourceRegistry#clearCaches()
+     */
+    protected void clearCaches() {
+        foreach( k,v; stringToFontRecord ){
+            v.dispose();
+        }
+
+        disposeFonts(staleFonts);
+        stringToFontRecord.clear();
+        staleFonts.clear();
+    }
+
+    /**
+     * Dispose of all of the fonts in this iterator.
+     * @param iterator over Collection of Font
+     */
+    private void disposeFonts( Seq!(Font) list ) {
+        foreach( fnt; list ){
+            fnt.dispose();
+        }
+    }
+
+    /**
+     * Hook a dispose listener on the DWT display.
+     */
+    private void hookDisplayDispose(Display display) {
+        display.disposeExec(displayRunnable);
+    }
+
+    /**
+     * Checks whether the given font is in the list of fixed fonts.
+     */
+    private bool isFixedFont(FontData[] fixedFonts, FontData fd) {
+        // Can't use FontData.equals() since some values aren't
+        // set if a fontdata isn't used.
+        int height = fd.getHeight();
+        String name = fd.getName();
+        for (int i = 0; i < fixedFonts.length; i++) {
+            FontData fixed = fixedFonts[i];
+            if (fixed.getHeight() is height && fixed.getName().equals(name)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Converts a String into a FontData object.
+     */
+    private FontData makeFontData(String value) {
+        try {
+            return StringConverter.asFontData(value.trim());
+        } catch (DataFormatException e) {
+            throw new MissingResourceException(
+                    "Wrong font data format. Value is: \"" ~ value ~ "\"", this.classinfo.name, value); //$NON-NLS-2$//$NON-NLS-1$
+        }
+    }
+
+    /**
+     * Adds (or replaces) a font to this font registry under the given
+     * symbolic name.
+     * <p>
+     * A property change event is reported whenever the mapping from
+     * a symbolic name to a font changes. The source of the event is
+     * this registry; the property name is the symbolic font name.
+     * </p>
+     *
+     * @param symbolicName the symbolic font name
+     * @param fontData an Array of FontData
+     */
+    public void put(String symbolicName, FontData[] fontData) {
+        put(symbolicName, fontData, true);
+    }
+
+    /**
+     * Adds (or replaces) a font to this font registry under the given
+     * symbolic name.
+     * <p>
+     * A property change event is reported whenever the mapping from
+     * a symbolic name to a font changes. The source of the event is
+     * this registry; the property name is the symbolic font name.
+     * </p>
+     *
+     * @param symbolicName the symbolic font name
+     * @param fontData an Array of FontData
+     * @param update - fire a font mapping changed if true. False
+     *  if this method is called from the get method as no setting
+     *  has changed.
+     */
+    private void put(String symbolicName, FontData[] fontData, bool update) {
+
+        Assert.isNotNull(symbolicName);
+        Assert.isTrue(fontData.length > 0 );
+
+        FontData[] existing = stringToFontData.get(symbolicName);
+        if (ArrayEquals(existing, fontData)) {
+            return;
+        }
+
+        FontRecord oldFont = stringToFontRecord.get(symbolicName);
+        stringToFontRecord.removeKey(symbolicName);
+        stringToFontData.add(symbolicName, fontData);
+        if (update) {
+            fireMappingChanged(symbolicName, new ArrayWrapperT!(FontData)(existing), new ArrayWrapperT!(FontData)(fontData));
+        }
+
+        if (oldFont !is null) {
+            oldFont.addAllocatedFontsToStale(defaultFontRecord().getBaseFont());
+        }
+    }
+
+    /**
+     * Reads the resource bundle.  This puts FontData[] objects
+     * in the mapping table.  These will lazily be turned into
+     * real Font objects when requested.
+     */
+    private void readResourceBundle(ResourceBundle bundle, String bundleName) {
+        foreach( key; bundle.getKeys() ){
+            int pos = key.lastIndexOf('.');
+            if (pos is -1) {
+                stringToFontData.add(key, [ makeFontData(bundle.getString(key)) ]);
+            } else {
+                String name = key.substring(0, pos);
+                int i = 0;
+                try {
+                    i = tango.text.convert.Integer.toInt(key.substring(pos + 1));
+                } catch (IllegalArgumentException e) {
+                    //Panic the file can not be parsed.
+                    throw new MissingResourceException(
+                            "Wrong key format ", bundleName, key); //$NON-NLS-1$
+                }
+                FontData[] elements = stringToFontData.get(name);
+                if (elements is null) {
+                    elements = new FontData[8];
+                    stringToFontData.add(name, elements);
+                }
+                if (i > elements.length) {
+                    FontData[] na = new FontData[i + 8];
+                    System.arraycopy(elements, 0, na, 0, elements.length);
+                    elements = na;
+                    stringToFontData.add(name, elements);
+                }
+                elements[i] = makeFontData(bundle.getString(key));
+            }
+        }
+    }
+
+    /**
+     * Returns the font descriptor for the JFace default font.
+     *
+     * @return the font descriptor for the JFace default font
+     * @since 3.3
+     */
+    public FontDescriptor defaultFontDescriptor() {
+        return FontDescriptor.createFrom(defaultFontData());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/JFaceResources.d	Fri Mar 28 23:32:40 2008 +0100
@@ -0,0 +1,589 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.resource.JFaceResources;
+
+import dwtx.jface.resource.FontRegistry;
+
+import dwt.dwthelper.utils;
+public class JFaceResources {
+    public static const String DEFAULT_FONT = "dwtx.jface.defaultfont"; //$NON-NLS-1$
+    public static FontRegistry getFontRegistry() ;
+    public static String getString(String key) ;
+}
+/++
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+import dwt.graphics.Font;
+import dwt.graphics.Image;
+import dwt.widgets.Display;
+import dwtx.core.runtime.Assert;
+import dwtx.jface.dialogs.Dialog;
+import dwtx.jface.dialogs.TitleAreaDialog;
+import dwtx.jface.preference.PreferenceDialog;
+import dwtx.jface.wizard.Wizard;
+
+/**
+ * Utility methods to access JFace-specific resources.
+ * <p>
+ * All methods declared on this class are static. This class cannot be
+ * instantiated.
+ * </p>
+ * <p>
+ * The following global state is also maintained by this class:
+ * <ul>
+ * <li>a font registry</li>
+ * <li>a color registry</li>
+ * <li>an image registry</li>
+ * <li>a resource bundle</li>
+ * </ul>
+ * </p>
+ */
+public class JFaceResources {
+
+    /**
+     * The path to the icons in the resources.
+     */
+    private final static String ICONS_PATH = "$nl$/icons/full/";//$NON-NLS-1$
+
+    /**
+     * Map of Display onto DeviceResourceManager. Holds all the resources for
+     * the associated display.
+     */
+    private static final Map registries = new HashMap();
+
+    /**
+     * The symbolic font name for the banner font (value
+     * <code>"dwtx.jface.bannerfont"</code>).
+     */
+    public static final String BANNER_FONT = "dwtx.jface.bannerfont"; //$NON-NLS-1$
+
+    /**
+     * The JFace resource bundle; eagerly initialized.
+     */
+    private static final ResourceBundle bundle = ResourceBundle
+            .getBundle("dwtx.jface.messages"); //$NON-NLS-1$
+
+    /**
+     * The JFace color registry; <code>null</code> until lazily initialized or
+     * explicitly set.
+     */
+    private static ColorRegistry colorRegistry;
+
+    /**
+     * The symbolic font name for the standard font (value
+     * <code>"dwtx.jface.defaultfont"</code>).
+     */
+    public static final String DEFAULT_FONT = "dwtx.jface.defaultfont"; //$NON-NLS-1$
+
+    /**
+     * The symbolic font name for the dialog font (value
+     * <code>"dwtx.jface.dialogfont"</code>).
+     */
+    public static final String DIALOG_FONT = "dwtx.jface.dialogfont"; //$NON-NLS-1$
+
+    /**
+     * The JFace font registry; <code>null</code> until lazily initialized or
+     * explicitly set.
+     */
+    private static FontRegistry fontRegistry = null;
+
+    /**
+     * The symbolic font name for the header font (value
+     * <code>"dwtx.jface.headerfont"</code>).
+     */
+    public static final String HEADER_FONT = "dwtx.jface.headerfont"; //$NON-NLS-1$
+
+    /**
+     * The JFace image registry; <code>null</code> until lazily initialized.
+     */
+    private static ImageRegistry imageRegistry = null;
+
+    /**
+     * The symbolic font name for the text font (value
+     * <code>"dwtx.jface.textfont"</code>).
+     */
+    public static final String TEXT_FONT = "dwtx.jface.textfont"; //$NON-NLS-1$
+
+    /**
+     * The symbolic font name for the viewer font (value
+     * <code>"dwtx.jface.viewerfont"</code>).
+     *
+     * @deprecated This font is not in use
+     */
+    public static final String VIEWER_FONT = "dwtx.jface.viewerfont"; //$NON-NLS-1$
+
+    /**
+     * The symbolic font name for the window font (value
+     * <code>"dwtx.jface.windowfont"</code>).
+     *
+     * @deprecated This font is not in use
+     */
+    public static final String WINDOW_FONT = "dwtx.jface.windowfont"; //$NON-NLS-1$
+
+    /**
+     * Returns the formatted message for the given key in JFace's resource
+     * bundle.
+     *
+     * @param key
+     *            the resource name
+     * @param args
+     *            the message arguments
+     * @return the string
+     */
+    public static String format(String key, Object[] args) {
+        return MessageFormat.format(getString(key), args);
+    }
+
+    /**
+     * Returns the JFace's banner font. Convenience method equivalent to
+     *
+     * <pre>
+     * JFaceResources.getFontRegistry().get(JFaceResources.BANNER_FONT)
+     * </pre>
+     *
+     * @return the font
+     */
+    public static Font getBannerFont() {
+        return getFontRegistry().get(BANNER_FONT);
+    }
+
+    /**
+     * Returns the resource bundle for JFace itself. The resouble bundle is
+     * obtained from
+     * <code>ResourceBundle.getBundle("dwtx.jface.jface_nls")</code>.
+     * <p>
+     * Note that several static convenience methods are also provided on this
+     * class for directly accessing resources in this bundle.
+     * </p>
+     *
+     * @return the resource bundle
+     */
+    public static ResourceBundle getBundle() {
+        return bundle;
+    }
+
+    /**
+     * Returns the color registry for JFace itself.
+     * <p>
+     *
+     * @return the <code>ColorRegistry</code>.
+     * @since 3.0
+     */
+    public static ColorRegistry getColorRegistry() {
+        if (colorRegistry is null) {
+            colorRegistry = new ColorRegistry();
+        }
+        return colorRegistry;
+    }
+
+    /**
+     * Returns the global resource manager for the given display
+     *
+     * @since 3.1
+     *
+     * @param toQuery
+     *            display to query
+     * @return the global resource manager for the given display
+     */
+    public static ResourceManager getResources(final Display toQuery) {
+        ResourceManager reg = (ResourceManager) registries.get(toQuery);
+
+        if (reg is null) {
+            final DeviceResourceManager mgr = new DeviceResourceManager(toQuery);
+            reg = mgr;
+            registries.put(toQuery, reg);
+            toQuery.disposeExec(new Runnable() {
+                /*
+                 * (non-Javadoc)
+                 *
+                 * @see java.lang.Runnable#run()
+                 */
+                public void run() {
+                    mgr.dispose();
+                    registries.remove(toQuery);
+                }
+            });
+        }
+
+        return reg;
+    }
+
+    /**
+     * Returns the ResourceManager for the current display. May only be called
+     * from a UI thread.
+     *
+     * @since 3.1
+     *
+     * @return the global ResourceManager for the current display
+     */
+    public static ResourceManager getResources() {
+        return getResources(Display.getCurrent());
+    }
+
+    /**
+     * Returns JFace's standard font. Convenience method equivalent to
+     *
+     * <pre>
+     * JFaceResources.getFontRegistry().get(JFaceResources.DEFAULT_FONT)
+     * </pre>
+     *
+     * @return the font
+     */
+    public static Font getDefaultFont() {
+        return getFontRegistry().defaultFont();
+    }
+
+    /**
+     * Returns the descriptor for JFace's standard font. Convenience method
+     * equivalent to
+     *
+     * <pre>
+     * JFaceResources.getFontRegistry().getDescriptor(JFaceResources.DEFAULT_FONT)
+     * </pre>
+     *
+     * @return the font
+     * @since 3.3
+     */
+    public static FontDescriptor getDefaultFontDescriptor() {
+        return getFontRegistry().defaultFontDescriptor();
+    }
+
+    /**
+     * Returns the JFace's dialog font. Convenience method equivalent to
+     *
+     * <pre>
+     * JFaceResources.getFontRegistry().get(JFaceResources.DIALOG_FONT)
+     * </pre>
+     *
+     * @return the font
+     */
+    public static Font getDialogFont() {
+        return getFontRegistry().get(DIALOG_FONT);
+    }
+
+    /**
+     * Returns the descriptor for JFace's dialog font. Convenience method
+     * equivalent to
+     *
+     * <pre>
+     * JFaceResources.getFontRegistry().getDescriptor(JFaceResources.DIALOG_FONT)
+     * </pre>
+     *
+     * @return the font
+     * @since 3.3
+     */
+    public static FontDescriptor getDialogFontDescriptor() {
+        return getFontRegistry().getDescriptor(DIALOG_FONT);
+    }
+
+    /**
+     * Returns the font in JFace's font registry with the given symbolic font
+     * name. Convenience method equivalent to
+     *
+     * <pre>
+     * JFaceResources.getFontRegistry().get(symbolicName)
+     * </pre>
+     *
+     * If an error occurs, return the default font.
+     *
+     * @param symbolicName
+     *            the symbolic font name
+     * @return the font
+     */
+    public static Font getFont(String symbolicName) {
+        return getFontRegistry().get(symbolicName);
+    }
+
+    /**
+     * Returns the font descriptor for in JFace's font registry with the given
+     * symbolic name. Convenience method equivalent to
+     *
+     * <pre>
+     * JFaceResources.getFontRegistry().getDescriptor(symbolicName)
+     * </pre>
+     *
+     * If an error occurs, return the default font.
+     *
+     * @param symbolicName
+     *            the symbolic font name
+     * @return the font descriptor (never null)
+     * @since 3.3
+     */
+    public static FontDescriptor getFontDescriptor(String symbolicName) {
+        return getFontRegistry().getDescriptor(symbolicName);
+    }
+
+    /**
+     * Returns the font registry for JFace itself. If the value has not been
+     * established by an earlier call to <code>setFontRegistry</code>, is it
+     * initialized to
+     * <code>new FontRegistry("dwtx.jface.resource.jfacefonts")</code>.
+     * <p>
+     * Note that several static convenience methods are also provided on this
+     * class for directly accessing JFace's standard fonts.
+     * </p>
+     *
+     * @return the JFace font registry
+     */
+    public static FontRegistry getFontRegistry() {
+        if (fontRegistry is null) {
+            fontRegistry = new FontRegistry(
+                    "dwtx.jface.resource.jfacefonts"); //$NON-NLS-1$
+        }
+        return fontRegistry;
+    }
+
+    /**
+     * Returns the JFace's header font. Convenience method equivalent to
+     *
+     * <pre>
+     * JFaceResources.getFontRegistry().get(JFaceResources.HEADER_FONT)
+     * </pre>
+     *
+     * @return the font
+     */
+    public static Font getHeaderFont() {
+        return getFontRegistry().get(HEADER_FONT);
+    }
+
+    /**
+     * Returns the descriptor for JFace's header font. Convenience method
+     * equivalent to
+     *
+     * <pre>
+     * JFaceResources.getFontRegistry().get(JFaceResources.HEADER_FONT)
+     * </pre>
+     *
+     * @return the font descriptor (never null)
+     * @since 3.3
+     */
+    public static FontDescriptor getHeaderFontDescriptor() {
+        return getFontRegistry().getDescriptor(HEADER_FONT);
+    }
+
+    /**
+     * Returns the image in JFace's image registry with the given key, or
+     * <code>null</code> if none. Convenience method equivalent to
+     *
+     * <pre>
+     * JFaceResources.getImageRegistry().get(key)
+     * </pre>
+     *
+     * @param key
+     *            the key
+     * @return the image, or <code>null</code> if none
+     */
+    public static Image getImage(String key) {
+        return getImageRegistry().get(key);
+    }
+
+    /**
+     * Returns the image registry for JFace itself.
+     * <p>
+     * Note that the static convenience method <code>getImage</code> is also
+     * provided on this class.
+     * </p>
+     *
+     * @return the JFace image registry
+     */
+    public static ImageRegistry getImageRegistry() {
+        if (imageRegistry is null) {
+            imageRegistry = new ImageRegistry(
+                    getResources(Display.getCurrent()));
+            initializeDefaultImages();
+        }
+        return imageRegistry;
+    }
+
+    /**
+     * Initialize default images in JFace's image registry.
+     *
+     */
+    private static void initializeDefaultImages() {
+
+        Object bundle = null;
+        try {
+//FIXME
+//          bundle = JFaceActivator.getBundle();
+        } catch (NoClassDefFoundError exception) {
+            // Test to see if OSGI is present
+        }
+        declareImage(bundle, Wizard.DEFAULT_IMAGE, ICONS_PATH + "page.gif", //$NON-NLS-1$
+                Wizard.class, "images/page.gif"); //$NON-NLS-1$
+
+        // register default images for dialogs
+        declareImage(bundle, Dialog.DLG_IMG_MESSAGE_INFO, ICONS_PATH
+                + "message_info.gif", Dialog.class, "images/message_info.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+        declareImage(bundle, Dialog.DLG_IMG_MESSAGE_WARNING, ICONS_PATH
+                + "message_warning.gif", Dialog.class, //$NON-NLS-1$
+                "images/message_warning.gif"); //$NON-NLS-1$
+        declareImage(bundle, Dialog.DLG_IMG_MESSAGE_ERROR, ICONS_PATH
+                + "message_error.gif", Dialog.class, "images/message_error.gif");//$NON-NLS-1$ //$NON-NLS-2$
+        declareImage(bundle, Dialog.DLG_IMG_HELP, ICONS_PATH
+                + "help.gif", Dialog.class, "images/help.gif");//$NON-NLS-1$ //$NON-NLS-2$
+        declareImage(
+                bundle,
+                TitleAreaDialog.DLG_IMG_TITLE_BANNER,
+                ICONS_PATH + "title_banner.png", TitleAreaDialog.class, "images/title_banner.gif");//$NON-NLS-1$ //$NON-NLS-2$
+        declareImage(
+                bundle,
+                PreferenceDialog.PREF_DLG_TITLE_IMG,
+                ICONS_PATH + "pref_dialog_title.gif", PreferenceDialog.class, "images/pref_dialog_title.gif");//$NON-NLS-1$ //$NON-NLS-2$
+
+    }
+
+    /**
+     * Declares a JFace image given the path of the image file (relative to the
+     * JFace plug-in). This is a helper method that creates the image descriptor
+     * and passes it to the main <code>declareImage</code> method.
+     *
+     * @param bundle
+     *            the {@link Bundle} or <code>null</code> of the Bundle cannot
+     *            be found
+     * @param key
+     *            the symbolic name of the image
+     * @param path
+     *            the path of the image file relative to the base of the
+     *            workbench plug-ins install directory
+     * @param fallback
+     *            the {@link Class} where the fallback implementation of the
+     *            image is relative to
+     * @param fallbackPath
+     *            the path relative to the fallback {@link Class}
+     *
+     */
+    private static final void declareImage(Object bundle, String key,
+            String path, Class fallback, String fallbackPath) {
+
+
+        ImageDescriptor descriptor = null;
+
+        if (bundle !is null) {
+//FIXME
+//          URL url = FileLocator.find((Bundle) bundle, new Path(path), null);
+//          if (url !is null)
+//              descriptor = ImageDescriptor.createFromURL(url);
+        }
+
+        // If we failed then load from the backup file
+        if (descriptor is null)
+            descriptor = ImageDescriptor.createFromFile(fallback, fallbackPath);
+
+        imageRegistry.put(key, descriptor);
+    }
+
+    /**
+     * Returns the resource object with the given key in JFace's resource
+     * bundle. If there isn't any value under the given key, the key is
+     * returned.
+     *
+     * @param key
+     *            the resource name
+     * @return the string
+     */
+    public static String getString(String key) {
+        try {
+            return bundle.getString(key);
+        } catch (MissingResourceException e) {
+            return key;
+        }
+    }
+
+    /**
+     * Returns a list of string values corresponding to the given list of keys.
+     * The lookup is done with <code>getString</code>. The values are in the
+     * same order as the keys.
+     *
+     * @param keys
+     *            a list of keys
+     * @return a list of corresponding string values
+     */
+    public static String[] getStrings(String[] keys) {
+        Assert.isNotNull(keys);
+        int length = keys.length;
+        String[] result = new String[length];
+        for (int i = 0; i < length; i++) {
+            result[i] = getString(keys[i]);
+        }
+        return result;
+    }
+
+    /**
+     * Returns JFace's text font. Convenience method equivalent to
+     *
+     * <pre>
+     * JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT)
+     * </pre>
+     *
+     * @return the font
+     */
+    public static Font getTextFont() {
+        return getFontRegistry().get(TEXT_FONT);
+    }
+
+    /**
+     * Returns the descriptor for JFace's text font. Convenience method
+     * equivalent to
+     *
+     * <pre>
+     * JFaceResources.getFontRegistry().getDescriptor(JFaceResources.TEXT_FONT)
+     * </pre>
+     *
+     * @return the font descriptor (never null)
+     * @since 3.3
+     */
+    public static FontDescriptor getTextFontDescriptor() {
+        return getFontRegistry().getDescriptor(TEXT_FONT);
+    }
+
+    /**
+     * Returns JFace's viewer font. Convenience method equivalent to
+     *
+     * <pre>
+     * JFaceResources.getFontRegistry().get(JFaceResources.VIEWER_FONT)
+     * </pre>
+     *
+     * @return the font
+     * @deprecated This font is not in use
+     */
+    public static Font getViewerFont() {
+        return getFontRegistry().get(VIEWER_FONT);
+    }
+
+    /**
+     * Sets JFace's font registry to the given value. This method may only be
+     * called once; the call must occur before
+     * <code>JFaceResources.getFontRegistry</code> is invoked (either directly
+     * or indirectly).
+     *
+     * @param registry
+     *            a font registry
+     */
+    public static void setFontRegistry(FontRegistry registry) {
+        Assert.isTrue(fontRegistry is null,
+                "Font registry can only be set once."); //$NON-NLS-1$
+        fontRegistry = registry;
+    }
+
+    /*
+     * (non-Javadoc) Declare a private constructor to block instantiation.
+     */
+    private JFaceResources() {
+        // no-op
+    }
+}
+++/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/ResourceRegistry.d	Fri Mar 28 23:32:40 2008 +0100
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2005 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.resource.ResourceRegistry;
+
+import tango.util.collection.model.SetView;
+
+import dwtx.core.commands.common.EventManager;
+import dwtx.jface.util.IPropertyChangeListener;
+import dwtx.jface.util.PropertyChangeEvent;
+
+import dwt.dwthelper.utils;
+
+/**
+ * Abstract base class for various JFace registries.
+ *
+ * @since 3.0
+ */
+public abstract class ResourceRegistry : EventManager {
+
+    /**
+     * Adds a property change listener to this registry.
+     *
+     * @param listener a property change listener
+     */
+    public void addListener(IPropertyChangeListener listener) {
+        addListenerObject(cast(Object)listener);
+    }
+
+    /**
+     * Disposes all currently allocated resources.
+     */
+    protected abstract void clearCaches();
+
+    /**
+     * @return the set of keys this manager knows about.  This collection
+     * should be immutable.
+     */
+    public abstract SetView!(String) getKeySet();
+
+    /**
+     * Return whether or not the receiver has a value for the supplied key.
+     *
+     * @param key the key
+     * @return <code>true</code> if there is a value for this key
+     */
+    public abstract bool hasValueFor(String key);
+
+    /**
+     * Fires a <code>PropertyChangeEvent</code>.
+     *
+     * @param name the name of the symbolic value that is changing.
+     * @param oldValue the old value.
+     * @param newValue the new value.
+     */
+    protected void fireMappingChanged(String name, Object oldValue,
+            Object newValue) {
+        Object[] myListeners = getListeners();
+        if (myListeners.length > 0) {
+            PropertyChangeEvent event = new PropertyChangeEvent(this, name,
+                    oldValue, newValue);
+            for (int i = 0; i < myListeners.length; ++i) {
+                try {
+                    (cast(IPropertyChangeListener) myListeners[i])
+                            .propertyChange(event);
+                } catch (Exception e) {
+                    // TODO: how to log?
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes the given listener from this registry. Has no affect if the
+     * listener is not registered.
+     *
+     * @param listener a property change listener
+     */
+    public void removeListener(IPropertyChangeListener listener) {
+        removeListenerObject(cast(Object)listener);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/resource/StringConverter.d	Fri Mar 28 23:32:40 2008 +0100
@@ -0,0 +1,889 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.resource.StringConverter;
+
+import dwtx.jface.resource.JFaceResources;
+import dwtx.jface.resource.DataFormatException;
+
+import tango.util.collection.ArraySeq;
+
+import dwt.DWT;
+import dwt.graphics.FontData;
+import dwt.graphics.Point;
+import dwt.graphics.RGB;
+import dwt.graphics.Rectangle;
+import dwtx.core.runtime.Assert;
+
+import dwt.dwthelper.utils;
+static import tango.text.Util;
+static import tango.text.convert.Float;
+static import tango.text.convert.Integer;
+static import tango.text.Text;
+alias tango.text.Text.Text!(char) StringBuffer;
+
+/**
+ * Helper class for converting various data types to and from
+ * strings. Supported types include:
+ * <ul>
+ *   <li><code>bool</code></li>
+ *   <li><code>int</code></li>
+ *   <li><code>long</code></li>
+ *   <li><code>float</code></li>
+ *   <li><code>double</code></li>
+ *   <li><code>dwt.graphics.Point</code></li>
+ *   <li><code>dwt.graphics.Rectangle</code></li>
+ *   <li><code>dwt.graphics.RGB</code></li>
+ *   <li><code>dwt.graphics.FontData</code></li>
+ * </ul>
+ * <p>
+ * All methods declared on this class are static. This
+ * class cannot be instantiated.
+ * </p>
+ */
+public class StringConverter {
+
+    /**
+     * Internal font style constant for regular fonts.
+     */
+    private static const String REGULAR = "regular"; //$NON-NLS-1$
+
+    /**
+     * Internal font style constant for bold fonts.
+     */
+    private static const String BOLD = "bold"; //$NON-NLS-1$
+
+    /**
+     * Internal font style constant for italic fonts.
+     */
+    private static const String ITALIC = "italic"; //$NON-NLS-1$
+
+    /**
+     * Internal font style constant for bold italic fonts.
+     */
+    private static const String BOLD_ITALIC = "bold italic"; //$NON-NLS-1$
+
+    /**
+     * Internal constant for the separator character used in
+     * font specifications.
+     */
+    private static const char SEPARATOR = '-';
+
+    /**
+     * Internal constant for the seperator character used in font list
+     * specifications.
+     */
+    private static const String FONT_SEPARATOR = ";"; //$NON-NLS-1$
+
+    /* (non-Javadoc)
+     * Declare a private constructor to block instantiation.
+     */
+    private this() {
+        //no-op
+    }
+
+    /**
+     * Breaks out space-separated words into an array of words.
+     * For example: <code>"no comment"</code> into an array
+     * <code>a[0]="no"</code> and <code>a[1]= "comment"</code>.
+     *
+     * @param value the string to be converted
+     * @return the list of words
+     * @throws DataFormatException thrown if request string could not seperated
+     */
+    public static String[] asArray(String value) {
+        ArraySeq!(String) list = new ArraySeq!(String);
+        foreach ( s; tango.text.Util.delimit( value, " \t\n\r\f" )) {
+            list.append(s);
+        }
+        return list.toArray();
+    }
+
+    /**
+     /**
+     * Breaks out space-separated words into an array of words.
+     * For example: <code>"no comment"</code> into an array
+     * <code>a[0]="no"</code> and <code>a[1]= "comment"</code>.
+     * Returns the given default value if the value cannot be parsed.
+     *
+     * @param value the string to be converted
+     * @param dflt the default value
+     * @return the list of words, or the default value
+     */
+    public static String[] asArray(String value, String[] dflt) {
+        try {
+            return asArray(value);
+        } catch (DataFormatException e) {
+            return dflt;
+        }
+    }
+
+    /**
+     * Converts the given value into a bool.
+     * This method fails if the value does not represent a bool.
+     * <p>
+     * Valid representations of <code>true</code> include the strings
+     * "<code>t</code>", "<code>true</code>", or equivalent in mixed
+     * or upper case.
+     * Similarly, valid representations of <code>false</code> include the strings
+     * "<code>f</code>", "<code>false</code>", or equivalent in mixed
+     * or upper case.
+     * </p>
+     *
+     * @param value the value to be converted
+     * @return the value as a bool
+     * @exception DataFormatException if the given value does not represent
+     *  a bool
+     */
+    public static bool asBoolean(String value) {
+        String v = value.toLowerCase();
+        if (v.equals("t") || v.equals("true")) { //$NON-NLS-1$ //$NON-NLS-2$
+            return true;
+        }
+        if (value.equals("f") || v.equals("false")) { //$NON-NLS-1$ //$NON-NLS-2$
+            return false;
+        }
+        throw new DataFormatException(
+                "Value " ~ value ~ "doesn't represent a bool"); //$NON-NLS-2$//$NON-NLS-1$
+    }
+
+    /**
+     * Converts the given value into a bool.
+     * Returns the given default value if the
+     * value does not represent a bool.
+     *
+     * @param value the value to be converted
+     * @param dflt the default value
+     * @return the value as a bool, or the default value
+     */
+    public static bool asBoolean(String value, bool dflt) {
+        try {
+            return asBoolean(value);
+        } catch (DataFormatException e) {
+            return dflt;
+        }
+    }
+
+    /**
+     * Converts the given value into a double.
+     * This method fails if the value does not represent a double.
+     *
+     * @param value the value to be converted
+     * @return the value as a double
+     * @exception DataFormatException if the given value does not represent
+     *  a double
+     */
+    public static double asDouble(String value) {
+        try {
+            return tango.text.convert.Float.toFloat(value);
+        } catch (IllegalArgumentException e) {
+            throw new DataFormatException(e.msg);
+        }
+    }
+
+    /**
+     * Converts the given value into a double.
+     * Returns the given default value if the
+     * value does not represent a double.
+     *
+     * @param value the value to be converted
+     * @param dflt the default value
+     * @return the value as a double, or the default value
+     */
+    public static double asDouble(String value, double dflt) {
+        try {
+            return tango.text.convert.Float.toFloat(value);
+        } catch (IllegalArgumentException e) {
+            return dflt;
+        }
+    }
+
+    /**
+     * Converts the given value into a float.
+     * This method fails if the value does not represent a float.
+     *
+     * @param value the value to be converted
+     * @return the value as a float
+     * @exception DataFormatException if the given value does not represent
+     *  a float
+     */
+    public static float asFloat(String value) {
+        try {
+            return tango.text.convert.Float.toFloat(value);
+        } catch (IllegalArgumentException e) {
+            throw new DataFormatException(e.msg);
+        }
+    }
+
+    /**
+     * Converts the given value into a float.
+     * Returns the given default value if the
+     * value does not represent a float.
+     *
+     * @param value the value to be converted
+     * @param dflt the default value
+     * @return the value as a float, or the default value
+     */
+    public static float asFloat(String value, float dflt) {
+        try {
+            return tango.text.convert.Float.toFloat(value);
+        } catch (IllegalArgumentException e) {
+            return dflt;
+        }
+    }
+
+    /**
+     * Converts the given value into an DWT font data object.
+     * This method fails if the value does not represent font data.
+     * <p>
+     * A valid font data representation is a string of the form
+     * <code><it>fontname</it>-<it>style</it>-<it>height</it></code> where
+     * <code><it>fontname</it></code> is the name of a font,
+     * <code><it>style</it></code> is a font style (one of
+     * <code>"regular"</code>, <code>"bold"</code>,
+     * <code>"italic"</code>, or <code>"bold italic"</code>)
+     * and <code><it>height</it></code> is an integer representing the
+     * font height. Example: <code>Times New Roman-bold-36</code>.
+     * </p>
+     *
+     * @param value the value to be converted
+     * @return the value as font data
+     * @exception DataFormatException if the given value does not represent
+     *  font data
+     */
+    public static FontData asFontData(String value) {
+        if (value is null) {
+            throw new DataFormatException(
+                    "Null doesn't represent a valid font data"); //$NON-NLS-1$
+        }
+        String name = null;
+        int height = 0;
+        int style = 0;
+        try {
+            int length = value.length;
+            int heightIndex = value.lastIndexOf(SEPARATOR);
+            if (heightIndex is -1) {
+                throw new DataFormatException(
+                        "No correct font data format \"" ~ value ~ "\""); //$NON-NLS-2$//$NON-NLS-1$
+            }
+            height = StringConverter.asInt(value.substring(heightIndex + 1,
+                    length));
+            int faceIndex = value.lastIndexOf(SEPARATOR, heightIndex - 1);
+            if (faceIndex is -1) {
+                throw new DataFormatException(
+                        "No correct font data format \"" ~ value ~ "\""); //$NON-NLS-2$//$NON-NLS-1$
+            }
+            String s = value.substring(faceIndex + 1, heightIndex);
+            if (BOLD_ITALIC.equals(s)) {
+                style = DWT.BOLD | DWT.ITALIC;
+            } else if (BOLD.equals(s)) {
+                style = DWT.BOLD;
+            } else if (ITALIC.equals(s)) {
+                style = DWT.ITALIC;
+            } else if (REGULAR.equals(s)) {
+                style = DWT.NORMAL;
+            } else {
+                throw new DataFormatException("Unknown face name \"" ~ s ~ "\""); //$NON-NLS-2$//$NON-NLS-1$
+            }
+            name = value.substring(0, faceIndex);
+        } catch (/+NoSuchElement+/Exception e) {
+            throw new DataFormatException(e.msg);
+        }
+        return new FontData(name, height, style);
+    }
+
+    /**
+     * Returns the result of converting a list of comma-separated tokens into an array
+     *
+     * @return the array of string tokens
+     * @param prop the initial comma-separated string
+     */
+    private static String[] getArrayFromList(String prop, String separator) {
+        if (prop is null || prop.trim().equals("")) { //$NON-NLS-1$
+            return new String[0];
+        }
+        ArraySeq!(String) list = new ArraySeq!(String);
+        foreach ( s; tango.text.Util.delimit( prop, separator )) {
+            String token = s.trim();
+            if (!token.equals("")) { //$NON-NLS-1$
+                list.append(token);
+            }
+        }
+        return list.drained() ? null : list.toArray();
+    }
+
+    /**
+     * Convert the given value into an array of DWT font data objects.
+     *
+     * @param value the font list string
+     * @return the value as a font list
+     * @since 3.0
+     */
+    public static FontData[] asFontDataArray(String value) {
+        String[] strings = getArrayFromList(value, FONT_SEPARATOR);
+        ArraySeq!(FontData) data = new ArraySeq!(FontData);
+        data.capacity(strings.length);
+        for (int i = 0; i < strings.length; i++) {
+            try {
+                data.append(StringConverter.asFontData(strings[i]));
+            } catch (DataFormatException e) {
+                //do-nothing
+            }
+        }
+        return data.toArray();
+    }
+
+    /**
+     * Converts the given value into an DWT font data object.
+     * Returns the given default value if the
+     * value does not represent a font data object.
+     *
+     * @param value the value to be converted
+     * @param dflt the default value
+     * @return the value as a font data object, or the default value
+     */
+    public static FontData asFontData(String value, FontData dflt) {
+        try {
+            return asFontData(value);
+        } catch (DataFormatException e) {
+            return dflt;
+        }
+    }
+
+    /**
+     * Converts the given value into an int.
+     * This method fails if the value does not represent an int.
+     *
+     * @param value the value to be converted
+     * @return the value as an int
+     * @exception DataFormatException if the given value does not represent
+     *  an int
+     */
+    public static int asInt(String value) {
+        try {
+            return tango.text.convert.Integer.toInt(value);
+        } catch (IllegalArgumentException e) {
+            throw new DataFormatException(e.msg);
+        }
+    }
+
+    /**
+     * Converts the given value into an int.
+     * Returns the given default value if the
+     * value does not represent an int.
+     *
+     * @param value the value to be converted
+     * @param dflt the default value
+     * @return the value as an int, or the default value
+     */
+    public static int asInt(String value, int dflt) {
+        try {
+            return tango.text.convert.Integer.toInt(value);
+        } catch (IllegalArgumentException e) {
+            return dflt;
+        }
+    }
+
+    /**
+     * Converts the given value into a long.
+     * This method fails if the value does not represent a long.
+     *
+     * @param value the value to be converted
+     * @return the value as a long
+     * @exception DataFormatException if the given value does not represent
+     *  a long
+     */
+    public static long asLong(String value) {
+        try {
+            return tango.text.convert.Integer.toInt(value);
+        } catch (IllegalArgumentException e) {
+            throw new DataFormatException(e.msg);
+        }
+    }
+
+    /**
+     * Converts the given value into a long.
+     * Returns the given default value if the
+     * value does not represent a long.
+     *
+     * @param value the value to be converted
+     * @param dflt the default value
+     * @return the value as a long, or the default value
+     */
+    public static long asLong(String value, long dflt) {
+        try {
+            return tango.text.convert.Integer.toInt(value);
+        } catch (IllegalArgumentException e) {
+            return dflt;
+        }
+    }
+
+    /**
+     * Converts the given value into an DWT point.
+     * This method fails if the value does not represent a point.
+     * <p>
+     * A valid point representation is a string of the form
+     * <code><it>x</it>,<it>y</it></code> where
+     * <code><it>x</it></code> and <code><it>y</it></code>
+     * are valid ints.
+     * </p>
+     *
+     * @param value the value to be converted
+     * @return the value as a point
+     * @exception DataFormatException if the given value does not represent
+     *  a point
+     */
+    public static Point asPoint(String value) {
+        if (value is null) {
+            throw new DataFormatException(
+                    "Null doesn't represent a valid point"); //$NON-NLS-1$
+        }
+        auto stok = tango.text.Util.delimit( value, "," );
+        String x = stok[0];
+        String y = stok[1];
+        int xval = 0, yval = 0;
+        try {
+            xval = tango.text.convert.Integer.toInt(x);
+            yval = tango.text.convert.Integer.toInt(y);
+        } catch (IllegalArgumentException e) {
+            throw new DataFormatException(e.msg);
+        }
+        return new Point(xval, yval);
+    }
+
+    /**
+     * Converts the given value into an DWT point.
+     * Returns the given default value if the
+     * value does not represent a point.
+     *
+     * @param value the value to be converted
+     * @param dflt the default value
+     * @return the value as a point, or the default value
+     */
+    public static Point asPoint(String value, Point dflt) {
+        try {
+            return asPoint(value);
+        } catch (DataFormatException e) {
+            return dflt;
+        }
+    }
+
+    /**
+     * Converts the given value into an DWT rectangle.
+     * This method fails if the value does not represent a rectangle.
+     * <p>
+     * A valid rectangle representation is a string of the form
+     * <code><it>x</it>,<it>y</it>,<it>width</it>,<it>height</it></code>
+     * where <code><it>x</it></code>, <code><it>y</it></code>,
+     * <code><it>width</it></code>, and <code><it>height</it></code>
+     * are valid ints.
+     * </p>
+     *
+     * @param value the value to be converted
+     * @return the value as a rectangle
+     * @exception DataFormatException if the given value does not represent
+     *  a rectangle
+     */
+    public static Rectangle asRectangle(String value) {
+        if (value is null) {
+            throw new DataFormatException(
+                    "Null doesn't represent a valid rectangle"); //$NON-NLS-1$
+        }
+        auto stok = tango.text.Util.delimit( value, "," );
+        String x = stok[0];
+        String y = stok[1];
+        String width = stok[2];
+        String height = stok[3];
+        int xval = 0, yval = 0, wval = 0, hval = 0;
+        try {
+            xval = tango.text.convert.Integer.toInt(x);
+            yval = tango.text.convert.Integer.toInt(y);
+            wval = tango.text.convert.Integer.toInt(width);
+            hval = tango.text.convert.Integer.toInt(height);
+        } catch (IllegalArgumentException e) {
+            throw new DataFormatException(e.msg);
+        }
+        return new Rectangle(xval, yval, wval, hval);
+    }
+
+    /**
+     * Converts the given value into an DWT rectangle.
+     * Returns the given default value if the
+     * value does not represent a rectangle.
+     *
+     * @param value the value to be converted
+     * @param dflt the default value
+     * @return the value as a rectangle, or the default value
+     */
+    public static Rectangle asRectangle(String value, Rectangle dflt) {
+        try {
+            return asRectangle(value);
+        } catch (DataFormatException e) {
+            return dflt;
+        }
+    }
+
+    /**
+     * Converts the given value into an DWT RGB color value.
+     * This method fails if the value does not represent an RGB
+     * color value.
+     * <p>
+     * A valid RGB color value representation is a string of the form
+     * <code><it>red</it>,<it>green</it></code>,<it>blue</it></code> where
+     * <code><it>red</it></code>, <it>green</it></code>, and
+     * <code><it>blue</it></code> are valid ints.
+     * </p>
+     *
+     * @param value the value to be converted
+     * @return the value as an RGB color value
+     * @exception DataFormatException if the given value does not represent
+     *  an RGB color value
+     */
+    public static RGB asRGB(String value) {
+        if (value is null) {
+            throw new DataFormatException("Null doesn't represent a valid RGB"); //$NON-NLS-1$
+        }
+        auto stok = tango.text.Util.delimit( value, "," );
+        if( stok.length < 3 ){
+            throw new DataFormatException( "not enough values" );
+        }
+        String red = stok[0];
+        String green = stok[1];
+        String blue = stok[2];
+        int rval = 0, gval = 0, bval = 0;
+        try {
+            rval = tango.text.convert.Integer.toInt(red);
+            gval = tango.text.convert.Integer.toInt(green);
+            bval = tango.text.convert.Integer.toInt(blue);
+        } catch (IllegalArgumentException e) {
+            throw new DataFormatException(e.msg);
+        }
+        return new RGB(rval, gval, bval);
+    }
+
+    /**
+     * Converts the given value into an DWT RGB color value.
+     * Returns the given default value if the
+     * value does not represent an RGB color value.
+     *
+     * @param value the value to be converted
+     * @param dflt the default value
+     * @return the value as a RGB color value, or the default value
+     */
+    public static RGB asRGB(String value, RGB dflt) {
+        try {
+            return asRGB(value);
+        } catch (DataFormatException e) {
+            return dflt;
+        }
+    }
+
+    /**
+     * Converts the given double value to a string.
+     * Equivalent to <code>String.valueOf(value)</code>.
+     *
+     * @param value the double value
+     * @return the string representing the given double
+     */
+    public static String asString(double value) {
+        return tango.text.convert.Float.toString(value);
+    }
+
+    /**
+     * Converts the given float value to a string.
+     * Equivalent to <code>String.valueOf(value)</code>.
+     *
+     * @param value the float value
+     * @return the string representing the given float
+     */
+    public static String asString(float value) {
+        return tango.text.convert.Float.toString(value);
+    }
+
+    /**
+     * Converts the given int value to a string.
+     * Equivalent to <code>String.valueOf(value)</code>.
+     *
+     * @param value the int value
+     * @return the string representing the given int
+     */
+    public static String asString(int value) {
+        return tango.text.convert.Integer.toString(value);
+    }
+
+    /**
+     * Converts the given long value to a string.
+     * Equivalent to <code>String.valueOf(value)</code>.
+     *
+     * @param value the long value
+     * @return the string representing the given long
+     */
+    public static String asString(long value) {
+        return tango.text.convert.Integer.toString(value);
+    }
+
+//     /**
+//      * Converts the given bool object to a string.
+//      * Equivalent to <code>String.valueOf(value.booleanValue())</code>.
+//      *
+//      * @param value the bool object
+//      * @return the string representing the given bool value
+//      */
+//     public static String asString(Boolean value) {
+//         Assert.isNotNull(value);
+//         return String.valueOf(value.booleanValue());
+//     }
+//
+//     /**
+//      * Converts the given double object to a string.
+//      * Equivalent to <code>String.valueOf(value.doubleValue())</code>.
+//      *
+//      * @param value the double object
+//      * @return the string representing the given double value
+//      */
+//     public static String asString(Double value) {
+//         Assert.isNotNull(value);
+//         return String.valueOf(value.doubleValue());
+//     }
+//
+//     /**
+//      * Converts the given float object to a string.
+//      * Equivalent to <code>String.valueOf(value.floatValue())</code>.
+//      *
+//      * @param value the float object
+//      * @return the string representing the given float value
+//      */
+//     public static String asString(Float value) {
+//         Assert.isNotNull(value);
+//         return String.valueOf(value.floatValue());
+//     }
+//
+//     /**
+//      * Converts the given integer object to a string.
+//      * Equivalent to <code>String.valueOf(value.intValue())</code>.
+//      *
+//      * @param value the integer object
+//      * @return the string representing the given integer value
+//      */
+//     public static String asString(Integer value) {
+//         Assert.isNotNull(value);
+//         return String.valueOf(value.intValue());
+//     }
+//
+//     /**
+//      * Converts the given long object to a string.
+//      * Equivalent to <code>String.valueOf(value.longValue())</code>.
+//      *
+//      * @param value the long object
+//      * @return the string representing the given long value
+//      */
+//     public static String asString(Long value) {
+//         Assert.isNotNull(value);
+//         return String.valueOf(value.longValue());
+//     }
+
+    /**
+     * Converts a font data array  to a string. The string representation is
+     * that of asString(FontData) seperated by ';'
+     *
+     * @param value The font data.
+     * @return The string representation of the font data arra.
+     * @since 3.0
+     */
+    public static String asString(FontData[] value) {
+        StringBuffer buffer = new StringBuffer();
+        for (int i = 0; i < value.length; i++) {
+            buffer.append(asString(value[i]));
+            if (i !is value.length - 1) {
+                buffer.append(FONT_SEPARATOR);
+            }
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Converts a font data object to a string. The string representation is
+     * "font name-style-height" (for example "Times New Roman-bold-36").
+     * @param value The font data.
+     * @return The string representation of the font data object.
+     */
+    public static String asString(FontData value) {
+        Assert.isNotNull(value);
+        StringBuffer buffer = new StringBuffer();
+        buffer.append(value.getName());
+        buffer.append(SEPARATOR);
+        int style = value.getStyle();
+        bool bold = (style & DWT.BOLD) is DWT.BOLD;
+        bool italic = (style & DWT.ITALIC) is DWT.ITALIC;
+        if (bold && italic) {
+            buffer.append(BOLD_ITALIC);
+        } else if (bold) {
+            buffer.append(BOLD);
+        } else if (italic) {
+            buffer.append(ITALIC);
+        } else {
+            buffer.append(REGULAR);
+        }
+
+        buffer.append(SEPARATOR);
+        buffer.append(value.getHeight());
+        return buffer.toString();
+    }
+
+    /**
+     * Converts the given DWT point object to a string.
+     * <p>
+     * The string representation of a point has the form
+     * <code><it>x</it>,<it>y</it></code> where
+     * <code><it>x</it></code> and <code><it>y</it></code>
+     * are string representations of integers.
+     * </p>
+     *
+     * @param value the point object
+     * @return the string representing the given point
+     */
+    public static String asString(Point value) {
+        Assert.isNotNull(value);
+        StringBuffer buffer = new StringBuffer();
+        buffer.append(value.x);
+        buffer.append(',');
+        buffer.append(value.y);
+        return buffer.toString();
+    }
+
+    /**
+     * Converts the given DWT rectangle object to a string.
+     * <p>
+     * The string representation of a rectangle has the form
+     * <code><it>x</it>,<it>y</it>,<it>width</it>,<it>height</it></code>
+     * where <code><it>x</it></code>, <code><it>y</it></code>,
+     * <code><it>width</it></code>, and <code><it>height</it></code>
+     * are string representations of integers.
+     * </p>
+     *
+     * @param value the rectangle object
+     * @return the string representing the given rectangle
+     */
+    public static String asString(Rectangle value) {
+        Assert.isNotNull(value);
+        StringBuffer buffer = new StringBuffer();
+        buffer.append(value.x);
+        buffer.append(',');
+        buffer.append(value.y);
+        buffer.append(',');
+        buffer.append(value.width);
+        buffer.append(',');
+        buffer.append(value.height);
+        return buffer.toString();
+    }
+
+    /**
+     * Converts the given DWT RGB color value object to a string.
+     * <p>
+     * The string representation of an RGB color value has the form
+     * <code><it>red</it>,<it>green</it></code>,<it>blue</it></code> where
+     * <code><it>red</it></code>, <it>green</it></code>, and
+     * <code><it>blue</it></code> are string representations of integers.
+     * </p>
+     *
+     * @param value the RGB color value object
+     * @return the string representing the given RGB color value
+     */
+    public static String asString(RGB value) {
+        Assert.isNotNull(value);
+        StringBuffer buffer = new StringBuffer();
+        buffer.append(value.red);
+        buffer.append(',');
+        buffer.append(value.green);
+        buffer.append(',');
+        buffer.append(value.blue);
+        return buffer.toString();
+    }
+
+    /**
+     * Converts the given bool value to a string.
+     * Equivalent to <code>String.valueOf(value)</code>.
+     *
+     * @param value the bool value
+     * @return the string representing the given bool
+     */
+    public static String asString(bool value) {
+        return value ? "true" : "false";
+    }
+
+    /**
+     * Returns the given string with all whitespace characters removed.
+     * <p>
+     * All characters that have codes less than or equal to <code>'&#92;u0020'</code>
+     * (the space character) are considered to be a white space.
+     * </p>
+     *
+     * @param s the source string
+     * @return the string with all whitespace characters removed
+     */
+    public static String removeWhiteSpaces(String s) {
+        //check for no whitespace (common case)
+        bool found = false;
+        int wsIndex = -1;
+        int size = s.length;
+        for (int i = 0; i < size; i++) {
+            found = CharacterIsWhitespace( s.charAt(i) );
+            if (found) {
+                wsIndex = i;
+                break;
+            }
+        }
+        if (!found) {
+            return s;
+        }
+
+        StringBuffer result = new StringBuffer(s.substring(0, wsIndex));
+        for (int i = wsIndex + 1; i < size; i++) {
+            char ch = s.charAt(i);
+            if (!CharacterIsWhitespace(ch)) {
+                result.append(ch);
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * Converts a font data object to a string representation for display.
+     *  The string representation is
+     * "font name-style-height" (for example "Times New Roman-bold-36").
+     * @param value The font data.
+     * @return The string representation of the font data object.
+     * @deprecated use asString(FontData)
+     */
+    public static String asDisplayableString(FontData value) {
+        Assert.isNotNull(value);
+        StringBuffer buffer = new StringBuffer();
+        buffer.append(value.getName());
+        buffer.append(SEPARATOR);
+        int style = value.getStyle();
+        bool bold = (style & DWT.BOLD) is DWT.BOLD;
+        bool italic = (style & DWT.ITALIC) is DWT.ITALIC;
+        if (bold && italic) {
+            buffer.append(JFaceResources.getString("BoldItalicFont")); //$NON-NLS-1$
+        } else if (bold) {
+            buffer.append(JFaceResources.getString("BoldFont")); //$NON-NLS-1$
+        } else if (italic) {
+            buffer.append(JFaceResources.getString("ItalicFont")); //$NON-NLS-1$
+        } else {
+            buffer.append(JFaceResources.getString("RegularFont")); //$NON-NLS-1$
+        }
+        buffer.append(SEPARATOR);
+        buffer.append(value.getHeight());
+        return buffer.toString();
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/window/DefaultToolTip.d	Fri Mar 28 23:32:40 2008 +0100
@@ -0,0 +1,297 @@
+/*******************************************************************************
+ * 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.window.DefaultToolTip;
+
+import dwt.DWT;
+import dwt.custom.CLabel;
+import dwt.graphics.Color;
+import dwt.graphics.Font;
+import dwt.graphics.Image;
+import dwt.graphics.Point;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Event;
+
+import dwtx.jface.window.ToolTip;
+
+import dwt.dwthelper.utils;
+
+/**
+ * Default implementation of ToolTip that provides an iconofied label with font
+ * and color controls by subclass.
+ *
+ * @since 3.3
+ */
+public class DefaultToolTip : ToolTip {
+    private String text;
+
+    private Color backgroundColor;
+
+    private Font font;
+
+    private Image backgroundImage;
+
+    private Color foregroundColor;
+
+    private Image image;
+
+    private int style = DWT.SHADOW_NONE;
+
+    /**
+     * Create new instance which add TooltipSupport to the widget
+     *
+     * @param control the control on whose action the tooltip is shown
+     */
+    public this(Control control) {
+        super(control);
+    }
+
+    /**
+     * Create new instance which add TooltipSupport to the widget
+     *
+     * @param control the control to which the tooltip is bound
+     * @param style style passed to control tooltip behaviour
+     * @param manualActivation <code>true</code> if the activation is done manually using
+     *            {@link #show(Point)}
+     * @see #RECREATE
+     * @see #NO_RECREATE
+     */
+    public this(Control control, int style, bool manualActivation) {
+        super(control, style, manualActivation);
+    }
+
+    /**
+     * Creates the content are of the the tooltip. By default this creates a
+     * CLabel to display text. To customize the text Subclasses may override the
+     * following methods
+     * <ul>
+     * <li>{@link #getStyle(Event)}</li>
+     * <li>{@link #getBackgroundColor(Event)}</li>
+     * <li>{@link #getForegroundColor(Event)}</li>
+     * <li>{@link #getFont(Event)}</li>
+     * <li>{@link #getImage(Event)}</li>
+     * <li>{@link #getText(Event)}</li>
+     * <li>{@link #getBackgroundImage(Event)}</li>
+     * </ul>
+     *
+     * @param event
+     *            the event that triggered the activation of the tooltip
+     * @param parent
+     *            the parent of the content area
+     * @return the content area created
+     */
+    protected Composite createToolTipContentArea(Event event, Composite parent) {
+        Image image = getImage(event);
+        Image bgImage = getBackgroundImage(event);
+        String text = getText(event);
+        Color fgColor = getForegroundColor(event);
+        Color bgColor = getBackgroundColor(event);
+        Font font = getFont(event);
+
+        CLabel label = new CLabel(parent, getStyle(event));
+        if (text !is null) {
+            label.setText(text);
+        }
+
+        if (image !is null) {
+            label.setImage(image);
+        }
+
+        if (fgColor !is null) {
+            label.setForeground(fgColor);
+        }
+
+        if (bgColor !is null) {
+            label.setBackground(bgColor);
+        }
+
+        if (bgImage !is null) {
+            label.setBackgroundImage(image);
+        }
+
+        if (font !is null) {
+            label.setFont(font);
+        }
+
+        return label;
+    }
+
+    /**
+     * The style used to create the {@link CLabel} in the default implementation
+     *
+     * @param event
+     *            the event triggered the popup of the tooltip
+     * @return the style
+     */
+    protected int getStyle(Event event) {
+        return style;
+    }
+
+    /**
+     * The {@link Image} displayed in the {@link CLabel} in the default
+     * implementation implementation
+     *
+     * @param event
+     *            the event triggered the popup of the tooltip
+     * @return the {@link Image} or <code>null</code> if no image should be
+     *         displayed
+     */
+    protected Image getImage(Event event) {
+        return image;
+    }
+
+    /**
+     * The foreground {@link Color} used by {@link CLabel} in the default
+     * implementation
+     *
+     * @param event
+     *            the event triggered the popup of the tooltip
+     * @return the {@link Color} or <code>null</code> if default foreground
+     *         color should be used
+     */
+    protected Color getForegroundColor(Event event) {
+        return (foregroundColor is null) ? event.widget.getDisplay()
+                .getSystemColor(DWT.COLOR_INFO_FOREGROUND) : foregroundColor;
+    }
+
+    /**
+     * The background {@link Color} used by {@link CLabel} in the default
+     * implementation
+     *
+     * @param event
+     *            the event triggered the popup of the tooltip
+     * @return the {@link Color} or <code>null</code> if default background
+     *         color should be used
+     */
+    protected Color getBackgroundColor(Event event) {
+        return (backgroundColor is null) ? event.widget.getDisplay()
+                .getSystemColor(DWT.COLOR_INFO_BACKGROUND) : backgroundColor;
+    }
+
+    /**
+     * The background {@link Image} used by {@link CLabel} in the default
+     * implementation
+     *
+     * @param event
+     *            the event triggered the popup of the tooltip
+     * @return the {@link Image} or <code>null</code> if no image should be
+     *         displayed in the background
+     */
+    protected Image getBackgroundImage(Event event) {
+        return backgroundImage;
+    }
+
+    /**
+     * The {@link Font} used by {@link CLabel} in the default implementation
+     *
+     * @param event
+     *            the event triggered the popup of the tooltip
+     * @return the {@link Font} or <code>null</code> if the default font
+     *         should be used
+     */
+    protected Font getFont(Event event) {
+        return font;
+    }
+
+    /**
+     * The text displayed in the {@link CLabel} in the default implementation
+     *
+     * @param event
+     *            the event triggered the popup of the tooltip
+     * @return the text or <code>null</code> if no text has to be displayed
+     */
+    protected String getText(Event event) {
+        return text;
+    }
+
+    /**
+     * The background {@link Image} used by {@link CLabel} in the default
+     * implementation
+     *
+     * @param backgroundColor
+     *            the {@link Color} or <code>null</code> if default background
+     *            color ({@link DWT#COLOR_INFO_BACKGROUND}) should be used
+     */
+    public void setBackgroundColor(Color backgroundColor) {
+        this.backgroundColor = backgroundColor;
+    }
+
+    /**
+     * The background {@link Image} used by {@link CLabel} in the default
+     * implementation
+     *
+     * @param backgroundImage
+     *            the {@link Image} or <code>null</code> if no image should be
+     *            displayed in the background
+     */
+    public void setBackgroundImage(Image backgroundImage) {
+        this.backgroundImage = backgroundImage;
+    }
+
+    /**
+     * The {@link Font} used by {@link CLabel} in the default implementation
+     *
+     * @param font
+     *            the {@link Font} or <code>null</code> if the default font
+     *            should be used
+     */
+    public void setFont(Font font) {
+        this.font = font;
+    }
+
+    /**
+     * The foreground {@link Color} used by {@link CLabel} in the default
+     * implementation
+     *
+     * @param foregroundColor
+     *            the {@link Color} or <code>null</code> if default foreground
+     *            color should be used
+     */
+    public void setForegroundColor(Color foregroundColor) {
+        this.foregroundColor = foregroundColor;
+    }
+
+    /**
+     * The {@link Image} displayed in the {@link CLabel} in the default
+     * implementation implementation
+     *
+     * @param image
+     *            the {@link Image} or <code>null</code> if no image should be
+     *            displayed
+     */
+    public void setImage(Image image) {
+        this.image = image;
+    }
+
+    /**
+     * The style used to create the {@link CLabel} in the default implementation
+     *
+     * @param style
+     *            the event triggered the popup of the tooltip
+     */
+    public void setStyle(int style) {
+        this.style = style;
+    }
+
+    /**
+     * The text displayed in the {@link CLabel} in the default implementation
+     *
+     * @param text
+     *            the text or <code>null</code> if no text has to be displayed
+     */
+    public void setText(String text) {
+        this.text = text;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/window/IShellProvider.d	Fri Mar 28 23:32:40 2008 +0100
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.window.IShellProvider;
+
+import dwt.widgets.Shell;
+
+/**
+ * Interface for objects that can return a shell. This is normally used for 
+ * opening child windows. An object that wants to open child shells can take 
+ * an IShellProvider in its constructor, and the object that implements IShellProvider
+ * can dynamically choose where child shells should be opened.  
+ * 
+ * @since 3.1
+ */
+public interface IShellProvider {
+    /**
+     * Returns the current shell (or null if none). This return value may
+     * change over time, and should not be cached.
+     * 
+     * @return the current shell or null if none
+     */
+    Shell getShell();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/window/SameShellProvider.d	Fri Mar 28 23:32:40 2008 +0100
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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.window.SameShellProvider;
+
+import dwt.widgets.Control;
+import dwt.widgets.Shell;
+
+import dwtx.jface.window.IShellProvider;
+
+import dwt.dwthelper.utils;
+
+/**
+ * Standard shell provider that always returns the shell containing the given
+ * control. This will always return the correct shell for the control, even if
+ * the control is reparented.
+ *
+ * @since 3.1
+ */
+public class SameShellProvider : IShellProvider {
+
+    private Control targetControl;
+
+    /**
+     * Returns a shell provider that always returns the current
+     * shell for the given control.
+     *
+     * @param targetControl control whose shell will be tracked, or null if getShell() should always
+     * return null
+     */
+    public this(Control targetControl) {
+        this.targetControl = targetControl;
+    }
+
+    /* (non-javadoc)
+     * @see IShellProvider#getShell()
+     */
+    public Shell getShell() {
+        if ( auto res = cast(Shell)targetControl ) {
+            return res;
+        }
+
+        return targetControl is null? null :targetControl.getShell();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/window/ToolTip.d	Fri Mar 28 23:32:40 2008 +0100
@@ -0,0 +1,643 @@
+/*******************************************************************************
+ * 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:
+ *     Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+
+module dwtx.jface.window.ToolTip;
+
+import tango.util.collection.HashMap;
+
+import dwt.DWT;
+import dwt.events.DisposeEvent;
+import dwt.events.DisposeListener;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.layout.FillLayout;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Event;
+import dwt.widgets.Listener;
+import dwt.widgets.Monitor;
+import dwt.widgets.Shell;
+// import dwtx.jface.viewers.ColumnViewer;
+// import dwtx.jface.viewers.ViewerCell;
+
+import dwt.dwthelper.utils;
+import dwt.dwthelper.Runnable;
+
+/**
+ * This class gives implementors to provide customized tooltips for any control.
+ *
+ * @since 3.3
+ */
+public abstract class ToolTip {
+    private Control control;
+
+    private int xShift = 3;
+
+    private int yShift = 0;
+
+    private int popupDelay = 0;
+
+    private int hideDelay = 0;
+
+    private ToolTipOwnerControlListener listener;
+
+    private HashMap!(String,Object) data;
+
+    // Ensure that only one tooltip is active in time
+    private static Shell CURRENT_TOOLTIP;
+
+    /**
+     * Recreate the tooltip on every mouse move
+     */
+    public static const int RECREATE = 1;
+
+    /**
+     * Don't recreate the tooltip as long the mouse doesn't leave the area
+     * triggering the Tooltip creation
+     */
+    public static const int NO_RECREATE = 1 << 1;
+
+    private TooltipHideListener hideListener;
+
+    private bool hideOnMouseDown = true;
+
+    private bool respectDisplayBounds = true;
+
+    private bool respectMonitorBounds = true;
+
+    private int style;
+
+    private Object currentArea;
+
+    /**
+     * Create new instance which add TooltipSupport to the widget
+     *
+     * @param control
+     *            the control on whose action the tooltip is shown
+     */
+    public this(Control control) {
+        this(control, RECREATE, false);
+    }
+
+    /**
+     * @param control
+     *            the control to which the tooltip is bound
+     * @param style
+     *            style passed to control tooltip behaviour
+     *
+     * @param manualActivation
+     *            <code>true</code> if the activation is done manually using
+     *            {@link #show(Point)}
+     * @see #RECREATE
+     * @see #NO_RECREATE
+     */
+    public this(Control control, int style, bool manualActivation) {
+        this.control = control;
+        this.style = style;
+        this.hideListener = new TooltipHideListener();
+        this.control.addDisposeListener(new class DisposeListener {
+
+            public void widgetDisposed(DisposeEvent e) {
+                deactivate();
+            }
+
+        });
+
+        this.listener = new ToolTipOwnerControlListener();
+
+        if (!manualActivation) {
+            activate();
+        }
+    }
+
+    /**
+     * Restore arbitary data under the given key
+     *
+     * @param key
+     *            the key
+     * @param value
+     *            the value
+     */
+    public void setData(String key, Object value) {
+        if (data is null) {
+            data = new HashMap!(String,Object);
+        }
+        data.add(key, value);
+    }
+
+    /**
+     * Get the data restored under the key
+     *
+     * @param key
+     *            the key
+     * @return data or <code>null</code> if no entry is restored under the key
+     */
+    public Object getData(String key) {
+        if (data !is null) {
+            return data.get(key);
+        }
+        return null;
+    }
+
+    /**
+     * Set the shift (from the mouse position triggered the event) used to
+     * display the tooltip. By default the tooltip is shifted 3 pixels to the
+     * left
+     *
+     * @param p
+     *            the new shift
+     */
+    public void setShift(Point p) {
+        xShift = p.x;
+        yShift = p.y;
+    }
+
+    /**
+     * Activate tooltip support for this control
+     */
+    public void activate() {
+        deactivate();
+        control.addListener(DWT.Dispose, listener);
+        control.addListener(DWT.MouseHover, listener);
+        control.addListener(DWT.MouseMove, listener);
+        control.addListener(DWT.MouseExit, listener);
+        control.addListener(DWT.MouseDown, listener);
+    }
+
+    /**
+     * Deactivate tooltip support for the underlying control
+     */
+    public void deactivate() {
+        control.removeListener(DWT.Dispose, listener);
+        control.removeListener(DWT.MouseHover, listener);
+        control.removeListener(DWT.MouseMove, listener);
+        control.removeListener(DWT.MouseExit, listener);
+        control.removeListener(DWT.MouseDown, listener);
+    }
+
+    /**
+     * Return whther the tooltip respects bounds of the display.
+     *
+     * @return <code>true</code> if the tooltip respects bounds of the display
+     */
+    public bool isRespectDisplayBounds() {
+        return respectDisplayBounds;
+    }
+
+    /**
+     * Set to <code>false</code> if display bounds should not be respected or
+     * to <code>true</code> if the tooltip is should repositioned to not
+     * overlap the display bounds.
+     * <p>
+     * Default is <code>true</code>
+     * </p>
+     *
+     * @param respectDisplayBounds
+     */
+    public void setRespectDisplayBounds(bool respectDisplayBounds) {
+        this.respectDisplayBounds = respectDisplayBounds;
+    }
+
+    /**
+     * Return whther the tooltip respects bounds of the monitor.
+     *
+     * @return <code>true</code> if tooltip respects the bounds of the monitor
+     */
+    public bool isRespectMonitorBounds() {
+        return respectMonitorBounds;
+    }
+
+    /**
+     * Set to <code>false</code> if monitor bounds should not be respected or
+     * to <code>true</code> if the tooltip is should repositioned to not
+     * overlap the monitors bounds. The monitor the tooltip belongs to is the
+     * same is control's monitor the tooltip is shown for.
+     * <p>
+     * Default is <code>true</code>
+     * </p>
+     *
+     * @param respectMonitorBounds
+     */
+    public void setRespectMonitorBounds(bool respectMonitorBounds) {
+        this.respectMonitorBounds = respectMonitorBounds;
+    }
+
+    /**
+     * Should the tooltip displayed because of the given event.
+     * <p>
+     * <b>Subclasses may overwrite this to get custom behaviour</b>
+     * </p>
+     *
+     * @param event
+     *            the event
+     * @return <code>true</code> if tooltip should be displayed
+     */
+    protected bool shouldCreateToolTip(Event event) {
+        if ((style & NO_RECREATE) !is 0) {
+            Object tmp = getToolTipArea(event);
+
+            // No new area close the current tooltip
+            if (tmp is null) {
+                hide();
+                return false;
+            }
+
+            bool rv = !tmp.opEquals(currentArea);
+            return rv;
+        }
+
+        return true;
+    }
+
+    /**
+     * This method is called before the tooltip is hidden
+     *
+     * @param event
+     *            the event trying to hide the tooltip
+     * @return <code>true</code> if the tooltip should be hidden
+     */
+    private bool shouldHideToolTip(Event event) {
+        if (event !is null && event.type is DWT.MouseMove
+                && (style & NO_RECREATE) !is 0) {
+            Object tmp = getToolTipArea(event);
+
+            // No new area close the current tooltip
+            if (tmp is null) {
+                hide();
+                return false;
+            }
+
+            bool rv = !tmp.opEquals(currentArea);
+            return rv;
+        }
+
+        return true;
+    }
+
+    /**
+     * This method is called to check for which area the tooltip is
+     * created/hidden for. In case of {@link #NO_RECREATE} this is used to
+     * decide if the tooltip is hidden recreated.
+     *
+     * <code>By the default it is the widget the tooltip is created for but could be any object. To decide if
+     * the area changed the {@link Object#equals(Object)} method is used.</code>
+     *
+     * @param event
+     *            the event
+     * @return the area responsible for the tooltip creation or
+     *         <code>null</code> this could be any object describing the area
+     *         (e.g. the {@link Control}  onto which the tooltip is bound to, a part of
+     *         this area e.g. for {@link ColumnViewer} this could be a
+     *         {@link ViewerCell})
+     */
+    protected Object getToolTipArea(Event event) {
+        return control;
+    }
+
+    /**
+     * Start up the tooltip programmatically
+     *
+     * @param location
+     *            the location relative to the control the tooltip is shown
+     */
+    public void show(Point location) {
+        Event event = new Event();
+        event.x = location.x;
+        event.y = location.y;
+        event.widget = control;
+        toolTipCreate(event);
+    }
+
+    private Shell toolTipCreate(Event event) {
+        if (shouldCreateToolTip(event)) {
+            Shell shell = new Shell(control.getShell(), DWT.ON_TOP | DWT.TOOL
+                    | DWT.NO_FOCUS);
+            shell.setLayout(new FillLayout());
+
+            toolTipOpen(shell, event);
+
+            return shell;
+        }
+
+        return null;
+    }
+
+    private void toolTipShow(Shell tip, Event event) {
+        if (!tip.isDisposed()) {
+            currentArea = getToolTipArea(event);
+            createToolTipContentArea(event, tip);
+            if (isHideOnMouseDown()) {
+                toolTipHookBothRecursively(tip);
+            } else {
+                toolTipHookByTypeRecursively(tip, true, DWT.MouseExit);
+            }
+
+            tip.pack();
+            tip.setLocation(fixupDisplayBounds(tip.getSize(), getLocation(tip
+                    .getSize(), event)));
+            tip.setVisible(true);
+        }
+    }
+
+    private Point fixupDisplayBounds(Point tipSize, Point location) {
+        if (respectDisplayBounds || respectMonitorBounds) {
+            Rectangle bounds;
+            Point rightBounds = new Point(tipSize.x + location.x, tipSize.y
+                    + location.y);
+
+            dwt.widgets.Monitor.Monitor[] ms = control.getDisplay().getMonitors();
+
+            if (respectMonitorBounds && ms.length > 1) {
+                // By default present in the monitor of the control
+                bounds = control.getMonitor().getBounds();
+                Point p = new Point(location.x, location.y);
+
+                // Search on which monitor the event occurred
+                Rectangle tmp;
+                for (int i = 0; i < ms.length; i++) {
+                    tmp = ms[i].getBounds();
+                    if (tmp.contains(p)) {
+                        bounds = tmp;
+                        break;
+                    }
+                }
+
+            } else {
+                bounds = control.getDisplay().getBounds();
+            }
+
+            if (!(bounds.contains(location) && bounds.contains(rightBounds))) {
+                if (rightBounds.x > bounds.width) {
+                    location.x -= rightBounds.x - bounds.width;
+                }
+
+                if (rightBounds.y > bounds.height) {
+                    location.y -= rightBounds.y - bounds.height;
+                }
+
+                if (location.x < bounds.x) {
+                    location.x = bounds.x;
+                }
+
+                if (location.y < bounds.y) {
+                    location.y = bounds.y;
+                }
+            }
+        }
+
+        return location;
+    }
+
+    /**
+     * Get the display relative location where the tooltip is displayed.
+     * Subclasses may overwrite to implement custom positioning.
+     *
+     * @param tipSize
+     *            the size of the tooltip to be shown
+     * @param event
+     *            the event triggered showing the tooltip
+     * @return the absolute position on the display
+     */
+    public Point getLocation(Point tipSize, Event event) {
+        return control.toDisplay(event.x + xShift, event.y + yShift);
+    }
+
+    private void toolTipHide(Shell tip, Event event) {
+        if (tip !is null && !tip.isDisposed() && shouldHideToolTip(event)) {
+            currentArea = null;
+            tip.dispose();
+            CURRENT_TOOLTIP = null;
+            afterHideToolTip(event);
+        }
+    }
+
+    private void toolTipOpen(Shell shell, Event event) {
+        // Ensure that only one Tooltip is shown in time
+        if (CURRENT_TOOLTIP !is null) {
+            toolTipHide(CURRENT_TOOLTIP, null);
+        }
+
+        CURRENT_TOOLTIP = shell;
+
+        if (popupDelay > 0) {
+            control.getDisplay().timerExec(popupDelay, new class Runnable {
+                Shell shell_;
+                Event event_;
+                this(){ shell_=shell; event_=event; }
+                public void run() {
+                    toolTipShow(shell_, event_);
+                }
+            });
+        } else {
+            toolTipShow(CURRENT_TOOLTIP, event);
+        }
+
+        if (hideDelay > 0) {
+            control.getDisplay().timerExec(popupDelay + hideDelay,
+                    new class Runnable {
+                        Shell shell_;
+                        this(){ shell_=shell; }
+                        public void run() {
+                            toolTipHide(shell, null);
+                        }
+                    });
+        }
+    }
+
+    private void toolTipHookByTypeRecursively(Control c, bool add, int type) {
+        if (add) {
+            c.addListener(type, hideListener);
+        } else {
+            c.removeListener(type, hideListener);
+        }
+
+        if ( auto c2 = cast(Composite)c ) {
+            Control[] children = c2.getChildren();
+            for (int i = 0; i < children.length; i++) {
+                toolTipHookByTypeRecursively(children[i], add, type);
+            }
+        }
+    }
+
+    private void toolTipHookBothRecursively(Control c) {
+        c.addListener(DWT.MouseDown, hideListener);
+        c.addListener(DWT.MouseExit, hideListener);
+
+        if ( auto comp = cast(Composite) c ) {
+            Control[] children = comp.getChildren();
+            for (int i = 0; i < children.length; i++) {
+                toolTipHookBothRecursively(children[i]);
+            }
+        }
+    }
+
+    /**
+     * Creates the content area of the the tooltip.
+     *
+     * @param event
+     *            the event that triggered the activation of the tooltip
+     * @param parent
+     *            the parent of the content area
+     * @return the content area created
+     */
+    protected abstract Composite createToolTipContentArea(Event event,
+            Composite parent);
+
+    /**
+     * This method is called after a Tooltip is hidden.
+     * <p>
+     * <b>Subclasses may override to clean up requested system resources</b>
+     * </p>
+     *
+     * @param event
+     *            event triggered the hiding action (may be <code>null</code>
+     *            if event wasn't triggered by user actions directly)
+     */
+    protected void afterHideToolTip(Event event) {
+
+    }
+
+    /**
+     * Set the hide delay.
+     *
+     * @param hideDelay
+     *            the delay before the tooltip is hidden. If <code>0</code>
+     *            the tooltip is shown until user moves to other item
+     */
+    public void setHideDelay(int hideDelay) {
+        this.hideDelay = hideDelay;
+    }
+
+    /**
+     * Set the popup delay.
+     *
+     * @param popupDelay
+     *            the delay before the tooltip is shown to the user. If
+     *            <code>0</code> the tooltip is shown immediately
+     */
+    public void setPopupDelay(int popupDelay) {
+        this.popupDelay = popupDelay;
+    }
+
+    /**
+     * Return if hiding on mouse down is set.
+     *
+     * @return <code>true</code> if hiding on mouse down in the tool tip is on
+     */
+    public bool isHideOnMouseDown() {
+        return hideOnMouseDown;
+    }
+
+    /**
+     * If you don't want the tool tip to be hidden when the user clicks inside
+     * the tool tip set this to <code>false</code>. You maybe also need to
+     * hide the tool tip yourself depending on what you do after clicking in the
+     * tooltip (e.g. if you open a new {@link Shell})
+     *
+     * @param hideOnMouseDown
+     *            flag to indicate of tooltip is hidden automatically on mouse
+     *            down inside the tool tip
+     */
+    public void setHideOnMouseDown(bool hideOnMouseDown) {
+        // Only needed if there's currently a tooltip active
+        if (CURRENT_TOOLTIP !is null && !CURRENT_TOOLTIP.isDisposed()) {
+            // Only change if value really changed
+            if (hideOnMouseDown !is this.hideOnMouseDown) {
+                control.getDisplay().syncExec(new class Runnable {
+                    bool hideOnMouseDown_;
+                    this(){ hideOnMouseDown_=hideOnMouseDown; }
+                    public void run() {
+                        if (CURRENT_TOOLTIP !is null
+                                && CURRENT_TOOLTIP.isDisposed()) {
+                            toolTipHookByTypeRecursively(CURRENT_TOOLTIP,
+                                    hideOnMouseDown_, DWT.MouseDown);
+                        }
+                    }
+
+                });
+            }
+        }
+
+        this.hideOnMouseDown = hideOnMouseDown;
+    }
+
+    /**
+     * Hide the currently active tool tip
+     */
+    public void hide() {
+        toolTipHide(CURRENT_TOOLTIP, null);
+    }
+
+    private class ToolTipOwnerControlListener : Listener {
+        public void handleEvent(Event event) {
+            switch (event.type) {
+            case DWT.Dispose:
+            case DWT.KeyDown:
+            case DWT.MouseDown:
+            case DWT.MouseMove:
+                toolTipHide(CURRENT_TOOLTIP, event);
+                break;
+            case DWT.MouseHover:
+                toolTipCreate(event);
+                break;
+            case DWT.MouseExit:
+                /*
+                 * Check if the mouse exit happend because we move over the
+                 * tooltip
+                 */
+                if (CURRENT_TOOLTIP !is null && !CURRENT_TOOLTIP.isDisposed()) {
+                    if (CURRENT_TOOLTIP.getBounds().contains(
+                            control.toDisplay(event.x, event.y))) {
+                        break;
+                    }
+                }
+
+                toolTipHide(CURRENT_TOOLTIP, event);
+                break;
+            }
+        }
+    }
+
+    private class TooltipHideListener : Listener {
+        public void handleEvent(Event event) {
+            if ( auto c = cast(Control)event.widget ) {
+
+                Shell shell = c.getShell();
+
+                switch (event.type) {
+                case DWT.MouseDown:
+                    if (isHideOnMouseDown()) {
+                        toolTipHide(shell, event);
+                    }
+                    break;
+                case DWT.MouseExit:
+                    /*
+                     * Give some insets to ensure we get exit informations from
+                     * a wider area ;-)
+                     */
+                    Rectangle rect = shell.getBounds();
+                    rect.x += 5;
+                    rect.y += 5;
+                    rect.width -= 10;
+                    rect.height -= 10;
+
+                    if (!rect.contains(c.getDisplay().getCursorLocation())) {
+                        toolTipHide(shell, event);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/window/Window.d	Fri Mar 28 23:32:40 2008 +0100
@@ -0,0 +1,1092 @@
+/*******************************************************************************
+ * 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.window.Window;
+
+import dwtx.jface.window.IShellProvider;
+import dwtx.jface.window.WindowManager;
+import dwtx.jface.window.SameShellProvider;
+
+import tango.util.collection.ArraySeq;
+
+import dwt.DWT;
+import dwt.events.ShellAdapter;
+import dwt.events.ShellEvent;
+import dwt.events.ShellListener;
+import dwt.graphics.Image;
+import dwt.graphics.Point;
+import dwt.graphics.Rectangle;
+import dwt.layout.GridLayout;
+import dwt.widgets.Composite;
+import dwt.widgets.Control;
+import dwt.widgets.Display;
+import dwt.widgets.Event;
+import dwt.widgets.Layout;
+import dwt.widgets.Listener;
+import dwt.widgets.Monitor;
+import dwt.widgets.Shell;
+import dwtx.core.runtime.Assert;
+import dwtx.jface.resource.JFaceResources;
+import dwtx.jface.util.Geometry;
+import dwtx.jface.util.IPropertyChangeListener;
+import dwtx.jface.util.PropertyChangeEvent;
+
+import dwt.dwthelper.utils;
+import dwt.dwthelper.Integer;
+import tango.io.Stdout;
+
+/**
+ * A JFace window is an object that has no visual representation (no widgets)
+ * until it is told to open.
+ * <p>
+ * Creating a window involves the following steps:
+ * <ul>
+ * <li>creating an instance of a concrete subclass of <code>Window</code>
+ * </li>
+ * <li>creating the window's shell and widget tree by calling
+ * <code>create</code> (optional)</li>
+ * <li>assigning the window to a window manager using
+ * <code>WindowManager.add</code> (optional)</li>
+ * <li>opening the window by calling <code>open</code></li>
+ * </ul>
+ * Opening the window will create its shell and widget tree if they have not
+ * already been created. When the window is closed, the shell and widget tree
+ * are disposed of and are no longer referenced, and the window is automatically
+ * removed from its window manager. A window may be reopened.
+ * </p>
+ * <p>
+ * The JFace window framework (this package) consists of this class,
+ * <code>Window</code>, the abstract base of all windows, and one concrete
+ * window classes (<code>ApplicationWindow</code>) which may also be
+ * subclassed. Clients may define additional window subclasses as required.
+ * </p>
+ * <p>
+ * The <code>Window</code> class provides methods that subclasses may
+ * override to configure the window, including:
+ * <ul>
+ * <li><code>close</code>- extend to free other DWT resources</li>
+ * <li><code>configureShell</code>- extend or reimplement to set shell
+ * properties before window opens</li>
+ * <li><code>createContents</code>- extend or reimplement to create controls
+ * before window opens</li>
+ * <li><code>getInitialSize</code>- reimplement to give the initial size for
+ * the shell</li>
+ * <li><code>getInitialLocation</code>- reimplement to give the initial
+ * location for the shell</li>
+ * <li><code>getShellListener</code>- extend or reimplement to receive shell
+ * events</li>
+ * <li><code>handleFontChange</code>- reimplement to respond to font changes
+ * </li>
+ * <li><code>handleShellCloseEvent</code>- extend or reimplement to handle
+ * shell closings</li>
+ * </ul>
+ * </p>
+ */
+public abstract class Window : IShellProvider {
+
+    /**
+     * Standard return code constant (value 0) indicating that the window was
+     * opened.
+     *
+     * @see #open
+     */
+    public static const int OK = 0;
+
+    /**
+     * Standard return code constant (value 1) indicating that the window was
+     * canceled.
+     *
+     * @see #open
+     */
+    public static const int CANCEL = 1;
+
+    /**
+     * An array of images to be used for the window. It is expected that the
+     * array will contain the same icon rendered at different resolutions.
+     */
+    private static Image[] defaultImages;
+
+    /**
+     * This interface defines a Exception Handler which can be set as a global
+     * handler and will be called if an exception happens in the event loop.
+     */
+    public static interface IExceptionHandler {
+        /**
+         * Handle the exception.
+         *
+         * @param t
+         *            The exception that occured.
+         */
+        public void handleException(Exception t);
+    }
+
+    /**
+     * Defines a default exception handler.
+     */
+    private static class DefaultExceptionHandler : IExceptionHandler {
+        /*
+         * (non-Javadoc)
+         *
+         * @see dwtx.jface.window.Window.IExceptionHandler#handleException(java.lang.Throwable)
+         */
+        public void handleException(Exception t) {
+            /+
+            if (t instanceof ThreadDeath) {
+                // Don't catch ThreadDeath as this is a normal occurrence when
+                // the thread dies
+                throw (ThreadDeath) t;
+            }
+            +/
+            // Try to keep running.
+            ExceptionPrintStackTrace(t);
+        }
+    }
+
+    /**
+     * The exception handler for this application.
+     */
+    private static IExceptionHandler exceptionHandler;
+    static this(){
+        exceptionHandler = new DefaultExceptionHandler();
+    }
+    /**
+     * The default orientation of the window. By default
+     * it is DWT#NONE but it can also be DWT#LEFT_TO_RIGHT
+     * or DWT#RIGHT_TO_LEFT
+     */
+    private static int orientation = DWT.NONE;
+
+    /**
+     * Object used to locate the default parent for modal shells
+     */
+    private static IShellProvider defaultModalParent;
+    static this(){
+        defaultModalParent = new class IShellProvider {
+            public Shell getShell() {
+                Display d = Display.getCurrent();
+
+                if (d is null) {
+                    return null;
+                }
+
+                Shell parent = d.getActiveShell();
+
+                // Make sure we don't pick a parent that has a modal child (this can lock the app)
+                if (parent is null) {
+                    // If this is a top-level window, then there must not be any open modal windows.
+                    parent = getModalChild(Display.getCurrent().getShells());
+                } else {
+                    // If we picked a parent with a modal child, use the modal child instead
+                    Shell modalChild = getModalChild(parent.getShells());
+                    if (modalChild !is null) {
+                        parent = modalChild;
+                    }
+                }
+
+                return parent;
+            }
+        };
+    }
+
+    /**
+     * Object that returns the parent shell.
+     */
+    private IShellProvider parentShell;
+
+    /**
+     * Shell style bits.
+     *
+     * @see #setShellStyle
+     */
+    private int shellStyle = DWT.SHELL_TRIM;
+
+    /**
+     * Window manager, or <code>null</code> if none.
+     *
+     * @see #setWindowManager
+     */
+    private WindowManager windowManager;
+
+    /**
+     * Window shell, or <code>null</code> if none.
+     */
+    private Shell shell;
+
+    /**
+     * Top level DWT control, or <code>null</code> if none
+     */
+    private Control contents;
+
+    /**
+     * Window return code; initially <code>OK</code>.
+     *
+     * @see #setReturnCode
+     */
+    private int returnCode = OK;
+
+    /**
+     * <code>true</code> if the <code>open</code> method should not return
+     * until the window closes, and <code>false</code> if the
+     * <code>open</code> method should return immediately; initially
+     * <code>false</code> (non-blocking).
+     *
+     * @see #setBlockOnOpen
+     */
+    private bool block = false;
+
+    /**
+     * Internal class for informing this window when fonts change.
+     */
+    private class FontChangeListener : IPropertyChangeListener {
+        public void propertyChange(PropertyChangeEvent event) {
+            handleFontChange(event);
+        }
+    }
+
+    /**
+     * Internal font change listener.
+     */
+    private FontChangeListener fontChangeListener;
+
+    /**
+     * Internal fields to detect if shell size has been set
+     */
+    private bool resizeHasOccurred = false;
+
+    private Listener resizeListener;
+
+    /**
+     * Creates a window instance, whose shell will be created under the given
+     * parent shell. Note that the window will have no visual representation
+     * until it is told to open. By default, <code>open</code> does not block.
+     *
+     * @param parentShell
+     *            the parent shell, or <code>null</code> to create a top-level
+     *            shell. Try passing "(Shell)null" to this method instead of "null"
+     *            if your compiler complains about an ambiguity error.
+     * @see #setBlockOnOpen
+     * @see #getDefaultOrientation()
+     */
+    protected this(Shell parentShell) {
+        this(new SameShellProvider(parentShell));
+
+        if(parentShell is null) {
+            setShellStyle(getShellStyle() | getDefaultOrientation());
+        }
+    }
+
+    /**
+     * Creates a new window which will create its shell as a child of whatever
+     * the given shellProvider returns.
+     *
+     * @param shellProvider object that will return the current parent shell. Not null.
+     *
+     * @since 3.1
+     */
+    protected this(IShellProvider shellProvider) {
+        Assert.isNotNull(cast(Object)shellProvider);
+        this.parentShell = shellProvider;
+    }
+
+    /**
+     * Determines if the window should handle the close event or do nothing.
+     * <p>
+     * The default implementation of this framework method returns
+     * <code>true</code>, which will allow the
+     * <code>handleShellCloseEvent</code> method to be called. Subclasses may
+     * extend or reimplement.
+     * </p>
+     *
+     * @return whether the window should handle the close event.
+     */
+    protected bool canHandleShellCloseEvent() {
+        return true;
+    }
+
+    /**
+     * Closes this window, disposes its shell, and removes this window from its
+     * window manager (if it has one).
+     * <p>
+     * This framework method may be extended (<code>super.close</code> must
+     * be called).
+     * </p>
+     *
+     * @return <code>true</code> if the window is (or was already) closed, and
+     *         <code>false</code> if it is still open
+     */
+    public bool close() {
+
+        // stop listening for font changes
+        if (fontChangeListener !is null) {
+            JFaceResources.getFontRegistry().removeListener(fontChangeListener);
+            fontChangeListener = null;
+        }
+
+        // remove this window from a window manager if it has one
+        if (windowManager !is null) {
+            windowManager.remove(this);
+            windowManager = null;
+        }
+
+        if (shell is null || shell.isDisposed()) {
+            return true;
+        }
+
+        // If we "close" the shell recursion will occur.
+        // Instead, we need to "dispose" the shell to remove it from the
+        // display.
+        shell.dispose();
+        shell = null;
+        contents = null;
+
+        return true;
+    }
+
+    /**
+     * Configures the given shell in preparation for opening this window in it.
+     * <p>
+     * The default implementation of this framework method sets the shell's
+     * image and gives it a grid layout. Subclasses may extend or reimplement.
+     * </p>
+     *
+     * @param newShell
+     *            the shell
+     */
+    protected void configureShell(Shell newShell) {
+
+        // The single image version of this code had a comment related to bug
+        // 46624,
+        // and some code that did nothing if the stored image was already
+        // disposed.
+        // The equivalent in the multi-image version seems to be to remove the
+        // disposed images from the array passed to the shell.
+        if (defaultImages !is null && defaultImages.length > 0) {
+            auto nonDisposedImages = new ArraySeq!(Image);
+            nonDisposedImages.capacity(defaultImages.length);
+            for (int i = 0; i < defaultImages.length; ++i) {
+                if (defaultImages[i] !is null && !defaultImages[i].isDisposed()) {
+                    nonDisposedImages.append(defaultImages[i]);
+                }
+            }
+
+            if (nonDisposedImages.size() <= 0) {
+                Stderr.formatln("Window.configureShell: images disposed"); //$NON-NLS-1$
+            } else {
+                newShell.setImages(nonDisposedImages.toArray());
+            }
+        }
+
+        Layout layout = getLayout();
+        if (layout !is null) {
+            newShell.setLayout(layout);
+        }
+    }
+
+    /**
+     * Creates the layout for the shell. The layout created here will be
+     * attached to the composite passed into createContents. The default
+     * implementation returns a GridLayout with no margins. Subclasses that
+     * change the layout type by overriding this method should also override
+     * createContents.
+     *
+     * <p>
+     * A return value of null indicates that no layout should be attached to the
+     * composite. In this case, the layout may be attached within
+     * createContents.
+     * </p>
+     *
+     * @return a newly created Layout or null if no layout should be attached.
+     * @since 3.0
+     */
+    protected Layout getLayout() {
+        GridLayout layout = new GridLayout();
+        layout.marginHeight = 0;
+        layout.marginWidth = 0;
+        return layout;
+    }
+
+    /**
+     * Constrain the shell size to be no larger than the display bounds.
+     *
+     * @since 2.0
+     */
+    protected void constrainShellSize() {
+        // limit the shell size to the display size
+        Rectangle bounds = shell.getBounds();
+        Rectangle constrained = getConstrainedShellBounds(bounds);
+        if (!bounds.opEquals(constrained)) {
+            shell.setBounds(constrained);
+        }
+    }
+
+    /**
+     * Creates this window's widgetry in a new top-level shell.
+     * <p>
+     * The default implementation of this framework method creates this window's
+     * shell (by calling <code>createShell</code>), and its controls (by
+     * calling <code>createContents</code>), then initializes this window's
+     * shell bounds (by calling <code>initializeBounds</code>).
+     * </p>
+     */
+    public void create() {
+        shell = createShell();
+        contents = createContents(shell);
+
+        //initialize the bounds of the shell to that appropriate for the
+        // contents
+        initializeBounds();
+    }
+
+    /**
+     * Creates and returns this window's contents. Subclasses may attach any
+     * number of children to the parent. As a convenience, the return value of
+     * this method will be remembered and returned by subsequent calls to
+     * getContents(). Subclasses may modify the parent's layout if they overload
+     * getLayout() to return null.
+     *
+     * <p>
+     * It is common practise to create and return a single composite that
+     * contains the entire window contents.
+     * </p>
+     *
+     * <p>
+     * The default implementation of this framework method creates an instance
+     * of <code>Composite</code>. Subclasses may override.
+     * </p>
+     *
+     * @param parent
+     *            the parent composite for the controls in this window. The type
+     *            of layout used is determined by getLayout()
+     *
+     * @return the control that will be returned by subsequent calls to
+     *         getContents()
+     */
+    protected Control createContents(Composite parent) {
+        // by default, just create a composite
+        return new Composite(parent, DWT.NONE);
+    }
+
+    /**
+     * Creates and returns this window's shell.
+     * <p>
+     * The default implementation of this framework method creates a new shell
+     * and configures it using <code/>configureShell</code>. Rather than
+     * override this method, subclasses should instead override
+     * <code/>configureShell</code>.
+     * </p>
+     *
+     * @return the shell
+     */
+    protected final Shell createShell() {
+
+        Shell newParent = getParentShell();
+        if(newParent !is null &&  newParent.isDisposed()){
+            parentShell = new SameShellProvider(null);
+            newParent = getParentShell();//Find a better parent
+        }
+
+        //Create the shell
+        Shell newShell = new Shell(newParent, getShellStyle());
+
+        resizeListener = new class Listener {
+            public void handleEvent(Event e) {
+                resizeHasOccurred = true;
+            }
+        };
+
+        newShell.addListener(DWT.Resize, resizeListener);
+        newShell.setData(this);
+
+        //Add a listener
+        newShell.addShellListener(getShellListener());
+
+        //Set the layout
+        configureShell(newShell);
+
+        //Register for font changes
+        if (fontChangeListener is null) {
+            fontChangeListener = new FontChangeListener();
+        }
+        JFaceResources.getFontRegistry().addListener(fontChangeListener);
+
+        return newShell;
+    }
+
+    /**
+     * Returns the top level control for this window. The parent of this control
+     * is the shell.
+     *
+     * @return the top level control, or <code>null</code> if this window's
+     *         control has not been created yet
+     */
+    protected Control getContents() {
+        return contents;
+    }
+
+    /**
+     * Returns the default image. This is the image that will be used for
+     * windows that have no shell image at the time they are opened. There is no
+     * default image unless one is installed via <code>setDefaultImage</code>.
+     *
+     * @return the default image, or <code>null</code> if none
+     * @see #setDefaultImage
+     */
+    public static Image getDefaultImage() {
+        return (defaultImages is null || defaultImages.length < 1) ? null
+                : defaultImages[0];
+    }
+
+    /**
+     * Returns the array of default images to use for newly opened windows. It
+     * is expected that the array will contain the same icon rendered at
+     * different resolutions.
+     *
+     * @see dwt.widgets.Decorations#setImages(dwt.graphics.Image[])
+     *
+     * @return the array of images to be used when a new window is opened
+     * @see #setDefaultImages
+     * @since 3.0
+     */
+    public static Image[] getDefaultImages() {
+        return (defaultImages is null ? new Image[0] : defaultImages);
+    }
+
+    /**
+     * Returns the initial location to use for the shell. The default
+     * implementation centers the shell horizontally (1/2 of the difference to
+     * the left and 1/2 to the right) and vertically (1/3 above and 2/3 below)
+     * relative to the parent shell, or display bounds if there is no parent
+     * shell.
+     *
+     * @param initialSize
+     *            the initial size of the shell, as returned by
+     *            <code>getInitialSize</code>.
+     * @return the initial location of the shell
+     */
+    protected Point getInitialLocation(Point initialSize) {
+        Composite parent = shell.getParent();
+
+        dwt.widgets.Monitor.Monitor monitor = shell.getDisplay().getPrimaryMonitor();
+        if (parent !is null) {
+            monitor = parent.getMonitor();
+        }
+
+        Rectangle monitorBounds = monitor.getClientArea();
+        Point centerPoint;
+        if (parent !is null) {
+            centerPoint = Geometry.centerPoint(parent.getBounds());
+        } else {
+            centerPoint = Geometry.centerPoint(monitorBounds);
+        }
+
+        return new Point(centerPoint.x - (initialSize.x / 2), Math.max(
+                monitorBounds.y, Math.min(centerPoint.y
+                        - (initialSize.y * 2 / 3), monitorBounds.y
+                        + monitorBounds.height - initialSize.y)));
+    }
+
+    /**
+     * Returns the initial size to use for the shell. The default implementation
+     * returns the preferred size of the shell, using
+     * <code>Shell.computeSize(DWT.DEFAULT, DWT.DEFAULT, true)</code>.
+     *
+     * @return the initial size of the shell
+     */
+    protected Point getInitialSize() {
+        return shell.computeSize(DWT.DEFAULT, DWT.DEFAULT, true);
+    }
+
+    /**
+     * Returns the most specific modal child from the given list of Shells.
+     *
+     * @param toSearch shells to search for modal children
+     * @return the most specific modal child, or null if none
+     *
+     * @since 3.1
+     */
+    private static Shell getModalChild(Shell[] toSearch) {
+        int modal = DWT.APPLICATION_MODAL | DWT.SYSTEM_MODAL | DWT.PRIMARY_MODAL;
+
+        for (int i = toSearch.length - 1; i >= 0; i--) {
+            Shell shell = toSearch[i];
+
+            // Check if this shell has a modal child
+            Shell[] children = shell.getShells();
+            Shell modalChild = getModalChild(children);
+            if (modalChild !is null) {
+                return modalChild;
+            }
+
+            // If not, check if this shell is modal itself
+            if (shell.isVisible() && (shell.getStyle() & modal) !is 0) {
+                return shell;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns parent shell, under which this window's shell is created.
+     *
+     * @return the parent shell, or <code>null</code> if there is no parent
+     *         shell
+     */
+    protected Shell getParentShell() {
+        Shell parent = parentShell.getShell();
+
+        int modal = DWT.APPLICATION_MODAL | DWT.SYSTEM_MODAL | DWT.PRIMARY_MODAL;
+
+        if ((getShellStyle() & modal) !is 0) {
+            // If this is a modal shell with no parent, pick a shell using defaultModalParent.
+            if (parent is null) {
+                parent = defaultModalParent.getShell();
+            }
+        }
+
+        return parent;
+    }
+
+    /**
+     * Returns this window's return code. A window's return codes are
+     * window-specific, although two standard return codes are predefined:
+     * <code>OK</code> and <code>CANCEL</code>.
+     *
+     * @return the return code
+     */
+    public int getReturnCode() {
+        return returnCode;
+    }
+
+    /**
+     * Returns this window's shell.
+     *
+     * @return this window's shell, or <code>null</code> if this window's
+     *         shell has not been created yet
+     */
+    public Shell getShell() {
+        return shell;
+    }
+
+    /**
+     * Returns a shell listener. This shell listener gets registered with this
+     * window's shell.
+     * <p>
+     * The default implementation of this framework method returns a new
+     * listener that makes this window the active window for its window manager
+     * (if it has one) when the shell is activated, and calls the framework
+     * method <code>handleShellCloseEvent</code> when the shell is closed.
+     * Subclasses may extend or reimplement.
+     * </p>
+     *
+     * @return a shell listener
+     */
+    protected ShellListener getShellListener() {
+        return new class ShellAdapter {
+            public void shellClosed(ShellEvent event) {
+                event.doit = false; // don't close now
+                if (canHandleShellCloseEvent()) {
+                    handleShellCloseEvent();
+                }
+            }
+        };
+    }
+
+    /**
+     * Returns the shell style bits.
+     * <p>
+     * The default value is <code>DWT.CLOSE|DWT.MIN|DWT.MAX|DWT.RESIZE</code>.
+     * Subclassers should call <code>setShellStyle</code> to change this
+     * value, rather than overriding this method.
+     * </p>
+     *
+     * @return the shell style bits
+     */
+    protected int getShellStyle() {
+        return shellStyle;
+    }
+
+    /**
+     * Returns the window manager of this window.
+     *
+     * @return the WindowManager, or <code>null</code> if none
+     */
+    public WindowManager getWindowManager() {
+        return windowManager;
+    }
+
+    /**
+     * Notifies of a font property change.
+     * <p>
+     * The default implementation of this framework method does nothing.
+     * Subclasses may reimplement.
+     * </p>
+     *
+     * @param event
+     *            the property change event detailing what changed
+     */
+    protected void handleFontChange(PropertyChangeEvent event) {
+        // do nothing
+    }
+
+    /**
+     * Notifies that the window's close button was pressed, the close menu was
+     * selected, or the ESCAPE key pressed.
+     * <p>
+     * The default implementation of this framework method sets the window's
+     * return code to <code>CANCEL</code> and closes the window using
+     * <code>close</code>. Subclasses may extend or reimplement.
+     * </p>
+     */
+    protected void handleShellCloseEvent() {
+        setReturnCode(CANCEL);
+        close();
+    }
+
+    /**
+     * Initializes the location and size of this window's DWT shell after it has
+     * been created.
+     * <p>
+     * This framework method is called by the <code>create</code> framework
+     * method. The default implementation calls <code>getInitialSize</code>
+     * and <code>getInitialLocation</code> and passes the results to
+     * <code>Shell.setBounds</code>. This is only done if the bounds of the
+     * shell have not already been modified. Subclasses may extend or
+     * reimplement.
+     * </p>
+     */
+    protected void initializeBounds() {
+        if (resizeListener !is null) {
+            shell.removeListener(DWT.Resize, resizeListener);
+        }
+        if (resizeHasOccurred) { // Check if shell size has been set already.
+            return;
+        }
+
+        Point size = getInitialSize();
+        Point location = getInitialLocation(size);
+        shell.setBounds(getConstrainedShellBounds(new Rectangle(location.x,
+                location.y, size.x, size.y)));
+    }
+
+    /**
+     * Opens this window, creating it first if it has not yet been created.
+     * <p>
+     * If this window has been configured to block on open (
+     * <code>setBlockOnOpen</code>), this method waits until the window is
+     * closed by the end user, and then it returns the window's return code;
+     * otherwise, this method returns immediately. A window's return codes are
+     * window-specific, although two standard return codes are predefined:
+     * <code>OK</code> and <code>CANCEL</code>.
+     * </p>
+     *
+     * @return the return code
+     *
+     * @see #create()
+     */
+    public int open() {
+
+        if (shell is null || shell.isDisposed()) {
+            shell = null;
+            // create the window
+            create();
+        }
+
+        // limit the shell size to the display size
+        constrainShellSize();
+
+        // open the window
+        shell.open();
+
+        // run the event loop if specified
+        if (block) {
+            runEventLoop(shell);
+        }
+
+        return returnCode;
+    }
+
+    /**
+     * Runs the event loop for the given shell.
+     *
+     * @param loopShell
+     *            the shell
+     */
+    private void runEventLoop(Shell loopShell) {
+
+        //Use the display provided by the shell if possible
+        Display display;
+        if (shell is null) {
+            display = Display.getCurrent();
+        } else {
+            display = loopShell.getDisplay();
+        }
+
+        while (loopShell !is null && !loopShell.isDisposed()) {
+            try {
+                if (!display.readAndDispatch()) {
+                    display.sleep();
+                }
+            } catch (Exception e) {
+                exceptionHandler.handleException(e);
+            }
+        }
+        display.update();
+    }
+
+    /**
+     * Sets whether the <code>open</code> method should block until the window
+     * closes.
+     *
+     * @param shouldBlock
+     *            <code>true</code> if the <code>open</code> method should
+     *            not return until the window closes, and <code>false</code>
+     *            if the <code>open</code> method should return immediately
+     */
+    public void setBlockOnOpen(bool shouldBlock) {
+        block = shouldBlock;
+    }
+
+    /**
+     * Sets the default image. This is the image that will be used for windows
+     * that have no shell image at the time they are opened. There is no default
+     * image unless one is installed via this method.
+     *
+     * @param image
+     *            the default image, or <code>null</code> if none
+     */
+    public static void setDefaultImage(Image image) {
+        defaultImages = image is null ? null : [ image ];
+    }
+
+    /**
+     * Sets the array of default images to use for newly opened windows. It is
+     * expected that the array will contain the same icon rendered at different
+     * resolutions.
+     *
+     * @see dwt.widgets.Decorations#setImages(dwt.graphics.Image[])
+     *
+     * @param images
+     *            the array of images to be used when this window is opened
+     * @since 3.0
+     */
+    public static void setDefaultImages(Image[] images) {
+        Image[] newArray = new Image[images.length];
+        System.arraycopy(images, 0, newArray, 0, newArray.length);
+        defaultImages = newArray;
+    }
+
+    /**
+     * Changes the parent shell. This is only safe to use when the shell is not
+     * yet realized (i.e., created). Once the shell is created, it must be
+     * disposed (i.e., closed) before this method can be called.
+     *
+     * @param newParentShell
+     *            The new parent shell; this value may be <code>null</code> if
+     *            there is to be no parent.
+     * @since 3.1
+     */
+    protected void setParentShell(Shell newParentShell) {
+        Assert.isTrue((shell is null), "There must not be an existing shell."); //$NON-NLS-1$
+        parentShell = new SameShellProvider(newParentShell);
+    }
+
+    /**
+     * Sets this window's return code. The return code is automatically returned
+     * by <code>open</code> if block on open is enabled. For non-blocking
+     * opens, the return code needs to be retrieved manually using
+     * <code>getReturnCode</code>.
+     *
+     * @param code
+     *            the return code
+     */
+    protected void setReturnCode(int code) {
+        returnCode = code;
+    }
+
+    /**
+     * Returns the monitor whose client area contains the given point. If no
+     * monitor contains the point, returns the monitor that is closest to the
+     * point. If this is ever made public, it should be moved into a separate
+     * utility class.
+     *
+     * @param toSearch
+     *            point to find (display coordinates)
+     * @param toFind
+     *            point to find (display coordinates)
+     * @return the montor closest to the given point
+     */
+    private static dwt.widgets.Monitor.Monitor getClosestMonitor(Display toSearch, Point toFind) {
+        int closest = Integer.MAX_VALUE;
+
+        dwt.widgets.Monitor.Monitor[] monitors = toSearch.getMonitors();
+        dwt.widgets.Monitor.Monitor result = monitors[0];
+
+        for (int idx = 0; idx < monitors.length; idx++) {
+            dwt.widgets.Monitor.Monitor current = monitors[idx];
+
+            Rectangle clientArea = current.getClientArea();
+
+            if (clientArea.contains(toFind)) {
+                return current;
+            }
+
+            int distance = Geometry.distanceSquared(Geometry
+                    .centerPoint(clientArea), toFind);
+            if (distance < closest) {
+                closest = distance;
+                result = current;
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Given the desired position of the window, this method returns an adjusted
+     * position such that the window is no larger than its monitor, and does not
+     * extend beyond the edge of the monitor. This is used for computing the
+     * initial window position, and subclasses can use this as a utility method
+     * if they want to limit the region in which the window may be moved.
+     *
+     * @param preferredSize
+     *            the preferred position of the window
+     * @return a rectangle as close as possible to preferredSize that does not
+     *         extend outside the monitor
+     *
+     * @since 3.0
+     */
+    protected Rectangle getConstrainedShellBounds(Rectangle preferredSize) {
+        Rectangle result = new Rectangle(preferredSize.x, preferredSize.y,
+                preferredSize.width, preferredSize.height);
+
+        dwt.widgets.Monitor.Monitor mon = getClosestMonitor(getShell().getDisplay(), Geometry
+                .centerPoint(result));
+
+        Rectangle bounds = mon.getClientArea();
+
+        if (result.height > bounds.height) {
+            result.height = bounds.height;
+        }
+
+        if (result.width > bounds.width) {
+            result.width = bounds.width;
+        }
+
+        result.x = Math.max(bounds.x, Math.min(result.x, bounds.x
+                + bounds.width - result.width));
+        result.y = Math.max(bounds.y, Math.min(result.y, bounds.y
+                + bounds.height - result.height));
+
+        return result;
+    }
+
+    /**
+     * Sets the shell style bits. This method has no effect after the shell is
+     * created.
+     * <p>
+     * The shell style bits are used by the framework method
+     * <code>createShell</code> when creating this window's shell.
+     * </p>
+     *
+     * @param newShellStyle
+     *            the new shell style bits
+     */
+    protected void setShellStyle(int newShellStyle) {
+        shellStyle = newShellStyle;
+    }
+
+    /**
+     * Sets the window manager of this window.
+     * <p>
+     * Note that this method is used by <code>WindowManager</code> to maintain
+     * a backpointer. Clients must not call the method directly.
+     * </p>
+     *
+     * @param manager
+     *            the window manager, or <code>null</code> if none
+     */
+    public void setWindowManager(WindowManager manager) {
+        windowManager = manager;
+
+        // Code to detect invalid usage
+
+        if (manager !is null) {
+            Window[] windows = manager.getWindows();
+            for (int i = 0; i < windows.length; i++) {
+                if (windows[i] is this) {
+                    return;
+                }
+            }
+            manager.add(this);
+        }
+    }
+
+    /**
+     * Sets the exception handler for this application.
+     * <p>
+     * Note that the handler may only be set once.  Subsequent calls to this method will be
+     * ignored.
+     * <p>
+     *
+     * @param handler
+     *            the exception handler for the application.
+     */
+    public static void setExceptionHandler(IExceptionHandler handler) {
+        if ( cast(DefaultExceptionHandler)exceptionHandler ) {
+            exceptionHandler = handler;
+        }
+    }
+
+    /**
+     * Sets the default parent for modal Windows. This will be used to locate
+     * the parent for any modal Window constructed with a null parent.
+     *
+     * @param provider shell provider that will be used to locate the parent shell
+     * whenever a Window is created with a null parent
+     * @since 3.1
+     */
+    public static void setDefaultModalParent(IShellProvider provider) {
+        defaultModalParent = provider;
+    }
+
+    /**
+     * Gets the default orientation for windows. If it is not
+     * set the default value will be unspecified (DWT#NONE).
+     *
+     *
+     * @return DWT#NONE, DWT.RIGHT_TO_LEFT or DWT.LEFT_TO_RIGHT
+     * @see DWT#RIGHT_TO_LEFT
+     * @see DWT#LEFT_TO_RIGHT
+     * @see DWT#NONE
+     * @since 3.1
+     */
+    public static int getDefaultOrientation() {
+        return orientation;
+
+    }
+
+    /**
+     * Sets the default orientation of windows.
+     * @param defaultOrientation one of
+     *  DWT#RIGHT_TO_LEFT, DWT#LEFT_TO_RIGHT ,DWT#NONE
+     * @see DWT#RIGHT_TO_LEFT
+     * @see DWT#LEFT_TO_RIGHT
+     * @see DWT#NONE
+     * @since 3.1
+     */
+    public static void setDefaultOrientation(int defaultOrientation) {
+        orientation = defaultOrientation;
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/window/WindowManager.d	Fri Mar 28 23:32:40 2008 +0100
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * 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.window.WindowManager;
+
+import dwtx.jface.window.Window;
+
+import tango.util.collection.ArraySeq;
+import tango.util.collection.model.Seq;
+
+import dwtx.core.runtime.Assert;
+
+import dwt.dwthelper.utils;
+
+/**
+ * A manager for a group of windows. Window managers are an optional JFace
+ * feature used in applications which create many different windows (dialogs,
+ * wizards, etc.) in addition to a main window. A window manager can be used to
+ * remember all the windows that an application has created (independent of
+ * whether they are presently open or closed). There can be several window
+ * managers, and they can be arranged into a tree. This kind of organization
+ * makes it simple to close whole subgroupings of windows.
+ * <p>
+ * Creating a window manager is as simple as creating an instance of
+ * <code>WindowManager</code>. Associating a window with a window manager is
+ * done with <code>WindowManager.add(Window)</code>. A window is automatically
+ * removed from its window manager as a side effect of closing the window.
+ * </p>
+ *
+ * @see Window
+ */
+public class WindowManager {
+
+    /**
+     * List of windows managed by this window manager
+     * (element type: <code>Window</code>).
+     */
+    private ArraySeq!(Window) windows;
+
+    /**
+     * List of window managers who have this window manager
+     * as their parent (element type: <code>WindowManager</code>).
+     */
+    private Seq!(WindowManager) subManagers;
+
+    /**
+     * Creates an empty window manager without a parent window
+     * manager (that is, a root window manager).
+     */
+    public this() {
+        windows = new ArraySeq!(Window);
+    }
+
+    /**
+     * Creates an empty window manager with the given
+     * window manager as parent.
+     *
+     * @param parent the parent window manager
+     */
+    public this(WindowManager parent) {
+        windows = new ArraySeq!(Window);
+        Assert.isNotNull(parent);
+        parent.addWindowManager(this);
+    }
+
+    /**
+     * Adds the given window to the set of windows managed by
+     * this window manager. Does nothing is this window is
+     * already managed by this window manager.
+     *
+     * @param window the window
+     */
+    public void add(Window window) {
+        if (!windows.contains(window)) {
+            windows.append(window);
+            window.setWindowManager(this);
+        }
+    }
+
+    /**
+     * Adds the given window manager to the list of
+     * window managers that have this one as a parent.
+     * </p>
+     * @param wm the child window manager
+     */
+    private void addWindowManager(WindowManager wm) {
+        if (subManagers is null) {
+            subManagers = new ArraySeq!(WindowManager);
+        }
+        if (!subManagers.contains(wm)) {
+            subManagers.append(wm);
+        }
+    }
+
+    /**
+     * Attempts to close all windows managed by this window manager,
+     * as well as windows managed by any descendent window managers.
+     *
+     * @return <code>true</code> if all windows were sucessfully closed,
+     * and <code>false</code> if any window refused to close
+     */
+    public bool close() {
+        auto t = windows.dup(); // make iteration robust
+        foreach( window; t ){
+            bool closed = window.close();
+            if (!closed) {
+                return false;
+            }
+        }
+        if (subManagers !is null) {
+            foreach( wm; subManagers ){
+                bool closed = wm.close();
+                if (!closed) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns this window manager's number of windows
+     *
+     * @return the number of windows
+     * @since 3.0
+     */
+    public int getWindowCount() {
+        return windows.size();
+    }
+
+    /**
+     * Returns this window manager's set of windows.
+     *
+     * @return a possibly empty list of window
+     */
+    public Window[] getWindows() {
+        return windows.toArray();
+    }
+
+    /**
+     * Removes the given window from the set of windows managed by
+     * this window manager. Does nothing is this window is
+     * not managed by this window manager.
+     *
+     * @param window the window
+     */
+    public final void remove(Window window) {
+        if (windows.contains(window)) {
+            windows.remove(window);
+            window.setWindowManager(null);
+        }
+    }
+}