Revision 75746 of Building Trees

  • Revision slug: XUL/Template_Guide/Building_Trees
  • Revision title: Building Trees
  • Revision id: 75746
  • Created:
  • Creator: Enn
  • Is current revision? No
  • Comment

Revision Content

{{template.PreviousNext("XUL:Template Guide:Using Multiple Queries to Generate More Results", "XUL:Template Guide:Building Hierarchical Trees")}}

The most common element to use with a template is the tree. You can use a template with a tree just like any other template. However, since templates are often used with trees, especially with large amounts of data, the template system supports a special builder just for creating trees. Rather than generate content for each row in the tree, the results are just stored in a list inside the builder. This means that DOM nodes are not constructed for any of the items. This is much more efficient as creating a lot of DOM nodes would add a lot of additional overhead. This performance advantage is possible since trees can only display text so the builder only has a few pieces of information to keep track of.

To use the tree builder, you need to add a flags attribute to the root node:

<tree datasources="template-guide-streets.rdf"
      ref="http://www.xulplanet.com/rdf/myneighbourhood"
      flags="dont-build-content">

The "dont-build-content" flag causes no content to be built for the template. However, what it really does is use a subtype of the main builder specific to trees, called the tree builder. Without this flag, the template will be handled using the other type of builder, which is called a content builder, as it generates content. Note that while a tree builder can only be used with trees, a content builder can be used with any type of content. You can also choose to use the content builder for a tree, if you wish. There may be uses for this, especially for small amounts of data. However, you will find that the content builder will be slower as the amount of data to display gets larger.

Apart from the flags attribute, the template syntax is exactly the same for the tree builder as with the content builder. One thing though is that the tree builder requires a very specific form to the action body, specifically, the action body should be a single treeitem with its row and cells. Here is an example using an RDF source:

<tree id="photosList" flex="1" datasources="template-guide-photos5.rdf"
      ref="http://www.xulplanet.com/rdf/myphotos" flags="dont-build-content">
  <treecols>
    <treecol id="name" label="Name" flex="1"/>
    <treecol id="date" label="Date" flex="1"/>
  </treecols>
  <template>
    <treechildren>
      <treeitem uri="rdf:*">
        <treerow>
          <treecell label="rdf:http://purl.org/dc/elements/1.1/title"/>
          <treecell label="rdf:http://purl.org/dc/elements/1.1/date"/>
        </treerow>
      </treeitem>
    </treechildren>
  </template>
</tree>

The tree columns are declared outside the template as static content since we only want to declare them once. This template uses the simple rule syntax, although the extended syntax could also be used. When using the tree builder, the {{template.XULAttr("uri")}} attribute must be declared on the {{template.XULElem("treeitem")}} element. Here, the simple RDF query syntax is used, so the membr variable is 'rdf:*'. The remaining tags are like the syntax of a tree with a single row. This row will be used as the template data by the tree builder. Instead of generating content, the builder will use the cell attributes to determine what to display. The tree builder implements the nsITreeView interface so it becomes the tree's view. (That is, the tree's view and the tree's builder are the same object.) When the tree is displayed, it asks the view for the contents of each cell. The builder looks at the label for the corresponding cell, translates any variables or predicates into values, and returns the value.

In the example above, the first cell should display the title. The builder doesn't compute any labels until the view asks for them. When the view does request a label for the first cell, the builder looks up the 'http://purl.org/dc/elements/1.1/title' predicate for the row in question and returns it.

The content builder will generate the content in the template body and do substitution of the data from the datasource right away. However, it will generate the same result on screen to the user as with the tree builder. Compare the example with a tree builder and the same example using a content builder.

Here is an example of a tree using an Sqlite datasource:

<vbox datasources="profile:messages.sqlite" ref="*" querytype="storage">
  <treecols>
    <treecol id="subject" label="Subject" flex="3"/>
    <treecol id="sender" label="Sender" flex="2"/>
    <treecol id="date" label="Date" flex="1"/>
  </treecols>
  <template>
    <query>
      select subject, sender, date from messages
    </query>
    <action>
      <treechildren>
        <treeitem uri="rdf:*">
          <treerow>
            <treecell label="?subject"/>
            <treecell label="?sender"/>
            <treecell label="?date"/>
          </treerow>
        </treeitem>
      </treechildren>
    </action>
  </template>
</vbox>

Features of the Tree Builder

Besides the label of a cell, there are several other cell properties you can set when using the tree builder. The supported properties are: label, mode, properties, src and value. The label attribute is used to set the label for a cell. The mode is used for progress meter columns. It may be set to either 'normal' for a normal progress meter or 'undetermined' for an undetermined progress meter. The value attribute is used to set the current progress value for normal progress meters. The value attribute may also be used for checkbox columns by setting it to either true or false. Whether a cell is a normal labeled value, a progress meter or a checkbox is determined by the type attribute on the column the cell is in.

For cells in normal columns, you can use the value attribute to store some other value and you can use the view's getCellValue method to retrieve it. Naturally, this will retrieve the value after any variables have been substituted. Besides the attributes mentioned above, any other attributes specified on the tree rows and cells are ignored. Since no elements are generated, you won't be able to retrieve the values for them either. Thus, the value attribute may be useful to associate an additional value with a row since it will be easier to retrieve.

The src attribute may be used to set an image to appear in a cell. For example:

<tree id="photosList" flex="1" datasources="template-guide-photos5.rdf"
      ref="http://www.xulplanet.com/rdf/myphotos" flags="dont-build-content">
  <treecols>
    <treecol id="photo" label="Photo" flex="1"/>
  </treecols>
  <template>
    <treechildren>
      <treeitem uri="rdf:*">
        <treerow>
          <treecell src="rdf:*"/>
        </treerow>
      </treeitem>
    </treechildren>
  </template>
</tree>

This tree displays each photo in the tree cells. In this case, the member resource is used since that holds the photo's URL, however it could be any other variable, a static value, or a combination of both.

Image:Template-guide-p31.png

Of course, we can't really see the photos, since the tree's rows are too small. Normally, you wouldn't put photos in a tree like this; instead the images would be used for icons. However, you could use a stylesheet to change the default height of the tree rows. You cannot make each row a different height, but you can change the height of all rows with some CSS:

treechildren::-moz-tree-row {
  height: 150px;
}

Since no elements are constructed by the tree builder, you cannot use the style or class attributes to change the style of a cell (This is the case with all trees). You must use syntax like that above to change the appearance. In the example above, it changes the height of a row to 150 pixels. You may want to change the syntax to refer to a specific <treechildren> element rather than all of them. Once the row height is changed, we can see the entirety of the photos.

Using Tree Properties

Since we need to use special CSS for trees, the properties attribute on a cell becomes useful. It can be used to define extra properties that can be refered to in a stylesheet. For example, if the properties attribute was set to the value "?creator", you could style the photos created by different people differently. You can also use static values in addition to variables in the properties attribute. For instance, consider the following CSS:

treechildren::-moz-tree-cell(Dave) {
  background-color: lightgreen;
}

This would set the background colour of a cell to green for any cell with the "Dave" property. You can also use the properties attribute on the <treerow> to change the style for an entire row. This example sets the country associated with a photo as a property of a tree's rows. We can use that property to change the appearance of each row.

<rule>
  <conditions>
    <content uri="?start"/>
    <member container="?start" child="?photo"/>
    <triple subject="?photo"
            predicate="http://www.xulplanet.com/rdf/country"
            object="?country"/>
    <triple subject="?country"
            predicate="http://purl.org/dc/elements/1.1/title"
            object="?countrytitle"/>
  </conditions>
  <action>
    <treechildren>
      <treeitem uri="?photo">
        <treerow properties="?countrytitle">
          <treecell src="?photo" label="Cat"/>
        </treerow>
      </treeitem>
    </treechildren>
  </action>
</rule>

You might use the following CSS to change the border around rows with a particular country:

treechildren::-moz-tree-row(Netherlands) {
  border: green 1px solid;
}

The result of this example is a tree where one row has a green border around it.

{{template.PreviousNext("XUL:Template Guide:Using Multiple Queries to Generate More Results", "XUL:Template Guide:Building Hierarchical Trees")}}

Revision Source

<p>
{{template.PreviousNext("XUL:Template Guide:Using Multiple Queries to Generate More Results", "XUL:Template Guide:Building Hierarchical Trees")}}
</p><p>The most common element to use with a template is the tree. You can use a template with a tree just like any other template. However, since templates are often used with trees, especially with large amounts of data, the template system supports a special builder just for creating trees. Rather than generate content for each row in the tree, the results are just stored in a list inside the builder. This means that DOM nodes are not constructed for any of the items. This is much more efficient as creating a lot of DOM nodes would add a lot of additional overhead. This performance advantage is possible since trees can only display text so the builder only has a few pieces of information to keep track of.
</p><p>To use the tree builder, you need to add a flags attribute to the root node:
</p>
<pre>&lt;tree datasources="template-guide-streets.rdf"
      ref="http://www.xulplanet.com/rdf/myneighbourhood"
      flags="dont-build-content"&gt;
</pre>
<p>The "dont-build-content" flag causes no content to be built for the template. However, what it really does is use a subtype of the main builder specific to trees, called the tree builder. Without this flag, the template will be handled using the other type of builder, which is called a content builder, as it generates content. Note that while a tree builder can only be used with trees, a content builder can be used with any type of content. You can also choose to use the content builder for a tree, if you wish. There may be uses for this, especially for small amounts of data. However, you will find that the content builder will be slower as the amount of data to display gets larger.
</p><p>Apart from the flags attribute, the template syntax is exactly the same for the tree builder as with the content builder. One thing though is that the tree builder requires a very specific form to the action body, specifically, the action body should be a single treeitem with its row and cells. Here is an example using an RDF source:
</p>
<pre>&lt;tree id="photosList" flex="1" datasources="template-guide-photos5.rdf"
      ref="http://www.xulplanet.com/rdf/myphotos" flags="dont-build-content"&gt;
  &lt;treecols&gt;
    &lt;treecol id="name" label="Name" flex="1"/&gt;
    &lt;treecol id="date" label="Date" flex="1"/&gt;
  &lt;/treecols&gt;
  &lt;template&gt;
    &lt;treechildren&gt;
      &lt;treeitem uri="rdf:*"&gt;
        &lt;treerow&gt;
          &lt;treecell label="rdf:http://purl.org/dc/elements/1.1/title"/&gt;
          &lt;treecell label="rdf:http://purl.org/dc/elements/1.1/date"/&gt;
        &lt;/treerow&gt;
      &lt;/treeitem&gt;
    &lt;/treechildren&gt;
  &lt;/template&gt;
&lt;/tree&gt;
</pre>
<p>The tree columns are declared outside the template as static content since we only want to declare them once. This template uses the simple rule syntax, although the extended syntax could also be used. When using the tree builder, the {{template.XULAttr("uri")}} attribute must be declared on the {{template.XULElem("treeitem")}} element. Here, the simple RDF query syntax is used, so the membr variable is 'rdf:*'. The remaining tags are like the syntax of a tree with a single row. This row will be used as the template data by the tree builder. Instead of generating content, the builder will use the cell attributes to determine what to display. The tree builder implements the
<a class="external" href="http://www.xulplanet.com/references/xpcomref/ifaces/nsITreeView.html">nsITreeView</a> interface so it becomes the tree's view. (That is, the tree's view and the tree's builder are the same object.) When the tree is displayed, it asks the view for the contents of each cell. The builder looks at the label for the corresponding cell, translates any variables or predicates into values, and returns the value.
</p><p>In the example above, the first cell should display the title. The builder doesn't compute any labels until the view asks for them. When the view does request a label for the first cell, the builder looks up the '<span class="plain">http://purl.org/dc/elements/1.1/title</span>' predicate for the row in question and returns it.
</p><p>The content builder will generate the content in the template body and do substitution of the data from the datasource right away. However, it will generate the same result on screen to the user as with the tree builder. Compare the
example with a <a class="external" href="http://developer.mozilla.org/samples/xultemp/template-guide-ex30.xul">tree builder</a> and the same example using a <a class="external" href="http://developer.mozilla.org/samples/xultemp/template-guide-ex30b.xul">content builder</a>.
</p><p>Here is an example of a tree using an Sqlite datasource:
</p>
<pre>&lt;vbox datasources="profile:messages.sqlite" ref="*" querytype="storage"&gt;
  &lt;treecols&gt;
    &lt;treecol id="subject" label="Subject" flex="3"/&gt;
    &lt;treecol id="sender" label="Sender" flex="2"/&gt;
    &lt;treecol id="date" label="Date" flex="1"/&gt;
  &lt;/treecols&gt;
  &lt;template&gt;
    &lt;query&gt;
      select subject, sender, date from messages
    &lt;/query&gt;
    &lt;action&gt;
      &lt;treechildren&gt;
        &lt;treeitem uri="rdf:*"&gt;
          &lt;treerow&gt;
            &lt;treecell label="?subject"/&gt;
            &lt;treecell label="?sender"/&gt;
            &lt;treecell label="?date"/&gt;
          &lt;/treerow&gt;
        &lt;/treeitem&gt;
      &lt;/treechildren&gt;
    &lt;/action&gt;
  &lt;/template&gt;
&lt;/vbox&gt;
</pre>
<h3 name="Features_of_the_Tree_Builder"> Features of the Tree Builder </h3>
<p>Besides the label of a cell, there are several other cell properties you can set when using the tree builder. The supported properties are: label, mode, properties, src and value. The label attribute is used to set the label for a cell. The mode is used for progress meter columns. It may be set to either 'normal' for a normal progress meter or 'undetermined' for an undetermined progress meter. The value attribute is used to set the current progress value for normal progress meters. The value attribute may also be used for checkbox columns by setting it to either true or false. Whether a cell is a normal labeled value, a progress meter or a checkbox is determined by the type attribute on the column the cell is in.
</p><p>For cells in normal columns, you can use the value attribute to store some other value and you can use the view's getCellValue method to retrieve it. Naturally, this will retrieve the value after any variables have been substituted. Besides the attributes mentioned above, any other attributes specified on the tree rows and cells are ignored. Since no elements are generated, you won't be able to retrieve the values for them either. Thus, the value attribute may be useful to associate an additional value with a row since it will be easier to retrieve.
</p><p>The src attribute may be used to set an image to appear in a cell. For example:
</p>
<pre>&lt;tree id="photosList" flex="1" datasources="template-guide-photos5.rdf"
      ref="http://www.xulplanet.com/rdf/myphotos" flags="dont-build-content"&gt;
  &lt;treecols&gt;
    &lt;treecol id="photo" label="Photo" flex="1"/&gt;
  &lt;/treecols&gt;
  &lt;template&gt;
    &lt;treechildren&gt;
      &lt;treeitem uri="rdf:*"&gt;
        &lt;treerow&gt;
          &lt;treecell src="rdf:*"/&gt;
        &lt;/treerow&gt;
      &lt;/treeitem&gt;
    &lt;/treechildren&gt;
  &lt;/template&gt;
&lt;/tree&gt;
</pre>
<p>This <a class="external" href="http://developer.mozilla.org/samples/xultemp/template-guide-ex31.xul">tree</a> displays each photo in the tree cells. In this case, the member resource is used since that holds the photo's URL, however it could be any other variable, a static value, or a combination of both.
</p><p><img alt="Image:Template-guide-p31.png" src="File:en/Media_Gallery/Template-guide-p31.png">
</p><p>Of course, we can't really see the photos, since the tree's rows are too small. Normally, you wouldn't put photos in a tree like this; instead the images would be used for icons. However, you could use a stylesheet to change the default height of the tree rows. You cannot make each row a different height, but you can change the height of all rows with some CSS:
</p>
<pre>treechildren::-moz-tree-row {
  height: 150px;
}
</pre>
<p>Since no elements are constructed by the tree builder, you cannot use the style or class attributes to change the style of a cell (This is the case with all trees). You must use syntax like that above to change the appearance. In the example above, it changes the height of a row to 150 pixels. You may want to change the syntax to refer to a specific &lt;treechildren&gt; element rather than all of them. Once the row height is changed, we can see the <a class="external" href="http://developer.mozilla.org/samples/xultemp/template-guide-ex31b.xul">entirety of the photos</a>.
</p>
<h3 name="Using_Tree_Properties"> Using Tree Properties </h3>
<p>Since we need to use special CSS for trees, the properties attribute on a cell becomes useful. It can be used to define extra properties that can be refered to in a stylesheet. For example, if the properties attribute was set to the value "?creator", you could style the photos created by different people differently. You can also use static values in addition to variables in the properties attribute. For instance, consider the following CSS:
</p>
<pre>treechildren::-moz-tree-cell(Dave) {
  background-color: lightgreen;
}
</pre>
<p>This would set the background colour of a cell to green for any cell with the "Dave" property. You can also use the properties attribute on the &lt;treerow&gt; to change the style for an entire row. This example sets the country associated with a photo as a property of a tree's rows. We can use that property to change the appearance of each row.
</p>
<pre>&lt;rule&gt;
  &lt;conditions&gt;
    &lt;content uri="?start"/&gt;
    &lt;member container="?start" child="?photo"/&gt;
    &lt;triple subject="?photo"
            predicate="http://www.xulplanet.com/rdf/country"
            object="?country"/&gt;
    &lt;triple subject="?country"
            predicate="http://purl.org/dc/elements/1.1/title"
            object="?countrytitle"/&gt;
  &lt;/conditions&gt;
  &lt;action&gt;
    &lt;treechildren&gt;
      &lt;treeitem uri="?photo"&gt;
        &lt;treerow properties="?countrytitle"&gt;
          &lt;treecell src="?photo" label="Cat"/&gt;
        &lt;/treerow&gt;
      &lt;/treeitem&gt;
    &lt;/treechildren&gt;
  &lt;/action&gt;
&lt;/rule&gt;
</pre>
<p>You might use the following CSS to change the border around rows with a particular country:
</p>
<pre>treechildren::-moz-tree-row(Netherlands) {
  border: green 1px solid;
}
</pre>
<p>The result of this <a class="external" href="http://developer.mozilla.org/samples/xultemp/template-guide-ex31c.xul">example</a> is a tree where one row has a green border around it.
</p><p>{{template.PreviousNext("XUL:Template Guide:Using Multiple Queries to Generate More Results", "XUL:Template Guide:Building Hierarchical Trees")}}
</p>
Revert to this revision