# HG changeset patch # User Frank Benoit # Date 1207175145 -7200 # Node ID 2b36428a5ce41a1dd9b728a91647f716b3079dff # Parent 7615869f89e603daa1c730fbaef3d44730200795 DialogSettings diff -r 7615869f89e6 -r 2b36428a5ce4 dwtx/jface/dialogs/DialogMessageArea.d --- /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 + *******************************************************************************/ +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 null + */ + 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); + } + } +} diff -r 7615869f89e6 -r 2b36428a5ce4 dwtx/jface/dialogs/DialogSettings.d --- /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 + *******************************************************************************/ +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 (IDialogSettings) + * 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. + *

+ * This class was not designed to be subclassed. + * + * Here is an example of using a DialogSettings: + *

+ *
+ * 
+ * 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");
+ * 
+ * 
+ */ + +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 load(String) and store(String) + * 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 document + */ + 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 document. + */ + 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 = ""; //$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); + } + } + +} diff -r 7615869f89e6 -r 2b36428a5ce4 dwtx/jface/dialogs/IDialogSettings.d --- 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.