9 Sep 2008 waffel   » (Journeyer)

expanding richfaces tree on datamodel changes


Sometimes you will select a tree node in a richfaces tree, triggered by your datamodel. There are several hints how to do this with a tree state advisor, but I have found another way to do this.

My main problem was, that I do not have a relation between my datamodel and the richfaces UITree components (nodes). This problem was introduced because I use the recursiveTreeAdaptor. I have not found a way to get a TreeRowData object from the UITree for my datamodel object.

I have searched in the richfaces implementation, if there is another way to work with my datamodel which have to expand the tree, if the datamodel is changed.

Lets clearify what I want to do: I have a datamodel with some root nodes and “normal” nodes in a tree like structure. I have also (in my TreeManager) a parameter which holds a selectedNode. A node can selected from the UI (the user clicks on a tree node and causes a node selection event) or from my datamodel, which calls a method in the TreeManager to select a specific tree node.

The tree manager contains a method to select a specific node like this:


public void select(final Node nextStepNode) {
  this.selectedNode = nextStepNode;

}

To expand the tree to the selected node, I have changed to select method:


public void select(final Node nextStepNode) {
  this.selectedNode = nextStepNode;
  try {
      // walk over the tree which expands the tree and uses a complete tree
      // range
      tree.walk(FacesContext.getCurrentInstance(), expandingDataVisitor, new CompleteTreeRange(), null, null);
    } catch (final IOException e) {
      if (LOG.isErrorEnabled()) {
        LOG.error(String.format("problem %s", e.getMessage()));
      }
    }
}

The tree walk method walks over the tree using my own data visitor and tree range. The tree range implementation tolds the tree to walk also over hidden nodes. You remember? The tree should expand all nodes to the selected node, also if the selected node is hidden.

The tree range implementation looks like:


public class CompleteTreeRange implements TreeRange {

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  public boolean processChildren(final TreeRowKey rowKey) {
    return true;
  }

  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  public boolean processNode(final TreeRowKey rowKey) {
    return true;
  }

Now comes the hard stuff on my solution, the expandingDataVisitor:


public class ExpandingDataVisitor implements DataVisitor {
  public void process(final FacesContext theContext, final Object theRowKey, final Object theArgument)
      throws IOException {
    if (selectedNode.equals(tree.getRowData(theRowKey))) {
      tree.queueNodeExpand((TreeRowKey) tree.getParentRowKey(theRowKey));
    }
}

You can queue node expanding with a tree rowKey to the node, which you want to expand. You don’t need to queue all nodes on the path. The queueNodeExpand method works fine with one rowkey. The row describes itself the complete path to the node. If you use standard jsf ID’s, a possible treeRowKey looks like “jsp123:jsp124:jsp125″ wich is the complete path to your node (row key).

You have to know, that you don’t want expand the selected node (this is in most cases a leafe). You want to expand the tree to the parent of the selected node.

Syndicated 2008-09-09 12:19:13 from waffel's Weblog

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!