changeset 110:6acd96f8685f

Translation reloading as far as AContent name/desc supported. Limited & crude support for updating gui. Gave AContent support for multiple callbacks. New locale: "en".
author Diggory Hardy <diggory.hardy@gmail.com>
date Fri, 05 Dec 2008 11:29:39 +0000
parents 2a1428ec5344
children 1655693702fc
files data/L10n/en.mtt data/conf/options.mtt mde/content/Content.d mde/content/Items.d mde/gui/WidgetManager.d mde/gui/widget/Ifaces.d mde/gui/widget/TextWidget.d mde/gui/widget/Widget.d mde/lookup/Translation.d
diffstat 9 files changed, 129 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/L10n/en.mtt	Fri Dec 05 11:29:39 2008 +0000
@@ -0,0 +1,5 @@
+{MT01}
+!{en International English}
+<char[][]|depends=["en-GB"]>
+{MiscOptions}
+<entry|L10n={0:"Localization",1:"Specifies the language to use."}>
--- a/data/conf/options.mtt	Thu Dec 04 10:32:20 2008 +0000
+++ b/data/conf/options.mtt	Fri Dec 05 11:29:39 2008 +0000
@@ -2,7 +2,7 @@
 {MiscOptions}
 <int|maxThreads=1>
 <bool|exitImmediately=false>
-<char[]|L10n="en-GB">
+<char[]|L10n="en">
 <int|logLevel=1>
 <int|logOutput=3>
 <double|pollInterval=0.01>
--- a/mde/content/Content.d	Thu Dec 04 10:32:20 2008 +0000
+++ b/mde/content/Content.d	Fri Dec 05 11:29:39 2008 +0000
@@ -17,6 +17,8 @@
  */
 module mde.content.Content;
 
+import util = mde.util;
+
 debug {
     import tango.util.log.Log : Log, Logger;
     private Logger logger;
@@ -68,9 +70,14 @@
 	desc_ = d;
     }
     
-    /// Current implementation has 1 callback; can be changed to allow many.
+    /** Add a callback. Callbacks are called in the order added. */
     EventContent addCallback (void delegate (AContent) cb) {
-	this.cb = cb;
+	this.cb ~= cb;
+	return this;
+    }
+    /// ditto
+    EventContent addCallback (void function (AContent) cb) {
+	this.cb ~= util.toDg (cb);
 	return this;
     }
     
@@ -83,17 +90,16 @@
     
     /// End of an event, e.g. a button release or end of an edit (calls callbacks).
     void endEvent () {
-	if (cb)
-	    cb (this);
+	foreach (dg; cb)
+	    dg (this);
     }
     
     final char[] symbol;	// Symbol name for this content
 protected:
     char[] name_, desc_;	// name and description
-    void delegate (AContent) cb;
+    void delegate (AContent) cb[];
 }
 
-// FIXME: needs changes to allow updating translated strings. Move to Content and extend AContent?
 /** A generic way to handle a list of type IContent. */
 class ContentList : AContent
 {
--- a/mde/content/Items.d	Thu Dec 04 10:32:20 2008 +0000
+++ b/mde/content/Items.d	Fri Dec 05 11:29:39 2008 +0000
@@ -35,34 +35,21 @@
 
     /** Get a specific content item.
      *
+     * loadTranslation() $(B must) be called before this function.
+     *
      * E.g. get ("Options.MiscOptions.L10n") returns miscOpts.L10n,
      * Items.get ("Options.MiscOptions") returns a ContentList of all misc options. */
     AContent get (char[] item) {
+	assert (currentL10n is miscOpts.L10n(), "must call loadTranslation (code error)");
+	
 	char[] h = head (item);
 	if (h == "Options") {
-	    if (item is null) {
-		if (Options.allContentList is null) {
-		    AContent[] list;
-		    list.length = Options.optionsClasses.length;
-		    size_t i;
-		    foreach (n,opts; Options.optionsClasses) {
-			if (opts.contentList is null)
-			    loadTransl (opts, n);
-			list[i++] = opts.contentList;
-		    }
-		    Options.allContentList = new ContentList (h, list);
-		    Translation trl = Translation.get (h);
-		    Translation.Entry trle = trl.getStruct (h);
-		    Options.allContentList.name (trle.name, trle.desc);
-		}
+	    if (item is null)
 		return Options.allContentList;
-	    }
+	    
 	    h = head (item);
 	    auto p = h in Options.optionsClasses;
 	    if (p) {
-		if (p.contentList is null)
-		    loadTransl (*p, h);
-		
 		if (item == null)
 		    return p.contentList;
 		
@@ -71,19 +58,53 @@
 		    return *q;
 	    }
 	} else if (h == "imde") {
-	    if (!imdeTransl) {
-		Translation trl = Translation.get (h);
-		Translation.Entry trle = trl.getStruct ("quit");
-		quit.name (trle.name, trle.desc);
-		imdeTransl = true;
+	    h = head (item);
+	    if (h == "quit" && item is null)
+		return quit;
+	}
+	throw new ContentItemException (h);
+    }
+    
+    /** Creates some content on first run (required by get()).
+     *
+     * If the correct translation strings are not loaded, this loads them. */
+    void loadTranslation () {
+	if (currentL10n is miscOpts.L10n()) return;
+	
+	// Create Option classes' ContentLists if necessary:
+	if (Options.allContentList is null) {
+	    AContent[] list;
+	    list.length = Options.optionsClasses.length;
+	    size_t i;
+	    foreach (n,opts; Options.optionsClasses) {
+		opts.contentList = new ContentList (n, opts.content);
+		list[i++] = opts.contentList;
 	    }
-	    h = head (item);
-	    if (h == "quit" && item is null) {
-		quit.name ("Quit");	//FIXME
-		return quit;
+	    Options.allContentList = new ContentList ("Options", list);
+	}
+	
+	// Translate Options:
+	Translation.Entry trle;
+	with (Options.allContentList) {
+	    trle = Translation.get (symbol).getStruct (symbol);
+	    name (trle.name, trle.desc);
+	}
+	foreach (n,opts; Options.optionsClasses) {
+	    Translation trl;
+	    trl = Translation.get (n);
+	    trle = trl.getStruct (n);
+	    opts.contentList.name (trle.name, trle.desc);
+	    foreach (s, v; opts.content) {
+		trle = trl.getStruct (s);
+		v.name (trle.name, trle.desc);
 	    }
 	}
-	throw new ContentItemException (h);
+	
+	// Translate imde:
+	trle = Translation.get ("imde").getStruct ("quit");
+	quit.name (trle.name, trle.desc);
+	
+	currentL10n = miscOpts.L10n();
     }
     
 private:
@@ -101,16 +122,4 @@
 	return ret;
     }
     
-    void loadTransl (Options p, char[] n) {
-	debug logger.trace ("Loading translation strings for Options."~n);
-	Translation trans = Translation.get (n);
-	Translation.Entry transled = trans.getStruct (n);
-	p.contentList = new ContentList (n, p.content);
-	p.contentList.name (transled.name, transled.desc);
-	foreach (s, v; p.content) {
-	    transled = trans.getStruct (s);
-	    v.name (transled.name, transled.desc);
-	}
-    }
-    
-    bool imdeTransl = false;	// Has section imde been translated?
+    char[] currentL10n;	// Strings will be reloaded if this is not miscOpts.L10n().
--- a/mde/gui/WidgetManager.d	Thu Dec 04 10:32:20 2008 +0000
+++ b/mde/gui/WidgetManager.d	Fri Dec 05 11:29:39 2008 +0000
@@ -25,11 +25,12 @@
 import mde.gui.widget.Ifaces;
 import mde.gui.renderer.createRenderer;
 
-// For adding the input event callbacks and requesting redraws:
 import imde = mde.imde;
 import mde.input.Input;
 import mde.scheduler.Scheduler;
 import mde.setup.Screen;
+import Items = mde.content.Items;	// loadTranslation
+import mde.lookup.Options;	// miscOpts.L10n callback
 
 import tango.core.sync.Mutex;
 import tango.util.log.Log : Log, Logger;
@@ -69,6 +70,9 @@
         // Events we want to know about:
         imde.input.addMouseClickCallback(&clickEvent);
         imde.input.addMouseMotionCallback(&motionEvent);
+	
+	Items.loadTranslation ();
+	miscOpts.L10n.addCallback (&reloadStrings);
     }
     
     
@@ -437,6 +441,14 @@
         }
     }
     
+    /** Called when translation strings have been reloaded. */
+    void reloadStrings (AContent c) {
+	Items.loadTranslation;
+	child.reloadStrings;	//FIXME : all widgets, resize
+	requestRedraw;
+    }
+    
+protected:
     /** Second stage of loading the widgets.
     * 
     * loadDesign handles the data; this method needs to:
@@ -484,8 +496,9 @@
     
     /** Called before saving (usually when the GUI is about to be destroyed, although not
     *  necessarily). */
-    void preSave () {}
+    void preSave ();
     
+public:
     //BEGIN IWidgetManager methods
     IChildWidget makeWidget (widgetID id, IContent content = null) {
         debug (mdeWidgets) logger.trace ("Creating widget \""~id~'"');
--- a/mde/gui/widget/Ifaces.d	Thu Dec 04 10:32:20 2008 +0000
+++ b/mde/gui/widget/Ifaces.d	Fri Dec 05 11:29:39 2008 +0000
@@ -185,6 +185,14 @@
      * Should be propegated up to parents. */
     void childChanged ();
     +/
+    
+    /** Called if translated strings have been reloaded and widgets need to reload theirs.
+     * 
+     * Returns: true when widget's dimensions (may) have changed.
+     * 
+     * Should be propegated down to all child widgets. */
+    bool reloadStrings ();
+    
 //END Load and save
     
 //BEGIN Size and position
--- a/mde/gui/widget/TextWidget.d	Thu Dec 04 10:32:20 2008 +0000
+++ b/mde/gui/widget/TextWidget.d	Fri Dec 05 11:29:39 2008 +0000
@@ -44,6 +44,14 @@
         super (mgr, id, data);
     }
     
+    bool reloadStrings () {
+	adapter.getDimensions (mw, mh);
+	bool r = (mw != w || mh != h) ? true : false;
+	w = mw;
+	h = mh;
+	return true;
+    }
+    
     void draw () {
         super.draw();
         adapter.draw (x,y);
@@ -82,6 +90,11 @@
         super (mgr, id,data);
     }
     
+    bool reloadStrings () {
+	adapter.text = content.toString(index);
+	return super.reloadStrings;
+    }
+    
 protected:
     IContent content;
     int index;
--- a/mde/gui/widget/Widget.d	Thu Dec 04 10:32:20 2008 +0000
+++ b/mde/gui/widget/Widget.d	Fri Dec 05 11:29:39 2008 +0000
@@ -71,6 +71,11 @@
     bool rendererChanged () {
         return false;
     }
+    
+    // Widgets displaying strings will need this.
+    bool reloadStrings () {
+	return false;
+    }
 //END Load and save
     
 //BEGIN Size and position
@@ -177,6 +182,13 @@
         super (mgr, id, data);
     }
     
+    // Tells all subWidgets to reload strings, but cannot adjust size of self, so not ultimately useful.
+    bool reloadStrings () {
+	foreach (widg; subWidgets)
+	    widg.reloadStrings;
+	return false;
+    }
+    
     IChildWidget[] children () {
         return subWidgets;
     }
--- a/mde/lookup/Translation.d	Thu Dec 04 10:32:20 2008 +0000
+++ b/mde/lookup/Translation.d	Fri Dec 05 11:29:39 2008 +0000
@@ -78,8 +78,14 @@
 	 * On errors, a message is logged and the function continues, likely resulting in some
 	 * symbol names being untranslated. */
 	Translation get (char[] section) {
-	    if (sections is null) {
-		char[][] files = [miscOpts.L10n()];	// initial locale plus dependencies
+	    if (sections is null || loadedL10n !is miscOpts.L10n()) {
+		if (sections) {	// Clear entries hash-map, but re-use classes
+		    foreach (s; sections)
+			s.entries = null;
+		}
+		loadedL10n = miscOpts.L10n();
+		debug logger.trace ("Loading L10n: "~loadedL10n);
+		char[][] files = [loadedL10n];	// initial locale plus dependencies
 		size_t read = 0;	// index in files of next file to read
 		while (read < files.length) {
 		    try {
@@ -113,7 +119,8 @@
 	    }
 	    return *p;
 	}
-	Translation[char[]] sections;
+	private Translation[char[]] sections;
+	private char[] loadedL10n;	// reload if different
     }
     
     final char[] section;	// ONLY used to log an error message
@@ -160,16 +167,8 @@
     }
     
     /* Mergetag functionality.
-    *
-    * Merge tags in to entries, prefering existing values.
-    * Replace depends.
-    *
-    * User-defined type "entry":
-    *   first two element is string and must exist
-    *   second element is description and is optional
-    *   third element is version and is optional
-    *   no limit on number of elements to allow future extensions
-    */
+     *
+     * Merge tags in to entries, prefering existing values. */
     void addTag (char[] tp, ID id, char[] dt) {
         if (tp == "entry") {
             // If the tag already exists, don't replace it
@@ -181,8 +180,6 @@
                 return;
             }
             entries[cast(char[]) id] = entry;
-        } else if (tp == "char[][]") {
-            if (id == cast(ID)"depends") depends = cast(ID[]) parseTo!(char[][]) (dt);
         }
     }
     
@@ -209,8 +206,6 @@
     static Logger logger;
     
     Entry[char[]] entries;  // all entries
-    
-    ID[] depends;           // dependancy sections (only used while loading)
     //END Data
     
     debug (mdeUnitTest) unittest {