Hello,
I just wanted to post this tree ctrl mixin class in case
someone finds it useful. It provides tree expansion history
based on tree item labels. Its most prominent shortcoming is
that it may wrongly expand nodes with identical labels,
depending on circumstances. There's a bit of discussion on
improvement thereof in the __record_subtree_expansion()
docstring.
# ========================================================================
class cTreeExpansionHistoryMixin:
"""TreeCtrl mixin class to record expansion history."""
def __init__(self):
if not isinstance(self, wx.TreeCtrl):
raise TypeError('[%s]: mixin can only be applied to wx.TreeCtrl, not [%s]' % (cTreeExpansionHistoryMixin, self.__class__.__name__))
self.expansion_state = {}
···
#--------------------------------------------------------
# public API
#--------------------------------------------------------
def snapshot_expansion(self):
self.__record_subtree_expansion(start_node_id = self.GetRootItem())
#--------------------------------------------------------
def restore_expansion(self):
if len(self.expansion_state) == 0:
return True
self.__restore_subtree_expansion(start_node_id = self.GetRootItem())
#--------------------------------------------------------
def print_expansion(self):
if len(self.expansion_state) == 0:
print "currently no expansion snapshot available"
return True
print "last snapshot of state of expansion"
print "-----------------------------------"
print "listing expanded nodes:"
for node_id in self.expansion_state.keys():
print "node ID:", node_id
print " selected:", self.expansion_state[node_id]
#--------------------------------------------------------
# internal API
#--------------------------------------------------------
def __record_subtree_expansion(self, start_node_id=None):
"""This records node expansion states based on the item label.
A side effect of this is that identically named items can
become unduly synchronized in their expand state after a
snapshot/restore cycle.
Better choices might be
id(item.GetPyData()) or
item.GetPyData().get_tree_uid()
where get_tree_uid():
'[%s:%s]' % (self.__class__.__name__, id(self))
or some such. This would survive renaming of the item.
For database items it may be useful to include the
primary key which would - contrary to id() - survive
reloads from the database.
"""
if not self.IsExpanded(start_node_id):
return True
self.expansion_state[self.GetItemText(start_node_id)] = self.IsSelected(start_node_id)
child_id, cookie = self.GetFirstChild(start_node_id)
while child_id.IsOk():
self.__record_subtree_expansion(start_node_id = child_id)
child_id, cookie = self.GetNextChild(start_node_id, cookie)
return
#--------------------------------------------------------
def __restore_subtree_expansion(self, start_node_id=None):
start_node_label = self.GetItemText(start_node_id)
try:
node_selected = self.expansion_state[start_node_label]
except KeyError:
return
self.Expand(start_node_id)
if node_selected:
self.SelectItem(start_node_id)
child_id, cookie = self.GetFirstChild(start_node_id)
while child_id.IsOk():
self.__restore_subtree_expansion(start_node_id = child_id)
child_id, cookie = self.GetNextChild(start_node_id, cookie)
return
# ========================================================================
Comments and improvements welcome !
Thanks,
Karsten
--
GPG key ID E4071346 @ wwwkeys.pgp.net
E167 67FD A291 2BEA 73BD 4537 78B9 A9F9 E407 1346