# HG changeset patch # User Frank Benoit # Date 1206743560 -3600 # Node ID 8a302fdb4140afc19a8a00aa94271e89d0f9263c # Parent 1a6747be662dc2bf31e45b94a00456e4bb98ecee Jface some window and resource classes diff -r 1a6747be662d -r 8a302fdb4140 dwtx/core/runtime/Assert.d --- 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 null. If this * is not the case, some kind of unchecked exception is thrown. diff -r 1a6747be662d -r 8a302fdb4140 dwtx/jface/resource/ArrayFontDescriptor.d --- /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 + *******************************************************************************/ +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(); + } + +} diff -r 1a6747be662d -r 8a302fdb4140 dwtx/jface/resource/DataFormatException.d --- /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 + *******************************************************************************/ +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); + } +} diff -r 1a6747be662d -r 8a302fdb4140 dwtx/jface/resource/FontDescriptor.d --- /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 + *******************************************************************************/ +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. + * + *

Does not modify the reciever.

+ * + * @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; + } + + /** + *

Returns a FontDescriptor that is equivalent to the reciever, but + * has the given style bits, in addition to any styles the reciever already has.

+ * + *

Does not modify the reciever.

+ * + * @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; + } + + /** + *

Returns a new FontDescriptor that is equivalent to the reciever, but + * has the given height.

+ * + *

Does not modify the reciever.

+ * + * @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; + } + + /** + *

Returns a FontDescriptor that is equivalent to the reciever, but whose height + * is larger by the given number of points.

+ * + *

Does not modify the reciever.

+ * + * @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); + } +} diff -r 1a6747be662d -r 8a302fdb4140 dwtx/jface/resource/FontRegistry.d --- /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 + *******************************************************************************/ +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. + *

+ * 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. + *

+ *

+ * A special constructor is provided for populating a font registry + * from a property files using the standard Java resource bundle mechanism. + *

+ *

+ * Methods are provided for registering listeners that will be kept + * apprised of changes to list of registed fonts. + *

+ *

+ * Clients may instantiate this class (it was not designed to be subclassed). + *

+ * + * 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: String, + * value type: FontRecord. + */ + private Map!(String,FontRecord) stringToFontRecord; + + /** + * Table of known font data, keyed by symbolic font name + * (key type: String, + * value type: dwt.graphics.FontData[]). + */ + 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. + *

+ * There must be an DWT Display created in the current + * thread before calling this method. + *

+ */ + public this() { + this(Display.getCurrent(), true); + } + + /** + * Creates a font registry and initializes its content from + * a property file. + *

+ * There must be an DWT Display created in the current + * thread before calling this method. + *

+ *

+ * The OS name (retrieved using System.getProperty("os.name")) + * is converted to lowercase, purged of whitespace, and appended + * as suffix (separated by an underscore '_') to the given + * location string to yield the base name of a resource bundle + * acceptable to ResourceBundle.getBundle. + * The standard Java resource bundle mechanism is then used to locate + * and open the appropriate properties file, taking into account + * locale specific variations. + *

+ *

+ * For example, on the Windows 2000 operating system the location string + * "com.example.myapp.Fonts" yields the base name + * "com.example.myapp.Fonts_windows2000". For the US English locale, + * this further elaborates to the resource bundle name + * "com.example.myapp.Fonts_windows2000_en_us". + *

+ *

+ * If no appropriate OS-specific resource bundle is found, the + * process is repeated using the location as the base bundle name. + *

+ *

+ * The property file contains entries that look like this: + *

+     *  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
+     * 
+ * Each entry maps a symbolic font names (the font registry keys) with + * a ".n suffix to standard font names + * on the right. The suffix indicated order of preference: + * ".0" indicates the first choice, + * ".1" indicates the second choice, and so on. + *

+ * The following example shows how to use the font registry: + *
+     *  FontRegistry registry = new FontRegistry("com.example.myapp.fonts");
+     *  Font font = registry.get("textfont");
+     *  control.setFont(font);
+     *  ...
+     * 
+ * + * @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 Display + * @param cleanOnDisplayDisposal + * whether all fonts allocated by this FontRegistry + * 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 + * null 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 null. + * + * @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 null. + * + * @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 null + * if there is no data. + * @return FontRecord for the new Font or null. + */ + 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. + *

+ * 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. + *

+ * + * @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. + *

+ * 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. + *

+ * + * @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()); + } +} diff -r 1a6747be662d -r 8a302fdb4140 dwtx/jface/resource/JFaceResources.d --- /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 + *******************************************************************************/ +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. + *

+ * All methods declared on this class are static. This class cannot be + * instantiated. + *

+ *

+ * The following global state is also maintained by this class: + *

    + *
  • a font registry
  • + *
  • a color registry
  • + *
  • an image registry
  • + *
  • a resource bundle
  • + *
+ *

+ */ +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 + * "dwtx.jface.bannerfont"). + */ + 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; null until lazily initialized or + * explicitly set. + */ + private static ColorRegistry colorRegistry; + + /** + * The symbolic font name for the standard font (value + * "dwtx.jface.defaultfont"). + */ + public static final String DEFAULT_FONT = "dwtx.jface.defaultfont"; //$NON-NLS-1$ + + /** + * The symbolic font name for the dialog font (value + * "dwtx.jface.dialogfont"). + */ + public static final String DIALOG_FONT = "dwtx.jface.dialogfont"; //$NON-NLS-1$ + + /** + * The JFace font registry; null until lazily initialized or + * explicitly set. + */ + private static FontRegistry fontRegistry = null; + + /** + * The symbolic font name for the header font (value + * "dwtx.jface.headerfont"). + */ + public static final String HEADER_FONT = "dwtx.jface.headerfont"; //$NON-NLS-1$ + + /** + * The JFace image registry; null until lazily initialized. + */ + private static ImageRegistry imageRegistry = null; + + /** + * The symbolic font name for the text font (value + * "dwtx.jface.textfont"). + */ + public static final String TEXT_FONT = "dwtx.jface.textfont"; //$NON-NLS-1$ + + /** + * The symbolic font name for the viewer font (value + * "dwtx.jface.viewerfont"). + * + * @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 + * "dwtx.jface.windowfont"). + * + * @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 + * + *
+     * JFaceResources.getFontRegistry().get(JFaceResources.BANNER_FONT)
+     * 
+ * + * @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 + * ResourceBundle.getBundle("dwtx.jface.jface_nls"). + *

+ * Note that several static convenience methods are also provided on this + * class for directly accessing resources in this bundle. + *

+ * + * @return the resource bundle + */ + public static ResourceBundle getBundle() { + return bundle; + } + + /** + * Returns the color registry for JFace itself. + *

+ * + * @return the ColorRegistry. + * @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 + * + *

+     * JFaceResources.getFontRegistry().get(JFaceResources.DEFAULT_FONT)
+     * 
+ * + * @return the font + */ + public static Font getDefaultFont() { + return getFontRegistry().defaultFont(); + } + + /** + * Returns the descriptor for JFace's standard font. Convenience method + * equivalent to + * + *
+     * JFaceResources.getFontRegistry().getDescriptor(JFaceResources.DEFAULT_FONT)
+     * 
+ * + * @return the font + * @since 3.3 + */ + public static FontDescriptor getDefaultFontDescriptor() { + return getFontRegistry().defaultFontDescriptor(); + } + + /** + * Returns the JFace's dialog font. Convenience method equivalent to + * + *
+     * JFaceResources.getFontRegistry().get(JFaceResources.DIALOG_FONT)
+     * 
+ * + * @return the font + */ + public static Font getDialogFont() { + return getFontRegistry().get(DIALOG_FONT); + } + + /** + * Returns the descriptor for JFace's dialog font. Convenience method + * equivalent to + * + *
+     * JFaceResources.getFontRegistry().getDescriptor(JFaceResources.DIALOG_FONT)
+     * 
+ * + * @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 + * + *
+     * JFaceResources.getFontRegistry().get(symbolicName)
+     * 
+ * + * 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 + * + *
+     * JFaceResources.getFontRegistry().getDescriptor(symbolicName)
+     * 
+ * + * 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 setFontRegistry, is it + * initialized to + * new FontRegistry("dwtx.jface.resource.jfacefonts"). + *

+ * Note that several static convenience methods are also provided on this + * class for directly accessing JFace's standard fonts. + *

+ * + * @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 + * + *
+     * JFaceResources.getFontRegistry().get(JFaceResources.HEADER_FONT)
+     * 
+ * + * @return the font + */ + public static Font getHeaderFont() { + return getFontRegistry().get(HEADER_FONT); + } + + /** + * Returns the descriptor for JFace's header font. Convenience method + * equivalent to + * + *
+     * JFaceResources.getFontRegistry().get(JFaceResources.HEADER_FONT)
+     * 
+ * + * @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 + * null if none. Convenience method equivalent to + * + *
+     * JFaceResources.getImageRegistry().get(key)
+     * 
+ * + * @param key + * the key + * @return the image, or null if none + */ + public static Image getImage(String key) { + return getImageRegistry().get(key); + } + + /** + * Returns the image registry for JFace itself. + *

+ * Note that the static convenience method getImage is also + * provided on this class. + *

+ * + * @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 declareImage method. + * + * @param bundle + * the {@link Bundle} or null 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 getString. 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 + * + *
+     * JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT)
+     * 
+ * + * @return the font + */ + public static Font getTextFont() { + return getFontRegistry().get(TEXT_FONT); + } + + /** + * Returns the descriptor for JFace's text font. Convenience method + * equivalent to + * + *
+     * JFaceResources.getFontRegistry().getDescriptor(JFaceResources.TEXT_FONT)
+     * 
+ * + * @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 + * + *
+     * JFaceResources.getFontRegistry().get(JFaceResources.VIEWER_FONT)
+     * 
+ * + * @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 + * JFaceResources.getFontRegistry 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 diff -r 1a6747be662d -r 8a302fdb4140 dwtx/jface/resource/ResourceRegistry.d --- /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 + *******************************************************************************/ +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 true if there is a value for this key + */ + public abstract bool hasValueFor(String key); + + /** + * Fires a PropertyChangeEvent. + * + * @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); + } +} diff -r 1a6747be662d -r 8a302fdb4140 dwtx/jface/resource/StringConverter.d --- /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 + *******************************************************************************/ +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: + *
    + *
  • bool
  • + *
  • int
  • + *
  • long
  • + *
  • float
  • + *
  • double
  • + *
  • dwt.graphics.Point
  • + *
  • dwt.graphics.Rectangle
  • + *
  • dwt.graphics.RGB
  • + *
  • dwt.graphics.FontData
  • + *
+ *

+ * All methods declared on this class are static. This + * class cannot be instantiated. + *

+ */ +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: "no comment" into an array + * a[0]="no" and a[1]= "comment". + * + * @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: "no comment" into an array + * a[0]="no" and a[1]= "comment". + * 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. + *

+ * Valid representations of true include the strings + * "t", "true", or equivalent in mixed + * or upper case. + * Similarly, valid representations of false include the strings + * "f", "false", or equivalent in mixed + * or upper case. + *

+ * + * @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. + *

+ * A valid font data representation is a string of the form + * fontname-style-height where + * fontname is the name of a font, + * style is a font style (one of + * "regular", "bold", + * "italic", or "bold italic") + * and height is an integer representing the + * font height. Example: Times New Roman-bold-36. + *

+ * + * @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. + *

+ * A valid point representation is a string of the form + * x,y where + * x and y + * are valid ints. + *

+ * + * @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. + *

+ * A valid rectangle representation is a string of the form + * x,y,width,height + * where x, y, + * width, and height + * are valid ints. + *

+ * + * @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. + *

+ * A valid RGB color value representation is a string of the form + * red,green,blue where + * red, green, and + * blue are valid ints. + *

+ * + * @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 String.valueOf(value). + * + * @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 String.valueOf(value). + * + * @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 String.valueOf(value). + * + * @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 String.valueOf(value). + * + * @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 String.valueOf(value.booleanValue()). +// * +// * @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 String.valueOf(value.doubleValue()). +// * +// * @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 String.valueOf(value.floatValue()). +// * +// * @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 String.valueOf(value.intValue()). +// * +// * @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 String.valueOf(value.longValue()). +// * +// * @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. + *

+ * The string representation of a point has the form + * x,y where + * x and y + * are string representations of integers. + *

+ * + * @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. + *

+ * The string representation of a rectangle has the form + * x,y,width,height + * where x, y, + * width, and height + * are string representations of integers. + *

+ * + * @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. + *

+ * The string representation of an RGB color value has the form + * red,green,blue where + * red, green, and + * blue are string representations of integers. + *

+ * + * @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 String.valueOf(value). + * + * @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. + *

+ * All characters that have codes less than or equal to '\u0020' + * (the space character) are considered to be a white space. + *

+ * + * @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(); + + } +} diff -r 1a6747be662d -r 8a302fdb4140 dwtx/jface/window/DefaultToolTip.d --- /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 + *******************************************************************************/ + +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 true 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 + *
    + *
  • {@link #getStyle(Event)}
  • + *
  • {@link #getBackgroundColor(Event)}
  • + *
  • {@link #getForegroundColor(Event)}
  • + *
  • {@link #getFont(Event)}
  • + *
  • {@link #getImage(Event)}
  • + *
  • {@link #getText(Event)}
  • + *
  • {@link #getBackgroundImage(Event)}
  • + *
+ * + * @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 null 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 null 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 null 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 null 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 null 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 null 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 null 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 null 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 null 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 null 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 null 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 null if no text has to be displayed + */ + public void setText(String text) { + this.text = text; + } + +} diff -r 1a6747be662d -r 8a302fdb4140 dwtx/jface/window/IShellProvider.d --- /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 + *******************************************************************************/ +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(); +} diff -r 1a6747be662d -r 8a302fdb4140 dwtx/jface/window/SameShellProvider.d --- /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 + *******************************************************************************/ +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(); + } + +} diff -r 1a6747be662d -r 8a302fdb4140 dwtx/jface/window/ToolTip.d --- /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 - initial API and implementation + * Port to the D programming language: + * Frank Benoit + *******************************************************************************/ + +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 + * true 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 null 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 true if the tooltip respects bounds of the display + */ + public bool isRespectDisplayBounds() { + return respectDisplayBounds; + } + + /** + * Set to false if display bounds should not be respected or + * to true if the tooltip is should repositioned to not + * overlap the display bounds. + *

+ * Default is true + *

+ * + * @param respectDisplayBounds + */ + public void setRespectDisplayBounds(bool respectDisplayBounds) { + this.respectDisplayBounds = respectDisplayBounds; + } + + /** + * Return whther the tooltip respects bounds of the monitor. + * + * @return true if tooltip respects the bounds of the monitor + */ + public bool isRespectMonitorBounds() { + return respectMonitorBounds; + } + + /** + * Set to false if monitor bounds should not be respected or + * to true 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. + *

+ * Default is true + *

+ * + * @param respectMonitorBounds + */ + public void setRespectMonitorBounds(bool respectMonitorBounds) { + this.respectMonitorBounds = respectMonitorBounds; + } + + /** + * Should the tooltip displayed because of the given event. + *

+ * Subclasses may overwrite this to get custom behaviour + *

+ * + * @param event + * the event + * @return true 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 true 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. + * + * 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. + * + * @param event + * the event + * @return the area responsible for the tooltip creation or + * null 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. + *

+ * Subclasses may override to clean up requested system resources + *

+ * + * @param event + * event triggered the hiding action (may be null + * 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 0 + * 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 + * 0 the tooltip is shown immediately + */ + public void setPopupDelay(int popupDelay) { + this.popupDelay = popupDelay; + } + + /** + * Return if hiding on mouse down is set. + * + * @return true 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 false. 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; + } + } + } + } +} diff -r 1a6747be662d -r 8a302fdb4140 dwtx/jface/window/Window.d --- /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 + *******************************************************************************/ +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. + *

+ * Creating a window involves the following steps: + *

    + *
  • creating an instance of a concrete subclass of Window + *
  • + *
  • creating the window's shell and widget tree by calling + * create (optional)
  • + *
  • assigning the window to a window manager using + * WindowManager.add (optional)
  • + *
  • opening the window by calling open
  • + *
+ * 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. + *

+ *

+ * The JFace window framework (this package) consists of this class, + * Window, the abstract base of all windows, and one concrete + * window classes (ApplicationWindow) which may also be + * subclassed. Clients may define additional window subclasses as required. + *

+ *

+ * The Window class provides methods that subclasses may + * override to configure the window, including: + *

    + *
  • close- extend to free other DWT resources
  • + *
  • configureShell- extend or reimplement to set shell + * properties before window opens
  • + *
  • createContents- extend or reimplement to create controls + * before window opens
  • + *
  • getInitialSize- reimplement to give the initial size for + * the shell
  • + *
  • getInitialLocation- reimplement to give the initial + * location for the shell
  • + *
  • getShellListener- extend or reimplement to receive shell + * events
  • + *
  • handleFontChange- reimplement to respond to font changes + *
  • + *
  • handleShellCloseEvent- extend or reimplement to handle + * shell closings
  • + *
+ *

+ */ +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 null if none. + * + * @see #setWindowManager + */ + private WindowManager windowManager; + + /** + * Window shell, or null if none. + */ + private Shell shell; + + /** + * Top level DWT control, or null if none + */ + private Control contents; + + /** + * Window return code; initially OK. + * + * @see #setReturnCode + */ + private int returnCode = OK; + + /** + * true if the open method should not return + * until the window closes, and false if the + * open method should return immediately; initially + * false (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, open does not block. + * + * @param parentShell + * the parent shell, or null 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. + *

+ * The default implementation of this framework method returns + * true, which will allow the + * handleShellCloseEvent method to be called. Subclasses may + * extend or reimplement. + *

+ * + * @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). + *

+ * This framework method may be extended (super.close must + * be called). + *

+ * + * @return true if the window is (or was already) closed, and + * false 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. + *

+ * The default implementation of this framework method sets the shell's + * image and gives it a grid layout. Subclasses may extend or reimplement. + *

+ * + * @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. + * + *

+ * 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. + *

+ * + * @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. + *

+ * The default implementation of this framework method creates this window's + * shell (by calling createShell), and its controls (by + * calling createContents), then initializes this window's + * shell bounds (by calling initializeBounds). + *

+ */ + 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. + * + *

+ * It is common practise to create and return a single composite that + * contains the entire window contents. + *

+ * + *

+ * The default implementation of this framework method creates an instance + * of Composite. Subclasses may override. + *

+ * + * @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. + *

+ * The default implementation of this framework method creates a new shell + * and configures it using configureShell. Rather than + * override this method, subclasses should instead override + * configureShell. + *

+ * + * @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 null 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 setDefaultImage. + * + * @return the default image, or null 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 + * getInitialSize. + * @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 + * Shell.computeSize(DWT.DEFAULT, DWT.DEFAULT, true). + * + * @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 null 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: + * OK and CANCEL. + * + * @return the return code + */ + public int getReturnCode() { + return returnCode; + } + + /** + * Returns this window's shell. + * + * @return this window's shell, or null 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. + *

+ * 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 handleShellCloseEvent when the shell is closed. + * Subclasses may extend or reimplement. + *

+ * + * @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. + *

+ * The default value is DWT.CLOSE|DWT.MIN|DWT.MAX|DWT.RESIZE. + * Subclassers should call setShellStyle to change this + * value, rather than overriding this method. + *

+ * + * @return the shell style bits + */ + protected int getShellStyle() { + return shellStyle; + } + + /** + * Returns the window manager of this window. + * + * @return the WindowManager, or null if none + */ + public WindowManager getWindowManager() { + return windowManager; + } + + /** + * Notifies of a font property change. + *

+ * The default implementation of this framework method does nothing. + * Subclasses may reimplement. + *

+ * + * @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. + *

+ * The default implementation of this framework method sets the window's + * return code to CANCEL and closes the window using + * close. Subclasses may extend or reimplement. + *

+ */ + protected void handleShellCloseEvent() { + setReturnCode(CANCEL); + close(); + } + + /** + * Initializes the location and size of this window's DWT shell after it has + * been created. + *

+ * This framework method is called by the create framework + * method. The default implementation calls getInitialSize + * and getInitialLocation and passes the results to + * Shell.setBounds. This is only done if the bounds of the + * shell have not already been modified. Subclasses may extend or + * reimplement. + *

+ */ + 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. + *

+ * If this window has been configured to block on open ( + * setBlockOnOpen), 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: + * OK and CANCEL. + *

+ * + * @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 open method should block until the window + * closes. + * + * @param shouldBlock + * true if the open method should + * not return until the window closes, and false + * if the open 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 null 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 null 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 open if block on open is enabled. For non-blocking + * opens, the return code needs to be retrieved manually using + * getReturnCode. + * + * @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. + *

+ * The shell style bits are used by the framework method + * createShell when creating this window's shell. + *

+ * + * @param newShellStyle + * the new shell style bits + */ + protected void setShellStyle(int newShellStyle) { + shellStyle = newShellStyle; + } + + /** + * Sets the window manager of this window. + *

+ * Note that this method is used by WindowManager to maintain + * a backpointer. Clients must not call the method directly. + *

+ * + * @param manager + * the window manager, or null 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. + *

+ * Note that the handler may only be set once. Subsequent calls to this method will be + * ignored. + *

+ * + * @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; + + } + +} diff -r 1a6747be662d -r 8a302fdb4140 dwtx/jface/window/WindowManager.d --- /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 + *******************************************************************************/ +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. + *

+ * Creating a window manager is as simple as creating an instance of + * WindowManager. Associating a window with a window manager is + * done with WindowManager.add(Window). A window is automatically + * removed from its window manager as a side effect of closing the window. + *

+ * + * @see Window + */ +public class WindowManager { + + /** + * List of windows managed by this window manager + * (element type: Window). + */ + private ArraySeq!(Window) windows; + + /** + * List of window managers who have this window manager + * as their parent (element type: WindowManager). + */ + 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. + *

+ * @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 true if all windows were sucessfully closed, + * and false 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); + } + } +}