X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fxwt%2FTemplate.java;h=95846c1ce446f132c2be6b627c1401701191d223;hb=8235361e8601ae7b36ab707058de3b52225d15a2;hp=6ee6f0b605214e7ee1fff5a7cdfd5b137ab4da23;hpb=52ffc2a48fc74d013ae7fa401d9d0d405543c38e;p=org.ibex.core.git diff --git a/src/org/xwt/Template.java b/src/org/xwt/Template.java index 6ee6f0b..95846c1 100644 --- a/src/org/xwt/Template.java +++ b/src/org/xwt/Template.java @@ -1,4 +1,4 @@ -// Copyright 2002 Adam Megacz, see the COPYING file for licensing [GPL] +// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] package org.xwt; import java.io.*; @@ -10,12 +10,7 @@ import org.xwt.util.*; /** * Encapsulates a template node (the <template/> element of a - * .xwt file, or any child element thereof). Each instance of - * Template has a nodeName -- this is the resource name of - * the file that the template node occurs in, concatenated with the - * path from the root element to this node, each step of which is in - * the form .n for some integer n. Static nodes use the string "._" - * as a path. + * .xwt file, or any child element thereof). * * Note that the Template instance corresponding to the * <template/> node carries all the header information -- hence @@ -26,27 +21,23 @@ import org.xwt.util.*; * See the XWT reference for information on the order in which * templates are applied, attributes are put, and scripts are run. */ + +// FIXME imports public class Template { // Instance Members /////////////////////////////////////////////////////// - /** this instance's nodeName */ - String nodeName; + /** the id of this box */ + String id = null; /** the id of the redirect target; only meaningful on a root node */ String redirect = null; /** templates that should be preapplied (in the order of application); only meaningful on a root node */ - private String[] preapply; - - /** 'linked' form of preapply -- the String references have been resolved into instance references */ - private Template[] _preapply = null; + private Template[] preapply; /** templates that should be postapplied (in the order of application); only meaningful on a root node */ - private String[] postapply; - - /** 'linked' form of postapply -- the String references have been resolved into instance references */ - private Template[] _postapply = null; + private Template[] postapply; /** keys to be "put" to instances of this template; elements correspond to those of vals */ private String[] keys; @@ -54,23 +45,14 @@ public class Template { /** values to be "put" to instances of this template; elements correspond to those of keys */ private Object[] vals; - /** array of strings representing the importlist for this template */ - private String[] importlist; - /** child template objects */ private Template[] children; - /** an array of the names of properties to be preserved when retheming; only meaningful on a root node */ - private String[] preserve = null; - - /** the id attribute on this node */ - private String id = ""; - /** see numUnits(); -1 means that this value has not yet been computed */ private int numunits = -1; - /** true iff the resolution of this template's preapply/postapply sets changed as a result of the most recent call to retheme() */ - private boolean changed = false; + /** the scope in which the static block is executed */ + private JS.Scope staticScope = null; /** the script on the static node of this template, null if it has already been executed */ private JS.CompiledFunction staticscript = null; @@ -78,6 +60,12 @@ public class Template { /** the script on this node */ private JS.CompiledFunction script = null; + /** the filename this node came from; used only for debugging */ + private String fileName = "unknown"; + + + // Only used during parsing ///////////////////////////////////////////////////////////////// + /** during XML parsing, this holds the list of currently-parsed children; null otherwise */ private Vec childvect = new Vec(); @@ -93,44 +81,27 @@ public class Template { /** the line number that this element starts on */ private int startLine = -1; - // Static data/methods /////////////////////////////////////////////////////////////////// - - /** a template cache so that only one Template object is created for each xwt */ - private static Hashtable cache = new Hashtable(1000); - - /** The default importlist; in future revisions this will contain "xwt.*" */ - public static final String[] defaultImportList = new String[] { }; - /** returns the appropriate template, resolving and theming as needed */ - public static Template getTemplate(String name, String[] importlist) { - String resolved = Resources.resolve(name + ".xwt", importlist); - Template t = resolved == null ? null : (Template)cache.get(resolved.substring(0, resolved.length() - 4)); - if (t != null) return t; - if (resolved == null) return null; + // Static data/methods /////////////////////////////////////////////////////////////////// - // note that Templates in xwar's are instantiated as read in via loadStream() -- - // the following code only runs when XWT is reading templates from a filesystem. - ByteArrayInputStream bais = new ByteArrayInputStream(Resources.getResource(resolved)); - return buildTemplate(bais, resolved.substring(0, resolved.length() - 4)); - } + private Template(String fileName) { this.fileName = fileName; } - public static Template buildTemplate(InputStream is, String nodeName) { - return buildTemplate(is, nodeName, new TemplateHelper()); - } - - public static Template buildTemplate(InputStream is, String nodeName, TemplateHelper t) { + public static Template getTemplate(Res r) { try { - return new Template(is, nodeName, t); + if (r.t != null) return r.t; + r.t = new Template(r.getDescriptiveName()); + new TemplateHelper().parseit(r.getInputStream(), r.t); + return r.t; } catch (XML.SchemaException e) { - if (Log.on) Log.log(Template.class, "error parsing template " + nodeName); + if (Log.on) Log.log(Template.class, "error parsing template " + r.t.fileName); if (Log.on) Log.log(Template.class, e.getMessage()); return null; } catch (XML.XMLException e) { - if (Log.on) Log.log(Template.class, "error parsing template at " + nodeName + ":" + e.getLine() + "," + e.getCol()); + if (Log.on) Log.log(Template.class, "error parsing template at " + r.t.fileName + ":" + e.getLine() + "," + e.getCol()); if (Log.on) Log.log(Template.class, e.getMessage()); return null; } catch (IOException e) { - if (Log.on) Log.log(Template.class, "IOException while parsing template " + nodeName + " -- this should never happen"); + if (Log.on) Log.log(Template.class, "IOException while parsing template " + r.t.fileName + " -- this should never happen"); if (Log.on) Log.log(Template.class, e); return null; } @@ -139,268 +110,77 @@ public class Template { // Methods to apply templates //////////////////////////////////////////////////////// - private Template(String nodeName) { - this.nodeName = nodeName; - cache.put(nodeName, this); - } - private Template(InputStream is, String nodeName, TemplateHelper th) throws XML.XMLException, IOException { - this(nodeName); - th.parseit(is, this); - } - - /** calculates, caches, and returns an integer approximation of how long it will take to apply this template, including pre/post and children */ + /** calculates, caches, and returns an integer approximation of how long it will take to apply this template, + * including pre/post and children */ int numUnits() { - link(); if (numunits != -1) return numunits; numunits = 1; - for(int i=0; _preapply != null && i<_preapply.length; i++) if (_preapply[i] != null) numunits += _preapply[i].numUnits(); - for(int i=0; _postapply != null && i<_postapply.length; i++) if (_postapply[i] != null) numunits += _postapply[i].numUnits(); + for(int i=0; preapply != null && i elements of any - // of the templates which would be applied in step 7." - Vec keys = new Vec(); - b.template.gatherPreserves(keys); - Object[] vals = new Object[keys.size()]; - for(int i=0; i= 0; i--) { - kids[i] = b.redirect.getChild(i); - kids[i].remove(); - } - } - - // Ref 7.5.4: "Set the box's redirect target to self" - b.redirect = b; - - // Ref 7.5.5: "Remove all of the box's immediate children" - for(Box cur = b.getChild(b.numChildren() - 1); cur != null;) { - Box oldcur = cur; - cur = cur.prevSibling(); - oldcur.remove(); - } - - // Ref 7.5.6: "Remove all traps set by scripts run during the application of any template to this box" - Trap.removeAllTrapsByBox(b); - - // Ref 7.5.7: "Apply the template to the box according to the usual application procedure" - b.template.apply(b, null, null, null, 0, 1); - - // Ref 7.5.8: "Re-add the saved children which were removed in step 3" - for(int i=0; kids != null && ichange as needed */ - void link() { link(false); } - - /** same as link(), except that with a true value, it will force a re-link */ - private void link(boolean force) { - - if (staticscript != null) try { - JS.Scope s = Static.createStatic(nodeName, false); - if (staticscript != null) { - JS.CompiledFunction temp = staticscript; - staticscript = null; - - // we layer a transparent scope over the Static so that we can catch requests for the xwt object - // yet not screw up paths that include a package called xwt (ie xwt.static.org.xwt.foo) - JS.Scope varScope = new JS.Scope(s) { - public boolean isTransparent() { return true; } - public Object get(Object key) { - if ("xwt".equals(key)) return XWT.singleton; else return super.get(key); - } }; - - temp.call(new JS.Array(), varScope); - } - } catch (JS.Exn e) { - if (Log.on) Log.log(this, "WARNING: uncaught ecmascript exception: " + e.getMessage()); - } - - if (!(force || (preapply != null && _preapply == null) || (postapply != null && _postapply == null))) return; - - if (preapply != null) { - if (_preapply == null) _preapply = new Template[preapply.length]; - for(int i=0; i<_preapply.length; i++) { - Template t = getTemplate(preapply[i], importlist); - if (t != _preapply[i]) changed = true; - _preapply[i] = t; - } - } - if (postapply != null) { - if (_postapply == null) _postapply = new Template[postapply.length]; - for(int i=0; i<_postapply.length; i++) { - Template t = getTemplate(postapply[i], importlist); - if (t != _postapply[i]) changed = true; - _postapply[i] = t; - } - } - - for(int i=0; children != null && i node must have exactly one attribute, which must be called 'name'"); String importpackage = c.vals[0].toString(); if (importpackage.endsWith(".*")) importpackage = importpackage.substring(0, importpackage.length() - 2); - importlist.addElement(importpackage); return; } else if (c.localName.equals("redirect")) { @@ -511,24 +284,11 @@ public class Template { staticNodeHasBeenEncountered = true; return; - } else if (c.localName.equals("preserve")) { - if (c.len != 1 || !c.keys[0].equals("attributes")) - throw new XML.SchemaException(" node must have exactly one attribute, which must be called 'attributes'"); - if (t.preserve != null) - throw new XML.SchemaException(" header element may not appear more than once"); - - StringTokenizer tok = new StringTokenizer(c.vals[0].toString(), ",", false); - t.preserve = new String[tok.countTokens()]; - for(int i=0; i 0) preapply.copyInto(t.preapply = new String[preapply.size()]); - if (postapply.size() > 0) postapply.copyInto(t.postapply = new String[postapply.size()]); - importlist.setSize(0); preapply.setSize(0); postapply.setSize(0); + if (preapply.size() > 0) preapply.copyInto(t.preapply = new Template[preapply.size()]); + if (postapply.size() > 0) postapply.copyInto(t.postapply = new Template[postapply.size()]); templateNodeHasBeenEncountered = true; } else { @@ -541,23 +301,28 @@ public class Template { // push the last node we were in onto the stack nodeStack.addElement(t); - // instantiate a new node, and set its nodeName/importlist/preapply - Template t2 = new Template(t.nodeName + "." + t.childvect.size()); - t2.importlist = t.importlist; + // instantiate a new node, and set its fileName/importlist/preapply + Template t2 = new Template(t.fileName); t2.startLine = getLine(); - if (!c.localName.equals("box")) t2.preapply = new String[] { c.localName }; + if (!c.localName.equals("box")) t2.preapply = new Template[] { /*c.localName FIXME */ }; // make the new node the current node t = t2; } - // TODO: Sort contents straight from one array to another t.keys = new String[c.len]; t.vals = new Object[c.len]; - System.arraycopy(c.keys, 0, t.keys, 0, c.len); - System.arraycopy(c.vals, 0, t.vals, 0, c.len); - quickSortAttributes(0, t.keys.length - 1); + Hash h = new Hash(c.len * 2, 3); + for(int i=0; i left && t.keys[--j].compareTo(t.keys[right]) > 0); - if (i >= j) break; - s = t.keys[i]; t.keys[i] = t.keys[j]; t.keys[j] = s; - o = t.vals[i]; t.vals[i] = t.vals[j]; t.vals[j] = o; + private JS.CompiledFunction genscript(boolean isstatic) { + JS.CompiledFunction thisscript = null; + try { + thisscript = JS.parse(t.fileName + (isstatic ? "._" : ""), t.content_start, new StringReader(t.content.toString())); + } catch (IOException ioe) { + if (Log.on) Log.log(this, " ERROR: " + ioe.getMessage()); + thisscript = null; } - s = t.keys[right]; t.keys[right] = t.keys[i]; t.keys[i] = s; - o = t.vals[right]; t.vals[right] = t.vals[i]; t.vals[i] = o; - return i; - } - /** simple quicksort, from http://sourceforge.net/snippet/detail.php?type=snippet&id=100240 */ - private void quickSortAttributes(int left, int right) { - if (left >= right) return; - int p = partitionAttributes(left, right); - quickSortAttributes(left, p - 1); - quickSortAttributes(p + 1, right); + t.content = null; + t.content_start = 0; + t.content_lines = 0; + return thisscript; } public void endElement(XML.Element c) throws XML.SchemaException { if (rootNodeHasBeenEncountered && !templateNodeHasBeenEncountered) { if ("static".equals(nameOfHeaderNodeBeingProcessed) && t.content != null) t.staticscript = genscript(true); nameOfHeaderNodeBeingProcessed = null; - + } else if (templateNodeHasBeenEncountered && !templateNodeHasBeenFinished) { // turn our childvect into a Template[] t.childvect.copyInto(t.children = new Template[t.childvect.size()]); @@ -639,7 +393,7 @@ public class Template { if (nodeStack.size() == 0) { // templateNodeHasBeenFinished = true; - + } else { // add this template as a child of its parent Template oldt = t; @@ -647,32 +401,13 @@ public class Template { nodeStack.setSize(nodeStack.size() - 1); t.childvect.addElement(oldt); } - - } - } - - private JS.CompiledFunction genscript(boolean isstatic) { - JS.CompiledFunction thisscript = null; - try { - thisscript = JS.parse(t.nodeName + (isstatic ? "._" : ""), t.content_start, new StringReader(t.content.toString())); - } catch (JS.Exn ee) { - if (Log.on) Log.log(this, " ERROR: " + ee.getMessage()); - thisscript = null; - } catch (IOException ioe) { - if (Log.on) Log.log(this, " ERROR: " + ioe.getMessage()); - thisscript = null; } - - t.content = null; - t.content_start = 0; - t.content_lines = 0; - return thisscript; - } + } public void characters(char[] ch, int start, int length) throws XML.SchemaException { // invoke the no-tab crusade for (int i=0; length >i; i++) if (ch[start+i] == '\t') throw new XML.SchemaException( - t.nodeName+ ":" + getLine() + "," + getCol() + ": tabs are not allowed in XWT files"); + t.fileName+ ":" + getLine() + "," + getCol() + ": tabs are not allowed in XWT files"); if ("static".equals(nameOfHeaderNodeBeingProcessed) || templateNodeHasBeenEncountered) { if (t.content == null) { @@ -693,6 +428,35 @@ public class Template { } } + private static class PerInstantiationScope extends JS.Scope { + Res resourceRoot = null; + public PerInstantiationScope(Scope parentScope, Res resourceRoot) { + super(parentScope); + this.resourceRoot = resourceRoot; + } + public boolean isTransparent() { return true; } + public boolean has(Object key) { return false; } + public void declare(String s) { super.declare(s); } + public Object get(Object key) { + // FIXME: access statics here + if (Box.SpecialBoxProperty.specialBoxProperties.get(key) == null && + !super.has(key)) { + Object ret = resourceRoot.get(key); + if (ret != null) return ret; + throw new JS.Exn("must declare " + key + " before using it!"); + } + return super.get(key); + } + public void put(Object key, Object val) { + // FIXME: access statics here + if (Box.SpecialBoxProperty.specialBoxProperties.get(key) == null && + !super.has(key)) { + throw new JS.Exn("must declare " + key + " before using it!"); + } + super.put(key, val); + } + } + }