Uploaded image for project: 'MyFaces Tomahawk'
  1. MyFaces Tomahawk
  2. TOMAHAWK-296

tree2 TreeState wrong after node deletion/reposition, causes Servlet Exception

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 1.1.2
    • Component/s: None
    • Labels:
      None
    • Environment:
       Tomcat 4.1.31, SDK 1.4.2, windows XP Pro

      Description

      We are using the tree2 component in a situation where nodes can be dynamically added, deleted and re-parented.
      The tree can also be completely re-populated with a different version of data.
      We have also simulated multiple node selection, by placing a checkbox
      next to certain nodes. Clicking a button then causes bulk-deletion of all ticked nodes.

      We were using the myfaces 1.0.9 version in this way:

      <t:tree2 value="#

      {xxx.treeData}

      "
      var="n"
      varNodeToggler="tn"
      clientSideToggle="false">

      The backing bean is in Session Scope; treeData was a TreeNode.

      All this was basically working, with the exception of a refresh problem after a re-population (reported in MYFACES-404),
      and a problem whereby you had to click twice to expand the root node when the page first displayed.

      We want to migrate to the nightly builds, in which these two issues are fixed (thanks!)
      But we hit problems with the new TreeState: (using nightly build of 11-Sep-05)

      1. When moving to another page and then coming back, the tree is always collapsed.
      2. When re-populating the tree with a different data set, OR
      3. When deleting or reparenting a node, often this kind of error (eventually) occurs:

      javax.servlet.ServletException:
      Encountered a node [0:4] + with an illogical state.
      Node is expanded but it is also considered a leaf (a leaf cannot be considered expanded.

      By reading thru the various postings and forums I have fixed:

      1 by creating our own TreeModel and value-binding to that (rather than a TreeNode)
      (Incidentally, adding a component-binding, ie <t:tree2 binding="#

      {xxx.treeComponent}

      " value="#

      {xxx.treeNode}

      "..>
      also fixed the problem without using our own TreeModel)

      2 by setting the Transient property of our TreeModel's TreeState to True
      (which I understand is OK since our backing bean is session-scoped)

      But I can't figure out 3.
      How can you fix up the TreeState after programatically causing nodes to change positions or disappear,
      since the TreeState maintains its node expansion knowledge via a Hashmap keyed on positional node ids
      (0:1:4, etc).

      As a work-around I've thought of collapsing any node (and its subnodes) before trying to delete or move it, or even
      collapsing the whole tree, but I can't work out how....
      UITreeData only gives you the nodeId of the 'current' node, so I don't understand how you get at
      nodeIds of arbitrary nodes to feed to the new collapsePath() method.

      (Incidentally, maybe a collapseAll() method might be useful to have as well as expandAll()?)

      Thanks for any help, and please set me straight if I've misunderstood anything about the changes made to tree2 along the way!

      Regards, Bett

      1. tree2_bitmask.txt
        1 kB
        Mathias Werlitz

        Issue Links

          Activity

          Hide
          mathias.werlitz Mathias Werlitz added a comment -

          I made the HtmlTreeRenderer more flexible regarding dynamic tree-structures ... it now ignores the expand state, if the current node is a leaf.
          This should fix various invalid bitmask problems.

          Show
          mathias.werlitz Mathias Werlitz added a comment - I made the HtmlTreeRenderer more flexible regarding dynamic tree-structures ... it now ignores the expand state, if the current node is a leaf. This should fix various invalid bitmask problems.
          Hide
          jtravis Jon Travis added a comment -

          Bett,

          I've run into the same problem as you. We are working with a server-based tree and
          need to do dynamic updates to it.

          The way I resolved it was to bind the HtmlTree, get the state, and manually collapse
          and convert nodes to leaves as their children disappear. You can formulate the
          path for any node by simply starting at that node and traversing up the tree to
          each of its parents. (i.e. for each node, you see where it lies in the parents 'children'
          collection, and add it to the id string)

          One of the big problems with this method is that you need to make your own subclass
          for treenodes that knows how to manage the parent/child relationship. As it stands
          right now, you can't get to a parent from the children. You'll need to add that functionality
          yourself. (I've added an addChild(), getParent(), setParent() to my extended base class
          that provides this functionality)

          – Jon

          Show
          jtravis Jon Travis added a comment - Bett, I've run into the same problem as you. We are working with a server-based tree and need to do dynamic updates to it. The way I resolved it was to bind the HtmlTree, get the state, and manually collapse and convert nodes to leaves as their children disappear. You can formulate the path for any node by simply starting at that node and traversing up the tree to each of its parents. (i.e. for each node, you see where it lies in the parents 'children' collection, and add it to the id string) One of the big problems with this method is that you need to make your own subclass for treenodes that knows how to manage the parent/child relationship. As it stands right now, you can't get to a parent from the children. You'll need to add that functionality yourself. (I've added an addChild(), getParent(), setParent() to my extended base class that provides this functionality) – Jon
          Hide
          mathias.werlitz Mathias Werlitz added a comment -

          I'm not really up-to-date with the release of 1.1.1 but I think this patch should be included ... it will save us a lot of illogical state exceptions

          Show
          mathias.werlitz Mathias Werlitz added a comment - I'm not really up-to-date with the release of 1.1.1 but I think this patch should be included ... it will save us a lot of illogical state exceptions
          Hide
          mmarinschek Martin Marinschek added a comment -

          Thanks to Mathias Werlitz - sorry for the delay.

          Show
          mmarinschek Martin Marinschek added a comment - Thanks to Mathias Werlitz - sorry for the delay.
          Hide
          dirkl Dirk Laube added a comment -

          Even with the patch by Mathias there's on small issue left; consider this tree:
          Node A contains node B, which contains node C. Then

          • expand node B,
          • delete node B,
          • add a new node newB to A.

          Node newB will have the status "expanded", as seen by the displayed icon (eg. openfolder.gif). (You can get rid of the "expanded" status, if you add a new subnode, collapse newB and delete the just now added subnode.)

          My workaround looks like this: After the new node is added I

          • get the path information of newB
          • from this I retrieve the parent's node path
          • I collapse the new node: tree.collapsePath( path )
          • and expand the parent node: tree.expandPath( ppath )

          This (nasty) workaround is not meant as solution but rather as a hint for someone who knows the code to get the idea what might be wrong.

          Best Regards,
          Dirk

          Show
          dirkl Dirk Laube added a comment - Even with the patch by Mathias there's on small issue left; consider this tree: Node A contains node B, which contains node C. Then expand node B, delete node B, add a new node newB to A. Node newB will have the status "expanded", as seen by the displayed icon (eg. openfolder.gif). (You can get rid of the "expanded" status, if you add a new subnode, collapse newB and delete the just now added subnode.) My workaround looks like this: After the new node is added I get the path information of newB from this I retrieve the parent's node path I collapse the new node: tree.collapsePath( path ) and expand the parent node: tree.expandPath( ppath ) This (nasty) workaround is not meant as solution but rather as a hint for someone who knows the code to get the idea what might be wrong. Best Regards, Dirk
          Hide
          mathias.werlitz Mathias Werlitz added a comment -

          The remaining issue is due to the internal naming of tree2. Every node gets the index position in the child-array of the parent node. The node does not get a real ID, thus exchanging a node cannot be detected by the tree.

          Show
          mathias.werlitz Mathias Werlitz added a comment - The remaining issue is due to the internal naming of tree2. Every node gets the index position in the child-array of the parent node. The node does not get a real ID, thus exchanging a node cannot be detected by the tree.

            People

            • Assignee:
              mmarinschek Martin Marinschek
              Reporter:
              bettk Bett Koch
            • Votes:
              5 Vote for this issue
              Watchers:
              6 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development