X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Fxwt%2FTemplate.java;h=f85f3a7ae8a4289da67f007af80fc28f389a5446;hb=9c2602143956cd39ecf5ef4c9eb31f5f56b5bd66;hp=a9ea9b91502a90352a6c92d33b17de5d7435181e;hpb=e58686eae8a823ed64ed0ec92c2274c41d90ec93;p=org.ibex.core.git diff --git a/src/org/xwt/Template.java b/src/org/xwt/Template.java index a9ea9b9..f85f3a7 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.*; @@ -6,16 +6,12 @@ import java.util.zip.*; import java.util.*; import java.lang.*; import org.xwt.js.*; +import org.xwt.translators.*; 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 @@ -30,383 +26,155 @@ public class Template { // Instance Members /////////////////////////////////////////////////////// - /** this instance's nodeName */ - String nodeName; + String id = null; ///< the id of this box + String redirect = null; ///< the id of the redirect target; only meaningful on a root node + private String[] keys; ///< keys to be "put" to instances of this template; elements correspond to those of vals + private Object[] vals; ///< values to be "put" to instances of this template; elements correspond to those of keys + private Vec children = new Vec(); ///< during XML parsing, this holds the list of currently-parsed children; null otherwise + private int numunits = -1; ///< see numUnits(); -1 means that this value has not yet been computed - /** the id of the redirect target; only meaningful on a root node */ - String redirect = null; + private JSFunction script = null; ///< the script on this node + private String fileName = "unknown"; ///< the filename this node came from; used only for debugging + private Vec preapply = new Vec(); ///< templates that should be preapplied (in the order of application) - /** 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; + // Instance Members that are only meaningful on root Template ////////////////////////////////////// - /** templates that should be postapplied (in the order of application); only meaningful on a root node */ - private String[] postapply; + private JSScope staticScope = null; ///< the scope in which the static block is executed + private JSFunction staticscript = null; ///< the script on the static node of this template, null already performed - /** 'linked' form of postapply -- the String references have been resolved into instance references */ - private Template[] _postapply = null; - /** keys to be "put" to instances of this template; elements correspond to those of vals */ - private String[] keys; + // Only used during parsing ///////////////////////////////////////////////////////////////// - /** values to be "put" to instances of this template; elements correspond to those of keys */ - private Object[] vals; + private StringBuffer content = null; ///< during XML parsing, this holds partially-read character data; null otherwise + private int content_start = 0; ///< line number of the first line of content + private int startLine = -1; ///< the line number that this element starts on + private final Stream r; ///< the resource we came from - /** 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 script on the static node of this template, null if it has already been executed */ - private JS.Script staticscript = null; - - /** the script on this node */ - private JS.Script script = null; - - /** during XML parsing, this holds the list of currently-parsed children; null otherwise */ - private Vec childvect = new Vec(); - - /** during XML parsing, this holds partially-read character data; null otherwise */ - private StringBuffer content = null; - - /** line number of the first line of content */ - private int content_start = 0; - - /** number of lines in content */ - private int content_lines = 0; - - /** 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; - - // 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)); + // FIXME need to provide the XWT object too + public static Template getTemplate(Stream r) throws JSExn { + try { + r = r.addExtension(".xwt"); + if (r.t != null) return r.t; + r.t = new Template(r); + new TemplateHelper().parseit(r.getInputStream(), r.t); + return r.t; + } catch (Exception e) { + throw new JSExn("Error reading template stream: " + r + "\n" + e.toString()); + } } - public static Template buildTemplate(InputStream is, String nodeName) { - return buildTemplate(is, nodeName, new TemplateHelper()); - } + public static Stream resolveStringToResource(String str, XWT xwt, boolean permitAbsolute) throws JSExn { + // URL + if (str.indexOf("://") != -1) { + if (permitAbsolute) return (Stream)xwt.url2res(str); + throw new JSExn("absolute URL " + str + " not permitted here"); + } - public static Template buildTemplate(InputStream is, String nodeName, TemplateHelper t) { - try { - return new Template(is, nodeName, t); - } catch (XML.SchemaException e) { - if (Log.on) Log.log(Template.class, "error parsing template " + nodeName); - 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, 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, e); - return null; + // root-relative + Stream ret = xwt.rr; + while(str.indexOf('.') != -1) { + String path = str.substring(0, str.indexOf('.')); + str = str.substring(str.indexOf('.') + 1); + ret = (Stream)ret.get(path); } + ret = (Stream)ret.get(str); + return ret; } // 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); + private Template(Stream r) { + this.r = r; + String f = r.toString(); + if (f != null && !f.equals("")) + fileName = f.substring(f.lastIndexOf('/')+1, f.endsWith(".xwt") ? f.length() - 4 : f.length()); } - /** 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(); - if (script != null) numunits += 10; - numunits += keys == null ? 0 : keys.length; - for(int i=0; children != 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(); + if (val != null && val instanceof String && ((String)val).length() > 0) { + switch (((String)val).charAt(0)) { + case '$': + val = pis.get(val); + if (val == null) throw new JSExn("unknown box id '"+vals[i]+"' referenced in XML attribute"); + break; + case '.': + val = resolveStringToResource(((String)val).substring(1), xwt, true); } } - - // 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.Script 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); - } }; - - JS.Array args = new JS.Array(); - args.addElement(varScope); - temp.call(args); + if (val != null && "redirect".equals(key)) { + val = pis.get("$"+val); + if (val == null) throw new JSExn("redirect target '"+vals[i]+"' not found"); } - } 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; + try { + b.putAndTriggerTraps(key, val); + } catch(JSExn e) { + e.addBacktrace(fileName + ":attr-" + key,0); + throw e; } } - - for(int i=0; children != null && iroot */ - void parseit(InputStream is, Template root) throws XML.XMLException, IOException { - rootNodeHasBeenEncountered = false; - templateNodeHasBeenEncountered = false; - staticNodeHasBeenEncountered = false; - templateNodeHasBeenFinished = false; - nameOfHeaderNodeBeingProcessed = null; + private int state; + private static final int STATE_INITIAL = 0; + private static final int STATE_IN_XWT_NODE = 1; + private static final int STATE_IN_TEMPLATE_NODE = 2; + private static final int STATE_FINISHED_TEMPLATE_NODE = 3; - nodeStack.setSize(0); - importlist.setSize(0); - preapply.setSize(0); - postapply.setSize(0); + private String nameOfHeaderNodeBeingProcessed; - importlist.fromArray(defaultImportList); + Vec nodeStack = new Vec(); ///< stack of Templates whose XML elements we have seen open-tags for but not close-tags + Template t = null; ///< the template we're currently working on + /** parse an XML input stream, building a Template tree off of root */ + void parseit(InputStream is, Template root) throws XML.Exn, IOException { + state = STATE_INITIAL; + nameOfHeaderNodeBeingProcessed = null; + nodeStack.setSize(0); t = root; parse(new InputStreamReader(is)); } - /** parsing state: true iff we have already encountered the open-tag */ - boolean rootNodeHasBeenEncountered = false; - - /** parsing state: true iff we have already encountered the