[ZPT] CVS: Zope/lib/python/ZTUtils - Tree.py:1.6.6.7
Martijn Pieters
mj@zope.com
Mon, 7 Oct 2002 16:03:31 -0400
Update of /cvs-repository/Zope/lib/python/ZTUtils
In directory cvs.zope.org:/tmp/cvs-serv4425/lib/python/ZTUtils
Modified Files:
Tag: Zope-2_6-branch
Tree.py
Log Message:
Merge additional TreeMaker accessor methods and stateFunction functionality
from the trunk.
=== Zope/lib/python/ZTUtils/Tree.py 1.6.6.6 => 1.6.6.7 ===
--- Zope/lib/python/ZTUtils/Tree.py:1.6.6.6 Mon Oct 7 15:45:10 2002
+++ Zope/lib/python/ZTUtils/Tree.py Mon Oct 7 16:03:30 2002
@@ -64,8 +64,11 @@
_assume_children = 0
_values_filter = None
_values_function = None
+ _state_function = None
_expand_root = 1
+ _cached_children = None
+
def setChildAccess(self, attrname=_marker, filter=_marker,
function=_marker):
'''Set the criteria for fetching child nodes.
@@ -83,6 +86,60 @@
else:
self._values_function = function
+ def setIdAttr(self, id):
+ """Set the attribute or method name called to get a unique Id.
+
+ The id attribute or method is used to get a unique id for every node in
+ the tree, so that the state of the tree can be encoded as a string using
+ Tree.encodeExpansion(). The returned id should be unique and stable
+ across Zope requests.
+
+ If the attribute or method isn't found on an object, either the objects
+ persistence Id or the result of id() on the object is used instead.
+
+ """
+ self._id = id
+
+ def setExpandRoot(self, expand):
+ """Set wether or not to expand the root node by default.
+
+ When no expanded flag or mapping is passed to .tree(), assume the root
+ node is expanded, and leave all subnodes closed.
+
+ The default is to expand the root node.
+
+ """
+ self._expand_root = not not expand
+
+ def setAssumeChildren(self, assume):
+ """Set wether or not to assume nodes have children.
+
+ When a node is not expanded, when assume children is set, don't
+ determine if it is a leaf node, but assume it can be opened. Use this
+ when determining the children for a node is expensive.
+
+ The default is to not assume there are children.
+
+ """
+ self._assume_children = not not assume
+
+ def setStateFunction(self, function):
+ """Set the expansion state function.
+
+ This function will be called to determine if a node should be open or
+ collapsed, or should be treated as a leaf node. The function is passed
+ the current object, and the intended state for that object. It should
+ return the actual state the object should be in. State is encoded as an
+ integer, meaning:
+
+ -1: Node closed. Children will not be processed.
+ 0: Leaf node, cannot be opened or closed, no children are
+ processed.
+ 1: Node opened. Children will be processed as part of the tree.
+
+ """
+ self._state_function = function
+
def tree(self, root, expanded=None, subtree=0):
'''Create a tree from root, with specified nodes expanded.
@@ -97,14 +154,17 @@
# Assume a mapping
expanded = expanded.has_key(node.id)
child_exp = child_exp.get(node.id)
- if expanded or (not subtree and self._expand_root):
- children = self.getChildren(root)
- if children:
- node.state = 1 # expanded
- for child in children:
- node._add_child(self.tree(child, child_exp, 1))
- elif self.hasChildren(root):
- node.state = -1 # collapsed
+
+ expanded = expanded or (not subtree and self._expand_root)
+ # Set state to 0 (leaf), 1 (opened), or -1 (closed)
+ state = self.hasChildren(root) and (expanded or -1)
+ if self._state_function is not None:
+ state = self._state_function(node.object, state)
+ node.state = state
+ if state > 0:
+ for child in self.getChildren(root):
+ node._add_child(self.tree(child, child_exp, 1))
+
if not subtree:
node.depth = 0
return node
@@ -127,9 +187,18 @@
def hasChildren(self, object):
if self._assume_children:
return 1
- return self.getChildren(object)
+ # Cache generated children for a subsequent call to getChildren
+ self._cached_children = (object, self.getChildren(object))
+ return not not self._cached_children[1]
def getChildren(self, object):
+ # Check and clear cache first
+ if self._cached_children is not None:
+ ob, children = self._cached_children
+ self._cached_children = None
+ if ob is object:
+ return children
+
if self._values_function is not None:
return self._values_function(object)