changeset 19:2b36428a5ce4

DialogSettings
author Frank Benoit <benoit@tionex.de>
date Thu, 03 Apr 2008 00:25:45 +0200
parents 7615869f89e6
children d1f4edab3f34
files dwtx/jface/dialogs/DialogMessageArea.d dwtx/jface/dialogs/DialogSettings.d dwtx/jface/dialogs/IDialogSettings.d
diffstat 3 files changed, 706 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/dialogs/DialogMessageArea.d	Thu Apr 03 00:25:45 2008 +0200
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.dialogs.DialogMessageArea;
+
+import dwtx.jface.dialogs.Dialog;
+import dwtx.jface.dialogs.IMessageProvider;
+
+import dwt.DWT;
+import dwt.custom.CLabel;
+import dwt.graphics.Image;
+import dwt.layout.GridData;
+import dwt.layout.GridLayout;
+import dwt.widgets.Composite;
+import dwt.widgets.Label;
+import dwt.widgets.Text;
+import dwtx.jface.resource.JFaceResources;
+
+import dwt.dwthelper.utils;
+
+/**
+ * The DialogMessageArea is a resusable component for adding an accessible
+ * message area to a dialog.
+ *
+ * When the message is normal a CLabel is used but an errors replaces the
+ * message area with a non editable text that can take focus for use by screen
+ * readers.
+ *
+ * @since 3.0
+ */
+public class DialogMessageArea : Object {
+    private Text messageText;
+
+    private Label messageImageLabel;
+
+    private Composite messageComposite;
+
+    private String lastMessageText;
+
+    private int lastMessageType;
+
+    private CLabel titleLabel;
+
+    /**
+     * Create a new instance of the receiver.
+     */
+    public this() {
+        //No initial behaviour
+    }
+
+    /**
+     * Create the contents for the receiver.
+     *
+     * @param parent
+     *            the Composite that the children will be created in
+     */
+    public void createContents(Composite parent) {
+
+        // Message label
+        titleLabel = new CLabel(parent, DWT.NONE);
+        titleLabel.setFont(JFaceResources.getBannerFont());
+        messageComposite = new Composite(parent, DWT.NONE);
+        GridLayout messageLayout = new GridLayout();
+        messageLayout.numColumns = 2;
+        messageLayout.marginWidth = 0;
+        messageLayout.marginHeight = 0;
+        messageLayout.makeColumnsEqualWidth = false;
+        messageComposite.setLayout(messageLayout);
+        messageImageLabel = new Label(messageComposite, DWT.NONE);
+        messageImageLabel.setImage(JFaceResources
+                .getImage(Dialog.DLG_IMG_MESSAGE_INFO));
+        messageImageLabel.setLayoutData(new GridData(
+                GridData.VERTICAL_ALIGN_CENTER));
+
+        messageText = new Text(messageComposite, DWT.NONE);
+        messageText.setEditable(false);
+
+        GridData textData = new GridData(GridData.GRAB_HORIZONTAL
+                | GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_CENTER);
+        messageText.setLayoutData(textData);
+
+    }
+
+    /**
+     * Set the layoutData for the title area. In most cases this will be a copy
+     * of the layoutData used in setMessageLayoutData.
+     *
+     * @param layoutData
+     *            the layoutData for the title
+     * @see #setMessageLayoutData(Object)
+     */
+    public void setTitleLayoutData(Object layoutData) {
+        titleLabel.setLayoutData(layoutData);
+    }
+
+    /**
+     * Set the layoutData for the messageArea. In most cases this will be a copy
+     * of the layoutData used in setTitleLayoutData.
+     *
+     * @param layoutData
+     *            the layoutData for the message area composite.
+     * @see #setTitleLayoutData(Object)
+     */
+    public void setMessageLayoutData(Object layoutData) {
+        messageComposite.setLayoutData(layoutData);
+    }
+
+    /**
+     * Show the title.
+     *
+     * @param titleMessage
+     *            String for the titke
+     * @param titleImage
+     *            Image or <code>null</code>
+     */
+    public void showTitle(String titleMessage, Image titleImage) {
+        titleLabel.setImage(titleImage);
+        titleLabel.setText(titleMessage);
+        restoreTitle();
+        return;
+    }
+
+    /**
+     * Enable the title and disable the message text and image.
+     */
+    public void restoreTitle() {
+        titleLabel.setVisible(true);
+        messageComposite.setVisible(false);
+        lastMessageText = null;
+        lastMessageType = IMessageProvider.NONE;
+    }
+
+    /**
+     * Show the new message in the message text and update the image. Base the
+     * background color on whether or not there are errors.
+     *
+     * @param newMessage
+     *            The new value for the message
+     * @param newType
+     *            One of the IMessageProvider constants. If newType is
+     *            IMessageProvider.NONE show the title.
+     * @see IMessageProvider
+     */
+    public void updateText(String newMessage, int newType) {
+        Image newImage = null;
+        switch (newType) {
+        case IMessageProvider.NONE:
+            if (newMessage is null) {
+                restoreTitle();
+            } else {
+                showTitle(newMessage, null);
+            }
+            return;
+        case IMessageProvider.INFORMATION:
+            newImage = JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_INFO);
+            break;
+        case IMessageProvider.WARNING:
+            newImage = JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_WARNING);
+            break;
+        case IMessageProvider.ERROR:
+            newImage = JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_ERROR);
+
+            break;
+        }
+        messageComposite.setVisible(true);
+        titleLabel.setVisible(false);
+        // Any more updates required?
+        // If the message text equals the tooltip (i.e. non-shortened text is the same)
+        // and shortened text is the same (i.e. not a resize)
+        // and the image is the same then nothing to do
+        String shortText = Dialog.shortenText(newMessage,messageText);
+        if (newMessage.equals(messageText.getToolTipText())
+                && newImage is messageImageLabel.getImage()
+                    && shortText.equals(messageText.getText())) {
+            return;
+        }
+        messageImageLabel.setImage(newImage);
+        messageText.setText(Dialog.shortenText(newMessage,messageText));
+        messageText.setToolTipText(newMessage);
+        lastMessageText = newMessage;
+
+    }
+
+
+    /**
+     * Clear the error message. Restore the previously displayed message if
+     * there is one, if not restore the title label.
+     *
+     */
+    public void clearErrorMessage() {
+        if (lastMessageText is null) {
+            restoreTitle();
+        } else {
+            updateText(lastMessageText, lastMessageType);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/jface/dialogs/DialogSettings.d	Thu Apr 03 00:25:45 2008 +0200
@@ -0,0 +1,496 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2006 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.jface.dialogs.DialogSettings;
+
+import dwtx.jface.dialogs.IDialogSettings;
+
+import tango.util.collection.model.Map;
+import tango.util.collection.model.Seq;
+import tango.util.collection.HashMap;
+import tango.util.collection.ArraySeq;
+
+static import tango.text.xml.Document;
+static import tango.text.xml.SaxParser;
+static import tango.text.xml.PullParser;
+static import tango.text.xml.XmlPrinter;
+
+
+import dwt.dwthelper.utils;
+static import dwt.dwthelper.OutputStream;
+static import tango.text.convert.Integer;
+static import tango.text.convert.Float;
+static import tango.text.Text;
+static import tango.io.File;
+static import tango.io.Print;
+static import tango.io.model.IConduit;
+static import tango.io.stream.FileStream;
+static import tango.text.convert.Format;
+import tango.core.Exception;
+alias tango.text.Text.Text!(char) StringBuffer;
+
+/**
+ * Concrete implementation of a dialog settings (<code>IDialogSettings</code>)
+ * using a hash table and XML. The dialog store can be read
+ * from and saved to a stream. All keys and values must be strings or array of
+ * strings. Primitive types are converted to strings.
+ * <p>
+ * This class was not designed to be subclassed.
+ *
+ * Here is an example of using a DialogSettings:
+ * </p>
+ * <pre>
+ * <code>
+ * DialogSettings settings = new DialogSettings("root");
+ * settings.put("Boolean1",true);
+ * settings.put("Long1",100);
+ * settings.put("Array1",new String[]{"aaaa1","bbbb1","cccc1"});
+ * DialogSettings section = new DialogSettings("sectionName");
+ * settings.addSection(section);
+ * section.put("Int2",200);
+ * section.put("Float2",1.1);
+ * section.put("Array2",new String[]{"aaaa2","bbbb2","cccc2"});
+ * settings.save("c:\\temp\\test\\dialog.xml");
+ * </code>
+ * </pre>
+ */
+
+public class DialogSettings : IDialogSettings {
+    alias tango.text.xml.Document.Document!(char) Document;
+    alias tango.text.xml.Document.Document!(char).Node Element;
+    alias tango.text.xml.XmlPrinter.XmlPrinter!(char) XmlPrinter;
+    // The name of the DialogSettings.
+    private String name;
+
+    /* A Map of DialogSettings representing each sections in a DialogSettings.
+     It maps the DialogSettings' name to the DialogSettings */
+    private Map!(String,IDialogSettings) sections;
+
+    /* A Map with all the keys and values of this sections.
+     Either the keys an values are restricted to strings. */
+    private Map!(String,String) items;
+
+    // A Map with all the keys mapped to array of strings.
+    private Map!(String,String[]) arrayItems;
+
+    private static const String TAG_SECTION = "section";//$NON-NLS-1$
+
+    private static const String TAG_NAME = "name";//$NON-NLS-1$
+
+    private static const String TAG_KEY = "key";//$NON-NLS-1$
+
+    private static const String TAG_VALUE = "value";//$NON-NLS-1$
+
+    private static const String TAG_LIST = "list";//$NON-NLS-1$
+
+    private static const String TAG_ITEM = "item";//$NON-NLS-1$
+
+    /**
+     * Create an empty dialog settings which loads and saves its
+     * content to a file.
+     * Use the methods <code>load(String)</code> and <code>store(String)</code>
+     * to load and store this dialog settings.
+     *
+     * @param sectionName the name of the section in the settings.
+     */
+    public this(String sectionName) {
+        name = sectionName;
+        items = new HashMap!(String,String);
+        arrayItems = new HashMap!(String,String[]);
+        sections = new HashMap!(String,IDialogSettings);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public IDialogSettings addNewSection(String sectionName) {
+        DialogSettings section = new DialogSettings(sectionName);
+        addSection(section);
+        return section;
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public void addSection(IDialogSettings section) {
+        sections.add(section.getName(), section);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public String get(String key) {
+        return items.get(key);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public String[] getArray(String key) {
+        return arrayItems.get(key);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public bool getBoolean(String key) {
+        return items.get(key) == "true";
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public double getDouble(String key) {
+        String setting = items.get(key);
+        if (setting is null) {
+            throw new NumberFormatException(
+                    "There is no setting associated with the key \"" ~ key ~ "\"");//$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        return tango.text.convert.Float.toFloat(setting);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public float getFloat(String key) {
+        String setting = items.get(key);
+        if (setting is null) {
+            throw new NumberFormatException(
+                    "There is no setting associated with the key \"" ~ key ~ "\"");//$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        return tango.text.convert.Float.toFloat(setting);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public int getInt(String key) {
+        String setting = items.get(key);
+        if (setting is null) {
+            //new Integer(null) will throw a NumberFormatException and meet our spec, but this message
+            //is clearer.
+            throw new NumberFormatException(
+                    "There is no setting associated with the key \"" ~ key ~ "\"");//$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        return tango.text.convert.Integer.toInt(setting);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public long getLong(String key) {
+        String setting = items.get(key);
+        if (setting is null) {
+            //new Long(null) will throw a NumberFormatException and meet our spec, but this message
+            //is clearer.
+            throw new NumberFormatException(
+                    "There is no setting associated with the key \"" ~ key ~ "\"");//$NON-NLS-1$ //$NON-NLS-2$
+        }
+
+        return tango.text.convert.Integer.toLong(setting);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public IDialogSettings getSection(String sectionName) {
+        return sections.get(sectionName);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public IDialogSettings[] getSections() {
+        return sections.toArray();
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public void load( tango.io.model.IConduit.InputStream input) {
+        Document document = new Document();
+        try {
+            char[] content;
+            char[1024] readbuf;
+            int chunksize = 0;
+            while( (chunksize=input.read(readbuf)) !is tango.io.model.IConduit.InputStream.Eof ){
+                content ~=  readbuf[ 0 .. chunksize ];
+            }
+            document.parse( content );
+
+            //Strip out any comments first
+            foreach( n; document.query[].filter( delegate bool(Element n) {
+                    return n.type is tango.text.xml.PullParser.XmlNodeType.Comment ;
+                })){
+                //TODO: remove() was added after tango 0.99.5
+                //n.remove();
+            }
+            load(document, document.root.firstChild );
+        } catch (IOException e) {
+            // ignore
+        } catch (TextException e) {
+            // ignore
+        }
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    //TODO: solve overload load(char[])
+    public void load(String fileName) {
+        auto f = new tango.io.stream.FileStream.FileInput( fileName );
+        load( f.input );
+        f.close;
+    }
+
+    /* (non-Javadoc)
+     * Load the setting from the <code>document</code>
+     */
+    private void load(Document document, Element root) {
+
+        name = root.getAttribute(TAG_NAME).value();
+
+        foreach( n; root.query[TAG_ITEM] ){
+            if( root is n.parent() ){
+                String key = n.getAttribute(TAG_KEY).value().dup;
+                String value = n.getAttribute(TAG_VALUE).value().dup;
+                items.add(key, value);
+            }
+        }
+        foreach( n; root.query[TAG_LIST].dup ){
+            if( root is n.parent() ){
+                auto child = n;
+                String key = child.getAttribute(TAG_KEY).value().dup;
+                char[][] valueList;
+                foreach( node; root.query[TAG_ITEM].dup ){
+                    if (child is node.parent()) {
+                        valueList ~= node.getAttribute(TAG_VALUE).value().dup;
+                    }
+                }
+                arrayItems.add(key, valueList );
+            }
+        }
+        foreach( n; root.query[TAG_SECTION].dup ){
+            if( root is n.parent() ){
+                DialogSettings s = new DialogSettings("NoName");//$NON-NLS-1$
+                s.load(document, n);
+                addSection(s);
+            }
+        }
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public void put(String key, String[] value) {
+        arrayItems.add(key, value);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public void put(String key, double value) {
+        put(key, tango.text.convert.Float.toString(value));
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public void put(String key, float value) {
+        put(key, tango.text.convert.Float.toString(value));
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public void put(String key, int value) {
+        put(key, tango.text.convert.Integer.toString(value));
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public void put(String key, long value) {
+        put(key, tango.text.convert.Integer.toString(value));
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public void put(String key, String value) {
+        items.add(key, value);
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public void put(String key, bool value) {
+        put(key, value ? "true" : "false" );
+    }
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public void save(tango.io.model.IConduit.OutputStream writer) {
+        save(new XMLWriter(writer));
+    }
+
+
+    /* (non-Javadoc)
+     * Method declared on IDialogSettings.
+     */
+    public void save(String fileName) {
+        auto stream = new tango.io.stream.FileStream.FileOutput(fileName);
+        XMLWriter writer = new XMLWriter(stream.output);
+        save(writer);
+        writer.close();
+    }
+
+    /* (non-Javadoc)
+     * Save the settings in the <code>document</code>.
+     */
+    private void save(XMLWriter out_) {
+        HashMap!(String,String) attributes = new HashMap!(String,String);
+        attributes.add(TAG_NAME, name is null ? "" : name); //$NON-NLS-1$
+        out_.startTag(TAG_SECTION, attributes);
+        attributes.clear();
+
+        foreach( key,value; items ){
+            attributes.add(TAG_KEY, key is null ? "" : key); //$NON-NLS-1$
+            String string = value;cast(String) items.get(key);
+            attributes.add(TAG_VALUE, string is null ? "" : string); //$NON-NLS-1$
+            out_.printTag(TAG_ITEM, attributes, true);
+        }
+
+        attributes.clear();
+        foreach( key,value; arrayItems ){
+            attributes.add(TAG_KEY, key is null ? "" : key); //$NON-NLS-1$
+            out_.startTag(TAG_LIST, attributes);
+            attributes.clear();
+            if (value !is null) {
+                for (int index = 0; index < value.length; index++) {
+                    String string = value[index];
+                    attributes.add(TAG_VALUE, string is null ? "" : string); //$NON-NLS-1$
+                    out_.printTag(TAG_ITEM, attributes, true);
+                }
+            }
+            out_.endTag(TAG_LIST);
+            attributes.clear();
+        }
+        foreach( name, section; sections ){
+            section.save(out_);
+        }
+        out_.endTag(TAG_SECTION);
+    }
+
+
+    /**
+     * A simple XML writer.  Using this instead of the javax.xml.transform classes allows
+     * compilation against JCL Foundation (bug 80059).
+     */
+    private static class XMLWriter : tango.io.Print.Print!(char) {
+        /** current number of tabs to use for ident */
+        protected int tab;
+
+        /** the xml header */
+        protected static const String XML_VERSION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; //$NON-NLS-1$
+
+        /**
+         * Create a new XMLWriter
+         * @param output the write to used when writing to
+         */
+        public this(tango.io.model.IConduit.OutputStream output) {
+            super( tango.text.convert.Format.Format, output);
+            tab = 0;
+            print(XML_VERSION);
+            newline;
+        }
+
+        /**
+         * write the intended end tag
+         * @param name the name of the tag to end
+         */
+        public void endTag(String name) {
+            tab--;
+            printTag("/" ~ name, null, false); //$NON-NLS-1$
+        }
+
+        private void printTabulation() {
+            for (int i = 0; i < tab; i++) {
+                super.print('\t');
+            }
+        }
+
+        /**
+         * write the tag to the stream and format it by itending it and add new line after the tag
+         * @param name the name of the tag
+         * @param parameters map of parameters
+         * @param close should the tag be ended automatically (=> empty tag)
+         */
+        public void printTag(String name, HashMap!(String,String) parameters, bool close) {
+            printTag(name, parameters, true, true, close);
+        }
+
+        private void printTag(String name, HashMap!(String,String) parameters, bool shouldTab, bool newLine, bool close) {
+            StringBuffer sb = new StringBuffer();
+            sb.append('<');
+            sb.append(name);
+            if (parameters !is null) {
+                foreach( key, value; parameters ){
+                    sb.append(" "); //$NON-NLS-1$
+                    sb.append(key);
+                    sb.append("=\""); //$NON-NLS-1$
+                    sb.append(xmlEscape(value.dup));
+                    sb.append("\""); //$NON-NLS-1$
+                }
+            }
+            if (close) {
+                sb.append('/');
+            }
+            sb.append('>');
+            if (shouldTab) {
+                printTabulation();
+            }
+            if (newLine) {
+                print(sb.toString());
+                newline;
+            } else {
+                print(sb.toString());
+            }
+        }
+
+        /**
+         * start the tag
+         * @param name the name of the tag
+         * @param parameters map of parameters
+         */
+        public void startTag(String name, HashMap!(String,String) parameters) {
+            startTag(name, parameters, true);
+            tab++;
+        }
+
+        private void startTag(String name, HashMap!(String,String) parameters, bool newLine) {
+            printTag(name, parameters, true, newLine, false);
+        }
+    }
+
+}
--- a/dwtx/jface/dialogs/IDialogSettings.d	Tue Apr 01 08:32:04 2008 +0200
+++ b/dwtx/jface/dialogs/IDialogSettings.d	Thu Apr 03 00:25:45 2008 +0200
@@ -18,6 +18,8 @@
 
 import dwt.dwthelper.utils;
 
+static import tango.io.model.IConduit;
+
 /**
  * An interface to a storage mechanism for making dialog settings persistent.
  * The store manages a collection of key/value pairs. The keys must be strings
@@ -163,7 +165,7 @@
      *            from.
      * @throws IOException
      */
-    public void load(Reader reader);
+    public void load(tango.io.model.IConduit.InputStream reader);
 
     /**
      * Load a dialog settings from a file and fill the receiver with its
@@ -257,7 +259,7 @@
      *            a Writer specifying the stream the settings are written in.
      * @throws IOException
      */
-    public void save(Writer writer);
+    public void save(tango.io.model.IConduit.OutputStream writer);
 
     /**
      * Save a dialog settings to a file.