Mercurial > projects > dwt-addons
diff dwtx/jface/dialogs/DialogSettings.d @ 19:2b36428a5ce4
DialogSettings
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Thu, 03 Apr 2008 00:25:45 +0200 |
parents | |
children | da5ad8eedf5d |
line wrap: on
line diff
--- /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); + } + } + +}