author adam Sun, 4 Apr 2004 05:31:11 +0000 (05:31 +0000) committer adam Sun, 4 Apr 2004 05:31:11 +0000 (05:31 +0000)
darcs-hash:20040404053111-5007d-2c384ee3c6c64eabaa85d785c5048474c5890aa5.gz

 Makefile patch | blob | history doc/reference/reference.xml patch | blob | history src/org/ibex/util/Doc.java patch | blob | history

index 136f4ef..3369b98 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -380,7 +380,7 @@ commit: propose-patch
darcs push --and-apply xwt@xwt.org:/var/www/org/ibex/core/

doc/%.pdf: build/class/org/ibex/util/XML.class build/class/org/ibex/util/Doc.class doc/%.xml
-       cd $(@D); java -cp ../../build/class org.ibex.util.Doc slides < basename$*.xml > basename $*.tex + cd$(@D); java -cp ../../build/class org.ibex.util.Doc < basename $*.xml > basename$*.tex
cd $(@D); pdflatex basename$*.tex
open doc/$*.pdf index 4c830b6..844bad6 100644 (file) @@ -1,18 +1,18 @@ <ibex-doc title="The Ibex Reference" subtitle="Nitrogen Release" author="Adam Megacz" email="adam@ibex.org"> -<!-- _______________________________________________________________________ --> +<!-- ----------------------------------------------------------------------- --> <section title="Introduction"> - <i> + ** If you are reading the html version of this document and are thinking of printing it out, you might be interested in the nicely typeset <link url="reference.pdf" text="pdf version"/> produced with LaTeX. - </i> + ** - This document is a <b>reference</b>. It is not a - <b>specification</b> or a - <b>tutorial</b>. + This document is a __reference__. It is not a + __specification__ or a + __tutorial__. This document does not guide the user gently through examples (as a tutorial would), and it doesn't provide enough detail and formality <definition term="The Core"> Ibex itself; the native code (or Java bytecode) that runs on - the client. This term does not include the <i>Wildebeest</i> - or the <i>UI</i></definition> + the client. This term does not include the **Wildebeest** + or the **UI**</definition> <definition term="The UI / The Application"> A set of files (mostly XML, JavaScript, and PNG images) - bundled up in a zip archive, ending with the "<t>.ibex</t>" + bundled up in a zip archive, ending with the "[[.ibex]]" extension. Together, these files specify the appearance and behavior of the application's user interface. </definition> <definition term="put/write"> In ECMAscript, when you change the value of a property on an - object, you are <i>putting</i> to that property, or - <i>writing</i> to it. For example, the ECMAscript expression - "<t>foo.bar = 5</t>" <i>puts</i> the value 5 to the bar + object, you are **putting** to that property, or + **writing** to it. For example, the ECMAscript expression + "[[foo.bar = 5]]" **puts** the value 5 to the bar property on object foo.</definition> <definition term="get/read"> In ECMAscript, when you access the value of a property on an - object, you are <i>getting</i> that property, or - <i>reading</i> from it. For example, the ECMAscript - expression "<t>return (3 + foo.bar)</t>" <i>gets</i> the + object, you are **getting** that property, or + **reading** from it. For example, the ECMAscript + expression "[[return (3 + foo.bar)]]" **gets** the value of bar property on object foo and then adds 3 to it before returning the result.</definition> @@ -94,8 +94,8 @@ The Wildebeest downloads the appropriate core for the user's machine and verifies its digital signature. It then launches the - core, which downloads the UI (an <t>.ibex</t> archive), loads it, - applies the <t>main.t</t> template (found in the archive), and + core, which downloads the UI (an [[.ibex]] archive), loads it, + applies the [[main.t]] template (found in the archive), and renders it onto the screen, running any associated JavaScript code. <image url="offscreen.pdf" width="2in" caption="An Ibex surface positioned at (83,0)"/> Each top-level window in an Ibex UI is called a - <i>surface</i>. There are two kinds of surfaces: <i>frames</i>, + **surface**. There are two kinds of surfaces: **frames**, which usually have a platform-specific titlebar and border, and - <i>windows</i>, which never have any additional platform-specific + **windows**, which never have any additional platform-specific decorations. Whenever we refer to the size or position Surfaces are not actual JavaScript objects; you cannot obtain a reference to a surface. However, each surface is uniquely identified - by its <i>root box</i>, described in the next section. + by its **root box**, described in the next section. </section> <section title="Boxes"> - A <i>box</i> is the fundamental unit from which all Ibex user + A **box** is the fundamental unit from which all Ibex user interfaces are built. Boxes can contain other boxes (referred to as - its <i>children</i>). Each surface has a single box associated with - it called the <i>root box</i>; the root box and its children (and - its children's children, and so on) form the surface's <i>box - tree</i>. + its **children**). Each surface has a single box associated with + it called the **root box**; the root box and its children (and + its children's children, and so on) form the surface's **box + tree**. There are three ways to think of a box: <list> - As a rendered visualization on the screen (the "<i>Visual Representation</i>") + As a rendered visualization on the screen (the "**Visual Representation**") - As a JavaScript object (the "<i>Object Representation</i>") + As a JavaScript object (the "**Object Representation**") As as an XML tag (the "XML Template Representation"). A template (discussed in the next section) is an XML file which acts as a blueprint for constructing a tree of boxes. We call this - construction process <i>applying</i>, since unlike - <i>instantiation</i> in object-oriented programming systems, you + construction process **applying**, since unlike + **instantiation** in object-oriented programming systems, you always apply a template to a pre-existing box, and you can apply multiple templates to the same box. Each XML tag corresponds to a single box, or to another template - which will be applied to that box. For example, a <t>scrollbar</t> + which will be applied to that box. For example, a [[scrollbar]] template, when applied, will construct a tree of boxes which has the visual appearance and behavior of a scrollbar. applying a template is complete, Ibex completely forgets the fact that it has applied a particular template to a particular box. One consequence of this approach is that if you think of templates as - classes, then Ibex has no equivalent for Java's <t>instanceof</t> + classes, then Ibex has no equivalent for Java's [[instanceof]] operator. Each template is an XML document whose root element is - <t>&lt;ibex></t>. Here is a sample template file: + [[&lt;ibex>]]. Here is a sample template file: <pre> <ibex xmlns:lib="ibex.lib"> </pre> The following two namespaces are predefined and need not be declared - using <t>xmlns</t>: + using [[xmlns]]: <definition term="meta"> - <t>http://xmlns.ibex.org/meta</t> + [[http://xmlns.ibex.org/meta]] - This will be referred to as the "<t>meta</t> namespace" in the + This will be referred to as the "[[meta]] namespace" in the remainder of this document. </definition> <definition term="ui"> - <t>http://xmlns.ibex.org/ui</t> + [[http://xmlns.ibex.org/ui]] - This will be referred to as the "<t>ui</t> namespace" in the + This will be referred to as the "[[ui]] namespace" in the remainder of this document. </definition> <section title="Static Code"> -<!-- ----------------------------------------------------------------------- --> -<section title="Layout and Rendering"> + If the root [[&lt;ibex&gt;]] element contains any non-whitespace + text content, this text is interpreted as JavaScript code and is + executed the first time the template is referenced. This code is + executed in a fresh scope containing two predefined properties: + + <definition term="ibex"> + The Ibex Object (described in <ref section="The Ibex Object"/>) + </definition> + + <definition term="static"> + A reference to this template's **static object**, which is + initially [[null]]. The static object can be accessed (read + and written) from both static scripts as well as instance + scripts in a particular template. FIXME + </definition> </section> <section title="Metadata"> Any immediate children of the root element which are in the - <t>meta</t> namespace are treated as metadata and are exempted from + [[meta]] namespace are treated as metadata and are exempted from the rest of the template application process. Currently only one type of metadata element is defined: <list> - <t>&lt;meta:doc&gt;</t>: structured documentation for the + [[&lt;meta:doc&gt;]]: structured documentation for the template. </list> <section title="Other Elements"> All remaining children of the root element are treated as elements - to be <i>applied</i> to the box, in the order in which they appear + to be **applied** to the box, in the order in which they appear in the file using the following procedure. <remark text="While this process outlined below sounds very ... FIXME During a box initialization, script-private references to a - box's descendants with <t>id</t> attributes are placed on the + box's descendants with [[id]] attributes are placed on the box. These references allow scripts on that box to easily refer to descendant nodes created by the template in which the script appears. For example, these two blocks of code have exactly the <heading title="Precise Description"/> - To apply an XML tag <t><b>x</b></t> to a box <t><b>b</b></t>, perform the following + To apply an XML tag [[__x__]] to a box [[__b__]], perform the following operations, in this order: <list type="ordered"> - Allocate a fresh scope <t><b>s</b></t> whose parent scope is - <t><b>b</b></t>. + Allocate a fresh scope [[__s__]] whose parent scope is + [[__b__]]. - Process each child element or text segment of <t><b>x</b></t> + Process each child element or text segment of [[__x__]] in the order they appear in the document: <list> - Treat each text segment <t><b>t</b></t> as JavaScript code - and execute it with <t><b>s</b></t> as the root scope. + Treat each text segment [[__t__]] as JavaScript code + and execute it with [[__s__]] as the root scope. - For each child element <t><b>x'</b></t> of <t><b>x</b></t>: + For each child element [[__x'__]] of [[__x__]]: <list> - Create a new box <t><b>b'</b></t>. + Create a new box [[__b'__]]. - If the name of tag <t><b>x'</b></t> is not - "<t>box</t>" in the <t>ui</t> namespace, prepend the + If the name of tag [[__x'__]] is not + "[[box]]" in the [[ui]] namespace, prepend the tag's namespace identifier uri (if any) to the name of the tag, and use the result as a key to retrieve a property from the root stream (defined later). Interpret the resulting stream as a template and apply - that template to <t><b>b'</b></t>. + that template to [[__b'__]]. - (recursively) apply <t><b>x'</b></t> to <t><b>b'</b></t>. + (recursively) apply [[__x'__]] to [[__b'__]]. - If <t><b>x'</b></t> has an <t>id</t> attribute, declare a variable - in <t><b>s</b></t> whose name is the value of the <t>id</t> - attribute, prefixed with the <t>$</t> character, and whose
-                  value is <t><b>b'</b></t>
+                  If [[__x'__]] has an [[id]] attribute, declare a variable
+                  in [[__s__]] whose name is the value of the [[id]]
+                  attribute, prefixed with the [[$]] character, and whose + value is [[__b'__]] - Copy any <t>$</t>-variables created during the application
-                  of <t><b>x'</b></t> into scope <t><b>s</b></t>.
+                  Copy any [[$]]-variables created during the application + of [[__x'__]] into scope [[__s__]]. - Append <t><b>b'</b></t> as the last child of <t><b>b</b></t>. + Append [[__b'__]] as the last child of [[__b__]]. </list> </list> - Apply any attributes on <t><b>x</b></t> to <t><b>b</b></t>, except for - <t>id</t>. Since XML specifies that the order of attributes + Apply any attributes on [[__x__]] to [[__b__]], except for + [[id]]. Since XML specifies that the order of attributes cannot be significant, Ibex processes attributes in alphabetical order by attribute name. For example, if - <t><b>x</b></t> has the attribute <t>foo="bar"</t>, then the - equivalent of the statement <t>B.foo="bar";</t> will be + [[__x__]] has the attribute [[foo="bar"]], then the + equivalent of the statement [[B.foo="bar";]] will be performed, with the following exceptions: <list> If the value portion of the attribute is the string - "<t>true</t>", put the boolean <t>true</t>. If the - value is "<t>false</t>", put the boolean <t>false</t>. + "[[true]]", put the boolean [[true]]. If the + value is "[[false]]", put the boolean [[false]]. If the value is a valid ECMAscript number, put it as a number (instead of a string). - If the value begins with a dollar sign (<t>$</t>),
+              If the value begins with a dollar sign ([[]]), retrieve the value of the corresponding variable in - <t><b>s</b></t> and use that value instead. + [[__s__]] and use that value instead. - If the value begins with a dot (<t>.</t>), prepend the + If the value begins with a dot ([[.]]), prepend the attributes' namespace identifier uri (if any) and interpret the remainder as a property to be retrieved from the root stream (defined later). <heading title="Initialization Invariants"/> - The last two steps are referred to as the <i>initialization</i> of the + The last two steps are referred to as the **initialization** of the node. There are two important aspects of this ordering to be aware of: <list type="unordered"> certain that they will never wind up accessing a box when it is in a partially-initialized state. - Attributes are applied <i>after</i> scripts are run so that - the attributes will trigger any <i>traps</i> (defined later) + Attributes are applied **after** scripts are run so that + the attributes will trigger any **traps** (defined later) placed by the script. </list> Each box occupies a rectangular region on the surface. The visual appearance of a surface is created by rendering each box in its tree. - Unless the <t>clip</t> attribute is <t>false</t>, each box will + Unless the [[clip]] attribute is [[false]], each box will clip its childrens' visual representations to its own, so that the children appear "confined to" the parent. Children are rendered after their parents so they appear "on top of" their parents. <definition term="path"> - A box's <t>path</t> consists of zero or more lines and curves. + A box's [[path]] consists of zero or more lines and curves. The path may be filled with a color, gradient, or texture, and may be stroked with a line of a given thickness and color. If the path is not specified, it defaults to the perimiter of the - box. [<i>Note: Vector Graphics support (including the ability - to set the <t>path</t> property to anything other than the - default) is currently not implemented</i>]. + box. [**Note: Vector Graphics support (including the ability + to set the [[path]] property to anything other than the + default) is currently not implemented**]. A path also has: <list> - an associated <t>strokecolor</t>, which is a color + an associated [[strokecolor]], which is a color - an associated <t>strokewidth</t>, which is a number - specifying the width of the stroke. [<i>Note: Vector - Graphics support (including the <t>strokewidth</t> - property) is currently not implemented</i>] + an associated [[strokewidth]], which is a number + specifying the width of the stroke. [**Note: Vector + Graphics support (including the [[strokewidth]] + property) is currently not implemented**] - a <t>fill</t>, which is either a color, gradient, or + a [[fill]], which is either a color, gradient, or texture </list> </definition> <definition term="text"> - Each box also has a single line of <t>text</t>, whose + Each box also has a single line of [[text]], whose appearance is determined by its: <list> - associated <t>font</t>, which can be any font supported by + associated [[font]], which can be any font supported by the <link url="http://www.freetype.org" text="FreeType2"/> library. - an associated <t>fontsize</t> in <i>pixels</i> + an associated [[fontsize]] in **pixels** - an associated <t>textcolor</t> + an associated [[textcolor]] </list> </definition> The size and position of every box is determined by its properties, its childrens' sizes, and its parent's size and position. Box layout and rendering happens in four phases: - <i>packing</i>, <i>constraining</i>, <i>placing</i>, and - <i>rendering</i>. The Core is careful to only perform a phase on + **packing**, **constraining**, **placing**, and + **rendering**. The Core is careful to only perform a phase on a box if the box has changed in a way that invalidates the work done the last time that phase was performed. The packing and constraining phases are performed in a single traversal of the For brevity, the rest of this chapter deals only with width and columns. Height and rows is treated identically and independently. - Also, it is important to note that the term <i>minimum width</i> is - not the same thing as the property <t>minwidth</t>, although they + Also, it is important to note that the term **minimum width** is + not the same thing as the property [[minwidth]], although they are closely related. <heading title="The Size of the Root Box"/> When the user resizes a window, Ibex changes the root box's - <t>maxwidth</t> and <t>maxheight</t> to match the size chosen by + [[maxwidth]] and [[maxheight]] to match the size chosen by the user and then determines the root box's size using the same sizing rules it uses for other boxes. Ibex will always attempt to prevent the user from making the surface smaller than the root box's - <t>minwidth</t> and <t>minheight</t>. If the <t>hshrink</t> or - <t>vshrink</t> flag is set, Ibex will try to prevent the user from + [[minwidth]] and [[minheight]]. If the [[hshrink]] or + [[vshrink]] flag is set, Ibex will try to prevent the user from resizing the surface at all. However, not all platforms give Ibex enough control to do this. <image url="alignmentpoint.pdf" caption="The effect of alignment points on layout" width="3in"/> + <heading title="The alignment point"/> When talking about positioning, we will often refer to the - <i>alignment point</i>. + **alignment point**. - If the <t>align</t> property is "<t>center</t>", then the + If the [[align]] property is "[[center]]", then the alignment point is the center of the box. - If the <t>align</t> property is "<t>topleft</t>", - "<t>bottomleft</t>", "<t>topright</t>", or - "<t>bottomright</t>", then the alignment point is + If the [[align]] property is "[[topleft]]", + "[[bottomleft]]", "[[topright]]", or + "[[bottomright]]", then the alignment point is corresponding corner of the box. - If the <t>align</t> property is "<t>top</t>", - "<t>bottom</t>", "<t>right</t>", or "<t>left</t>", then + If the [[align]] property is "[[top]]", + "[[bottom]]", "[[right]]", or "[[left]]", then the alignment point is middle of the corresponding edge of the box. - When positioning a child box, the alignment point is determined by - the <i>parent's</i> <t>align</t> property. When rendering a - visual element (a texture, path, or text string) within a box, the - alignment point is determined by the <i>box's own</i> <t>align</t> - property. - - A simple way to think about this is that whenever there are two boxes - involved in the decision, you should use the parent's alignment point. - <section title="Packing"> - A grid of <i>cells</i> is created within the parent. If the - parent's <t>cols</t> property is set to 0, the cell grid has an - infinite number of columns. Either <t>cols</t> or <t>rows</t> + A grid of **cells** is created within the parent. If the + parent's [[cols]] property is set to 0, the cell grid has an + infinite number of columns. Either [[cols]] or [[rows]] must be zero, but not both. - If a child's <t>visible</t> property is <t>false</t>, it does + If a child's [[visible]] property is [[false]], it does not occupy any cells (and is not rendered). Otherwise, each child - occupies a rectangular set of cells <t>child.colspan</t> cells - wide and <t>child.rowspan</t> cells high. + occupies a rectangular set of cells [[child.colspan]] cells + wide and [[child.rowspan]] cells high. The Core iterates over the cells in the grid in the following - order: if <t>rows</t> is 0, the Core iterates across each column + order: if [[rows]] is 0, the Core iterates across each column before proceeding to the next row; otherwise rows come before - columns. At each cell, the Core attempts to place the <i>first - remaining unplaced child's</i> top-left corner in that cell + columns. At each cell, the Core attempts to place the **first + remaining unplaced child's** top-left corner in that cell (with the child occupying some set of cells extending down and to the right of that cell). If the parent has a fixed number of - columns and the child's <t>colspan</t> exceeds that limit, the + columns and the child's [[colspan]] exceeds that limit, the child is placed in column zero regardless, but only occupies the available set of cells (it does not "hang off the end" of the box). <image url="layout.pdf" width="1in"/> <section title="Constraining"> - Each box's minimum width is computed recursively as the - maximum of: + Each box's minimum width is computed recursively as the + maximum of: - <list> - Its <t>minwidth</t> + <list> + Its [[minwidth]] - The width of the box's <t>text</t> (after applying the - box's <t>transform</t>) [<i>Note: Vector Graphics support - (including the <t>transform</t> property) is currently not - implemented</i>]. + The width of the box's [[text]] (after applying the + box's [[transform]]) [**Note: Vector Graphics support + (including the [[transform]] property) is currently not + implemented**]. - The width of the box's path (after applying the box's - <t>transform</t>) <i>if the box is <t>packed</t></i>. + The width of the box's path (after applying the box's + [[transform]]) **if the box is [[packed]]**. - The width of the bounding box enclosing the box's cells. - </list> - - The minimum width of each cell is computed as the minimum - width of the box occupying it divided by the box's - <t>colspan</t>. - - If a box's <t>hshrink</t> property is set to - <t>true</t>, the box's maximum width is the same as its - minimum width; otherwise it is the box's - <t>maxwidth</t>. + The minimum width of the children in each row. + </list> - The maximum width of each cell is the <t>maxwidth</t> of - the box occupying it divided by the box's - <t>colspan</t>. + If a box's [[hshrink]] property is set to + [[true]], the box's maximum width is the same as its + minimum width; otherwise it is the box's + [[maxwidth]]. + </section> <section title="Placing"> - Each column's <i>actual width</i> is set to the maximum - <i>minimum width</i> of all the cells in that column. - <b>NOTE:</b> although a column or row can be sized smaller - than its "minimum width" or larger than its "maximum width", a - box will <i>never</i> be smaller than its <t>minwidth</t> or - larger than its <t>maxwidth</t>. - - Each column's maximum width is the largest maximum width of - the cells in that column, but no smaller than the column's - minimum width. - - A value <t>k</t> is chosen such that when each column's width - is set to <t>min(maximum width, max(minimum width, k))</t>, - the sum of all the column widths equals the parent's width. - If no such value exists, positive or negative infinity is used - (whichever is appropriate). Each column is then set to the - width dictated by <t>k</t>. - - Next, the rows and columns are positioned within the parent - box. The rows and columns are transformed according to the - parent's <t>transform</t> property [<i>Note: Vector Graphics - support (including the <t>transform</t> property) is currently - not implemented</i>]., and the bounding box of the resulting - cells are placed such that the cells' alignment point - coincides with the parent's alignment point (both alignment - points are determined by the parent's <t>align</t> property). - - <image url="grid.pdf" caption="Positioning grid cells"/> + <section title="Packed Boxes"> + + Ibex formulates a set of constraints for placing a box's + **packed** children as follows: + + <list> + - A box's width can be no greater than the sum of the + columns it occupies + - The sum of a set of colums cannot be smaller than the + minimum width of a box that spans them. + - The sum of the widths of the parents' columns will be at + least as large as the parent's width is (but possibly + larger). + </list> - <b>Packed boxes:</b> Each packed box's actual position - and size is then set to the aggregation of the actual sizes of - the cells it spans. If this size exceeds the box's maximum - width, the box is sized to its maximum width and centered - horizontally within the space occupied by its cells. - - <b>Non-packed boxes</b>: each non-packed box is transformed - according to the parent's <t>transform</t> property and then - positioned so that its alignment point is <t>(child.x, - child.y)</t> pixels from the parent's alignment point (both - alignment points are determined by the parent's <t>align</t> - property). - + Subject to these two unbreakable constraints, Ibex searches for + a solution which will optimize the following three goals, + prioritized from most important to least important: + + <list> + - (__Most Important__) The sum of all columns will be a close + to the parent's with as possible (ie as small as possible) + - Ibex will attempt to make a set of columns no wider than + the [[maxwidth]] of a box spanning them. + - (__Least Important__) Ibex will attempt to make all + columns the same width. + </list> + + Each packed box is then placed within the set of cells that it + spans. Usually the box will exactly fill this rectangle; if it + does not (due to [[maxwidth]] or minimum width constraints), the + box's will be placed so that its alignment point coincides with + the alignment point of that rectangle of cells. </section> + + <section title="Non-Packed Boxes"> + Each non-packed box is transformed according to the parent's + [[transform]] property and then positioned so that its alignment + point is [[(child.x, child.y)]] pixels from the corresponding + edge/corner/center of its parent. + </section> + </section> <section title="Rendering"> <list type="ordered"> - If the box's <t>transform</t> property is non-null, the + If the box's [[transform]] property is non-null, the coordinate space is transformed accordingly for the rest of - this phase and for the rendering of all children. [<i>Note: - Vector Graphics support (including the <t>transform</t> - property) is currently not implemented</i>]. + this phase and for the rendering of all children. [**Note: + Vector Graphics support (including the [[transform]] + property) is currently not implemented**]. - If the box is packed and has a non-<t>null</t> path, the + If the box is packed and has a non-[[null]] path, the path is translated such that the alignment point of the path's bounding box coincides with the box's alignment point (both - alignment points are determined by the box's <t>align</t> + alignment points are determined by the box's [[align]] property). If a box has a path, that path is filled with the color, - gradient, or image specified by the <t>fill</t> property and + gradient, or image specified by the [[fill]] property and stroked with the color and width specified by the - <t>strokecolor</t> and <t>strokewidth</t> properties. + [[strokecolor]] and [[strokewidth]] properties. - If the box has a non-null <t>text</t> attribute, - the text is rendered in <t>font</t> with size - <t>fontsize</t> and color <t>textcolor</t>. The text is + If the box has a non-null [[text]] attribute, + the text is rendered in [[font]] with size + [[fontsize]] and color [[textcolor]]. The text is then translated such that the alignment point of the text's bounding box coincides with the box's alignment point (both - alignment points are determined by the box's <t>align</t> + alignment points are determined by the box's [[align]] property). The box's children are rendered (pre-order traversal). </section> -<!-- _______________________________________________________________________ --> +<!-- ----------------------------------------------------------------------- --> <section title="Box Properties"> Each box is a full-fledged ECMAscript object, and can store key-value pairs as properties. Some of these keys have special meaning, which will be explained later. Each box's numeric - properties hold its <i>child boxes</i>. + properties hold its **child boxes**. <section title="Rendering Properties"> <property name="strokecolor" type="string" default="clear"> - If the value is a 5-character hex string (<t>#RGB</t>), - 7-character hex string (<t>#RRGGBB</t>), 9-character hex - string (<t>#AARRGGBB</t>), the box's stroke color will be set + If the value is a 5-character hex string ([[#RGB]]), + 7-character hex string ([[#RRGGBB]]), 9-character hex + string ([[#AARRGGBB]]), the box's stroke color will be set to that color. If the value is one of the <link text="ICC"/> colors (the same set of color names supported by SVG), the stroke color be set to that color. - If the value is <t>null</t>, the stroke color will be set - to clear (<t>#00000000</t>). + If the value is [[null]], the stroke color will be set + to clear ([[#00000000]]). </property> <property name="strokewidth" type="int" default="1"> <property name="fill"> This property can be set to any of the values specified for - <t>strokecolor</t>. + [[strokecolor]]. Alternatively, if the value written is an object, its stream will be read and interpreted as a PNG, GIF, or JPEG image, which will become the texture for this box, and the box's - <t>minwidth</t> and <t>minheight</t> properties will be + [[minwidth]] and [[minheight]] properties will be automatically set to the dimensions of the image. </property> </property> <property name="text" type="string" default='""'> - The box's text; writing <t>null</t> to this property sets it - to <t>""</t>. + The box's text; writing [[null]] to this property sets it + to [[""]]. </property> <property name="textcolor" type="number" default="black"> - The color in which to render the font; accepts the same values as <t>strokecolor</t>. + The color in which to render the font; accepts the same values as [[strokecolor]]. </property> <property name="font" type="stream" default=".ibex.ui.font.sansserif"> When an object is written to this property, its stream is read using the <link url="http://www.freetype.org" text="FreeType 2 library"/>, and the resulting font is used to render the - box's <t>text</t>. + box's [[text]]. </property> <property name="fontsize" type="number" default="10"> <section title="Layout Properties"> <property name="shrink" type="boolean" default="false"> - If set to <t>true</t>, this box will shrink + If set to [[true]], this box will shrink (horizontally/vertically/both) to the smallest size allowed by its children and the bounding box of its path. </property> <property name="x y" type="integer" default="varies"> If the box is a root box, this is the (x/y)-coordinate of the surface; otherwise it is the distance between the parent's - alignment point and this box's alignment point. + alignment point and the corresponding corner/edge/center of + its parent. </property> <property name="minwidth minheight" type="integer" default="0"> <property name="width height" type="integer"> When read, this is the current (width/height) of this box. Writing to this property is equivalent to writing to - <i>both</i> the minimum and maximum (width/height). + **both** the minimum and maximum (width/height). </property> <property name="cols rows" type="integer" default="0"> The number of (columns/rows) in which to lay out the children of this box. If set to zero, the number of (columns/rows) is unconstrained. - Either <t>rows</t> or <t>cols</t> must be zero. If - <t>0</t> is written to <t>cols</t> when <t>rows</t> is - <t>0</t>, the write is ignored. If a nonzero value is - written to <t>cols</t> when <t>rows</t> is nonzero, - <t>rows</t> is set to <t>0</t>, and vice versa. + Either [[rows]] or [[cols]] must be zero. If + [[0]] is written to [[cols]] when [[rows]] is + [[0]], the write is ignored. If a nonzero value is + written to [[cols]] when [[rows]] is nonzero, + [[rows]] is set to [[0]], and vice versa. </property> <property name="colspan rowspan" type="integer" default="1"> </property> <property name="visible" type="boolean" default="true"> - If set to <t>false</t>, this box will be rendered as if its + If set to [[false]], this box will be rendered as if its width and height were zero. If this is a root box, the associated surface will be hidden. - When reading from this property, the value <t>false</t> will - be returned if this box <i>or any of its ancestors</i> is not - visible. Thus it is possible to write <t>true</t> to a box's - <t>visible</t> property and then read back <t>false</t>. + When reading from this property, the value [[false]] will + be returned if this box **or any of its ancestors** is not + visible. Thus it is possible to write [[true]] to a box's + [[visible]] property and then read back [[false]]. </property> <property name="packed" type="boolean" default="true"> - The layout strategy for this box. If set to <t>true</t>, the + The layout strategy for this box. If set to [[true]], the box occupies no cells and is laid out independently of its siblings. </property> <property name="redirect" type="box" default="thisbox"> Writing to this property sets the box's redirect target. This property cannot be read from, and can only be written to if - the value being written is a <i>descendant</i> of the current + the value being written is a **descendant** of the current value. If a box has a non-null redirect target, reads and writes to any of the other properties in this section will be forwarded to the redirect target. - The <t>redirect</t> attribute is very useful for hiding the + The [[redirect]] attribute is very useful for hiding the internal structure of a widget, and for allowing widgets to act as "smart" containers for other widgets. For example, a menu widget might have an invisible child as its redirect target; this way, when boxes </property> <property name="numeric properties" type="int" default=""> - The <i>n</i>th child of box <t>b</t> can be accessed by reading from - <t>b[n]</t>. The <i>n</i>th child can be removed by writing - <t>null</t> to <t>b[n]</t> (the child will become parentless). A - new child can be inserted <i>before</i> the <i>n</i>th child by - writing it to <t>b[n]</t>; if the value written is already a child of - <t>b</t>, it will be removed from <t>b</t> first. It is important + The **n**th child of box [[b]] can be accessed by reading from + [[b[n]]]. The **n**th child can be removed by writing + [[null]] to [[b[n]]] (the child will become parentless). A + new child can be inserted **before** the **n**th child by + writing it to [[b[n]]]; if the value written is already a child of + [[b]], it will be removed from [[b]] first. It is important to note that this behavior is different from ECMAscript arrays -- - writing a non-<t>null</t> value to <t>b[n]</t> does not eliminate - the <i>n</i>th child; it merely shifts it over one position. - <b>Note:</b> Unlike most JavaScript objects, enumerating a Box's - properties with the JavaScript <t>for..in</t> construct will - enumerate <i>only</i> the box's children and not any other properties. + writing a non-[[null]] value to [[b[n]]] does not eliminate + the **n**th child; it merely shifts it over one position. + __Note:__ Unlike most JavaScript objects, enumerating a Box's + properties with the JavaScript [[for..in]] construct will + enumerate **only** the box's children and not any other properties. </property> <property name="clip" type="boolean" default="true"> - If <t>true</t>, the visual representation of this box's + If [[true]], the visual representation of this box's children will be clipped to the boundaries of this box. - <b>Note:</b> setting this property to <t>false</t> imposes a + __Note:__ setting this property to [[false]] imposes a substantial performance penalty. </property> <property name="surface" type="" default="null"> FIXME If this box has a parent, this property returns - <t><i>parent</i>.surface</t>; otherwise it returns null. + [[**parent**.surface]]; otherwise it returns null. This property is a simple building block that the widget library uses to implement more complex functionality such as focus control and popups. <property name="cursor" type="string" default="null"> The shape that the cursor should take when inside this - box. Valid values are: "<t>default</t>" , "<t>wait</t>", - "<t>crosshair</t>", "<t>text</t>", "<t>hand</t>", and - "<t>move</t>", as well as resizing cursors"<t>east</t>", - "<t>west</t>", "<t>north</t>", "<t>south</t>", - "<t>northwest</t>", "<t>northeast</t>", - "<t>southwest</t>", and "<t>southeast</t>". Note that on + box. Valid values are: "[[default]]" , "[[wait]]", + "[[crosshair]]", "[[text]]", "[[hand]]", and + "[[move]]", as well as resizing cursors"[[east]]", + "[[west]]", "[[north]]", "[[south]]", + "[[northwest]]", "[[northeast]]", + "[[southwest]]", and "[[southeast]]". Note that on some platforms, resize cursors for opposite directions (such - as <t>northwest</t> and <t>southeast</t> are the + as [[northwest]] and [[southeast]] are the same). - If a box's cursor is <t>null</t>, its parent's cursor will + If a box's cursor is [[null]], its parent's cursor will be used. If the root box's cursor is null, the - "<t>default</t>" cursor will be used. + "[[default]]" cursor will be used. </property> <property name="static" type="object" default="N/A"> Reading from this property will return the parent scope used - to execute the <t><static/></t> block of the template + to execute the [[<static/>]] block of the template in which the currently-executing code resides. </property> <property name="thisbox" type="box" default=" "> Returns a reference to the box itself. - If <t>null</t> is written to this property, and this box is + If [[null]] is written to this property, and this box is the root box of a surface, the box will be detached and the surface destroyed. If this box has a parent, it will be detached from its parent. <property name="indexof()" type="function" default=" "> This property is actually a function; invoking - <t>parent.indexof(child)</t> will return the numerical index - of <t>child</t> in <t>parent</t> if <t>child</t> is a - child of <t>parent</t> (or <t>parent</t>'s redirect - target), and <t>-1</t> otherwise. Writing to this property + [[parent.indexof(child)]] will return the numerical index + of [[child]] in [[parent]] if [[child]] is a + child of [[parent]] (or [[parent]]'s redirect + target), and [[-1]] otherwise. Writing to this property has no effect. </property> <property name="distanceto()" type="function" default=" "> This property is actually a function; invoking - <t>box.distanceto(otherbox)</t> will return an object with two - properties, <t>x</t> and <t>y</t>, containing the horizontal + [[box.distanceto(otherbox)]] will return an object with two + properties, [[x]] and [[y]], containing the horizontal and vertical distance between the two boxes (negative if - <t>otherbox</t> is to the left of / above <t>box</t>). This + [[otherbox]] is to the left of / above [[box]]). This can be used to determine the relative placement of two boxes on different branches of the box tree. </property> of a surface. <property name="Focused"> - The value <t>true</t> is put to this property on the root box - when the surface gains the input focus, and <t>false</t> when + The value [[true]] is put to this property on the root box + when the surface gains the input focus, and [[false]] when the surface loses the input focus. Reading from this value will - return <t>true</t> if the surface is focused and <t>false</t> - if it is not. Putting <t>true</t> to this property will - <i>not</i> cause the surface to "steal" the input focus from other + return [[true]] if the surface is focused and [[false]] + if it is not. Putting [[true]] to this property will + **not** cause the surface to "steal" the input focus from other windows. </property> <property name="Maximized"> - The value <t>true</t> is put to this property on the root box - when the surface is maximized, and <t>false</t> when the surface - is un-maximized. Reading from this value will return <t>true</t> - if the surface is maximized and <t>false</t> if it is - not. Putting <t>true</t> to this property will maximize the - window, and putting <t>false</t> to this property will + The value [[true]] is put to this property on the root box + when the surface is maximized, and [[false]] when the surface + is un-maximized. Reading from this value will return [[true]] + if the surface is maximized and [[false]] if it is + not. Putting [[true]] to this property will maximize the + window, and putting [[false]] to this property will unmaximize the window. Note that not all platforms support maximization. </property> <property name="Minimized"> - The value <t>true</t> is put to this property on the root box - when the surface is minimized, and <t>false</t> when the surface - is unminimized. Reading from this value will return <t>true</t> - if the surface is minimized and <t>false</t> if it is - not. Putting <t>true</t> to this property will minimize the - window, and putting <t>false</t> will unminimize it. + The value [[true]] is put to this property on the root box + when the surface is minimized, and [[false]] when the surface + is unminimized. Reading from this value will return [[true]] + if the surface is minimized and [[false]] if it is + not. Putting [[true]] to this property will minimize the + window, and putting [[false]] will unminimize it. </property> <property name="Close"> When the user attempts to close a surface, the value - <t>true</t> will be put to this property. Scripts may trap + [[true]] will be put to this property. Scripts may trap this property to prevent the window from closing. Putting the value - <t>true</t> to this property on a root box has the same - effect as putting <t>null</t> to the <t>thisbox</t> + [[true]] to this property on a root box has the same + effect as putting [[null]] to the [[thisbox]] property. </property> </section> -<!-- _______________________________________________________________________ --> +<!-- ----------------------------------------------------------------------- --> <section title="Streams"> <heading title="Every object has a stream..."/> - Every object has a <i>stream</i> associated with it. A stream is a + Every object has a **stream** associated with it. A stream is a sequence of bytes that can be read or written to. By default an object has an empty stream (zero bytes). However, some objects - (returned from special methods on the <t>ibex</t> object) have + (returned from special methods on the [[ibex]] object) have streams yielding data read from an url, file, or a component of a zip archive. In a future release, the stream associated with a box will be an .ibex template which, when applied, will fully reconstitute the <section title="Getting Substreams"> Most stream objects let you access - substreams using the usual JavaScript operators <t>[]</t> and - <t>.</t>, as well as the <t>for..in</t> syntax. + substreams using the usual JavaScript operators [[[]]] and + [[.]], as well as the [[for..in]] syntax. <pre> // r1 and r2 are equivalent but not equal (!=) <section title="The Root Stream"> - The empty-string property on the <t>ibex</t> object is called the - <i>root stream</i>. You can access this object as <t>ibex..</t> or - <t>ibex[""]</t>. Additionally, any expression which starts with a + The empty-string property on the [[ibex]] object is called the + **root stream**. You can access this object as [[ibex..]] or + [[ibex[""]]]. Additionally, any expression which starts with a dot is treated as property to be retrieved from the root stream. The following three expressions are equivalent: FIXME You can access variables within the static block of a template by - appending a double period (<t>..</t>) and the variable name to the + appending a double period ([[..]]) and the variable name to the stream used to load that template: <pre> If you attempt to send a stream as part of an XML-RPC call, the stream will be read in its entirity, Base64-encoded, and transmitted - as a <t><base64/></t> element. + as a [[<base64/>]] element. - Ibex supports two special URL protocols. The first is <t>data:</t>, + Ibex supports two special URL protocols. The first is [[data:]], which inteprets the rest of the URL as a Base64 encoded sequence of - bytes to use as a source. The other is <t>utf8:</t> which + bytes to use as a source. The other is [[utf8:]] which interpretets the rest of the string as a Unicode character sequence to be UTF-8 encoded as a string of bytes to use as a source. </section> -<!-- _______________________________________________________________________ --> +<!-- ----------------------------------------------------------------------- --> <section title="The Ibex object"> - The <t>ibex</t> object is present in the top-level scope of every + The [[ibex]] object is present in the top-level scope of every script. It has the following properties: <heading title="General"/> this object contains the ECMA math functions </property> <property name="ibex.regexp(s)"> - return a regexp object corresponding to string <i>s</i> + return a regexp object corresponding to string **s** </property> <property name="ibex.string"> this object contains the ECMA string manipulation functions <heading title="Logging"/> <property name="ibex.log.debug(m1, ... mn)"> - log the debug messages <i>m1</i> through <i>mn</i>. - <i>o</i> + log the debug messages **m1** through **mn**. + **o** </property> <property name="ibex.log.info(m1, ... mn)"> - log the info messages <i>m1</i> through <i>mn</i>. + log the info messages **m1** through **mn**. </property> <property name="ibex.log.warn(m1, ... mn)"> - log the warning messages <i>m1</i> through <i>mn</i>. + log the warning messages **m1** through **mn**. </property> <property name="ibex.log.error(m1, ... mn)"> - log the error messages <i>m1</i> through <i>mn</i>. + log the error messages **m1** through **mn**. </property> <heading title="User Interface"/> <property name="ibex.ui.browser(u)"> - opens a new browser window with URL <i>u</i> + opens a new browser window with URL **u** </property> <property name="ibex.ui.key.control"> <heading title="Networking"/> <property name="ibex.net.rpc.xml(u)"> - return an XML-RPC call object with endpoint URL <i>u</i> + return an XML-RPC call object with endpoint URL **u** </property> <property name="ibex.net.rpc.soap(u,"> - return a SOAP call object with endpoint URL <i>u</i>, - SoapAction <i>a</i>, and XML Namespace <i>n</i> + return a SOAP call object with endpoint URL **u**, + SoapAction **a**, and XML Namespace **n** </property> <heading title="Threads"/> </property> <property name="ibex.thread.sleep(n)"> - sleep for <i>n</i> milliseconds + sleep for **n** milliseconds </property> <heading title="Streams"/> <property name="ibex.stream.url(u)"> - returns a new object whose stream is drawn from URL <i>u</i> + returns a new object whose stream is drawn from URL **u** </property> <property name="ibex.stream.unzip(s)"> - unpacks a zip archive from <i>s</i>'s stream + unpacks a zip archive from **s**'s stream </property> <property name="ibex.stream.uncab(s)"> - unpacks a cab archive from <i>s</i>'s stream + unpacks a cab archive from **s**'s stream </property> <property name="ibex.stream.cache(s,k)"> - valign=top>wraps a disk-backed read cache keyed on <i>k</i> - around <i>s</i>'s stream + valign=top>wraps a disk-backed read cache keyed on **k** + around **s**'s stream </property> <property name="ibex.stream.watch(s,f)"> - returns an object whose stream is drawn from <i>s</i>'s - stream, but invokes <i>f(n,d)</i> as it is read from. + returns an object whose stream is drawn from **s**'s + stream, but invokes **f(n,d)** as it is read from. </property> <property name="ibex.stream.parse.xml(s, h)"> - Use SAX to parse the XML document on stream <i>s</i> with - handler <i>h</i> + Use SAX to parse the XML document on stream **s** with + handler **h** </property> <property name="ibex.stream.parse.html(s, h)"> - Same as <t>parse.xml()</t>, but tries to fix broken HTML. + Same as [[parse.xml()]], but tries to fix broken HTML. </property> <property name="ibex.stream.parse.utf8(s)"> - treat <i>s</i>'s stream as a string encoded as a UTF-8 byte stream and return the string + treat **s**'s stream as a string encoded as a UTF-8 byte stream and return the string </property> <property name="ibex.stream.homedir"> - <t>ibex.stream.tempdir</t> + [[ibex.stream.tempdir]] </property> <heading title="Cryptography"/> <property name="ibex.crypto.rsa(k,s)"> - <i>not implemented yet:</i> return a - stream which rsa-decrypts stream <i>s</i> with key <i>k</i> + **not implemented yet:** return a + stream which rsa-decrypts stream **s** with key **k** </property> <property name="ibex.crypto.rc4(k,s)"> - <i>not implemented yet:</i> return a - stream which rc4-decrypts stream <i>s</i> with key <i>k</i> + **not implemented yet:** return a + stream which rc4-decrypts stream **s** with key **k** </property> <property name="ibex.crypto.md5(s)"> - <i>not implemented yet:</i> immediately - MD5-hash stream <i>s</i> + **not implemented yet:** immediately + MD5-hash stream **s** </property> <property name="ibex.crypto.sha1(s)"> - <i>not implemented yet:</i> immediately - SHA1-hash stream <i>s</i> + **not implemented yet:** immediately + SHA1-hash stream **s** </property> </section> -<!-- _______________________________________________________________________ --> +<!-- ----------------------------------------------------------------------- --> <section title="Traps"> - You can add a trap to a property by applying the <t>++=</t> operator + You can add a trap to a property by applying the [[++=]] operator to a function with one argument. The trap will be invoked whenever that property is written to. </ui:box> </pre> - If another script were to set the property "<t>foo</t>" - on the box above to the value <t>5</t>, the function above would be - invoked with the argument <t>5</t>. The function would then log - the string "<t>foo is 5</t>". + If another script were to set the property "[[foo]]" + on the box above to the value [[5]], the function above would be + invoked with the argument [[5]]. The function would then log + the string "[[foo is 5]]". - Within a trap, the expression <t>trapee</t> can be used to + Within a trap, the expression [[trapee]] can be used to get a reference to the box on which the trap was placed. - The expression <t>trapname</t> returns the name of the + The expression [[trapname]] returns the name of the trap executing the current function. This is useful when a function is applied to multiple traps. For example: <section title="Removing Traps"> - You can remove a trap by using the <t>--=</t> operator with the same + You can remove a trap by using the [[--=]] operator with the same function you added as a trap: <pre> <heading title="Multiple Traps on the Same Property"/> - When the trapped property is <i>written</i> to, each of the trap + When the trapped property is **written** to, each of the trap functions placed on it will be invoked in the opposite order that they were placed on the box -- the most recently placed trap will execute first. This last-to-first execution of traps is called - <i>cascading</i>. After the last trap is invoked, the value is + **cascading**. After the last trap is invoked, the value is stored on the box (remember, boxes are objects, so they can hold properties just like all other ECMAscript objects). <section title="Manual Cascades"> There are two additional tricks you can use when placing traps. The - first is a <i>manual cascade</i>. If you want to cascade to lower + first is a **manual cascade**. If you want to cascade to lower traps in the middle of a function, or you want to cascade with a different value than the value passed to you (in effect "lying" to - lower traps), you can use <t>cascade</t>. For example: + lower traps), you can use [[cascade]]. For example: <pre> <ui:box color="black"> This effectively creates a box whose color cannot be changed, and which complains loudly if you try to do so. - Do <i>not</i> try to do something like this: + Do **not** try to do something like this: <pre> <ui:box color="black"> } </ui:box> </pre> - To prevent automatic cascading, return <t>true</t> from your function: + To prevent automatic cascading, return [[true]] from your function: <pre> <ui:box color="black"> <section title="Read Traps"> - The other trick is a <i>read-trap</i>. Read traps are just like normal + The other trick is a **read-trap**. Read traps are just like normal traps, except that you use a function that takes zero arguments instead of one. Read traps also do not automatically cascade. <pre> <ui:box> - doublewidth <t>++=</t> function() { return 2 * width; } + doublewidth [[++=]] function() { return 2 * width; } </ui:box> </pre> - If another script attempts to read from the <t>doublewidth</t> + If another script attempts to read from the [[doublewidth]] property on this box, the value it gets will be twice the actual width of the box. Note that - the actual <t>doublewidth</t> property on the box never gets written + the actual [[doublewidth]] property on the box never gets written to, since the trap does not cascade. You can manually cascade on read traps as well: <pre> <ui:box> - text <t>++=</t> function() { return "my text is " + cascade; } + text [[++=]] function() { return "my text is " + cascade; } </ui:box> </pre> place traps on any of the properties described in the sections <link text="Box Layout Properties" section="Layout Properties"/>, <link section="Child-Control Properties"/>, or <link section="Other Box - Properties"/> except for <t>childadded</t>, - <t>childremoved</t> and <t>surface</t>. FIXME: remove? + Properties"/> except for [[childadded]], + [[childremoved]] and [[surface]]. FIXME: remove? <heading title="Exceptions and Traps"/> If an uncaught exception is thrown from a trap, Ibex will log the - exception, but will <i>not</i> propagate it to the code which + exception, but will **not** propagate it to the code which triggered the trap. If the trap was a read trap, the value - <t>null</t> will be returned. + [[null]] will be returned. FIXME: is this right? <heading title="Architectural Significance of Traps"/> <section title="Cloning"> - <i>Cloning</i> is a companion technique for traps; together they can + **Cloning** is a companion technique for traps; together they can be used to simulate any sort of environment you might need. When you - call <t>ibex.clone(o)</t>, Ibex returns a new object (called the - <i>clone</i>) which compares with equality (<t>==</t>) to the + call [[ibex.clone(o)]], Ibex returns a new object (called the + **clone**) which compares with equality ([[==]]) to the original object. Furthermore, both objects are "equal" as keys in hashtables, so: properties on the original object, and reads from properties on the clone will read properties on the original object. In fact, the only thing that can be used to distinguish the original from the clone is - traps -- a trap placed on the clone is <i>not</i> placed on the + traps -- a trap placed on the clone is **not** placed on the original object as well. </section> -<!-- _______________________________________________________________________ --> +<!-- ----------------------------------------------------------------------- --> <section title="Threads"> <section title="Contexts"> From the perspective of an application writer, Ibex is strictly single-threaded. Ibex is always in exactly one of the following three - <i>contexts</i>: + **contexts**: <list type="unordered"> - <b>Rendering Context</b> -- (redrawing the screen) + __Rendering Context__ -- (redrawing the screen) - <b>Event Context</b> (executing javascript traps triggered by an event) + __Event Context__ (executing javascript traps triggered by an event) - <b>Thread Context</b> (executing a background thread spawned with <t>ibex.thread</t>) + __Thread Context__ (executing a background thread spawned with [[ibex.thread]]) </list> <list type="unordered"> - The <t>box.mouse</t> property and its subproperties - (<t>x</t>, <t>y</t>, and <t>inside</t>) can only be read + The [[box.mouse]] property and its subproperties + ([[x]], [[y]], and [[inside]]) can only be read from within the Event Context, or in a thread context - <i>after</i> a the <t>box.mouse</t> property on this box or + **after** a the [[box.mouse]] property on this box or an ancestor box has been written to. Blocking operations (anything that accesses the network or <section title="Background Threads"> Ibex offers easy access to threads. Spawning a background thread is as - simple as writing a function to the <t>ibex.thread</t> property: + simple as writing a function to the [[ibex.thread]] property: <pre> ibex.thread = function() { reserved for use in future versions of Ibex. Scripts should not depend on the number or content of these arguments. - Ibex is <i>cooperatively multitasked</i>, so threads must not process + Ibex is **cooperatively multitasked**, so threads must not process for too long. This was a deliberate choice; cooperatively multitasked environments do not require complex locking primitives like mutexes and semaphores which are difficult for novices to understand. The disadvantage of cooperative multitasking is that one thread can hog the CPU. This is unlikely to happen in Ibex for two reasons: - first, all blocking I/O operations <i>automatically</i> yield the CPU, + first, all blocking I/O operations **automatically** yield the CPU, so the overall user interface never becomes unresponsive because it is waiting for a disk or network transfer. Second, since Ibex is strictly a user interface platform, Ibex scripts are unlikely to perform highly Every execution of the Event Context begins with an event, which consists of a key/value pair, and a mouse position, which consists of - an x and y coordinate. The possible keys are <t>_Press[1-3]</t>, - <t>_Release[1-3]</t>, <t>_Click[1-3]</t>, <t>_DoubleClick[1-3]</t>, - <t>_Move</t>, <t>_KeyPressed</t>, and <t>_KeyReleased</t>. + an x and y coordinate. The possible keys are [[_Press[1-3]]], + [[_Release[1-3]]], [[_Click[1-3]]], [[_DoubleClick[1-3]]], + [[_Move]], [[_KeyPressed]], and [[_KeyReleased]]. Here are two example events: and writes the key and value to that box. If none of the box's children contain the mouse position, Ibex removes the leading underscore from the key name and writes the value to - <i>that</i> property. Once all the traps on that property have + **that** property. Once all the traps on that property have executed, the value is written to the box's parent. Intuitively, Ibex delivers the underscored event to every box from the </ui:box> </pre> - In general, you should use the <i>non-underscore</i> names to respond + In general, you should use the **non-underscore** names to respond to user input and use the underscored names when you want to override child boxes' behavior or route events to particular boxes (for example, when implementing a focus protocol). This is why the <heading title="Stopping the Process"/> At any point in this sequence, a trap handler can choose not to - cascade (by returning <t>true</t> from the trap handler function). + cascade (by returning [[true]] from the trap handler function). This will immediately cease the propagation of the event. This is how you would indicate that an event has been "handled". either up or down the tree. <property name="Enter Leave"> - The value <t>true</t> is written to this property when the mouse (enters/leaves) the box. + The value [[true]] is written to this property when the mouse (enters/leaves) the box. </property> <property name="SizeChange"> - The value <t>true</t> is put to this property after the size + The value [[true]] is put to this property after the size of this box changes. </property> <property name="ChildChange"> When a child is added or removed, that child is written to - this property. The write is always performed <i>after</i> the + this property. The write is always performed **after** the addition or removal, so these two cases can be distinguished - by checking <t>indexof(child)</t>. + by checking [[indexof(child)]]. Note that if the parent's redirect target is set to another box, this trap will only be invoked when children are manipulated by reading and writing to the parent. Reads and - writes directly to the redirect target will <i>not</i> trigger + writes directly to the redirect target will **not** trigger this trap. Note also that this traps is still triggered if a box's - <t>redirect</t> target is <i>null</i>. This is useful for + [[redirect]] target is **null**. This is useful for boxes that need to accept children and then relocate them elsewhere. </property> <property name="Press1 Press2 Press3"> Indicates that the use has pressed a mouse button. On - platforms with three mouse buttons, the <i>middle</i> button + platforms with three mouse buttons, the **middle** button is button 3 -- this ensures that applications written to only use two buttons (1 and 2) will work intuitively on three button platforms. <property name="Move"> Indicates that the mouse has moved while within this box, or that - the mouse while outside this box <i>if a button was pressed while within this box and has not yet been released</i> + the mouse while outside this box **if a button was pressed while within this box and has not yet been released** </property> <property name="KeyPressed KeyReleased"> If the shift key was depressed immediately before the event took place, then the string will be capitalized. Special keynames are also capitalized; shift+home is reported as - "<t>HOME</t>". Symbols are capitalized as they appear on the + "[[HOME]]". Symbols are capitalized as they appear on the keyboard; for example, on an American QWERTY keyboard, shift+2 - is reported as "<t>@</t>". + is reported as "[[@]]". If the alt, meta, or command key was depressed immediately before this key was pressed, then the string will be prefixed - with the string "<t>A-</t>". If the control key was depressed + with the string "[[A-]]". If the control key was depressed while this key was pressed, then the string will be prefixed - with the string "<t>C-</t>". If both alt and control are - depressed, the string is prefixed with "<t>C-A-</t>". + with the string "[[C-]]". If both alt and control are + depressed, the string is prefixed with "[[C-A-]]". Ibex does not distinguish between a key press resulting from the user physically pushing down a key, and a 'key press' </section> -<!-- _______________________________________________________________________ --> +<!-- ----------------------------------------------------------------------- --> <section title="Networking"> <section title="XML-RPC"> - XML-RPC objects can be created by calling <t>ibex.net.rpc.xml(<i>XML-RPC - URL</i>)</t>, and then invoking methods on that object. For example, + XML-RPC objects can be created by calling [[ibex.net.rpc.xml(**XML-RPC + URL**)]], and then invoking methods on that object. For example, <pre> Press1 += function(v) { </pre> When the user clicks the first mouse button on this box, it will - contact the server <t>xmlrpc.ibex.org</t>, route to the - <t>/RPC2/</t> handler and invoke the <t>getTodaysColor()</t> - method on the <t>color</t> object with a single string argument - "<t>Friday</t>". The return value will be used to change the color + contact the server [[xmlrpc.ibex.org]], route to the + [[/RPC2/]] handler and invoke the [[getTodaysColor()]] + method on the [[color]] object with a single string argument + "[[Friday]]". The return value will be used to change the color of the box the user clicked on. Note that in this example we spawned a background thread to handle the - request -- the <t>Press1</t> event is delivered in the foreground + request -- the [[Press1]] event is delivered in the foreground thread, and XML-RPC methods may only be invoked in background threads. This is to prevent the UI from "locking up" if the server takes a long time to reply. If the XML-RPC method faults, an object will be thrown with two - properties: <t>faultCode</t> and <t>faultString</t>, as defined in + properties: [[faultCode]] and [[faultString]], as defined in the <link url="http://www.xmlrpc.org/spec" text="XML-RPC specification"/>. If Ibex encounters a network, transport, or session-layer error, it will - throw a <t>String</t> object describing the error in a + throw a [[String]] object describing the error in a human-readable format. Scripts should not rely on the contents of this string having any special structure or significance. element. If a <base64/> element is found in the XML-RPC reply, it will be returned as an object with a stream drawn from that byte sequence. - Each object returned by <t>ibex.net.rpc.xml()</t> represents a + Each object returned by [[ibex.net.rpc.xml()]] represents a single HTTP connection. The connection will be held open until the object is garbage collected or the server closes the connection. If a second call is issued on the object before the text="pipelined"/>. This can dramatically improve performance. Ibex supports HTTP Basic and Digest authentication. To use - authentication, pass <t>ibex.net.rpc.xml()</t> a URL in the form + authentication, pass [[ibex.net.rpc.xml()]] a URL in the form <pre> http[s]://user:password@hostname/ <list type="ordered"> - <t>ibex.net.rpc.soap()</t> is used instead of - <t>ibex.net.rpc.xml()</t> + [[ibex.net.rpc.soap()]] is used instead of + [[ibex.net.rpc.xml()]] Instead of specifying just the URL of the service itself, you must specify the URL, the SOAPAction argument, and the </list> SOAP faults are handled the same way as XML-RPC faults except that the - capitalization of the <t>faultstring</t> and <t>faultcode</t> + capitalization of the [[faultstring]] and [[faultcode]] members is all lower-case, to match the SOAP spec. Here is a SOAP example: applications. The current Ibex SOAP stack does not support 'document style' or - multi-ref (<t>href</t>) data structures. + multi-ref ([[href]]) data structures. </section> </section> </section> -<!-- _______________________________________________________________________ --> +<!-- ----------------------------------------------------------------------- --> <section title="Error Handling"> If the Ibex Core encounters an error while servicing a function call </property> <property name="ibex.net.http."> Thrown when an HTTP error code is returned during an - operation. The three characters <t><i>xyz</i></t> will be + operation. The three characters [[**xyz**]] will be the three-digit HTTP status code. </property> <property name="ibex.net.xmlrpc.null"> - The caller attempted to transmit the <t>null</t> value via XML-RPC. + The caller attempted to transmit the [[null]] value via XML-RPC. </property> <property name="ibex.net.xmlrpc.circular"> The caller attempted to transmit a circular data structure via XML-RPC. XML-RPC (for example, a Box or the Ibex object). </property> <property name="ibex.null.put"> - A JavaScript attempted to put to a property on the <t>null</t> value + A JavaScript attempted to put to a property on the [[null]] value </property> <property name="ibex.null.get"> - A JavaScript attempted to get from a property on the <t>null</t> value + A JavaScript attempted to get from a property on the [[null]] value </property> <property name="ibex.null.call"> - A JavaScript attempted to call the <t>null</t> value + A JavaScript attempted to call the [[null]] value </property> If an exception is thrown inside a trap, the exception will propagate If an uncaught exception is thrown while applying a template, or the requested template could not be found, an error will be logged and the box to which the template was being applied will be made invisible - (<t>visible = false</t>). This ensures that half-applied widgets are + ([[visible = false]]). This ensures that half-applied widgets are never shown to the user. </section> -<!-- _______________________________________________________________________ --> +<!-- ----------------------------------------------------------------------- --> <section title="Advanced Topics"> <section title="Re-routing events"> - At any point in the Event Context, you can write to the <t>mouse</t> + At any point in the Event Context, you can write to the [[mouse]] property on any box. The value written should be an object with two - properties, <t>x</t> and <t>y</t>. For example: + properties, [[x]] and [[y]]. For example: <pre> _Press1 ++= function(p) { } </pre> - The coordinates specified are relative to the box whose <t>mouse</t> + The coordinates specified are relative to the box whose [[mouse]] property is being written to. There is no need to supply the - <t>inside</t> property; it is computed automatically. Writing to - the <t>mouse</t> property causes Ibex to recompute the eventual - target box, and also alter the values returned by <t>mouse.x</t>, - <t>mouse.y</t>, and <t>mouse.inside</t> for any <i>descendants</i> - of the current box. Writing to the <t>mouse</t> property also + [[inside]] property; it is computed automatically. Writing to + the [[mouse]] property causes Ibex to recompute the eventual + target box, and also alter the values returned by [[mouse.x]], + [[mouse.y]], and [[mouse.inside]] for any **descendants** + of the current box. Writing to the [[mouse]] property also automatically prevents the event from returning to the box's parents -- it is equivalent to not cascading on the non-underscored event. This ensures that child boxes cannot trick their parent boxes into <section title="Synthesizing Your Own Events"> - You can create "fake events" by simply writing to the <t>mouse</t> + You can create "fake events" by simply writing to the [[mouse]] property and then writing a value to one of the underscored properties on a box. This will have exactly the same effect as if the use had actually pressed a key, clicked a button, or moved the mouse -- they <section title="Ibex self-emulation"> - When the core first starts up, it clones the <t>ibex</t> object, + When the core first starts up, it clones the [[ibex]] object, creates a stream for the initial .ibex, and then places a trap on the - cloned <t>ibex</t> object so that its empty-string property returns + cloned [[ibex]] object so that its empty-string property returns the .ibex stream. The cloned Ibex object is then passed as the third - (optional) argument to <t>ibex.apply()</t>, making it the default - <t>ibex</t> object for the scripts that are executed as part of the + (optional) argument to [[ibex.apply()]], making it the default + [[ibex]] object for the scripts that are executed as part of the template instantiation. <pre> ibex.apply(ibex.box, new_ibex..main, new_ibex); </pre> - Note that we called <t>ibex.bless()</t> on the stream before tacking + Note that we called [[ibex.bless()]] on the stream before tacking it on to the new Ibex object. The bless function returns a clone of the object passed to it, with a few traps which are explained below. Additionally, any sub-streams retrieved by accessing properties of the blessed stream will also automatically be blessed (blessed streams are - <i>monadic</i>). + **monadic**). Blessing a stream serves three purposes: <list> If the stream is a template to be applied, the string - "<t>.ibex</t>" is appended. + "[[.ibex]]" is appended. - If the stream is an image, the string "<t>.png</t>" is - appended. If no stream is found, "<t>.jpeg</t>" and - "<t>.gif</t>" are tried, in that order. + If the stream is an image, the string "[[.png]]" is + appended. If no stream is found, "[[.jpeg]]" and + "[[.gif]]" are tried, in that order. - If the stream is an font, the string "<t>.ttf</t>" is + If the stream is an font, the string "[[.ttf]]" is appended. </list> - Every call to <t>ibex.bless()</t> returns a different object + Every call to [[ibex.bless()]] returns a different object (which happens to be a clone of the object passed to it) with a completely separate set of static blocks. </list> - Ibex can self-emulate by using <t>ibex.clone()</t> on the Ibex object; + Ibex can self-emulate by using [[ibex.clone()]] on the Ibex object; this technique is very similar to the use of ClassLoaders in Java. This is useful for a number of applications, including debuggers, IDEs, sandboxing untrusted code, remote-control, and </section> </section> -<!-- _______________________________________________________________________ --> +<!-- ----------------------------------------------------------------------- --> <appendix title="Security Architecture and Considerations"> Due to the expense and hassle imposed by the commercial PKI code such machines public IP addresses is a poor network security policy, and doing so squanders scarce public IPv4 addresses. As such, the onus is on the administrators of such machines to explicitly block access - to clients reporting a <t>User-Agent:</t> header beginning with the - four characters "<t>IBEX</t>". + to clients reporting a [[User-Agent:]] header beginning with the + four characters "[[IBEX]]". <heading title="Malicious UI attempts to trick user into divulging secret information"/> - All top-level windows created by Ibex are <i>scarred</i> -- a stripe + All top-level windows created by Ibex are **scarred** -- a stripe and a lock is drawn across the corner of the window. There is no way for a user interface to remove this scar. Ibex user interfaces may not create windows smaller than the size of the scar. </appendix> -<!-- _______________________________________________________________________ --> +<!-- ----------------------------------------------------------------------- --> <appendix title="ECMAscript compliance"> Ibex's scripts are written in a modified subset of ECMA-262, revision 3 <list type="unordered"> - The <t>undefined</t> value, <t>===</t>, and <t>!==</t> + The [[undefined]] value, [[===]], and [[!==]] - The <t>new</t> keyword (and ECMAScript object inheritance) - <t>eval</t> + The [[new]] keyword (and ECMAScript object inheritance) + [[eval]] - <t>getter</t> and <t>setter</t> + [[getter]] and [[setter]] - The ECMA <t>this</t> keyword. + The ECMA [[this]] keyword. - The <t>String</t>, <t>Number</t>, and <t>Boolean</t> - classes. Note that <t>string</t>, <t>number</t>, and - <t>boolean</t> values are supported, however. + The [[String]], [[Number]], and [[Boolean]] + classes. Note that [[string]], [[number]], and + [[boolean]] values are supported, however. - You may not <t>throw</t> the <t>null</t> value. + You may not [[throw]] the [[null]] value. </list> Additionally, you must declare all root-scope variables (with - <t>var</t>) before using them; failure to do so will result in an + [[var]]) before using them; failure to do so will result in an exception. Box properties are pre-defined in the scope that scripts are executed in. <list type="unordered"> - The token <t>..</t> is equivalent to <t>[""]</t>. + The token [[..]] is equivalent to [[[""]]]. Trapping Cloning - Extended <t>catch</t> syntax. The following code: + Extended [[catch]] syntax. The following code: <pre> } catch(e propname "foo.bar.baz") { // ... if it does appear, it must be the last one. Since Ibex ECMAscripts are wrapped in XML, the lexical token - "<t>lt</t>" is be interpreted as <t>&lt;</t>, the lexical - token "<t>gt</t>" is be interpreted as <t>&gt;</t>, and the - token "<t>and</t>" is interpreted as <t>&amp;&amp;</t>. + "[[lt]]" is be interpreted as [[&lt;]], the lexical + token "[[gt]]" is be interpreted as [[&gt;]], and the + token "[[and]]" is interpreted as [[&amp;&amp;]]. Thus these tokens cannot be used as variable names. - The identifier <t>static</t> is a reserved word in + The identifier [[static]] is a reserved word in ECMAScript, but not in Ibex. - Ibex defines an additional reserved word, "<t>assert</t>", + Ibex defines an additional reserved word, "[[assert]]", which will evaluate the expression which follows it, throwing - a <t>ibex.assertion.failed</t> exception if the expression - evaluates to <t>false</t>. + a [[ibex.assertion.failed]] exception if the expression + evaluates to [[false]]. To ensure that Ibex files appear the same in all text editors, tab characters are not allowed in Ibex files. </section> </appendix> -<!-- _______________________________________________________________________ --> +<!-- ----------------------------------------------------------------------- --> <appendix title="Logging and Command Line Invocation"> <pre> -l host:port emit log to TCP socket -l [file] write log to a file on disk -a check assertions - -w <window-id> reserved for libibex + -w [window-id] reserved for libibex -p dump profiling information [not yet supported] </pre> invoked. To inhibit this console window, provide a logging destination (file, port, etc). - The <t><i>source-location</i></t> parameter can be either the path - to an <t>.ibex</t> archive, the http url of an <t>.ibex</t> + The [[**source-location**]] parameter can be either the path + to an [[.ibex]] archive, the http url of an [[.ibex]] archive, or the path to a directory comprising an unpacked - <t>.ibex</t> archive. + [[.ibex]] archive. - The <t><i>initial-template</i></t> parameter is the stream name of + The [[**initial-template**]] parameter is the stream name of a template to be used as the initial template. If ommitted, it - defaults to <t>main</t>. + defaults to [[main]]. - The <t>-v</t> option causes Ibex to enable verbose logging; this will - cause it to log <i>lots</i> of information to the log file. This + The [[-v]] option causes Ibex to enable verbose logging; this will + cause it to log **lots** of information to the log file. This option will also substantially decrease Ibex's performance. </appendix> -<!-- _______________________________________________________________________ --> +<!-- ----------------------------------------------------------------------- --> <!-- <appendix title="Grammars"> - <i>Grammar support is experimental in this release + **Grammar support is experimental in this release and may not work properly. It may change in incompatible ways or - disappear completely from future releases</i> + disappear completely from future releases** Grammars are defined with a statement in the following form: result of executing the code block 'c' is returned. The property 'a' is read; if the value is a grammar, a new production - rule (ie a new alternative, as with '<t>|</t>') is added to that grammar + rule (ie a new alternative, as with '[[|]]') is added to that grammar (this is a destructive update). This allows you to add productions to pre-existing grammars (for example, adding a new type of expression to a programming language by extending the 'expr' grammar). If the old <list type="unordered"> string literals - grouping parens <t>()</t> + grouping parens [[()]] - combinators: <t> | + * ?</t> + combinators: [[ | + * ?]] references to other grammars </list> The identifier 'whole' is bound to the string matched by the entire expression. If the code block is omitted it behaves - as if it were "<t>{ return whole; }</t>". + as if it were "[[{ return whole; }]]". For every reference to another grammar which was matched in the pattern, the *name used to reference that other grammar* will </pre> --> -<i> +** Copyright (C) 2004 Adam Megacz, verbatim redistribution permitted. Ibex is a trademark of Adam Megacz -</i> +** -</ibex-doc> +</ibex-doc> \ No newline at end of file index 70ef527..9770a99 100644 (file) @@ -2,6 +2,7 @@ // FEATURE: <code type="c++"/> -- syntax highlighting // FEATURE: <code linenumbers="true"/> -- LaTeX moreverb package can help // FIXME: nest TextNodes within each other for bold+italic +// FEATURE: property tree package org.ibex.util; import java.util.*; @@ -9,7 +10,8 @@ import java.io.*; import org.ibex.util.*; public class Doc extends XML { - + + public static boolean slides = false; Root root = null; int skip = 0; Vec nodeStack = new Vec(); @@ -20,6 +22,7 @@ public class Doc extends XML { public Doc() { } public static void main(String[] s) throws Exception { + if (s.length > 0 && "slides".equals(s[0])) slides = true; Doc d = new Doc(); Reader r = new InputStreamReader(System.in); int len = 0; @@ -41,6 +44,14 @@ public class Doc extends XML { public void startElement(Element e) throws Exn { if (preStart != -1) return; + + Node target = (Node)nodeStack.lastElement(); + if (target == null) target = (Node)victim; + if (target != null) { + if (pending.length() > 0) target.addText(pending); + pending = ""; + } + String name = e.getLocalName(); Node newGuy = null; if (name.equals("ibex-doc")) { newGuy = new Root(e); @@ -52,11 +63,9 @@ public class Doc extends XML { } else if (name.equals("pre")) { preStart = getGlobalOffset(); } else if (name.equals("definition")) { newGuy = new Definition(e); + } else if (name.equals("math")) { newGuy = new Math(e); } else if (name.equals("property")) { newGuy = new Property(e); - } else if (name.equals("b")) { newGuy = new B(); - } else if (name.equals("i")) { newGuy = new I(); - } else if (name.equals("t")) { newGuy = new T(); } else if (name.equals("link")) { newGuy = new Link(e); } else if (name.equals("image")) { newGuy = new Image(e); @@ -71,22 +80,33 @@ public class Doc extends XML { } } + static Object victim = null; + public void whitespace(char[] ch, int start, int length) throws Exn, IOException { characters(ch, start, length); } public void endElement(Element e) throws Exn, IOException { + + Node target = (Node)nodeStack.lastElement(); + if (target == null) target = (Node)victim; if (preStart != -1) { if (!e.getLocalName().equals("pre")) return; - ((Node)nodeStack.lastElement()).addChild(new PRE(preStart, getGlobalOffset())); + target.addChild(new PRE(preStart, getGlobalOffset())); preStart = -1; } else if (skip > 0) { skip--; return; } else { + if (target != null) { + if (pending.length() > 0) target.addText(pending); + pending = ""; + } + if (nodeStack.lastElement() instanceof Section) victim = nodeStack.lastElement(); nodeStack.setSize(nodeStack.size() - 1); } } + public void characters(char[] ch, int start, int length) throws Exn, IOException { if (preStart != -1) return; - ((Node)nodeStack.lastElement()).addText(new String(ch, start, length)); + pending += new String(ch, start, length); } abstract class Node { @@ -96,20 +116,22 @@ public class Doc extends XML { public abstract void dumpLatex(StringBuffer sb); final String fixLatex(String s) { if (s == null) return ""; - s = s.replaceAll("\\", "\\\\\\$"); - s = s.replaceAll("\\\\([^\\$])", "\\$\\\\backslash\\$\\1");
+            s = s.replaceAll("\\\\", "\\$\\\\backslash\\$");
+            s = s.replaceAll("\\$", "\\\\\\$");
+            s = s.replaceAll("\\\\\\$\\\\backslash\\\\\\$", "\\$\\\\backslash\\$");
+            s = s.replaceAll("\\{", "\\\\{");
+            s = s.replaceAll("\\}", "\\\\}");
+            s = s.replaceAll("\\*\\*([^\n]+?)\\*\\*", "{\\\\it{$1}}"); + s = s.replaceAll("__([^\n]+?)__", "{\\\\textbf{$1}}");
+            s = s.replaceAll("\$\\[([^\n]+?)\$\\]", "{\\\\texttt{1}}"); s = s.replaceAll("LaTeX", "\\\\LaTeX"); s = s.replaceAll("\\%", "\\\\% "); s = s.replaceAll("#", "\\\\#"); - s = s.replaceAll("\\{", "\\\\{"); - s = s.replaceAll("\\}", "\\\\}"); s = s.replaceAll("\\&", "\\\\&"); s = s.replaceAll("\\~", "\\\\~"); s = s.replaceAll("_", "\\\\_"); - if (!(this instanceof T)) { - s = s.replaceAll(" \"", " "); - s = s.replaceAll("\"", "''"); - } + s = s.replaceAll(" \"", " "); + s = s.replaceAll("\"", "''"); return s; } } @@ -126,8 +148,38 @@ public class Doc extends XML { class Image extends EmptyNode { public String url; - public Image(XML.Element e) { url = e.getAttrVal("url"); } - public void dumpLatex(StringBuffer sb) { sb.append("\\hyperimage{" + url + "}"); } + public String caption; + public String width; + public String align; + public Image(XML.Element e) { + url = e.getAttrVal("url"); caption = e.getAttrVal("caption"); width = e.getAttrVal("width"); + align = e.getAttrVal("align"); + } + public void dumpLatex(StringBuffer sb) { + if (url.endsWith(".pdf")) { + if (width == null) { + sb.append("\\begin{figure}[H]\n"); + sb.append("\\begin{center}\n"); + sb.append("\\epsfig{file="+url.substring(0, url.length() - 4)+",width=\\textwidth}\n"); + if (caption != null) + sb.append("\\caption{"+fixLatex(caption)+"}\n"); + sb.append("\\end{center}\n"); + sb.append("\\end{figure}\n"); + } else { + if ("left".equals(align)) { + sb.append("\\begin{wrapfigure}{l}{"+width+"}\n"); + } else { + sb.append("\\begin{wrapfigure}{r}{"+width+"}\n"); + } + sb.append("\\epsfig{file="+url.substring(0, url.length() - 4)+",width="+width+"}%\n"); + if (caption != null) + sb.append("\\caption{"+fixLatex(caption)+"}\n"); + sb.append("\\end{wrapfigure}\n"); + } + } else { + sb.append("\\hyperimage{" + url + "}"); + } + } } class Heading extends EmptyNode { @@ -154,7 +206,7 @@ public class Doc extends XML { /** Nodes which contain only text; they split themselves if anything else is added */ class TextNode extends Node implements Cloneable { - protected String mytext = ""; + public String mytext = ""; private boolean canAcceptMoreText = true; public void dumpLatex(StringBuffer sb) { sb.append(fixLatex(mytext)); } public void addChild(Node o) { canAcceptMoreText = false; parent.addChild(o); } @@ -167,53 +219,47 @@ public class Doc extends XML { mytext = split[0]; parent.addChild(new ParagraphBreak()); o = ""; - for(int i=1; i<split.length; i++) o += split[i]; + for(int i=1; i<split.length; i++) o += split[i] + "\n\n"; } try { TextNode clone = (TextNode)clone(); clone.mytext = ""; clone.canAcceptMoreText = true; - clone.addText(o); parent.addChild(clone); + clone.addText(o); } catch (CloneNotSupportedException cnse) { throw new RuntimeException(cnse); } } } - class T extends TextNode { - public void dumpLatex(StringBuffer sb) { - sb.append("{\\texttt{"); - super.dumpLatex(sb); - sb.append("}}"); - } } - class B extends TextNode { - public void dumpLatex(StringBuffer sb) {sb.append("{\\textbf{"); super.dumpLatex(sb); sb.append("}}");}} - class I extends TextNode { - public void dumpLatex(StringBuffer sb) {sb.append("{\\it{"); super.dumpLatex(sb); sb.append("}}");}} class Link extends TextNode { public String url; public String section; public String appendix; public String text; public Link(XML.Element e) { - url = e.getAttrVal("url"); - text = e.getAttrVal("text"); - appendix = e.getAttrVal("appendix"); - section = e.getAttrVal("section"); + url = e.getAttrVal("url"); if ("".equals(url)) url = null; + appendix = e.getAttrVal("appendix"); if ("".equals(appendix)) appendix = null; + section = e.getAttrVal("section"); if ("".equals(section)) section = null; + text = e.getAttrVal("text"); if ("".equals(url)) text = null; + if (text == null) text = url; + if (text == null) text = section; + if (text == null) text = appendix; } public void dumpLatex(StringBuffer sb) { // FIXME: dotted underline for section/appendix, solid underline for url String text = fixLatex(this.text); if (text == null) text = "\\tt " + (url != null ? url : section != null ? section : appendix); if (url != null) { sb.append("\\href{" + url + "}{\\uline{" + text + "}} "); - } else if (section != null) { sb.append("\\hyperlink{" + section + "}{\\uwave{" + text + "}} "); - } else if (appendix != null) { sb.append("\\hyperlink{" + appendix + "}{\\uwave{" + text + "}} "); + } else if (section != null) { sb.append("\\hyperlink{" + section + "}{" + text + "} "); + } else if (appendix != null) { sb.append("\\hyperlink{" + appendix + "}{" + text + "} "); } } } class PRE extends TextNode { + int gobble = 0; public PRE(int start, int end) { while(Character.isWhitespace(buffer[start])) start++; while(buffer[start] != '\n') start--; @@ -224,9 +270,20 @@ public class Doc extends XML { end++; } mytext = new String(buffer, start, end - start); + gobble = 9999; + int i = 0; + while(true) { + int start2 = i; + while(i<mytext.length() && mytext.charAt(i) == ' ') i++; + if (i==mytext.length()) break; + gobble = java.lang.Math.min(gobble, i - start2); + i = mytext.indexOf('\n', i); + if (i == -1) break; + i++; + } } public void dumpLatex(StringBuffer sb) { - sb.append("\n\n\\begin{Verbatim}[fontfamily=courier,fontsize=\\footnotesize,frame=single,rulecolor=\\color{CodeBorder},resetmargins=true]\n"); + sb.append("\n\n\\begin{Verbatim}[fontfamily=courier,fontsize=\\tiny,frame=single,rulecolor=\\color{CodeBorder},resetmargins=true,gobble="+gobble+"]\n"); sb.append(mytext); sb.append("\\end{Verbatim}\n\n"); } @@ -270,7 +327,7 @@ public class Doc extends XML { while(Character.isSpace(s.charAt(0))) s = s.substring(1); String fname = fixLatex(name); type = type == null || type.equals("") ? "" : "({\\it{" + fixLatex(type) + "}})"; - if (name.trim().length() > 13) { + if (name.trim().length() > 13 && name.trim().indexOf(' ') == -1) { sb.append("\n\n{\\color{CodeBorder}\\hspace{-2cm}\\dotfill\\\\\\color{black}}"); sb.append("\\marginpar{\\raggedleft{\\texttt{\\textbf{\\footnotesize{"+fname+"}}}}\\\\"+type+" }"); sb.append("\\\\"); @@ -282,7 +339,10 @@ public class Doc extends XML { sb.append(s.substring(s.indexOf(' '))); } if (default_ != null) { - sb.append("\\\\{\\it default: }{\\texttt{" + fixLatex(default_) + "}}\n\n"); + String fd = fixLatex(default_); + fd = fd.replaceAll(" ", " \""); + fd = fd.replaceAll("''", "\""); + sb.append("\\\\{\\it default: }{\\texttt{" + fd + "}}\n\n"); } else { sb.append("\n\n"); } @@ -303,21 +363,52 @@ public class Doc extends XML { } } + class Math extends ParagraphNode { + String tex = ""; + public Math(XML.Element e) { tex = e.getAttrVal("tex"); if (tex == null) tex = ""; } + public void addText(String s) { tex += s; } + public void dumpLatex(StringBuffer sb) { sb.append("\n\n$$\n" + tex.replaceAll("\n", " ") + "\n$$\n\n"); } + } + class Section extends ParagraphNode { String name; - public Section(XML.Element e) { name = e.getAttrVal("title"); } + public Section(XML.Element e) { + name = e.getAttrVal("title"); + if (slides) super.addChild(new List()); + } + public void addText(String s) { + if (slides) ((List)children.elementAt(0)).addText(s); + else super.addText(s); + } + public void addChild(Node n) { + /* if (slides) ((List)children.elementAt(0)).addChild(n); + else*/ super.addChild(n); + } public void dumpLatex(StringBuffer sb) { String secs = ""; String base = "section"; + int count = 0; + String pile = ""; for(Node n = parent; n != null; n = n.parent) if (n instanceof Section || n instanceof Appendix) { base = "section"; secs += "sub"; + for (int i=0; i<count; i++) pile += "\\hspace{1cm}"; + pile += ((Section)n).name + "\\\\\n"; + count++; } - if (secs.length() == 0) - sb.append("\\newpage\n\n"); - sb.append("\n\n\\hypertarget{" + name + "}{\\" + secs + base + "{" + name + "}}\n\n"); - super.dumpLatex(sb); + if (slides) { + sb.append(pile); + sb.append("\n\n\\begin{slide}\n"); + sb.append("\\slideheading{"+fixLatex(name)+"}\n"); + super.dumpLatex(sb); + sb.append("\n\n\\end{slide}\n"); + } else { + if (secs.length() == 0) + sb.append("\\newpage\n\n"); + sb.append("\n\n\\hypertarget{" + name + "}{\\" + secs + base + "{" + name + "}}\n\n"); + super.dumpLatex(sb); + } } } @@ -332,32 +423,75 @@ public class Doc extends XML { } class List extends ParagraphNode { - Node textnode = null; + TextNode textnode = null; public List() { } + public void addChild(Node n) { + if (n != textnode) textnode = null; + super.addChild(n); + } public void addText(String s) { if (!(children.lastElement() == textnode) || (textnode == null && children.lastElement() == null)) addChild(textnode = new TextNode()); - ((TextNode)children.lastElement()).addText(s); + s = s.replaceAll("\n( +)\\- ", "\n\n1 ");
}
-        public void dumpLatex(StringBuffer sb) {
-            sb.append("\n\\begin{itemize}%\n");
+        public int indentof(String s) {
+            for(int i=0; i<s.length(); i++)
+                if (!Character.isWhitespace(s.charAt(i)))
+                    return i;
+            return s.length();
+        }
+        public void dumpLatex(StringBuffer sb0) {
+            StringBuffer sb = new StringBuffer();
+            boolean began = false;
boolean unusedItem = false;
+            List spawn = null;
+            int indentation = -1;
for(int i=0; i<children.size(); i++) {
Object kid = children.elementAt(i);
-                if (kid instanceof ParagraphBreak || kid instanceof List) unusedItem = false;
+                if (kid instanceof ParagraphBreak) { unusedItem = false; continue; }
+                if (kid instanceof List) unusedItem = true;
+                String txt = null;
if (kid instanceof String) {
if (kid.toString().trim().length() == 0) continue;
-                    if (!unusedItem) { unusedItem = true; sb.append("\n\n\\item\n"); }
-                    sb.append(children.elementAt(i));
+                    txt = (String)children.elementAt(i);
+                } else if (kid instanceof TextNode) {
+                    if (((TextNode)kid).mytext.trim().length() == 0) continue;
+                    txt = ((TextNode)kid).mytext;
} else {
-                    if (kid instanceof TextNode) {
-                        if (((TextNode)kid).mytext.trim().length() == 0) continue;
-                        if (!unusedItem) { unusedItem = true; sb.append("\n\n\\item\n"); }
+                    if (spawn != null) {
+                        spawn.dumpLatex(sb);
+                        unusedItem = false;
+                        spawn = null;
}
((Node)kid).dumpLatex(sb);
+                    continue;
+                }
+                if (txt.trim().length() == 0) continue;
+                if (indentation == -1) indentation = indentof(txt);
+                if (indentof(txt) > indentation) {
+                    if (spawn == null) spawn = new List();
+                    continue;
+                }
+                if (spawn != null) {
+                    spawn.dumpLatex(sb);
+                    unusedItem = false;
+                    spawn = null;
}
+                if (!unusedItem) { unusedItem = true; sb.append("\n\n\\item\n"); }
+                sb.append(fixLatex(txt));
+            }
+            if (spawn != null) {
+                spawn.dumpLatex(sb);
+                spawn = null;
+            }
+            if (sb.toString().replaceAll("\$.+\$", "").trim().length() > 0) {
+                sb0.append("\n\\begin{itemize}\n");
+                sb0.append(sb.toString());
+                sb0.append("\n\\end{itemize}\n");
}
-            sb.append("\n\\end{itemize}%\n");
}
}

@@ -373,63 +507,190 @@ public class Doc extends XML {
email = e.getAttrVal("email");
subtitle = e.getAttrVal("subtitle");
}
+        public void addText(String s) {
+            if (victim != null) ((Node)victim).addText(s);
+        }
+        public void addChild(Node n) {
+            if (!(n instanceof Section))
+            else
+        }
public void dumpLatex(StringBuffer sb) {
-            sb.append("\\documentclass{article}\n");
-            sb.append("\\def\\ninept{\\def\\baselinestretch{.95}\\let\\normalsize\\small\\normalsize}\n");
-            sb.append("\\ninept\n");
-            sb.append("\\usepackage{color}\n");
-            sb.append("\\definecolor{CodeBorder}{rgb}{0.6,0.6,0.6}\n");
-            sb.append("\\definecolor{CodeBackground}{rgb}{0.93,0.93,0.93}\n");
-            sb.append("\\usepackage{graphicx}\n");
-            sb.append("\\usepackage{courier}\n");
-            sb.append("\\usepackage{fancyvrb}\n");
-            sb.append("\\usepackage{fvrb-ex}\n");
-            sb.append("\\usepackage{bold-extra}\n");
-            sb.append("\\usepackage{ulem}\n");
-            sb.append("\\usepackage{appendix}\n");
-            sb.append("\\usepackage{amssymb,amsmath,epsfig,alltt}\n");
-            sb.append("\\sloppy\n");
-            sb.append("\\usepackage{palatino}\n");
-            sb.append("\\usepackage{sectsty}\n");
-            sb.append("\\allsectionsfont{\\sffamily}\n");
-            sb.append("\\sectionfont{\\color{black}\\leftskip=-2cm\\hrulefill\\\\\\sffamily\\bfseries\\raggedleft\\vspace{1cm}}\n");
-            sb.append("\\subsectionfont{\\color{black}\\dotfill\\\\\\sffamily\\raggedright\\hspace{-4cm}}\n");
-            sb.append("\\newdimen\\sectskip\n");
-            sb.append("\\newdimen\\subsectskip\n");
-            sb.append("\\newdimen\\saveskip\n");
-            sb.append("\\saveskip=\\leftskip\n");
-            sb.append("\\sectskip=-2cm\n");
-            sb.append("\\subsectskip=0cm\n");
-            sb.append("\\let\\oldsection\\section\n");
-            sb.append("\\let\\oldsubsection\\subsection\n");
-            sb.append("\\def\\subsection#1{\\leftskip=\\sectskip\\oldsubsection{#1}\\leftskip=0cm}\n");
-            sb.append("\\usepackage{parskip}\n");
-            sb.append("\\usepackage{tabularx}\n");
-            sb.append("\\usepackage{alltt}\n");
-            // FIXME: pdfauthor, pdftitle, pdfsubject, pdfkeywords?
-            sb.append("\n");
-            sb.append("\\begin{document}\n");
-            sb.append("\\reversemarginpar\n");
-            sb.append("\n");
-            sb.append("\\title{\\textbf{\\textsf{\n");
-            sb.append(title);
-            if (subtitle != null) sb.append("\\\\{\\large " + subtitle + "}\n");
-            sb.append("}}}\n");
-            if (author != null) {
-                sb.append("\\author{\n");
-                sb.append(author);
-                if (email != null) sb.append("\\\\{\\tt " + email + "}\n");
-                sb.append("}\n");
+            if (slides) {
+                sb.append("\\documentclass[letter]{seminar}\n");
+                sb.append("\\usepackage{calc}               % Simple computations with LaTeX variables\n");
+                sb.append("\\usepackage[hang]{caption2}     % Improved captions\n");
+                sb.append("\\usepackage{fancybox}           % To have several backgrounds\n");
+                sb.append("                                % (must be loaded before fancyvrb')\n");
+                sb.append("\\usepackage{fancyhdr}           % Headers and footers definitions\n");
+                sb.append("\\usepackage{fancyvrb}           % Fancy verbatim environments\n");
+                sb.append("\\usepackage{wrapfig}\n");
+                sb.append("\\usepackage{float}\n");
+                sb.append("\\usepackage{amsmath}\n");
+                sb.append("\\usepackage{amssymb}\n");
+                sb.append("\\usepackage{pdftricks}\n");
+                sb.append("\\begin{psinputs}\n");
+                sb.append("  \\usepackage{pstcol}             % PSTricks with the standard color package\n");
+                sb.append("                                  % (before graphicx' for the \\scalebox macro)\n");
+                sb.append("  \\usepackage{graphicx}           % Standard graphics package\n");
+                sb.append("  \\usepackage{multido}            % General loop macro\n");
+                sb.append("  \\usepackage{pifont}             % Ding symbols (mainly for lists)\n");
+                sb.append("  \\usepackage{pst-fr3d}           % PSTricks 3D framed boxes\n");
+                sb.append("  \\usepackage{pst-node}           % PSTricks nodes\n");
+                sb.append("  \\usepackage{pst-slpe}           % Improved PSTricks gradients\n");
+                sb.append("\\end{psinputs}\n");
+                sb.append("\\usepackage{color}\n");
+                sb.append("\\definecolor{CodeBorder}{rgb}{0.6,0.6,0.6}\n");
+                sb.append("\\definecolor{CodeBackground}{rgb}{0.93,0.93,0.93}\n");
+                sb.append("\\usepackage{graphicx}\n");
+                sb.append("\\usepackage{courier}\n");
+                sb.append("\\usepackage{fancyvrb}\n");
+                sb.append("\\usepackage{float}\n");
+                sb.append("\\usepackage{fvrb-ex}\n");
+                sb.append("\\usepackage{bold-extra}\n");
+                sb.append("\\usepackage{ulem}\n");
+                sb.append("\\usepackage{amssymb,amsmath,epsfig,alltt}\n");
+                sb.append("\\usepackage{semcolor}           % Seminar colored slides\n");
+                sb.append("\\usepackage{semhelv}            % Seminar helvetica fonts\n");
+                sb.append("\\usepackage{semlayer}           % Seminar overlays\n");
+                sb.append("\\usepackage{slidesec}           % Seminar sections and list of slides\n");
+                sb.append("\\usepackage{url}                % Convenient URL typesetting\n");
+                sb.append("            bookmarks=true]{hyperref} % Hyperlinks for PDF versions\n");
+                sb.append("\\usepackage{hcolor}\n");
+                sb.append("\\slidepagestyle{fancy}\n");
+                sb.append("\n");
+                sb.append("\\slidesmag{4}     % Set magnification of slide\n");
+                sb.append("\\def\\SeminarPaperWidth{\\paperwidth / 2}\n");
+                sb.append("\\def\\SeminarPaperHeight{\\paperheight / 2}\n");
+                sb.append("\\slideframe{none} % No default frame\n");
+                sb.append("\n");
+                sb.append("  \n");
+                sb.append("\n");
+                sb.append("  % General size parameters\n");
+                sb.append("\\renewcommand{\\slideparindent}{5mm}\n");
+                sb.append("\\raggedslides[0mm]\n");
+                sb.append("%  \\renewcommand{\\slidetopmargin}{15.5mm}\n");
+                sb.append("%  \\renewcommand{\\slidebottommargin}{13mm}\n");
+                sb.append("%  \\renewcommand{\\slideleftmargin}{4mm}\n");
+                sb.append("%  \\renewcommand{\\sliderightmargin}{4mm}\n");
+                sb.append("  % To adjust the frame length to the header and footer ones\n");
+                sb.append("%  \\autoslidemarginstrue\n");
+                sb.append("  % We suppress the header and footer fancyhdr' rules\n");
+                sb.append("\\fancyhf{} % Clear all fields\n");
+                sb.append("\\renewcommand{\\footrule}{}\n");
+                sb.append("\n");
+                sb.append("%  \\usepackage{nohyperref}       % To deactivate the hyperref' features\n");
+                sb.append("%  \\overlaysfalse                % To suppress overlays\n");
+                sb.append("%  \\def\\special@paper{}% Needed to avoid hyperref' to collapse with `dvips''\n");
+                sb.append("\\newslideframe{IMAGE}{%\n");
+                sb.append("  \\boxput{\\rput(0,0){%\n");
+                sb.append("      \\includegraphics[width=\\SeminarPaperHeight,height=\\SeminarPaperWidth]{background.pdf}}}{#1}}\n");
+                sb.append("\\slideframe*{IMAGE}\n");
+                sb.append("%\\renewcommand{\\slideleftmargin}{3cm}\n");
+                sb.append("\\RequirePackage[T1]{fontenc}\n");
+                sb.append("\\RequirePackage{textcomp}\n");
+                sb.append("\\renewcommand{\\rmdefault}{trebuchet}\n");
+                sb.append("\\renewcommand{\\slidefonts}{%\n");
+                sb.append("  \\renewcommand{\\rmdefault}{trebuchet}%\n");
+                sb.append("  \\renewcommand{\\ttdefault}{courier}}%\n");
+                sb.append("  \\newcommand{\\ParagraphTitle}[2][black]{%\n");
+                sb.append("  \\newcommand{\\CenteredParagraphTitle}[2][black]{%\n");
+                sb.append("  \\CenteredParagraphTitle[black]{%\n");
+                sb.append("    \\textcolor{black}{\\huge\\textbf{#1}}}}\n");
+                sb.append("    \\CenteredParagraphTitle{\\Large\\theslidesubsection{} -- #1}}\n");
+                sb.append("  \\renewenvironment{dinglist}[2][black]\n");
+                sb.append("  {\\begin{list}{\\ding{#2}}{}}{\\end{list}}\n");
+                sb.append("  \\newcommand{\\DingListSymbolA}{43}\n");
+                sb.append("  \\newcommand{\\DingListSymbolB}{243}\n");
+                sb.append("  \\newcommand{\\DingListSymbolC}{224}\n");
+                sb.append("  \\newcommand{\\DingListSymbolD}{219}\n");
+                sb.append("  \\newcommand{\\eqbox}[2][0.6]{%\n");
+                sb.append("  \\parbox{#1\\hsize}{%\n");
+                sb.append("      \$\n"); + sb.append(" \\textcolor{black} {#2}\n"); + sb.append(" \$}}}}\n");
+                sb.append("\\begin{document}\n");
+                sb.append("\\begin{slide}\n");
+                sb.append("\\begin{center}\n");
+                sb.append("\\ParagraphTitle{\\bf \\Large "+title+"}\n");
+                sb.append("\\vspace{5mm} \\\n");
+                sb.append("\\textit{\\large "+subtitle+"} \\\\\n");
+                sb.append("\\vspace{5mm} \\\n");
+                sb.append("\\textit{"+author+"} \\\n");
+                sb.append("\\end{center}\n");
+                sb.append("\\end{slide}\n\n");
+                super.dumpLatex(sb);
+                sb.append("\\end{document}");
+            } else {
+                sb.append("\\documentclass{article}\n");
+                sb.append("\\def\\ninept{\\def\\baselinestretch{.95}\\let\\normalsize\\small\\normalsize}\n");
+                sb.append("\\ninept\n");
+                sb.append("\\usepackage{color}\n");
+                sb.append("\\definecolor{CodeBorder}{rgb}{0.6,0.6,0.6}\n");
+                sb.append("\\definecolor{CodeBackground}{rgb}{0.93,0.93,0.93}\n");
+                sb.append("\\usepackage{graphicx}\n");
+                sb.append("\\usepackage{courier}\n");
+                sb.append("\\usepackage{fancyvrb}\n");
+                sb.append("\\usepackage{float}\n");
+                sb.append("\\usepackage{wrapfig}\n");
+                sb.append("\\usepackage{fvrb-ex}\n");
+                sb.append("\\usepackage{bold-extra}\n");
+                sb.append("\\usepackage{ulem}\n");
+                sb.append("\\usepackage{amssymb,amsmath,epsfig,alltt}\n");
+                sb.append("\\sloppy\n");
+                sb.append("\\usepackage{palatino}\n");
+                sb.append("\\usepackage{sectsty}\n");
+                sb.append("\\allsectionsfont{\\sffamily}\n");
+                sb.append("\\sectionfont{\\color{black}\\leftskip=-2cm");
+                sb.append("\\hrulefill\\\\\\sffamily\\bfseries\\raggedleft\\vspace{1cm}}\n");
+                sb.append("\\subsectionfont{\\color{black}\\dotfill\\\\\\sffamily\\raggedright\\hspace{-4cm}}\n");
+                sb.append("\\newdimen\\sectskip\n");
+                sb.append("\\newdimen\\subsectskip\n");
+                sb.append("\\newdimen\\saveskip\n");
+                sb.append("\\saveskip=\\leftskip\n");
+                sb.append("\\sectskip=-2cm\n");
+                sb.append("\\subsectskip=0cm\n");
+                sb.append("\\let\\oldsection\\section\n");
+                sb.append("\\let\\oldsubsection\\subsection\n");
+                sb.append("\\def\\subsection#1{\\leftskip=\\sectskip\\oldsubsection{#1}\\leftskip=0cm}\n");
+                sb.append("\\usepackage{parskip}\n");
+                sb.append("\\usepackage{tabularx}\n");
+                sb.append("\\usepackage{alltt}\n");
+                // FIXME: pdfauthor, pdftitle, pdfsubject, pdfkeywords?
+                sb.append("\n");
+                sb.append("\\begin{document}\n");
+                sb.append("\\reversemarginpar\n");
+                sb.append("\n");
+                sb.append("\\title{\\textbf{\\textsf{\n");
+                sb.append(title);
+                if (subtitle != null) sb.append("\\\\{\\large " + subtitle + "}\n");
+                sb.append("}}}\n");
+                if (author != null) {
+                    sb.append("\\author{\n");
+                    sb.append(author);
+                    if (email != null) sb.append("\\\\{\\tt " + email + "}\n");
+                    sb.append("}\n");
+                }
+                sb.append("\n");
+                sb.append("\\maketitle\n");
+                sb.append("\\clearpage\n");
+                sb.append("\\tableofcontents\n");
+                sb.append("\\clearpage\n");
+                sb.append("\\onecolumn\n");
+                super.dumpLatex(sb);
+                sb.append("\\end{document}");
}
-            sb.append("\n");
-            sb.append("\\maketitle\n");
-            sb.append("\\clearpage\n");
-            sb.append("\\tableofcontents\n");
-            sb.append("\\clearpage\n");
-            sb.append("\\onecolumn\n");
-            super.dumpLatex(sb);
-            sb.append("\\end{document}");
}
}
}