5 Replies Latest reply on Jan 29, 2008 3:13 PM by Daniel Spangler

    Rich:Tree Basics Question

    Andy Gibson Newbie

      I'm using Seam and trying to build my own TreeNode implementations without success. I've created a simple test TreeNode to try and get it working which I've included below :

      public class TestTreeNode implements Serializable, TreeNode {
      
       private Object data = null;
       private Map<Object, TreeNode> childNodes = null;
       private int level;
      
       public TestTreeNode(Object data) {
       this.data = data;
       this.level = 0;
       }
      
       protected Map<Object, TreeNode> getChildList() {
       //generate some random ndoes up to level 3 tree levels
       if (childNodes == null) {
       childNodes = new HashMap<Object, TreeNode>();
       if (level < 3) {
       for (int i = 1; i < 3; i++) {
       String s = String.valueOf(i);
       TestTreeNode node = new TestTreeNode(s);
       node.level = level + 1;
       childNodes.put(s, node);
       }
       }
       }
       return childNodes;
       }
      
       public void addChild(Object identifier, TreeNode child) {
       getChildList().put(identifier, child);
       }
      
       public TreeNode getChild(Object id) {
       return getChildList().get(id);
       }
      
       public Iterator getChildren() {
       return getChildList().entrySet().iterator();
       }
      
       public Object getData() {
       return data;
       }
      
       public TreeNode getParent() {
       return null;
       }
      
       public boolean isLeaf() {
       return false;
       }
      
       public void removeChild(Object id) {
       getChildList().remove(id);
       }
      
       public void setData(Object data) {
       this.data = data;
       }
      
       public void setParent(TreeNode parent) {
       // TODO Auto-generated method stub
       }
      
       @Override
       public String toString() {
       return "TestTreeNode : " + data;
       }
      
      }
      
      
      


      It simply creates a set of tree nodes with 2 child nodes each upto a depth of 3 levels.

      My web page is defined as :

      <rich:tree
       switchType="server"
       ajaxSubmitSelection="true"
       value="#{userRightAssignment.treeData}"
       var="v_node">
      
       <rich:treeNode type="simpleNode">
       <h:outputText value="#{v_node}" />
       </rich:treeNode>
      
      
      </rich:tree>
      


      In my backing bean (which is bean created fine) I have
      
      private TreeNode node = new TestTreeNode("1");
      
      ...
      ...
      ...
      
      public TreeNode getTreeData() {
      
       return node;
      
       }
      



      The tree is being created ok, I've created a method to write out the tree recursively to the log, and it comes out fine. However, in the page itself, there is nothing in the tree, no icons, no text etc..

      I couldn't find a simplistic example of implementing the tree node interface so I'm guessing, but I think I'm missing something out here.

      Anyone got any insights?

      Cheers,

      Andy



        • 1. Re: Rich:Tree Basics Question
          Florian Marwede Expert

          In my opinion you need a "getType" method in your tree node class which returns the String "simpleNode".

          Another idea you can try:

          We extend TreeNodeImpl so we don't have to implement "getChildren" and so on.
          But in our app it only works when the "getData"-Method is overriden like this:

           @Override
           public Object getData()
           {
           return this;
           }
          


          Perhaps somebody know more about this...but at the end it works (although we don't understand) and you can try.

          • 2. Re: Rich:Tree Basics Question
            Andy Gibson Newbie

            Hey, thanks for the reply.

            I took your ideas and gave them a whirl, and still no luck.

            I created a new tree node type which extends TreeNodeImpl, and does nothing else (I added a getType method which returns simpleNode). I put it in my tree and still nothing which is really odd.

            My node now looks like :

            import org.richfaces.model.TreeNodeImpl;
            
            public class SimpleTreeNode extends TreeNodeImpl {
            
             public String getType() {
             return "simpleNode";
             }
            
            }
            


            My page looks like :

            <h:outputText value="#{userRightAssignment.treeData}"></h:outputText>
            
            <rich:tree
             switchType="server"
             ajaxSubmitSelection="true"
             value="#{userRightAssignment.treeData}"
             var="v_node">
            
             <rich:treeNode type="simpleNode">
             <h:outputText value="#{v_node.data}" />
             </rich:treeNode>
            
            </rich:tree>
            


            I have a label that outputs the value of the treeData value and it does indeed contain the instance of SimpleTreeNode.

            I would have thought that for sure this would have put a single node on the tree but obviously I must be missing something.

            Any thoughts anyone?

            Cheers,

            Andy


            • 3. Re: Rich:Tree Basics Question
              Florian Marwede Expert

              Did you bear in mind my second hind (override getData)?

              Independently from that it would be nice to hear an expert to these questions...

              • 4. Re: Rich:Tree Basics Question
                Andy Gibson Newbie

                Aaahh, thanks for the reminder.

                I added the getData override in, and still no luck, it seems I do need an expert opinion to get the simplest case working.

                Cheers,

                Andy






                • 5. Re: Rich:Tree Basics Question
                  Daniel Spangler Newbie

                  Couple of things:

                  The tree will look at the nodeFace attribute of the tree and compare the result to the type attribute in your tree node to determine which tree node to use. One way of doing it could be to change your code to this.

                  <rich:tree
                   switchType="server"
                   ajaxSubmitSelection="true"
                   value="#{userRightAssignment.treeData}"
                   var="v_node"
                   nodeFace="#{v_node.class.simpleName}
                   >
                  
                   <rich:treeNode type="MyDataClass">
                   <h:outputText value="#{v_node}" />
                   </rich:treeNode>
                  
                  
                  </rich:tree>
                  


                  In this example the tree will look at the simple class name for the node data and compare it to the value of your treeNode type attribute.

                  One gotcha is that the v_node variable will point to the data attribute of your node. If you don't want this to happen, make your data attribute return "this" and add another accessor for the data backing your node. I added a separate property to my node which I call "model" and I have the data attribute return the node itself. By doing that, I can layout my tree like so:

                   <rich:tree id="question_tree" value="#{directedQuestionManagerModel.rootQuestionNode}" var="item" nodeFace="#{item.model.class.simpleName}" switchType="client">
                   <rich:treeNode type="DatabaseQuestionImpl" icon="/img/blue_cloud.png">
                   <h:outputText value="Q - #{item.model.questionText}">
                   </h:outputText>
                   <rich:componentControl for="questionPanel" operation="show" event="onselected">
                   <f:param name="questionId" value="#{item.model.id}"/>
                   <f:param name="questionText" value="#{item.model.questionText}"/>
                   <f:param name="questionMultipleAnswersPermitted" value="#{item.model.multipleAnswersPermitted}"/>
                   </rich:componentControl>
                   </rich:treeNode>
                   <rich:treeNode type="DatabaseOptionImpl" icon="/img/blue_double_cloud.png" iconLeaf="/img/blue_double_cloud.png">
                   <h:outputText value="O - #{item.model.optionValueAsString}">
                   </h:outputText>
                   <rich:componentControl for="optionPanel" operation="show" event="onselected">
                   <f:param name="optionId" value="#{item.model.id}"/>
                   <f:param name="optionValueAsString" value="#{item.model.optionValueAsString}"/>
                   <f:param name="optionFreeForm" value="#{item.model.freeForm}"/>
                   </rich:componentControl>
                   </rich:treeNode>
                   </rich:tree>
                   </s:div>
                  


                  Now, whether this is the right way of doing it... I don't know. It seems to work though...

                  Daniel