[Project_owners] Tree Widget Changes

Neil Deakin ndeakin at sympatico.ca
Mon Apr 26 12:22:21 EDT 2004


Based on information from Jan Varga, who implemented the changes, here 
is some information about the changes made recently to the XUL tree 
widget code as part of bug 221619, which fixes a number of issues with 
trees. This code was checked in on April 16 and is it builds after that, 
but not 1.7

--------------------------------------------------------------------------------------------------------------


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 at
http://lxr.mozilla.org/seamonkey/source/layout/xul/base/src/tree/public/nsITreeColumns.idl

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 JS:
  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[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;
}


/ Neil




More information about the Project_owners mailing list