Tutorials > " . "XUL Tutorial"; $pagetitle="7.6 - Custom Tree Views"; $customsidebar = "xultu-sidebar.php"; include "header.php"; ?>

Custom Tree Views

In addition to static content and RDF content, trees may also get their content from a custom view.

Creating a Custom View

So far, we have seen two ways to specify the content of a tree. You may place static rows and cells inside a tree, or you use an RDF datasource. The first method works fine provided you have a small amount of data to present. Using a datasource is suitable when one is available, either one provided with Mozilla or one you create yourself. In some cases, you may want to store the data is some other format, or perform computations on the data. XUL provides a third method, which involves creating a custom view object with a script.

This method can be used to hold data for hundreds of thousands of rows which the tree can display instantly. To do this, implement a tree just as before but leave the treechildren element empty. The following example shows this:

<tree id="my-tree" flex="1">
  <treecols>
    <treecol id="namecol" label="Name" flex="1"/>
    <treecol id="datecol" label="Date" flex="1"/>
  </treecols>
  <treechildren/>
</tree>

To assign data to be displayed in the tree, a script object needs to be created which is used to indicate the value of each cell, the total number of rows plus other optional information. The script object should be assigned to the tree. The tree will call methods of the object to get the information that it needs to display.

The script object, called the tree view, supports thirty or so methods that you can implement to supply information about the tree content and its appearance, but you only have to implement a small number of them. Two methods that you should implement are listed below.

Here is an example of defining such as object, which can be called whatever you want:

var treeView = {
    rowCount : 10000,
    getCellText : function(row,column){
      if (column=="namecol") return "Row "+row;
      else return "February 18";
    },
    setTree: function(treebox){ this.treebox=treebox; },
    isContainer: function(row){ return false; },
    isSeparator: function(row){ return false; },
    isSorted: function(row){ return false; },
    getLevel: function(row){ return 0; },
    getImageSrc: function(row,col){ return null; },
    getRowProperties: function(row,props){},
    getCellProperties: function(row,col,props){},
    getColumnProperties: function(colid,col,props){}
};

The functions in the example not described above do not need to perform any action, but they must be implemented as the tree calls them to gather additional information.

This example can be used for an tree with 10000 rows. The contents of the cells in the first column will be set to the text 'Row X' where X is the row number. The contents of the cells in the second column will be set to 'February 18'. The if statement in the function getCellText compares the column to the text 'namecol'. This text (namecol) corresponds to the id of the first treecol in the example above. This example is very simple of course -- in reality you would have more complex data in each cell.

The final step is to associate the view object with the tree. The tree has a property view, which can be assigned to the view object declared above. We can assign a value to this property at any time to set or change the view.

function setView()
{
    document.getElementById('my-tree').view=treeView;
}

The following presents the example together. An inline script has been used here to simplify the example. Normally, you would put the script in an external script file.

Example 7.6.1: Source
<?xml version="1.0"?>

<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

<window title="Tree Example" id="tree-window"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
   onload="setView();">

<script>
var treeView = {
    rowCount : 10000,
    getCellText : function(row,column){
      if (column=="namecol") return "Row "+row;
      else return "February 18";
    },
    setTree: function(treebox){ this.treebox=treebox; },
    isContainer: function(row){ return false; },
    isSeparator: function(row){ return false; },
    isSorted: function(row){ return false; },
    getLevel: function(row){ return 0; },
    getImageSrc: function(row,col){ return null; },
    getRowProperties: function(row,props){},
    getCellProperties: function(row,col,props){},
    getColumnProperties: function(colid,col,props){}
};

function setView()
{
    document.getElementById('my-tree').view=treeView;
}
</script>

<tree id="my-tree" flex="1">
  <treecols>
    <treecol id="namecol" label="Name" flex="1"/>
    <treecol id="datecol" label="Date" flex="1"/>
  </treecols>
  <treechildren/>
</tree>

</window>

In the image, you can see two columns, each with data taken from the getCellText function. The setView function has been called in the onload handler for the window. You could also set the view later if you wish. You can change the view at any time.

One thing to note is that the getCellText function is only called when necessary to display the contents. In the 10000 row example above, getCellText is only called for the cells that are currently displayed. It is called for other rows when the user scrolls through them. This makes the tree much more efficient.

Note that the view object is also available for trees without a custom view. For instance, trees built from RDF data will have a view object which gets the information from the RDF datasource. You can use the view object to retreive information about the data displayed in the tree.

The nsITreeView interface lists all of the properties and methods that you can implement for the tree view.


(Next) Next, we'll find out how to use commands.

Examples: 7.6.1