Tree Widget Changes

  • Revision slug: Tree_Widget_Changes
  • Revision title: Tree Widget Changes
  • Revision id: 104825
  • Created:
  • Creator: Dria
  • Is current revision? No
  • Comment /* Some specific changes */

Revision Content

There are no changes to XUL tree tags, however the id attribute is no longer required on treecol elements just to get them to work. That means that the ids can be left out, although it's probably a good idea to use them anyway.

Instead of identifying columns by id, a new column object is used. This object implements the nsITreeColumn interface and holds information about a single column in the tree. A tree will have one of these objects for each column (each treecol element) in the tree. The columns are grouped into a list which implements the nsITreeColumns interface. Both the nsITreeColumn and nsITreeColumns interfaces can be found here.

The column objects are created automatically, so you don't have to write any extra code. You can get the columns object which implements the nsITreeColumns interface for a tree using the tree's columns property. From there you can get specific columns, the current sort column, and position and size info about the columns. For the most part these objects are readonly; you can modify the columns by just adjusting the treecol attributes directly.

The tree and view methods no longer take ids as arguments when columns are used. Instead, they use nsITreeColumns. For example, getCellValue takes a row index and a nsITreeColumn as arguments, whereas before it took a row index and a column id.

To get a column in JavaScript:

 tree.columns.getColumnFor(treeColElement);
 tree.columns.getNamedColumn(treeColID);
 tree.columns.getColumnAt(index);

You can also just use array syntax to get a column:

 tree.columns["lastName"];
 tree.columns[5];

Once you have a column, you can get various properties of it:

  • column.index - the index of the column in displayed order
  • column.id - the id attribute of the column
  • column.element - the treecol element
  • column.x - the X position in the tree of the left edge of the column
  • column.width - the width of the column

In C++ code, you can also get the atom attribute of nsITreeColumn which returns an nsIAtom for the column, making it fast to do comparisons.

 nsCOMPtr<nsIAtom> atom;
 aCol->GetAtom(getter_AddRefs(atom));
 if (atom = kMyCol) ...

One feature that has been added is restoreNaturalOrder which may be used to restore the original order of the columns before the user moved them around.

tree.columns.restoreNaturalOrder()

There is also a command on the end of the tree's column picker which the user may use to restore the original column order. This will be hidden if the column redordering is disabled using enableColumnDrag="false".

Some specific changes

You should now get the tree selection object from the view, not the box object, meaning use tree.view.selection instead of tree.treeBoxObject.selection.

Use tree.columns{{mediawiki.external(1)}}.id instead of tree.treeBoxObject.getColumnID(1) to get the id of a column, in this case column 1.

Use tree.columns.getKeyColumn().index instead of tree.treeBoxObject.getKeyColumnIndex().

The getPageCount function has been renamed to make it clearer what it does. It returns the number of rows that can be displayed in the tree. This should correspond to the rows attribute on the tree if it was specified.

tree.treeBoxObject.getPageCount() is now tree.treeBoxObject.getPageLength().

The invalidatePrimaryCell(row) method has been removed, instead use invalidateCell(row, tree.columns.getPrimaryColumn()). This may be used to redraw a cell after it or its data has been changed.

cycleHeader(colID, element) is now just cycleHeader(column), since the code can get the element from the column object.

The constants below have been changed, and their integer values are different:

nsITreeView.inDropBefore          -> nsITreeView.DROP_BEFORE      (-1)
nsITreeView.inDropOn              -> nsITreeView.DROP_ON          (0)
nsITreeView.inDropAfter           -> nsITreeView.DROP_AFTER       (1)
nsITreeView.progressNormal        -> nsITreeView.PROGRESS_NORMAL  (1)
nsITreeView.progressUndetermined  -> nsITreeView.PROGRESS_UNDETERMINED  (2)
nsITreeView.progressNode          -> nsITreeView.PROGRESS_NONE    (3)

As well, the drag and drop methods canDropOn and canDropBeforeAfter have been replaced with a single method canDrop(idx,orientation) which handles both. It should return true if a drop is allowed on a row.

Checkbox columns

Tree columns now implement the checkbox type. Previously the value existed but was not implemented. Now it is. You can create a checkbox column by setting the type attribute of a column to checkbox.

<treecol type="checkbox">

You can then set or clear the checkbox for a particular cell in that column by setting the value attribute to true, or leaving out the attribute. Note that it's the value attribute you use, not the label attribute.

<treecell/>
<treecell value="true"/>

For theme authors, the -moz-tree-checkbox pseudo can be used to specify the checkmark image.

In addition, checkmark columns support editing:

<tree editable="true">
  <treecols>
    <treecol type="checkbox" editable="true">
    ...
</tree>

If the column is editable, the user can click the cell to change the state of the checkbox. When the user clicks the cell, the view's setCellValue method will be called with either the value true or false.

Note that the tree must also be marked as editable using the editable attribute in order for this to work. This is shown in the example above. Sometimes, you might have a particular row or cell which you do not want to be editable. In this case, disable editing for that cell by setting editable to false for that cell, as in the following:

<treecell value="true" editable="false"/>

Or, for custom views, return false from the isEditable method.

Currently, only checkbox columns support editing, although the content-based tree handles the setCellValue and setCellText functions to change the tree content with a script for other types of cells. For instance:

var col = tree.columns.getPrimaryColumn();
treecell.setCellText(5,col,"Banana");

This will change the label of the cell in row 5 and the primary column to Banana. However, this paves the way in the future for more general tree editing features.

Style improvements

You can now specify the cursor to use for a cell using the CSS cursor property.

treechildren::-moz-tree-cell-text {
cursor: pointer;
}

The allows you to create separate cursors for cells.

The ::-moz-tree-separator pseudo has been improved to make it a proper box type and now has additional styling capabilities. Example:

treechildren::-moz-tree-separator {
margin-top: 1px;
border-top: 1px solid ThreeDShadow;
border-right: 1px solid ThreeDHighlight;
border-bottom: 1px solid ThreeDHighlight;
border-left: 1px solid ThreeDShadow;
height: 2px;
}

Original Document Information

  • Author: Neil Deakin
  • Source: here

Revision Source

<p>
</p><p>There are no changes to <a href="en/XUL">XUL</a> tree tags, however the <code>id</code> attribute is no longer required on <code>treecol</code> elements just to get them to work. That means that the ids can be left out, although it's probably a good idea to use them anyway.
</p><p>Instead of identifying columns by id, a new column object is used. This 
object implements the <code><a href="en/NsITreeColumn">nsITreeColumn</a></code> interface and holds information about a single column in the tree. A tree will have one of these objects for each column (each <code>treecol</code> element) in the tree. The columns are grouped into a list which implements the <code><a href="en/NsITreeColumns">nsITreeColumns</a></code> interface. Both the <code><a href="en/NsITreeColumn">nsITreeColumn</a></code> and <code><a href="en/NsITreeColumns">nsITreeColumns</a></code> interfaces can be found <a class="external" href="http://lxr.mozilla.org/seamonkey/source/layout/xul/base/src/tree/public/nsITreeColumns.idl">here</a>.
</p><p>The <code><a class="external" href="http://www.xulplanet.com/references/elemref/ref_column.html">column</a></code> objects are created automatically, so you don't have to write any extra code. You can get the <code><a class="external" href="http://www.xulplanet.com/references/elemref/ref_columns.html">columns</a></code> object which implements the <code><a href="en/NsITreeColumns">nsITreeColumns</a></code> interface for a tree using the tree's <code>columns</code> property. From there you can get specific columns, the current sort column, and position and size info about the columns. For the most part these objects are readonly; you can modify the columns by just adjusting the <code><a class="external" href="http://www.xulplanet.com/references/elemref/ref_treecol.html">treecol</a></code> attributes directly.
</p><p>The <code>tree</code> and <code>view</code> methods no longer take ids as arguments when columns are used. Instead, they use <code><a href="en/NsITreeColumns">nsITreeColumns</a></code>. For example, <code><a class="external" href="http://www.xulplanet.com/references/objref/XULTreeBuilder.html#method_getCellValue">getCellValue</a></code> takes a <code>row</code> index and a <code><a href="en/NsITreeColumn">nsITreeColumn</a></code> as arguments, whereas before it took a row index and a column id.
</p><p>To get a column in <a href="en/JavaScript">JavaScript</a>:
</p>
<pre class="eval"> tree.columns.getColumnFor(treeColElement);
 tree.columns.getNamedColumn(treeColID);
 tree.columns.getColumnAt(index);
</pre>
<p>You can also just use array syntax to get a column:
</p>
<pre class="eval"> tree.columns["lastName"];
 tree.columns[5];
</pre>
<p>Once you have a column, you can get various properties of it:
</p>
<ul><li> <code>column.index</code> - the <code>index</code> of the column in displayed order
</li><li> <code>column.id</code> - the <code>id</code> attribute of the column
</li><li> <code>column.element</code> - the <code>treecol</code> element
</li><li> <code>column.x</code> - the X position in the tree of the left edge of the column
</li><li> <code>column.width</code> - the width of the column
</li></ul>
<p>In C++ code, you can also get the atom attribute of <code><a href="en/NsITreeColumn">nsITreeColumn</a></code> which returns an <code><a class="external" href="http://www.xulplanet.com/references/xpcomref/ifaces/nsIAtom.html">nsIAtom</a></code> for the column, making it fast to do comparisons.
</p>
<pre class="eval"> nsCOMPtr&lt;nsIAtom&gt; atom;
 aCol-&gt;GetAtom(getter_AddRefs(atom));
 if (atom = kMyCol) ...
</pre>
<p>One feature that has been added is <code>restoreNaturalOrder</code> which may be used to restore the original order of the columns before the user moved them around.
</p>
<pre class="eval">tree.columns.restoreNaturalOrder()
</pre>
<p>There is also a command on the end of the tree's column picker which the 
user may use to restore the original column order. This will be hidden 
if the column redordering is disabled using <code>enableColumnDrag="false"</code>.
</p>
<h3 name="Some_specific_changes"> Some specific changes </h3>
<p>You should now get the tree selection object from the view, not the box
object, meaning use <code>tree.view.selection</code> instead of
<code>tree.treeBoxObject.selection</code>.
</p><p>Use <code>tree.columns{{mediawiki.external(1)}}.id</code> instead of <code>tree.treeBoxObject.getColumnID(1)</code> to get the <code>id</code> of a column, in this case column 1.
</p><p>Use <code>tree.columns.getKeyColumn().index</code> instead of
<code>tree.treeBoxObject.getKeyColumnIndex()</code>.
</p><p>The <code><a class="external" href="http://www.xulplanet.com/references/xpcomref/ifaces/nsITreeBoxObject.html#method_getPageCount">getPageCount</a></code> function has been renamed to make it clearer what it does. It returns the number of rows that can be displayed in the tree. This should correspond to the <code>rows</code> attribute on the tree if it was specified.
</p><p><code>tree.treeBoxObject.getPageCount()</code> is now 
<code>tree.treeBoxObject.getPageLength()</code>.
</p><p>The <code>invalidatePrimaryCell(row)</code> method has been removed, instead use <code><a class="external" href="http://www.xulplanet.com/references/xpcomref/ifaces/nsITreeBoxObject.html#method_invalidateCell">invalidateCell(row, tree.columns.getPrimaryColumn())</a></code>. This may be used 
to redraw a cell after it or its data has been changed.
</p><p><code>cycleHeader(colID, element)</code> is now just <code><a class="external" href="http://www.xulplanet.com/references/objref/TreeContentView.html#method_cycleHeader">cycleHeader(column)</a></code>, since the code can get the element from the column object.
</p><p>The constants below have been changed, and their integer values are 
different:
</p>
<pre class="eval">nsITreeView.inDropBefore          -&gt; nsITreeView.DROP_BEFORE      (-1)
nsITreeView.inDropOn              -&gt; nsITreeView.DROP_ON          (0)
nsITreeView.inDropAfter           -&gt; nsITreeView.DROP_AFTER       (1)
nsITreeView.progressNormal        -&gt; nsITreeView.PROGRESS_NORMAL  (1)
nsITreeView.progressUndetermined  -&gt; nsITreeView.PROGRESS_UNDETERMINED  (2)
nsITreeView.progressNode          -&gt; nsITreeView.PROGRESS_NONE    (3)
</pre>
<p>As well, the drag and drop methods <code>canDropOn</code> and <code>canDropBeforeAfter</code> have been replaced with a single method <code>canDrop(idx,orientation)</code> which handles both. It should return <code>true</code> if a drop is allowed on a row.
</p>
<h3 name="Checkbox_columns"> Checkbox columns </h3>
<p>Tree columns now implement the <code>checkbox</code> type. Previously the value existed but was not implemented. Now it is. You can create a checkbox 
column by setting the <code>type</code> attribute of a column to <code>checkbox</code>.
</p>
<pre class="eval">&lt;treecol type="checkbox"&gt;
</pre>
<p>You can then set or clear the checkbox for a particular cell in that 
column by setting the value attribute to <code>true</code>, or leaving out the attribute. Note that it's the value attribute you use, not the label 
attribute.
</p>
<pre class="eval">&lt;treecell/&gt;
&lt;treecell value="true"/&gt;
</pre>
<p>For theme authors, the <code><a href="en/-moz-tree-checkbox">-moz-tree-checkbox</a></code> pseudo can be used to specify the checkmark image.
</p><p>In addition, checkmark columns support editing:
</p>
<pre class="eval">&lt;tree editable="true"&gt;
  &lt;treecols&gt;
    &lt;treecol type="checkbox" editable="true"&gt;
    ...
&lt;/tree&gt;
</pre>
<p>If the column is editable, the user can click the cell to change the 
state of the checkbox. When the user clicks the cell, the view's 
<code>setCellValue</code> method will be called with either the value <code>true</code> or <code>false</code>.
</p><p>Note that the tree must also be marked as editable using the <code>editable</code> attribute in order for this to work. This is shown in the example above. Sometimes, you might have a particular row or cell which you do not want to be editable. In this case, disable editing for that cell by setting editable to false for that cell, as in the following:
</p>
<pre class="eval">&lt;treecell value="true" editable="false"/&gt;
</pre>
<p>Or, for custom views, return <code>false</code> from the <code>isEditable</code> method.
</p><p>Currently, only checkbox columns support editing, although the 
content-based tree handles the <code><a class="external" href="http://www.xulplanet.com/references/objref/TreeContentView.html#method_setCellValue">setCellValue</a></code> and <code><a class="external" href="http://www.xulplanet.com/references/objref/TreeContentView.html#method_setCellText">setCellText</a></code> functions to change the tree content with a script for other types of cells. For instance:
</p>
<pre class="eval">var col = tree.columns.getPrimaryColumn();
treecell.setCellText(5,col,"Banana");
</pre>
<p>This will change the label of the cell in row 5 and the primary column 
to <i>Banana</i>. However, this paves the way in the future for more general 
tree editing features.
</p>
<h3 name="Style_improvements"> Style improvements </h3>
<p>You can now specify the cursor to use for a cell using the <a href="en/CSS">CSS</a> cursor
property.
</p>
<pre class="eval">treechildren::-moz-tree-cell-text {
cursor: pointer;
}
</pre>
<p>The allows you to create separate cursors for cells.
</p><p>The <code>::<a href="en/-moz-tree-separator">-moz-tree-separator</a></code> pseudo has been improved to make it a proper box type and now has additional styling capabilities. Example:
</p>
<pre class="eval">treechildren::-moz-tree-separator {
margin-top: 1px;
border-top: 1px solid ThreeDShadow;
border-right: 1px solid ThreeDHighlight;
border-bottom: 1px solid ThreeDHighlight;
border-left: 1px solid ThreeDShadow;
height: 2px;
}
</pre>
<div class="originaldocinfo">
<h3 name="Original_Document_Information"> Original Document Information </h3>
<ul><li> Author: Neil Deakin
</li><li> Source: <a class="external" href="http://mozdev.org/pipermail/project_owners/2004-April/002131.html">here</a>
</li></ul>
</div>
Revert to this revision