4 This module provides three mixin classes that can be used with tree
7 - VirtualTree is a class that, when mixed in with a tree control,
8 makes the tree control virtual, similar to a ListCtrl in virtual mode.
9 A virtual tree control builds the tree itself by means of callbacks,
10 so the programmer is freed from the burden of building the tree herself.
12 - DragAndDrop is a mixin class that helps with dragging and dropping of
13 items. The graphical part of dragging and dropping tree items is done by
14 this mixin class. You only need to implement the OnDrop method that is
15 called when the drop happens.
17 - ExpansionState is a mixin that can be queried for the expansion state of
18 all items in the tree to restore it later.
20 All mixin classes work with wx.TreeCtrl, wx.gizmos.TreeListCtrl,
21 and wx.lib.customtree.CustomTreeCtrl. They can be used together or
24 The VirtualTree and DragAndDrop mixins force the wx.TR_HIDE_ROOT style.
26 Author: Frank Niessink <frank@niessink.com>
27 License: wxWidgets license
31 ExpansionState is based on code and ideas from Karsten Hilbert.
32 Andrea Gavana provided help with the CustomTreeCtrl integration.
36 import wx
, wx
.lib
.customtreectrl
39 class TreeAPIHarmonizer(object):
40 ''' This class attempts to hide the differences in API between the
41 different tree controls that are part of wxPython. '''
43 def __callSuper(self
, methodName
, default
, *args
, **kwargs
):
44 # If our super class has a method called methodName, call it,
45 # otherwise return the default value.
46 superClass
= super(TreeAPIHarmonizer
, self
)
47 if hasattr(superClass
, methodName
):
48 return getattr(superClass
, methodName
)(*args
, **kwargs
)
52 def GetColumnCount(self
, *args
, **kwargs
):
53 # Only TreeListCtrl has columns, return 0 if we are mixed in
54 # with another tree control.
55 return self
.__callSuper
('GetColumnCount', 0, *args
, **kwargs
)
57 def GetItemType(self
, *args
, **kwargs
):
58 # Only CustomTreeCtrl has different item types, return the
59 # default item type if we are mixed in with another tree control.
60 return self
.__callSuper
('GetItemType', 0, *args
, **kwargs
)
62 def SetItemType(self
, item
, newType
):
63 # CustomTreeCtrl doesn't support changing the item type on the fly,
64 # so we create a new item and delete the old one. We currently only
65 # keep the item text, would be nicer to also retain other attributes.
66 text
= self
.GetItemText(item
)
67 newItem
= self
.InsertItem(self
.GetItemParent(item
), item
, text
,
72 def IsItemChecked(self
, *args
, **kwargs
):
73 # Only CustomTreeCtrl supports checkable items, return False if
74 # we are mixed in with another tree control.
75 return self
.__callSuper
('IsItemChecked', False, *args
, **kwargs
)
77 def GetItemChecked(self
, *args
, **kwargs
):
78 # For consistency's sake, provide a 'Get' and 'Set' method for
80 return self
.IsItemChecked(*args
, **kwargs
)
82 def SetItemChecked(self
, *args
, **kwargs
):
83 # For consistency's sake, provide a 'Get' and 'Set' method for
85 return self
.CheckItem(*args
, **kwargs
)
87 def GetMainWindow(self
, *args
, **kwargs
):
88 # Only TreeListCtrl has a separate main window, return self if we are
89 # mixed in with another tree control.
90 return self
.__callSuper
('GetMainWindow', self
, *args
, **kwargs
)
92 def GetItemImage(self
, item
, which
=wx
.TreeItemIcon_Normal
, column
=-1):
93 # CustomTreeCtrl always wants the which argument, so provide it
94 # TreeListCtr.GetItemImage has a different order of arguments than
95 # the other tree controls. Hide the differenes.
96 if self
.GetColumnCount():
97 args
= (item
, column
, which
)
100 return super(TreeAPIHarmonizer
, self
).GetItemImage(*args
)
102 def SetItemImage(self
, item
, imageIndex
, which
=wx
.TreeItemIcon_Normal
,
104 # The SetItemImage signature is different for TreeListCtrl and
105 # other tree controls. This adapter method hides the differences.
106 if self
.GetColumnCount():
107 args
= (item
, imageIndex
, column
, which
)
109 args
= (item
, imageIndex
, which
)
110 super(TreeAPIHarmonizer
, self
).SetItemImage(*args
)
112 def UnselectAll(self
):
113 # Unselect all items, regardless of whether we are in multiple
114 # selection mode or not.
115 if self
.HasFlag(wx
.TR_MULTIPLE
):
116 super(TreeAPIHarmonizer
, self
).UnselectAll()
118 # CustomTreeCtrl Unselect() doesn't seem to work in all cases,
119 # also invoke UnselectAll just to be sure.
121 super(TreeAPIHarmonizer
, self
).UnselectAll()
124 # TreeListCtrl correctly ignores the root item when it is hidden,
125 # but doesn't count the root item when it is visible
126 itemCount
= super(TreeAPIHarmonizer
, self
).GetCount()
127 if self
.GetColumnCount() and not self
.HasFlag(wx
.TR_HIDE_ROOT
):
131 def GetSelections(self
):
132 # Always return a list of selected items, regardless of whether
133 # we are in multiple selection mode or not.
134 if self
.HasFlag(wx
.TR_MULTIPLE
):
135 selections
= super(TreeAPIHarmonizer
, self
).GetSelections()
137 selection
= self
.GetSelection()
139 selections
= [selection
]
142 # If the root item is hidden, it should never be selected,
143 # unfortunately, CustomTreeCtrl allows it to be selected.
144 if self
.HasFlag(wx
.TR_HIDE_ROOT
):
145 rootItem
= self
.GetRootItem()
146 if rootItem
and rootItem
in selections
:
147 selections
.remove(rootItem
)
150 def GetFirstVisibleItem(self
):
151 # TreeListCtrl raises an exception or even crashes when invoking
152 # GetFirstVisibleItem on an empty tree.
153 if self
.GetRootItem():
154 return super(TreeAPIHarmonizer
, self
).GetFirstVisibleItem()
156 return wx
.TreeItemId()
158 def SelectItem(self
, item
, *args
, **kwargs
):
159 # Prevent the hidden root from being selected, otherwise TreeCtrl
161 if self
.HasFlag(wx
.TR_HIDE_ROOT
) and item
== self
.GetRootItem():
164 return super(TreeAPIHarmonizer
, self
).SelectItem(item
, *args
,
167 def HitTest(self
, *args
, **kwargs
):
168 ''' HitTest returns a two-tuple (item, flags) for tree controls
169 without columns and a three-tuple (item, flags, column) for tree
170 controls with columns. Our caller can indicate this method to
171 always return a three-tuple no matter what tree control we're mixed
172 in with by specifying the optional argument 'alwaysReturnColumn'
174 alwaysReturnColumn
= kwargs
.pop('alwaysReturnColumn', False)
175 hitTestResult
= super(TreeAPIHarmonizer
, self
).HitTest(*args
, **kwargs
)
176 if len(hitTestResult
) == 2 and alwaysReturnColumn
:
177 hitTestResult
+= (0,)
180 def ExpandAll(self
, item
=None):
181 # TreeListCtrl wants an item as argument. That's an inconsistency with
182 # the TreeCtrl API. Also, TreeCtrl doesn't allow invoking ExpandAll
183 # on a tree with hidden root node, so prevent that.
184 if self
.HasFlag(wx
.TR_HIDE_ROOT
):
185 rootItem
= self
.GetRootItem()
187 child
, cookie
= self
.GetFirstChild(rootItem
)
189 self
.ExpandAllChildren(child
)
190 child
, cookie
= self
.GetNextChild(rootItem
, cookie
)
193 super(TreeAPIHarmonizer
, self
).ExpandAll()
196 item
= self
.GetRootItem()
197 super(TreeAPIHarmonizer
, self
).ExpandAll(item
)
199 def ExpandAllChildren(self
, item
):
200 # TreeListCtrl and CustomTreeCtrl don't have ExpandallChildren
202 super(TreeAPIHarmonizer
, self
).ExpandAllChildren(item
)
203 except AttributeError:
205 child
, cookie
= self
.GetFirstChild(item
)
207 self
.ExpandAllChildren(child
)
208 child
, cookie
= self
.GetNextChild(item
, cookie
)
211 class TreeHelper(object):
212 ''' This class provides methods that are not part of the API of any
213 tree control, but are convenient to have available. '''
215 def GetItemChildren(self
, item
=None, recursively
=False):
216 ''' Return the children of item as a list. '''
218 item
= self
.GetRootItem()
222 child
, cookie
= self
.GetFirstChild(item
)
224 children
.append(child
)
226 children
.extend(self
.GetItemChildren(child
, True))
227 child
, cookie
= self
.GetNextChild(item
, cookie
)
230 def GetIndexOfItem(self
, item
):
231 ''' Return the index of item. '''
232 parent
= self
.GetItemParent(item
)
234 parentIndices
= self
.GetIndexOfItem(parent
)
235 ownIndex
= self
.GetItemChildren(parent
).index(item
)
236 return parentIndices
+ (ownIndex
,)
240 def GetItemByIndex(self
, index
):
241 ''' Return the item specified by index. '''
242 item
= self
.GetRootItem()
244 children
= self
.GetItemChildren(item
)
249 class VirtualTree(TreeAPIHarmonizer
, TreeHelper
):
250 ''' This is a mixin class that can be used to allow for virtual tree
251 controls. It can be mixed in with wx.TreeCtrl, wx.gizmos.TreeListCtrl,
252 wx.lib.customtree.CustomTreeCtrl.
254 To use it derive a new class from this class and one of the tree
256 class MyTree(VirtualTree, wx.TreeCtrl):
259 VirtualTree uses several callbacks (such as OnGetItemText) to
260 retrieve information needed to construct the tree and render the
261 items. To specify what item the callback needs information about,
262 the callback passes an item index. Whereas for list controls a simple
263 integer index can be used, for tree controls indicating a specific
264 item is a little bit more complicated. See below for a more detailed
265 explanation of the how index works.
267 Note that VirtualTree forces the wx.TR_HIDE_ROOT style.
269 In your subclass you *must* override OnGetItemText and
270 OnGetChildrenCount. These two methods are the minimum needed to
271 construct the tree and render the item labels. If you want to add
272 images, change fonts our colours, etc., you need to override the
273 appropriate OnGetXXX method as well.
275 About indices: your callbacks are passed a tuple of integers that
276 identifies the item the VirtualTree wants information about. An
277 empty tuple, i.e. (), represents the hidden root item. A tuple with
278 one integer, e.g. (3,), represents a visible root item, in this case
279 the fourth one. A tuple with two integers, e.g. (3,0), represents a
280 child of a visible root item, in this case the first child of the
284 def __init__(self
, *args
, **kwargs
):
285 kwargs
['style'] = kwargs
.get('style', wx
.TR_DEFAULT_STYLE
) | \
287 super(VirtualTree
, self
).__init
__(*args
, **kwargs
)
288 self
.Bind(wx
.EVT_TREE_ITEM_EXPANDING
, self
.OnItemExpanding
)
289 self
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
)
291 def OnGetChildrenCount(self
, index
):
292 ''' This function *must* be overloaded in the derived class.
293 It should return the number of child items of the item with the
294 provided index. If index == () it should return the number of
296 raise NotImplementedError
298 def OnGetItemText(self
, index
, column
=0):
299 ''' This function *must* be overloaded in the derived class. It
300 should return the string containing the text of the specified
302 raise NotImplementedError
304 def OnGetItemFont(self
, index
):
305 ''' This function may be overloaded in the derived class. It
306 should return the wx.Font to be used for the specified item. '''
309 def OnGetItemTextColour(self
, index
):
310 ''' This function may be overloaded in the derived class. It
311 should return the wx.Colour to be used as text colour for the
315 def OnGetItemBackgroundColour(self
, index
):
316 ''' This function may be overloaded in the derived class. It
317 should return the wx.Colour to be used as background colour for
318 the specified item. '''
321 def OnGetItemImage(self
, index
, which
=wx
.TreeItemIcon_Normal
, column
=0):
322 ''' This function may be overloaded in the derived class. It
323 should return the index of the image to be used. Don't forget
324 to associate an ImageList with the tree control. '''
327 def OnGetItemType(self
, index
):
328 ''' This function may be overloaded in the derived class, but
329 that only makes sense when this class is mixed in with a tree
330 control that supports checkable items, i.e. CustomTreeCtrl.
331 This method should return whether the item is to be normal (0,
332 the default), a checkbox (1) or a radiobutton (2).
333 Note that OnGetItemChecked needs to be implemented as well; it
334 should return whether the item is actually checked. '''
337 def OnGetItemChecked(self
, index
):
338 ''' This function may be overloaded in the derived class, but
339 that only makes sense when this class is mixed in with a tree
340 control that supports checkable items, i.e. CustomTreeCtrl.
341 This method should return whether the item is to be checked.
342 Note that OnGetItemType should return 1 (checkbox) or 2
343 (radiobutton) for this item. '''
346 def RefreshItems(self
):
347 ''' Redraws all visible items. '''
348 rootItem
= self
.GetRootItem()
350 rootItem
= self
.AddRoot('Hidden root')
351 self
.RefreshChildrenRecursively(rootItem
)
353 def RefreshItem(self
, index
):
354 ''' Redraws the item with the specified index. '''
356 item
= self
.GetItemByIndex(index
)
358 # There's no corresponding item for index, because its parent
359 # has not been expanded yet.
361 hasChildren
= bool(self
.OnGetChildrenCount(index
))
362 self
.DoRefreshItem(item
, index
, hasChildren
)
364 def RefreshChildrenRecursively(self
, item
, itemIndex
=None):
365 ''' Refresh the children of item, reusing as much of the
366 existing items in the tree as possible. '''
367 if itemIndex
is None:
368 itemIndex
= self
.GetIndexOfItem(item
)
369 reusableChildren
= self
.GetItemChildren(item
)
370 for childIndex
in self
.ChildIndices(itemIndex
):
372 child
= reusableChildren
.pop(0)
374 child
= self
.AppendItem(item
, '')
375 self
.RefreshItemRecursively(child
, childIndex
)
376 for child
in reusableChildren
:
379 def RefreshItemRecursively(self
, item
, itemIndex
):
380 ''' Refresh the item and its children recursively. '''
381 hasChildren
= bool(self
.OnGetChildrenCount(itemIndex
))
382 item
= self
.DoRefreshItem(item
, itemIndex
, hasChildren
)
383 # We need to refresh the children when the item is expanded and
384 # when the item has no children, because in the latter case we
385 # might have to delete old children from the tree:
386 if self
.IsExpanded(item
) or not hasChildren
:
387 self
.RefreshChildrenRecursively(item
, itemIndex
)
388 self
.SetItemHasChildren(item
, hasChildren
)
390 def DoRefreshItem(self
, item
, index
, hasChildren
):
391 ''' Refresh one item. '''
392 item
= self
.RefreshItemType(item
, index
)
393 self
.RefreshItemText(item
, index
)
394 self
.RefreshColumns(item
, index
)
395 self
.RefreshItemFont(item
, index
)
396 self
.RefreshTextColour(item
, index
)
397 self
.RefreshBackgroundColour(item
, index
)
398 self
.RefreshItemImage(item
, index
, hasChildren
)
399 self
.RefreshCheckedState(item
, index
)
402 def RefreshItemText(self
, item
, index
):
403 self
.__refreshAttribute
(item
, index
, 'ItemText')
405 def RefreshColumns(self
, item
, index
):
406 for columnIndex
in range(1, self
.GetColumnCount()):
407 self
.__refreshAttribute
(item
, index
, 'ItemText', columnIndex
)
409 def RefreshItemFont(self
, item
, index
):
410 self
.__refreshAttribute
(item
, index
, 'ItemFont')
412 def RefreshTextColour(self
, item
, index
):
413 self
.__refreshAttribute
(item
, index
, 'ItemTextColour')
415 def RefreshBackgroundColour(self
, item
, index
):
416 self
.__refreshAttribute
(item
, index
, 'ItemBackgroundColour')
418 def RefreshItemImage(self
, item
, index
, hasChildren
):
419 regularIcons
= [wx
.TreeItemIcon_Normal
, wx
.TreeItemIcon_Selected
]
420 expandedIcons
= [wx
.TreeItemIcon_Expanded
,
421 wx
.TreeItemIcon_SelectedExpanded
]
422 # Refresh images in first column:
423 for icon
in regularIcons
:
424 self
.__refreshAttribute
(item
, index
, 'ItemImage', icon
)
425 for icon
in expandedIcons
:
427 imageIndex
= self
.OnGetItemImage(index
, icon
)
430 if self
.GetItemImage(item
, icon
) != imageIndex
or imageIndex
== -1:
431 self
.SetItemImage(item
, imageIndex
, icon
)
432 # Refresh images in remaining columns, if any:
433 for columnIndex
in range(1, self
.GetColumnCount()):
434 for icon
in regularIcons
:
435 self
.__refreshAttribute
(item
, index
, 'ItemImage', icon
,
438 def RefreshItemType(self
, item
, index
):
439 return self
.__refreshAttribute
(item
, index
, 'ItemType')
441 def RefreshCheckedState(self
, item
, index
):
442 self
.__refreshAttribute
(item
, index
, 'ItemChecked')
444 def ChildIndices(self
, itemIndex
):
445 childrenCount
= self
.OnGetChildrenCount(itemIndex
)
446 return [itemIndex
+ (childNumber
,) for childNumber \
447 in range(childrenCount
)]
449 def OnItemExpanding(self
, event
):
450 self
.RefreshChildrenRecursively(event
.GetItem())
453 def OnItemCollapsed(self
, event
):
454 parent
= self
.GetItemParent(event
.GetItem())
456 parent
= self
.GetRootItem()
457 self
.RefreshChildrenRecursively(parent
)
460 def __refreshAttribute(self
, item
, index
, attribute
, *args
):
461 ''' Refresh the specified attribute if necessary. '''
462 value
= getattr(self
, 'OnGet%s'%attribute
)(index
, *args
)
463 if getattr(self
, 'Get%s'%attribute
)(item
, *args
) != value
:
464 return getattr(self
, 'Set%s'%attribute
)(item
, value
, *args
)
469 class DragAndDrop(TreeAPIHarmonizer
, TreeHelper
):
470 ''' This is a mixin class that can be used to easily implement
471 dragging and dropping of tree items. It can be mixed in with
472 wx.TreeCtrl, wx.gizmos.TreeListCtrl, or wx.lib.customtree.CustomTreeCtrl.
474 To use it derive a new class from this class and one of the tree
476 class MyTree(DragAndDrop, wx.TreeCtrl):
479 You *must* implement OnDrop. OnDrop is called when the user has
480 dropped an item on top of another item. It's up to you to decide how
481 to handle the drop. If you are using this mixin together with the
482 VirtualTree mixin, it makes sense to rearrange your underlying data
483 and then call RefreshItems to let the virtual tree refresh itself. '''
485 def __init__(self
, *args
, **kwargs
):
486 kwargs
['style'] = kwargs
.get('style', wx
.TR_DEFAULT_STYLE
) | \
488 super(DragAndDrop
, self
).__init
__(*args
, **kwargs
)
489 self
.Bind(wx
.EVT_TREE_BEGIN_DRAG
, self
.OnBeginDrag
)
491 def OnDrop(self
, dropItem
, dragItem
):
492 ''' This function must be overloaded in the derived class.
493 dragItem is the item being dragged by the user. dropItem is the
494 item dragItem is dropped upon. If the user doesn't drop dragItem
495 on another item, dropItem equals the (hidden) root item of the
497 raise NotImplementedError
499 def OnBeginDrag(self
, event
):
500 # We allow only one item to be dragged at a time, to keep it simple
501 self
._dragItem
= event
.GetItem()
502 if self
._dragItem
and self
._dragItem
!= self
.GetRootItem():
508 def OnEndDrag(self
, event
):
510 dropTarget
= event
.GetItem()
512 dropTarget
= self
.GetRootItem()
513 if self
.IsValidDropTarget(dropTarget
):
515 if dropTarget
!= self
.GetRootItem():
516 self
.SelectItem(dropTarget
)
517 self
.OnDrop(dropTarget
, self
._dragItem
)
519 def OnDragging(self
, event
):
520 if not event
.Dragging():
523 item
, flags
, column
= self
.HitTest(wx
.Point(event
.GetX(), event
.GetY()),
524 alwaysReturnColumn
=True)
526 item
= self
.GetRootItem()
527 if self
.IsValidDropTarget(item
):
528 self
.SetCursorToDragging()
530 self
.SetCursorToDroppingImpossible()
531 if flags
& wx
.TREE_HITTEST_ONITEMBUTTON
:
533 if self
.GetSelections() != [item
]:
535 if item
!= self
.GetRootItem():
536 self
.SelectItem(item
)
539 def StartDragging(self
):
540 self
.GetMainWindow().Bind(wx
.EVT_MOTION
, self
.OnDragging
)
541 self
.Bind(wx
.EVT_TREE_END_DRAG
, self
.OnEndDrag
)
542 self
.SetCursorToDragging()
544 def StopDragging(self
):
545 self
.GetMainWindow().Unbind(wx
.EVT_MOTION
)
546 self
.Unbind(wx
.EVT_TREE_END_DRAG
)
549 self
.SelectItem(self
._dragItem
)
551 def SetCursorToDragging(self
):
552 self
.GetMainWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_HAND
))
554 def SetCursorToDroppingImpossible(self
):
555 self
.GetMainWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_NO_ENTRY
))
557 def ResetCursor(self
):
558 self
.GetMainWindow().SetCursor(wx
.NullCursor
)
560 def IsValidDropTarget(self
, dropTarget
):
562 allChildren
= self
.GetItemChildren(self
._dragItem
, recursively
=True)
563 parent
= self
.GetItemParent(self
._dragItem
)
564 return dropTarget
not in [self
._dragItem
, parent
] + allChildren
569 class ExpansionState(TreeAPIHarmonizer
, TreeHelper
):
570 ''' This is a mixin class that can be used to save and restore
571 the expansion state (i.e. which items are expanded and which items
572 are collapsed) of a tree. It can be mixed in with wx.TreeCtrl,
573 wx.gizmos.TreeListCtrl, or wx.lib.customtree.CustomTreeCtrl.
575 To use it derive a new class from this class and one of the tree
577 class MyTree(ExpansionState, wx.TreeCtrl):
580 By default, ExpansionState uses the position of tree items in the tree
581 to keep track of which items are expanded. This should be sufficient
582 for the simple scenario where you save the expansion state of the tree
583 when the user closes the application or file so that you can restore
584 the expansion state when the user start the application or loads that
585 file for the next session.
587 If you need to add or remove items between the moments of saving and
588 restoring the expansion state (e.g. in case of a multi-user application)
589 you must override GetItemIdentity so that saving and loading of the
590 expansion doesn't depend on the position of items in the tree, but
591 rather on some more stable characteristic of the underlying domain
592 object, e.g. a social security number in case of persons or an isbn
593 number in case of books. '''
595 def GetItemIdentity(self
, item
):
596 ''' Return a hashable object that represents the identity of the
597 item. By default this returns the position of the item in the
598 tree. You may want to override this to return the item label
599 (if you know that labels are unique and don't change), or return
600 something that represents the underlying domain object, e.g.
602 return self
.GetIndexOfItem(item
)
604 def GetExpansionState(self
):
605 ''' GetExpansionState() -> list of expanded items. Expanded items
606 are coded as determined by the result of GetItemIdentity(item). '''
607 root
= self
.GetRootItem()
610 if self
.HasFlag(wx
.TR_HIDE_ROOT
):
611 return self
.GetExpansionStateOfChildren(root
)
613 return self
.GetExpansionStateOfItem(root
)
615 def SetExpansionState(self
, listOfExpandedItems
):
616 ''' SetExpansionState(listOfExpandedItems). Expands all tree items
617 whose identity, as determined by GetItemIdentity(item), is present
618 in the list and collapses all other tree items. '''
619 root
= self
.GetRootItem()
622 if self
.HasFlag(wx
.TR_HIDE_ROOT
):
623 self
.SetExpansionStateOfChildren(listOfExpandedItems
, root
)
625 self
.SetExpansionStateOfItem(listOfExpandedItems
, root
)
627 ExpansionState
= property(GetExpansionState
, SetExpansionState
)
629 def GetExpansionStateOfItem(self
, item
):
630 listOfExpandedItems
= []
631 if self
.IsExpanded(item
):
632 listOfExpandedItems
.append(self
.GetItemIdentity(item
))
633 listOfExpandedItems
.extend(self
.GetExpansionStateOfChildren(item
))
634 return listOfExpandedItems
636 def GetExpansionStateOfChildren(self
, item
):
637 listOfExpandedItems
= []
638 for child
in self
.GetItemChildren(item
):
639 listOfExpandedItems
.extend(self
.GetExpansionStateOfItem(child
))
640 return listOfExpandedItems
642 def SetExpansionStateOfItem(self
, listOfExpandedItems
, item
):
643 if self
.GetItemIdentity(item
) in listOfExpandedItems
:
645 self
.SetExpansionStateOfChildren(listOfExpandedItems
, item
)
649 def SetExpansionStateOfChildren(self
, listOfExpandedItems
, item
):
650 for child
in self
.GetItemChildren(item
):
651 self
.SetExpansionStateOfItem(listOfExpandedItems
, child
)