diff --git a/wxPython/demo/TreeMixin.py b/wxPython/demo/TreeMixin.py index f4b2c131b0..145370a4bf 100644 --- a/wxPython/demo/TreeMixin.py +++ b/wxPython/demo/TreeMixin.py @@ -104,9 +104,9 @@ class DemoTreeMixin(treemixin.VirtualTree, treemixin.DragAndDrop, return 1 def OnDrop(self, dropTarget, dragItem): - dropIndex = self.ItemIndex(dropTarget) + dropIndex = self.GetIndoxOfItem(dropTarget) dropText = self.model.GetText(dropIndex) - dragIndex = self.ItemIndex(dragItem) + dragIndex = self.GetIndexOfItem(dragItem) dragText = self.model.GetText(dragIndex) self.log.write('drop %s %s on %s %s'%(dragText, dragIndex, dropText, dropIndex)) @@ -168,7 +168,7 @@ class VirtualCustomTreeCtrl(DemoTreeMixin, def OnItemChecked(self, event): item = event.GetItem() - itemIndex = self.ItemIndex(item) + itemIndex = self.GetIndexOfItem(item) if self.GetItemType(item) == 2: # It's a radio item; reset other items on the same level for nr in range(self.GetChildrenCount(self.GetItemParent(item))): @@ -201,7 +201,7 @@ class TreeNotebook(wx.Notebook): def GetIndicesOfSelectedItems(self): tree = self.trees[self.GetSelection()] if tree.GetSelections(): - return [tree.ItemIndex(item) for item in tree.GetSelections()] + return [tree.GetIndexOfItem(item) for item in tree.GetSelections()] else: return [()] diff --git a/wxPython/docs/CHANGES.txt b/wxPython/docs/CHANGES.txt index 9c0e638ce2..bd7ef1ba07 100644 --- a/wxPython/docs/CHANGES.txt +++ b/wxPython/docs/CHANGES.txt @@ -1,9 +1,20 @@ Recent Changes for wxPython ===================================================================== +2.8.3.1 +------- +* + +wxGTK: Make wx.NO_BORDER style work with wx.RadioBox (patch 1525406) + +Update to 0.9 of TreeMixin. + + + + 2.8.3.0 ------- -* +* 22-March-2007 Added wx.ToolBar.SetToolNormalBitmap and SetToolDisabledBitmap methods. (Keep in mind however that the disabled bitmap is currently diff --git a/wxPython/tests/TreeMixinTest.py b/wxPython/tests/TreeMixinTest.py index 08315b1d04..a967b80568 100644 --- a/wxPython/tests/TreeMixinTest.py +++ b/wxPython/tests/TreeMixinTest.py @@ -1,4 +1,5 @@ -import wx, wx.gizmos, wx.lib.customtreectrl, unittest, treemixin +import wx, wx.gizmos, wx.lib.customtreectrl, unittest +from wx.lib.mixins import treemixin # VirtualTree tests @@ -51,13 +52,9 @@ class TreeCtrl(object): self.checked[index] = checked -class VirtualTreeCtrlWithTreeIndices(TreeCtrl, treemixin.VirtualTree, +class VirtualTreeCtrl(TreeCtrl, treemixin.VirtualTree, wx.lib.customtreectrl.CustomTreeCtrl): - def __init__(self, *args, **kwargs): - kwargs['tupleIndex'] = True - super(VirtualTreeCtrlWithTreeIndices, self).__init__(*args, **kwargs) - def OnGetItemText(self, indices): return 'item %s'%'.'.join([str(index) for index in indices]) @@ -69,27 +66,11 @@ class VirtualTreeCtrlWithTreeIndices(TreeCtrl, treemixin.VirtualTree, self.children[index] = childrenCount -class VirtualTreeCtrlWithListIndices(TreeCtrl, treemixin.VirtualTree, - wx.lib.customtreectrl.CustomTreeCtrl): - def __init__(self, *args, **kwargs): - kwargs['tupleIndex'] = False - super(VirtualTreeCtrlWithListIndices, self).__init__(*args, **kwargs) - - def OnGetItemText(self, index): - return 'item %d'%index - - def OnGetChildrenIndices(self, index=None): - return self.children.get(index, []) - - def PrepareChildrenIndices(self, index, indices): - self.children[index] = indices - - -class VirtualTreeCtrlTestWithTreeIndices_NoRootItems(unittest.TestCase): +class VirtualTreeCtrlTest_NoRootItems(unittest.TestCase): def setUp(self): self.frame = wx.Frame(None) - self.tree = VirtualTreeCtrlWithTreeIndices(self.frame) + self.tree = VirtualTreeCtrl(self.frame) self.tree.RefreshItems() def testNoRootItems(self): @@ -115,39 +96,11 @@ class VirtualTreeCtrlTestWithTreeIndices_NoRootItems(unittest.TestCase): self.assertEqual(3, self.tree.GetCount()) -class VirtualTreeCtrlWithListIndicesTest_NoRootItems(unittest.TestCase): + +class VirtualTreeCtrlTest_OneRoot(unittest.TestCase): def setUp(self): self.frame = wx.Frame(None) - self.tree = VirtualTreeCtrlWithListIndices(self.frame) - self.tree.RefreshItems() - - def testNoRootItems(self): - self.assertEqual(0, self.tree.GetCount()) - - def testAddTwoRootItems(self): - self.tree.PrepareChildrenIndices(None, [0,1]) - self.tree.RefreshItems() - self.assertEqual(2, self.tree.GetCount()) - - def testAddOneRootItemAndOneChild(self): - self.tree.PrepareChildrenIndices(None, [0]) - self.tree.PrepareChildrenIndices(0, [1]) - self.tree.RefreshItems() - self.tree.ExpandAll() - self.assertEqual(2, self.tree.GetCount()) - - def testAddOneRootItemAndTwoChildren(self): - self.tree.PrepareChildrenIndices(None, [0]) - self.tree.PrepareChildrenIndices(0, [1,2]) - self.tree.RefreshItems() - self.tree.ExpandAll() - self.assertEqual(3, self.tree.GetCount()) - - -class VirtualTreeCtrlTestWithTreeIndices_OneRoot(unittest.TestCase): - def setUp(self): - self.frame = wx.Frame(None) - self.tree = VirtualTreeCtrlWithTreeIndices(self.frame) + self.tree = VirtualTreeCtrl(self.frame) self.tree.PrepareChildrenCount((), 1) self.tree.RefreshItems() @@ -202,65 +155,19 @@ class VirtualTreeCtrlTestWithTreeIndices_OneRoot(unittest.TestCase): item, cookie = self.tree.GetFirstChild(self.tree.GetRootItem()) self.failUnless(self.tree.IsItemChecked(item)) - -class VirtualTreeCtrlWithListIndicesTest_OneRoot(unittest.TestCase): - def setUp(self): - self.frame = wx.Frame(None) - self.tree = VirtualTreeCtrlWithListIndices(self.frame) - self.tree.PrepareChildrenIndices(None, [0]) - self.tree.RefreshItems() - - def testOneRoot(self): - self.assertEqual(1, self.tree.GetCount()) - - def testDeleteRootItem(self): - self.tree.PrepareChildrenIndices(None, []) - self.tree.RefreshItems() - self.assertEqual(0, self.tree.GetCount()) - - def testAddOneChild(self): - self.tree.PrepareChildrenIndices(0, [1]) - self.tree.RefreshItems() - self.tree.ExpandAll() - self.assertEqual(2, self.tree.GetCount()) - - def testAddTwoChildren(self): - self.tree.PrepareChildrenIndices(0, [1,2]) - self.tree.RefreshItems() - self.tree.ExpandAll() - self.assertEqual(3, self.tree.GetCount()) - - def testChangeFont(self): - self.tree.PrepareItemFont(0, wx.SMALL_FONT) + def testChangeTypeAndAddChildren(self): + self.tree.PrepareType((0,), 1) + self.tree.PrepareChildrenCount((0,), 1) self.tree.RefreshItems() item, cookie = self.tree.GetFirstChild(self.tree.GetRootItem()) - self.assertEqual(wx.SMALL_FONT, self.tree.GetItemFont(item)) + self.failUnless(self.tree.ItemHasChildren(item)) - def testChangeColour(self): - self.tree.PrepareItemColour(0, wx.RED) - self.tree.RefreshItems() + def testRefreshItem(self): + self.tree.PrepareItemColour((0,), wx.RED) + self.tree.RefreshItem((0,)) item, cookie = self.tree.GetFirstChild(self.tree.GetRootItem()) self.assertEqual(wx.RED, self.tree.GetItemTextColour(item)) - def testChangeBackgroundColour(self): - self.tree.PrepareItemBackgroundColour(0, wx.RED) - self.tree.RefreshItems() - item, cookie = self.tree.GetFirstChild(self.tree.GetRootItem()) - self.assertEqual(wx.RED, self.tree.GetItemBackgroundColour(item)) - - def testChangeImage(self): - self.tree.PrepareImage(0, 0) - self.tree.RefreshItems() - item, cookie = self.tree.GetFirstChild(self.tree.GetRootItem()) - self.assertEqual(0, self.tree.GetItemImage(item)) - - def testChangeType(self): - self.tree.PrepareType(0, 2) - self.tree.PrepareChecked(0, True) - self.tree.RefreshItems() - item, cookie = self.tree.GetFirstChild(self.tree.GetRootItem()) - self.failUnless(self.tree.IsItemChecked(item)) - # TreeAPIHarmonizer tests @@ -272,6 +179,7 @@ class TreeAPIHarmonizerTestCase(unittest.TestCase): class HarmonizedTreeCtrl(treemixin.TreeAPIHarmonizer, self.TreeClass): pass self.tree = HarmonizedTreeCtrl(self.frame, style=self.style) + self.eventsReceived = [] self.populateTree() def populateTree(self): @@ -279,6 +187,9 @@ class TreeAPIHarmonizerTestCase(unittest.TestCase): self.item = self.tree.AppendItem(self.root, 'Item') self.items = [self.root, self.item] + def onEvent(self, event): + self.eventsReceived.append(event) + class TreeAPIHarmonizerCommonTests(object): ''' Tests that should succeed for all tree controls and all styles. ''' @@ -318,6 +229,14 @@ class TreeAPIHarmonizerCommonTests(object): self.assertEqual(-1, self.tree.GetItemImage(self.item, wx.TreeItemIcon_Selected, 1)) + def testExpandAll(self): + self.tree.ExpandAll() + + def testExpandAllChildren(self): + self.tree.AppendItem(self.item, 'child') + self.tree.ExpandAllChildren(self.item) + self.failUnless(self.tree.IsExpanded(self.item)) + class TreeAPIHarmonizerNoTreeListCtrlCommonTests(object): ''' Tests that should succeed for all tree controls, except the @@ -378,7 +297,6 @@ class TreeAPIHarmonizerMultipleSelectionTests(object): self.assertEqual([self.item, item2], self.tree.GetSelections()) - class TreeAPIHarmonizerVisibleRootTests(object): ''' Tests that should succeed for all tree controls when the root item is not hidden. ''' @@ -405,7 +323,6 @@ class TreeAPIHarmonizerHiddenRootTests(object): self.assertEqual([], self.tree.GetSelections()) - class TreeAPIHarmonizerWithTreeCtrlTestCase(TreeAPIHarmonizerTestCase): TreeClass = wx.TreeCtrl @@ -564,63 +481,64 @@ class TreeHelperTestCase(unittest.TestCase): self.child = self.tree.AppendItem(self.item, 'Child') -class TreeHelperVisibleRootTests(object): - def testIntegerIndexRootItem(self): - self.assertEqual(0, self.tree.ItemIndex(self.root, tupleIndex=False)) +class TreeHelperCommonTests(object): + def testGetItemChildren_EmptyTree(self): + self.tree.DeleteAllItems() + self.assertEqual([], self.tree.GetItemChildren()) - def testIntegerIndexRegularItem(self): - self.assertEqual(1, self.tree.ItemIndex(self.item, tupleIndex=False)) + def testGetItemChildren_NoParent(self): + self.assertEqual([self.item], self.tree.GetItemChildren()) - def testIntegerIndexChild(self): - self.assertEqual(2, self.tree.ItemIndex(self.child, tupleIndex=False)) + def testGetItemChildren_RootItem(self): + self.assertEqual([self.item], self.tree.GetItemChildren(self.root)) - def testTupleIndexRootItem(self): - self.assertEqual((), self.tree.ItemIndex(self.root)) + def testGetItemChildren_RegularItem(self): + self.assertEqual([self.child], self.tree.GetItemChildren(self.item)) - def testTupleIndexRegularItem(self): - self.assertEqual((0,), self.tree.ItemIndex(self.item)) + def testGetItemChildren_ItemWithoutChildren(self): + self.assertEqual([], self.tree.GetItemChildren(self.child)) - def testTupleIndexChild(self): - self.assertEqual((0,0), self.tree.ItemIndex(self.child)) + def testGetItemChildren_NoParent_Recursively(self): + self.assertEqual([self.item, self.child], + self.tree.GetItemChildren(recursively=True)) + + def testGetItemChildren_RootItem_Recursively(self): + self.assertEqual([self.item, self.child], + self.tree.GetItemChildren(self.root, True)) + + def testGetItemChildren_RegularItem_Recursively(self): + self.assertEqual([self.child], + self.tree.GetItemChildren(self.item, True)) + + def testGetItemChildren_ItemWithoutChildren_Recursively(self): + self.assertEqual([], self.tree.GetItemChildren(self.child, True)) + + def testGetItemByIndex_RootItem(self): + self.assertEqual(self.root, self.tree.GetItemByIndex(())) + + def testGetItemByIndex_RegularItem(self): + self.assertEqual(self.item, self.tree.GetItemByIndex((0,))) + + def testGetItemByIndex_Child(self): + self.assertEqual(self.child, self.tree.GetItemByIndex((0,0))) + + def testGetIndexOfItemRootItem(self): + self.assertEqual((), self.tree.GetIndexOfItem(self.root)) + + def testGetIndexOfItemRegularItem(self): + self.assertEqual((0,), self.tree.GetIndexOfItem(self.item)) + + def testGetIndexOfItemChild(self): + self.assertEqual((0,0), self.tree.GetIndexOfItem(self.child)) -class TreeHelperHiddenRootTests(object): - style = wx.TR_HIDE_ROOT - - def testIntegerIndexRootItem(self): - self.assertEqual(None, self.tree.ItemIndex(self.root, tupleIndex=False)) - - def testIntegerIndexRegularItem(self): - self.assertEqual(0, self.tree.ItemIndex(self.item, tupleIndex=False)) - - def testIntegerIndexChild(self): - self.assertEqual(1, self.tree.ItemIndex(self.child, tupleIndex=False)) - - def testTupleIndexRootItem(self): - self.assertEqual((), self.tree.ItemIndex(self.root)) - - def testTupleIndexRegularItem(self): - self.assertEqual((0,), self.tree.ItemIndex(self.item)) - - def testTupleIndexChild(self): - self.assertEqual((0,0), self.tree.ItemIndex(self.child)) - - -class TreeHelperWithTreeCtrlTestCase(TreeHelperTestCase): +class TreeHelperWithTreeCtrlTestCase(TreeHelperCommonTests, + TreeHelperTestCase): TreeClass = wx.TreeCtrl -class TreeHelperWithTreeCtrl_VisibleRoot(TreeHelperVisibleRootTests, - TreeHelperWithTreeCtrlTestCase): - pass - - -class TreeHelperWithTreeCtrl_HiddenRoot(TreeHelperHiddenRootTests, - TreeHelperWithTreeCtrlTestCase): - pass - - -class TreeHelperWithTreeListCtrlTestCase(TreeHelperTestCase): +class TreeHelperWithTreeListCtrlTestCase(TreeHelperCommonTests, + TreeHelperTestCase): TreeClass = wx.gizmos.TreeListCtrl def populateTree(self): @@ -628,29 +546,11 @@ class TreeHelperWithTreeListCtrlTestCase(TreeHelperTestCase): super(TreeHelperWithTreeListCtrlTestCase, self).populateTree() -class TreeHelperWithTreeListCtrl_VisibleRoot(TreeHelperVisibleRootTests, - TreeHelperWithTreeListCtrlTestCase): - pass - - -class TreeHelperWithTreeListCtrl_HiddenRoot(TreeHelperHiddenRootTests, - TreeHelperWithTreeListCtrlTestCase): - pass - -class TreeHelperWithCustomTreeCtrlTestCase(TreeHelperTestCase): +class TreeHelperWithCustomTreeCtrlTestCase(TreeHelperCommonTests, + TreeHelperTestCase): TreeClass = wx.lib.customtreectrl.CustomTreeCtrl -class TreeHelperWithCustomTreeCtrl_VisibleRoot(TreeHelperVisibleRootTests, - TreeHelperWithCustomTreeCtrlTestCase): - pass - - -class TreeHelperWithCustomTreeCtrl_HiddenRoot(TreeHelperHiddenRootTests, - TreeHelperWithCustomTreeCtrlTestCase): - pass - - # ExpansionState tests class ExpansionStateTreeCtrl(treemixin.ExpansionState, wx.TreeCtrl): @@ -769,6 +669,58 @@ class SetExpansionStateTestCase(unittest.TestCase): self.failUnless(self.tree.IsExpanded(grandChild)) +# Tests of the tree controls without any mixin, to document behaviour that +# already works, and works the same, for all tree control widgets + +class VanillaTreeTestCase(unittest.TestCase): + style = wx.TR_DEFAULT_STYLE + + def setUp(self): + self.frame = wx.Frame(None) + self.tree = self.TreeClass(self.frame, style=self.style) + self.eventsReceived = [] + self.populateTree() + + def populateTree(self): + self.root = self.tree.AddRoot('Root') + self.item = self.tree.AppendItem(self.root, 'Item') + self.items = [self.root, self.item] + + def onEvent(self, event): + self.eventsReceived.append(event) + + +class VanillaTreeCommonTests(object): + ''' Tests that should succeed for all tree controls and all styles. ''' + + def testSetItemHasChildren(self): + self.tree.SetItemHasChildren(self.item, True) + self.failUnless(self.tree.ItemHasChildren(self.item)) + + def testExpandItemWithPlus(self): + self.tree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.onEvent) + self.tree.SetItemHasChildren(self.item, True) + self.tree.Expand(self.item) + self.assertEqual(1, len(self.eventsReceived)) + + +class VanillaTreeCtrlTestCase(VanillaTreeCommonTests, VanillaTreeTestCase): + TreeClass = wx.TreeCtrl + + +class VanillaTreeListCtrlTestCase(VanillaTreeCommonTests, VanillaTreeTestCase): + TreeClass = wx.gizmos.TreeListCtrl + + def populateTree(self): + self.tree.AddColumn('Column 0') + super(VanillaTreeListCtrlTestCase, self).populateTree() + + +class VanillaCustomTreeCtrlTestCase(VanillaTreeCommonTests, + VanillaTreeTestCase): + TreeClass = wx.lib.customtreectrl.CustomTreeCtrl + + if __name__ == '__main__': app = wx.App(False) unittest.main() diff --git a/wxPython/wx/lib/mixins/treemixin.py b/wxPython/wx/lib/mixins/treemixin.py index be51284074..996101c5de 100644 --- a/wxPython/wx/lib/mixins/treemixin.py +++ b/wxPython/wx/lib/mixins/treemixin.py @@ -25,8 +25,8 @@ The VirtualTree and DragAndDrop mixins force the wx.TR_HIDE_ROOT style. Author: Frank Niessink License: wxWidgets license -Version: 0.8 -Date: 13 March 2007 +Version: 0.9 +Date: 18 March 2007 ExpansionState is based on code and ideas from Karsten Hilbert. Andrea Gavana provided help with the CustomTreeCtrl integration. @@ -179,21 +179,45 @@ class TreeAPIHarmonizer(object): def ExpandAll(self, item=None): # TreeListCtrl wants an item as argument. That's an inconsistency with - # the TreeCtrl API. + # the TreeCtrl API. Also, TreeCtrl doesn't allow invoking ExpandAll + # on a tree with hidden root node, so prevent that. + if self.HasFlag(wx.TR_HIDE_ROOT): + rootItem = self.GetRootItem() + if rootItem: + child, cookie = self.GetFirstChild(rootItem) + while child: + self.ExpandAllChildren(child) + child, cookie = self.GetNextChild(rootItem, cookie) + else: + try: + super(TreeAPIHarmonizer, self).ExpandAll() + except TypeError: + if item is None: + item = self.GetRootItem() + super(TreeAPIHarmonizer, self).ExpandAll(item) + + def ExpandAllChildren(self, item): + # TreeListCtrl and CustomTreeCtrl don't have ExpandallChildren try: - super(TreeAPIHarmonizer, self).ExpandAll() - except TypeError: - if item is None: - item = self.GetRootItem() - super(TreeAPIHarmonizer, self).ExpandAll(item) + super(TreeAPIHarmonizer, self).ExpandAllChildren(item) + except AttributeError: + self.Expand(item) + child, cookie = self.GetFirstChild(item) + while child: + self.ExpandAllChildren(child) + child, cookie = self.GetNextChild(item, cookie) class TreeHelper(object): ''' This class provides methods that are not part of the API of any tree control, but are convenient to have available. ''' - def GetItemChildren(self, item, recursively=False): + def GetItemChildren(self, item=None, recursively=False): ''' Return the children of item as a list. ''' + if not item: + item = self.GetRootItem() + if not item: + return [] children = [] child, cookie = self.GetFirstChild(item) while child: @@ -203,29 +227,23 @@ class TreeHelper(object): child, cookie = self.GetNextChild(item, cookie) return children - def ItemIndex(self, item, tupleIndex=True): - ''' Return the index of item. If tupleIndex is True, return a - an tuple-based index else return an integer-based index for item. ''' - if tupleIndex: - parent = self.GetItemParent(item) - if parent: - parentIndices = self.ItemIndex(parent) - ownIndex = self.GetItemChildren(parent).index(item) - return parentIndices + (ownIndex,) - else: - return () + def GetIndexOfItem(self, item): + ''' Return the index of item. ''' + parent = self.GetItemParent(item) + if parent: + parentIndices = self.GetIndexOfItem(parent) + ownIndex = self.GetItemChildren(parent).index(item) + return parentIndices + (ownIndex,) else: - rootItem = self.GetRootItem() - if self.HasFlag(wx.TR_HIDE_ROOT): - if item == rootItem: - return None - countRoot = 0 - else: - if item == rootItem: - return 0 - countRoot = 1 - return self.GetItemChildren(rootItem, - recursively=True).index(item) + countRoot + return () + + def GetItemByIndex(self, index): + ''' Return the item specified by index. ''' + item = self.GetRootItem() + for i in index: + children = self.GetItemChildren(item) + item = children[i] + return item class VirtualTree(TreeAPIHarmonizer, TreeHelper): @@ -241,73 +259,44 @@ class VirtualTree(TreeAPIHarmonizer, TreeHelper): VirtualTree uses several callbacks (such as OnGetItemText) to retrieve information needed to construct the tree and render the items. To specify what item the callback needs information about, - the callback passes an item index. VirtualTree supports two types of - indices: a tuple-based index (the default) and an integer based index. - See below for a more detailed explanation of the two index types. + the callback passes an item index. Whereas for list controls a simple + integer index can be used, for tree controls indicating a specific + item is a little bit more complicated. See below for a more detailed + explanation of the how index works. Note that VirtualTree forces the wx.TR_HIDE_ROOT style. - In your subclass you *must* override OnGetItemText and either - OnGetChildrenCount if you use the tuple-based index or - OnGetChildrenIndices if you use the integer-based index. These - methods are the minimum needed to construct the tree and render - the item labels. If you want to add images, change fonts our colours, - etc., you need to override the appropriate OnGetXXX method as well. + In your subclass you *must* override OnGetItemText and + OnGetChildrenCount. These two methods are the minimum needed to + construct the tree and render the item labels. If you want to add + images, change fonts our colours, etc., you need to override the + appropriate OnGetXXX method as well. - About the index types: VirtualTree supports two types of indices that - are passed to the several callbacks to retrieve information about - items in the tree. The default index type is tuple-based, the second - type is integer-based. - - If you use tuple-based indices, your callbacks are passed a tuple of - integers that identifies the item the VirtualTree wants information - about. An empty tuple, i.e. (), represents the hidden root item. - A tuple with one integer, e.g. (3,), represents a visible root item, - in this case the fourth one. A tuple with two integers, e.g. (3,0), - represents a child of a visible root item, in this case the first - child of the fourth root item. The tuple-based index is best suited - if your underlying data structure is organized as a tree and allows - for easy navigation to the right object in your tree data structure. - - If you use integer-based indices, your callbacks are passed a simple - integer (or None) that identifies the item the VirtualTree wants - information about. None represents the hidden root item. Zero (0) - represents the first visible root item. If the first visible root - item has children 1 represents the first child of the first visible - root item. If that child has children 2 represents the first grand - child of the first visible root item. If the first child has no - children, 2 would represent the second child of the first visible - root item, etc. Basically, the integer is the row number of the item - (when the tree is completely expanded). Integer-based indices are - more convenient when your underlying data structure is organized as - a list that is in the same order as the tree items in the tree need - to be. + About indices: your callbacks are passed a tuple of integers that + identifies the item the VirtualTree wants information about. An + empty tuple, i.e. (), represents the hidden root item. A tuple with + one integer, e.g. (3,), represents a visible root item, in this case + the fourth one. A tuple with two integers, e.g. (3,0), represents a + child of a visible root item, in this case the first child of the + fourth root item. ''' def __init__(self, *args, **kwargs): - self._tupleIndex = kwargs.pop('tupleIndex', True) kwargs['style'] = kwargs.get('style', wx.TR_DEFAULT_STYLE) | \ wx.TR_HIDE_ROOT super(VirtualTree, self).__init__(*args, **kwargs) self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnItemExpanding) self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed) - def OnGetChildrenCount(self, tupleIndex): - ''' This function must be overloaded in the derived class, if - you use the tuple-based indices. It should return the number - of child items of the item with the provided tupleIndex. If - tupleIndex == () it should return the number of root items. ''' - raise NotImplementedError - - def OnGetChildrenIndices(self, integerIndex=None): - ''' This function must be overloaded in the derived class, if - you want to use the integer-based index. The overridden method - should return a list containing the (integer) indices of the - children of the specified item. ''' + def OnGetChildrenCount(self, index): + ''' This function *must* be overloaded in the derived class. + It should return the number of child items of the item with the + provided index. If index == () it should return the number of + root items. ''' raise NotImplementedError def OnGetItemText(self, index, column=0): - ''' This function must be overloaded in the derived class. It + ''' This function *must* be overloaded in the derived class. It should return the string containing the text of the specified item. ''' raise NotImplementedError @@ -361,11 +350,17 @@ class VirtualTree(TreeAPIHarmonizer, TreeHelper): rootItem = self.AddRoot('Hidden root') self.RefreshChildrenRecursively(rootItem) + def RefreshItem(self, index): + ''' Redraws the item with the specified index. ''' + item = self.GetItemByIndex(index) + hasChildren = bool(self.OnGetChildrenCount(index)) + self.DoRefreshItem(item, index, hasChildren) + def RefreshChildrenRecursively(self, item, itemIndex=None): ''' Refresh the children of item, reusing as much of the existing items in the tree as possible. ''' if itemIndex is None: - itemIndex = self.ItemIndex(item, tupleIndex=self._tupleIndex) + itemIndex = self.GetIndexOfItem(item) reusableChildren = self.GetItemChildren(item) for childIndex in self.ChildIndices(itemIndex): if reusableChildren: @@ -378,8 +373,8 @@ class VirtualTree(TreeAPIHarmonizer, TreeHelper): def RefreshItemRecursively(self, item, itemIndex): ''' Refresh the item and its children recursively. ''' - hasChildren = bool(self.ChildIndices(itemIndex)) - self.RefreshItem(item, itemIndex, hasChildren) + hasChildren = bool(self.OnGetChildrenCount(itemIndex)) + item = self.DoRefreshItem(item, itemIndex, hasChildren) # We need to refresh the children when the item is expanded and # when the item has no children, because in the latter case we # might have to delete old children from the tree: @@ -387,7 +382,7 @@ class VirtualTree(TreeAPIHarmonizer, TreeHelper): self.RefreshChildrenRecursively(item, itemIndex) self.SetItemHasChildren(item, hasChildren) - def RefreshItem(self, item, index, hasChildren): + def DoRefreshItem(self, item, index, hasChildren): ''' Refresh one item. ''' item = self.RefreshItemType(item, index) self.RefreshItemText(item, index) @@ -397,6 +392,7 @@ class VirtualTree(TreeAPIHarmonizer, TreeHelper): self.RefreshBackgroundColour(item, index) self.RefreshItemImage(item, index, hasChildren) self.RefreshCheckedState(item, index) + return item def RefreshItemText(self, item, index): self.__refreshAttribute(item, index, 'ItemText') @@ -441,12 +437,9 @@ class VirtualTree(TreeAPIHarmonizer, TreeHelper): self.__refreshAttribute(item, index, 'ItemChecked') def ChildIndices(self, itemIndex): - if self._tupleIndex: - childrenCount = self.OnGetChildrenCount(itemIndex) - return [itemIndex + (childNumber,) for childNumber \ - in range(childrenCount)] - else: - return self.OnGetChildrenIndices(itemIndex) + childrenCount = self.OnGetChildrenCount(itemIndex) + return [itemIndex + (childNumber,) for childNumber \ + in range(childrenCount)] def OnItemExpanding(self, event): self.RefreshChildrenRecursively(event.GetItem()) @@ -601,7 +594,7 @@ class ExpansionState(TreeAPIHarmonizer, TreeHelper): (if you know that labels are unique and don't change), or return something that represents the underlying domain object, e.g. a database key. ''' - return self.ItemIndex(item) + return self.GetIndexOfItem(item) def GetExpansionState(self): ''' GetExpansionState() -> list of expanded items. Expanded items