net.sf.click.extras.tree
Class Tree.SessionHandler

java.lang.Object
  extended bynet.sf.click.extras.tree.Tree.SessionHandler
All Implemented Interfaces:
Tree.JavascriptHandler, TreeListener
Direct Known Subclasses:
CheckboxTree.CheckboxSessionHandler
Enclosing class:
Tree

protected class Tree.SessionHandler
extends Object
implements Tree.JavascriptHandler

Please note this class is only meant for developers of this control, not users.

This class implements a session based javascript handler. It manages the client side javascript behavior by tracking the client's selected tree paths.

The problem: when javascript is enabled, the entire tree must be sent to the browser to be navigatable without round trips to the server. However the tree should not be displayed in an expanded state so css is used to apply the 'display: none' idiom to 'collapse' the nodes even though they are really expanded.

On the browser as the user expands and collapses nodes he/she will make selections and deselections of certain nodes. Since the node's value is rendered as a hyperlink, selecting or deselecting the node will create a request to the server. After the round trip to the server the tree will again be rendered in a collapsed state because the server will apply the css 'display :none' idiom before returning to the browser. It would be nice if instead of collapsing the entire tree again, to keep those tree paths that lead to selected nodes in a expanded state.

The solution: SessionHandler keeps track of the selected paths and is queried at rendering time which nodes should be hidden and which nodes should be displayed. The selected path are all the node's from the selected node up to the root node.

SessionHandler also keeps track of the overlaid paths. Overlaid paths comes from two or more selected paths that share certain common nodes. Overlaid paths are used in determining when a selected path can be removed from the tracker. To understand this better here is an example tree (top to bottom):

                           root
       node1                            node2
 node1.1  node1.2          node2.1  node2.2
 
IF node1 is selected, the selected path would include the nodes "root and node1". If node1.1 is then selected, the selected path would also include the nodes "root, node1 and node1.1". The same ff node1.2 is selected. The overlaid path would include the shared nodes of the three selected paths. Thus the overlaid path would consist of "root" because that node is shared by all three paths. Overlaid path will also contain "node1" because it is shared by node1.1 and node1.2.

The implementation: To keep memory storage to a minimum, only the hashcode of a node is stored, and it is stored only once for any node on any selected path. Thus if n nodes in a tree are selected there will only be n hashcodes stored.

The overlaid paths are stored in a object consisting of a counter which increments and decrements each time a path is selected or deselected. The overlaid path also stores a boolean indicating if a a node is the last node on the path or not. The last node in the selected path should not be expanded because we do not want the children of the last node to be displayed. Lets look at our previous example again. The overlaid paths would contain the following information:

The overlaid paths indicates that the root node was found on three selected paths, and it is not the last node in the path. It cannot be the last node in the path because its child, node1 is also found on the selected path. node1 is also found on three selected paths (remember that node1 was itself selected) and is also not the last node in the path because both its children are found on selected paths as well. node1.1 is only found once on a selected path and because it does not have any children, it is the last node in the path. node1.2 is the same as node1.1.

When a user deselects a node, each node on the selected path are decremented from the overlaid path counter. If a overlaid counter is reduced to 0, the selected path is also removed from storage. Also as nodes are removed, each node's lastNodeInPath indicator is updated to reflect if that node is the new last node on the path. For example if a user deselects node1.1 the overlaid path will look as follows:

Only 1 instance of root and node1 are left on the paths, but both are still not the last node in the path. Because node1.2 counter was reduced to 0, it was removed from the selected path storage as well.

If the user deselects node1.1 overlaid path will look like this:

node1 is now the lastNodeInPath. node1.1 is also removed from the selected path storage.

Note: this class stores information between requests in the javax.servlet.http.HttpSession as a attribute. The attributes prefix is js_path_handler_ followed by the name of the tree AbstractControl.name. If two tree's in the same session have the same name they will overwrite each others session attribute!


Field Summary
protected  Tree.JavascriptRenderer javascriptRenderer
          Renders the needed javascript for this handler.
 
Constructor Summary
protected Tree.SessionHandler(Context context)
          This class is dependant on Context, so this constructor enforces a valid context before the handler can be used.
 
Method Summary
 void destroy()
          Called to indicate the user request cycle is complete.
 Tree.JavascriptRenderer getJavascriptRenderer()
          Returns the javascript renderer associated with this handler.
 void init(Context context)
          Retrieves the tracker from the http session if it exists.
 void nodeCollapsed(Tree tree, TreeNode node, Context context, boolean oldValue)
          Invoked when user collapsed the specified node.
 void nodeDeselected(Tree tree, TreeNode node, Context context, boolean oldValue)
          Removes all node's that are part of the selected path from the tracker.
 void nodeExpanded(Tree tree, TreeNode node, Context context, boolean oldValue)
          Invoked when user expanded the specified node.
 void nodeSelected(Tree tree, TreeNode node, Context context, boolean oldValue)
          Adds all node's that are part of the selected path to the tracker.
 boolean renderAsExpanded(TreeNode treeNode)
          Queries the handler if the specified node should be rendered as expanded or not.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

javascriptRenderer

protected Tree.JavascriptRenderer javascriptRenderer
Renders the needed javascript for this handler.

Constructor Detail

Tree.SessionHandler

protected Tree.SessionHandler(Context context)
This class is dependant on Context, so this constructor enforces a valid context before the handler can be used.

Parameters:
context - provides access to the http request, and session
Method Detail

init

public void init(Context context)
Retrieves the tracker from the http session if it exists. Otherwise it creates a new tracker and stores it in the http session.

Specified by:
init in interface Tree.JavascriptHandler
Parameters:
context - provides access to the http request, and session

renderAsExpanded

public boolean renderAsExpanded(TreeNode treeNode)
Queries the handler if the specified node should be rendered as expanded or not.

Specified by:
renderAsExpanded in interface Tree.JavascriptHandler
Parameters:
treeNode - the specified node to check if it is expanded or not
Returns:
true if the specified node should be expanded, false otherwise
See Also:
renderAsExpanded(TreeNode)

destroy

public void destroy()
Description copied from interface: Tree.JavascriptHandler
Called to indicate the user request cycle is complete. Any last minute tasks can be performed here.

Specified by:
destroy in interface Tree.JavascriptHandler
See Also:
destroy()

getJavascriptRenderer

public Tree.JavascriptRenderer getJavascriptRenderer()
Description copied from interface: Tree.JavascriptHandler
Returns the javascript renderer associated with this handler.

Specified by:
getJavascriptRenderer in interface Tree.JavascriptHandler
Returns:
currently installed javascript renderer
See Also:
getJavascriptRenderer()

nodeSelected

public void nodeSelected(Tree tree,
                         TreeNode node,
                         Context context,
                         boolean oldValue)
Adds all node's that are part of the selected path to the tracker.

Specified by:
nodeSelected in interface TreeListener
Parameters:
tree - tree the operation was made on
node - node that was selected
context - provides access to Context
oldValue - contains the previous value of selected state
See Also:
TreeListener.nodeSelected(Tree, TreeNode, Context, boolean)

nodeDeselected

public void nodeDeselected(Tree tree,
                           TreeNode node,
                           Context context,
                           boolean oldValue)
Removes all node's that are part of the selected path from the tracker.

Specified by:
nodeDeselected in interface TreeListener
Parameters:
tree - tree the operation was made on
node - node that was deselected
context - provides access to Context
oldValue - contains the previous value of selected state
See Also:
TreeListener.nodeDeselected(Tree, TreeNode, Context, boolean)

nodeExpanded

public void nodeExpanded(Tree tree,
                         TreeNode node,
                         Context context,
                         boolean oldValue)
Description copied from interface: TreeListener
Invoked when user expanded the specified node.

Specified by:
nodeExpanded in interface TreeListener
Parameters:
tree - tree the operation was made on
node - node that was expanded
context - provides access to Context
oldValue - contains the previous value of expanded state
See Also:
TreeListener.nodeExpanded(Tree, TreeNode, Context, boolean)

nodeCollapsed

public void nodeCollapsed(Tree tree,
                          TreeNode node,
                          Context context,
                          boolean oldValue)
Description copied from interface: TreeListener
Invoked when user collapsed the specified node.

Specified by:
nodeCollapsed in interface TreeListener
Parameters:
tree - tree the operation was made on
node - node that was collapsed
context - provides access to Context
oldValue - contains the previous value of selected state
See Also:
TreeListener.nodeCollapsed(Tree, TreeNode, Context, boolean)