JBoss.orgCommunity Documentation

Chapter 11. Trees

11.1. <rich:tree>
11.1.1. Basic usage
11.1.2. Appearance
11.1.3. Expanding and collapsing tree nodes
11.1.4. Selecting tree nodes
11.1.5. Identifying nodes with the rowKeyConverter attribute
11.1.6. Event handling
11.1.7. Reference data
11.1.8. Style classes
11.1.9. <rich:treeSelectionChangeListener>
11.1.10. <rich:treeNode>
11.2. Tree adaptors
11.2.1. <rich:treeModelAdaptor>
11.2.2. <rich:treeModelRecursiveAdaptor>

Read this chapter for details on components that use tree structures.

The <rich:tree> component provides a hierarchical tree control. Each <rich:tree> component typically consists of <rich:treeNode> child components. The appearance and behavior of the tree and its nodes can be fully customized.

The <rich:tree> component requires the value attribute to point to the data model for populating the tree. The data model must be either an org.richfaces.model.TreeNode interface, an org.richfaces.model.TreeDataModel interface, or a javax.swing.tree.TreeNode interface. The var attribute declares the variable used for iterating through the data model, so that child <rich:treeNode> components can reference each iteration.

Ideally, the <rich:tree> component needs one or more <rich:treeNode> components to work with the data model. However if no <rich:treeNode> components are provided the tree creates default nodes instead.

Example 11.1. Basic usage

This example demonstrates basic usage of the <rich:tree> component using an org.richfaces.model.TreeNode data model.

First extend the org.richfaces.model.TreeNodeImpl and add the data fields you require, with appropriate accessor methods, as in:

import org.richfaces.model.TreeNodeImpl;


public class DataHolderTreeNodeImpl extends TreeNodeImpl {
    private Object data;
    public DataHolderTreeNodeImpl() {
        super();
    }
    public DataHolderTreeNodeImpl(boolean leaf, Object data) {
        super(leaf);
        this.data = data;
    }
    public Object getData() {
        return data;
    }
    @Override
    public String toString() {
        return super.toString() + " >> " + data;
    }
}

Then, the data model is constructed as follows:

private DataHolderTreeNodeImpl stationRoot;

private DataHolderTreeNodeImpl rootNodes;
public DataHolderTreeNodeImpl getRootNodes() {
    if (rootNodes == null) {
        String[] kickRadioFeed = {"Hall & Oates - Kiss On My List",
                "David Bowie - Let's Dance",
                "Lyn Collins - Think (About It)",
                "Kim Carnes - Bette Davis Eyes",
                "KC & the Sunshine Band - Give It Up"};
        stationRoot = new DataHolderTreeNodeImpl(false, "KickRadio");
        for (int i = 0; i<kickRadioFeed.length; i++) {
            DataHolderTreeNodeImpl child = new DataHolderTreeNodeImpl(true, kickRadioFeed[i]);
            stationRoot.addChild(i, child);
        }
        rootNodes = new DataHolderTreeNodeImpl();
        rootNodes.addChild(0, stationRoot);
    }
    return rootNodes;
}

The tree then accesses the nodes of the model using the station variable:


<rich:tree value="#{stations.stationNodes}" var="station">
   <rich:treeNode>
      <h:outputText value="#{station}" />
   </rich:treeNode>
</rich:tree>

Different nodes in the tree can have different appearances, such as node icons, depending on the type of data the node contains. Use the nodeType attribute to differentiate the types of nodes; the node is then rendered according to the <rich:treeNode> component with the corresponding type attribute. Example 11.2, “nodeType attribute” shows a <rich:tree> component with three different child <rich:treeNode> components defined to represent three different node appearances. Refer to Section 11.1.10.2, “Appearance” for details on customizing the appearance of <rich:treeNode> components.


If the nodeType attribute returns null, the node is rendered as a "typeless" (or default) node. The typeless node is the first child <rich:treeNode> component with a valid rendered attribute, but without a defined type attribute.

If the nodeType attribute is not included and there are no child <rich:treeNode> components, the tree constructs a default node itself.

Icons for different nodes and node states can be defined for the whole tree using the following attributes:

iconLeaf

The iconLeaf attribute points to the icon to use for any node that does not contain any child nodes.

iconExpanded and iconCollapsed

The iconExpanded and iconCollapsed attributes point to the icons to use for expanded and collapsed nodes respectively. If these attributes are defined, the icon attribute is not used.

The <rich:treeNode> component is a child component of the <rich:tree> component. It represents nodes in the parent tree. The appearance and functionality of each tree node can be customized.

Refer to Section 11.1.2, “Appearance” for the <rich:tree> component for details and examples on styling nodes and icons. Icon styling for individual <rich:treeNode> components uses the same attributes as the parent <rich:tree> component: iconLeaf, iconExpanded, and iconCollapsed. Icon-related attributes specified for child <rich:treeNode> components overwrite any global icon attributes of the parent <rich:tree> component.

Use the rendered attribute to determine whether the node should actually be rendered in the tree or not. Using the rendered attribute in combination with the <rich:treeNode> type attribute can allow further style differentiation between node content.

Table 11.1. Style classes (selectors) and corresponding skin parameters

Class (selector)Skin ParametersMapped CSS properties
.rf-trn

This class defines styles for a tree node.

generalFamilyFont

font-family

generalSizeFont

font-size

.rf-trn-lbl

This class defines styles for a tree node label.

No skin parameters.
.rf-trn-cnt

This class defines styles for tree node content.

No skin parameters.
.rf-trn-sel

This class defines styles for a selected tree node.

additionalBackgroundColor

background

.rf-trn-ldn

This class defines styles for a tree node when it is loading.

additionalBackgroundColor

background

.rf-trn-hnd

This class defines styles for a tree node handle.

No skin parameters.
.rf-trn-hnd-lf

This class defines styles for the handle of a leaf node.

No skin parameters.
.rf-trn-hnd-colps

This class defines styles for the handle of a collapsed node.

No skin parameters.
.rf-trn-hnd-exp

This class defines styles for the handle of an expanded node.

No skin parameters.
.rf-trn-hnd-ldn-fct

This class defines styles for the loading facet of a tree node handle.

No skin parameters.
.rf-trn-ico

This class defines styles for tree node icon.

No skin parameters.
.rf-trn-ico-lf

This class defines styles for the icon of a leaf node.

No skin parameters.
.rf-trn-ico-colps

This class defines styles for the icon of a collapsed node.

No skin parameters.
.rf-trn-ico-exp

This class defines styles for the icon of an expanded node.

No skin parameters.
.rf-trn-ico-cst

This class defines styles for a custom node icon.

No skin parameters.

Use a tree adaptor to populate a tree model declaratively from a non-hierarchical model, such as a list or a map.

The <rich:treeModelRecursiveAdaptor> component iterates through recursive collections in order to populate a tree with hierarchical nodes, such as for a file system with multiple levels of directories and files.

The <rich:treeModelRecursiveAdaptor> component is an extension of the <rich:treeModelAdaptor> component. As such, the <rich:treeModelRecursiveAdaptor> component uses all of the same attributes. Refer to Section 11.2.1, “<rich:treeModelAdaptor>” for details on the <rich:treeModelAdaptor> component.

In addition, the <rich:treeModelRecursiveAdaptor> component requires the roots attribute. The roots attribute defines the collection to use at the top of the recursion. For subsequent levels, the nodes attribute is used for the collection.

Example 11.4, “Basic usage” demonstrates how the <rich:treeModelRecursiveAdaptor> component can be used in conjunction with the <rich:treeModelAdaptor> component to recursively iterate through a file system and create a tree of directories and files.

Example 11.4. Basic usage


<rich:tree var="item">
   <rich:treeModelRecursiveAdaptor roots="#{fileSystemBean.sourceRoots}" nodes="#{item.directories}" >
      <rich:treeNode>
         #{item.shortPath}
      </rich:treeNode>
      <rich:treeModelAdaptor nodes="#{item.files}">
         <rich:treeNode>#{item}</rich:treeNode>
      </rich:treeModelAdaptor>
   </rich:treeModelRecursiveAdaptor>
</rich:tree>

The <rich:treeModelRecursiveAdaptor> component references the FileSystemBean class as the source for the data.

@ManagedBean

@RequestScoped
public class FileSystemBean {
   private static final String SRC_PATH = "/WEB-INF";
   private List<FileSystemNode> srcRoots;
   public synchronized List<FileSystemNode> getSourceRoots() {
      if (srcRoots == null) {
         srcRoots = new FileSystemNode(SRC_PATH).getDirectories();
      }
      return srcRoots;
   }
}

The FileSystemBean class in turn uses the FileSystemNode class to recursively iterate through the collection.

public class FileSystemNode {

   ...
   public synchronized List<FileSystemNode> getDirectories() {
      if (directories == null) {
         directories = Lists.newArrayList();
         Iterables.addAll(directories, transform(filter(getResourcePaths(), containsPattern("/$")), FACTORY));
      }
      return directories;
   }
   public synchronized List<String> getFiles() {
      if (files == null) {
         files = new ArrayList<String>();
         Iterables.addAll(files, transform(filter(getResourcePaths(), not(containsPattern("/$"))), TO_SHORT_PATH));
      }
      return files;
   }
   private Iterable<String> getResourcePaths() {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ExternalContext externalContext = facesContext.getExternalContext();
        Set<String> resourcePaths = externalContext.getResourcePaths(this.path);
        
      if (resourcePaths == null) {
         resourcePaths = Collections.emptySet();
      }
      return resourcePaths;
   }   
   ...
}

The getDirectories() function is used recursively until the object has the collection of children. The model adaptor calls the getFiles() function at each level in order to add the file nodes.

The resulting tree hierarchically lists the directories and files in the collection.


Adaptors that use Map interfaces or models with non-string keys require a row key converter in order to correctly identify nodes. Refer to Section 11.1.5, “Identifying nodes with the rowKeyConverter attribute” for details on the use of the rowKeyConverter attribute.

Adaptors that use Iterable interfaces have simple integer row keys. A default converter is provided and does not need to be referenced explicitly.