266 lines
9.7 KiB
Python
266 lines
9.7 KiB
Python
|
import wx, wx.lib.customtreectrl, wx.gizmos
|
||
|
try:
|
||
|
import treemixin
|
||
|
except ImportError:
|
||
|
from wx.lib.mixins import treemixin
|
||
|
|
||
|
overview = treemixin.__doc__
|
||
|
|
||
|
class TreeModel(object):
|
||
|
''' TreeModel holds the domain objects that are shown in the different
|
||
|
tree controls. Each domain object is simply a two-tuple consisting of
|
||
|
a label and a list of child tuples, i.e. (label, [list of child tuples]).
|
||
|
'''
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
self.items = []
|
||
|
self.itemCounter = 0
|
||
|
super(TreeModel, self).__init__(*args, **kwargs)
|
||
|
|
||
|
def GetItem(self, indices):
|
||
|
text, children = 'Hidden root', self.items
|
||
|
for index in indices:
|
||
|
text, children = children[index]
|
||
|
return text, children
|
||
|
|
||
|
def GetText(self, indices):
|
||
|
return self.GetItem(indices)[0]
|
||
|
|
||
|
def GetChildren(self, indices):
|
||
|
return self.GetItem(indices)[1]
|
||
|
|
||
|
def GetChildrenCount(self, indices):
|
||
|
return len(self.GetChildren(indices))
|
||
|
|
||
|
def SetChildrenCount(self, indices, count):
|
||
|
children = self.GetChildren(indices)
|
||
|
while len(children) > count:
|
||
|
children.pop()
|
||
|
while len(children) < count:
|
||
|
children.append(('item %d'%self.itemCounter, []))
|
||
|
self.itemCounter += 1
|
||
|
|
||
|
def MoveItem(self, itemToMoveIndex, newParentIndex):
|
||
|
itemToMove = self.GetItem(itemToMoveIndex)
|
||
|
newParentChildren = self.GetChildren(newParentIndex)
|
||
|
newParentChildren.append(itemToMove)
|
||
|
oldParentChildren = self.GetChildren(itemToMoveIndex[:-1])
|
||
|
oldParentChildren.remove(itemToMove)
|
||
|
|
||
|
|
||
|
class DemoTreeMixin(treemixin.VirtualTree, treemixin.DragAndDrop,
|
||
|
treemixin.ExpansionState):
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
self.model = kwargs.pop('treemodel')
|
||
|
self.log = kwargs.pop('log')
|
||
|
super(DemoTreeMixin, self).__init__(*args, **kwargs)
|
||
|
self.CreateImageList()
|
||
|
|
||
|
def CreateImageList(self):
|
||
|
size = (16, 16)
|
||
|
self.imageList = wx.ImageList(*size)
|
||
|
for art in wx.ART_FOLDER, wx.ART_FILE_OPEN, wx.ART_NORMAL_FILE:
|
||
|
self.imageList.Add(wx.ArtProvider.GetBitmap(art, wx.ART_OTHER,
|
||
|
size))
|
||
|
self.AssignImageList(self.imageList)
|
||
|
|
||
|
def OnGetItemText(self, indices):
|
||
|
return self.model.GetText(indices)
|
||
|
|
||
|
def OnGetChildrenCount(self, indices):
|
||
|
return self.model.GetChildrenCount(indices)
|
||
|
|
||
|
def OnGetItemFont(self, indices):
|
||
|
# Show how to change the item font. Here we use a small font for
|
||
|
# items that have children and the default font otherwise.
|
||
|
if self.model.GetChildrenCount(indices) > 0:
|
||
|
return wx.SMALL_FONT
|
||
|
else:
|
||
|
return super(DemoTreeMixin, self).OnGetItemFont(indices)
|
||
|
|
||
|
def OnGetItemTextColour(self, indices):
|
||
|
# Show how to change the item text colour. In this case second level
|
||
|
# items are coloured red and third level items are blue. All other
|
||
|
# items have the default text colour.
|
||
|
if len(indices) % 2 == 0:
|
||
|
return wx.RED
|
||
|
elif len(indices) % 3 == 0:
|
||
|
return wx.BLUE
|
||
|
else:
|
||
|
return super(DemoTreeMixin, self).OnGetItemTextColour(indices)
|
||
|
|
||
|
def OnGetItemBackgroundColour(self, indices):
|
||
|
# Show how to change the item background colour. In this case the
|
||
|
# background colour of each third item is green.
|
||
|
if indices[-1] == 2:
|
||
|
return wx.GREEN
|
||
|
else:
|
||
|
return super(DemoTreeMixin,
|
||
|
self).OnGetItemBackgroundColour(indices)
|
||
|
|
||
|
def OnGetItemImage(self, indices, which):
|
||
|
# Return the right icon depending on whether the item has children.
|
||
|
if which in [wx.TreeItemIcon_Normal, wx.TreeItemIcon_Selected]:
|
||
|
if self.model.GetChildrenCount(indices):
|
||
|
return 0
|
||
|
else:
|
||
|
return 2
|
||
|
else:
|
||
|
return 1
|
||
|
|
||
|
def OnDrop(self, dropTarget, dragItem):
|
||
|
dropIndex = self.GetIndexOfItem(dropTarget)
|
||
|
dropText = self.model.GetText(dropIndex)
|
||
|
dragIndex = self.GetIndexOfItem(dragItem)
|
||
|
dragText = self.model.GetText(dragIndex)
|
||
|
self.log.write('drop %s %s on %s %s'%(dragText, dragIndex,
|
||
|
dropText, dropIndex))
|
||
|
self.model.MoveItem(dragIndex, dropIndex)
|
||
|
self.GetParent().RefreshItems()
|
||
|
|
||
|
|
||
|
class VirtualTreeCtrl(DemoTreeMixin, wx.TreeCtrl):
|
||
|
pass
|
||
|
|
||
|
|
||
|
class VirtualTreeListCtrl(DemoTreeMixin, wx.gizmos.TreeListCtrl):
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
kwargs['style'] = wx.TR_DEFAULT_STYLE | wx.TR_FULL_ROW_HIGHLIGHT
|
||
|
super(VirtualTreeListCtrl, self).__init__(*args, **kwargs)
|
||
|
self.AddColumn('Column 0')
|
||
|
self.AddColumn('Column 1')
|
||
|
for art in wx.ART_TIP, wx.ART_WARNING:
|
||
|
self.imageList.Add(wx.ArtProvider.GetBitmap(art, wx.ART_OTHER,
|
||
|
(16, 16)))
|
||
|
|
||
|
def OnGetItemText(self, indices, column=0):
|
||
|
# Return a different label depending on column.
|
||
|
return '%s, column %d'%\
|
||
|
(super(VirtualTreeListCtrl, self).OnGetItemText(indices), column)
|
||
|
|
||
|
def OnGetItemImage(self, indices, which, column=0):
|
||
|
# Also change the image of the other columns when the item has
|
||
|
# children.
|
||
|
if column == 0:
|
||
|
return super(VirtualTreeListCtrl, self).OnGetItemImage(indices,
|
||
|
which)
|
||
|
elif self.OnGetChildrenCount(indices):
|
||
|
return 4
|
||
|
else:
|
||
|
return 3
|
||
|
|
||
|
|
||
|
class VirtualCustomTreeCtrl(DemoTreeMixin,
|
||
|
wx.lib.customtreectrl.CustomTreeCtrl):
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
self.checked = {}
|
||
|
kwargs['ctstyle'] = wx.TR_DEFAULT_STYLE | wx.TR_HIDE_ROOT | \
|
||
|
wx.TR_HAS_BUTTONS | wx.TR_FULL_ROW_HIGHLIGHT
|
||
|
super(VirtualCustomTreeCtrl, self).__init__(*args, **kwargs)
|
||
|
self.Bind(wx.lib.customtreectrl.EVT_TREE_ITEM_CHECKED,
|
||
|
self.OnItemChecked)
|
||
|
|
||
|
def OnGetItemType(self, indices):
|
||
|
if len(indices) == 1:
|
||
|
return 1
|
||
|
elif len(indices) == 2:
|
||
|
return 2
|
||
|
else:
|
||
|
return 0
|
||
|
|
||
|
def OnGetItemChecked(self, indices):
|
||
|
return self.checked.get(indices, False)
|
||
|
|
||
|
def OnItemChecked(self, event):
|
||
|
item = event.GetItem()
|
||
|
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))):
|
||
|
self.checked[itemIndex[:-1]+(nr,)] = False
|
||
|
self.checked[itemIndex] = True
|
||
|
|
||
|
|
||
|
|
||
|
class TreeNotebook(wx.Notebook):
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
treemodel = kwargs.pop('treemodel')
|
||
|
log = kwargs.pop('log')
|
||
|
super(TreeNotebook, self).__init__(*args, **kwargs)
|
||
|
self.trees = []
|
||
|
for class_, title in [(VirtualTreeCtrl, 'TreeCtrl'),
|
||
|
(VirtualTreeListCtrl, 'TreeListCtrl'),
|
||
|
(VirtualCustomTreeCtrl, 'CustomTreeCtrl')]:
|
||
|
tree = class_(self, treemodel=treemodel, log=log)
|
||
|
self.trees.append(tree)
|
||
|
self.AddPage(tree, title)
|
||
|
self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
|
||
|
|
||
|
def OnPageChanged(self, event):
|
||
|
oldTree = self.GetPage(event.OldSelection)
|
||
|
newTree = self.GetPage(event.Selection)
|
||
|
newTree.RefreshItems()
|
||
|
newTree.SetExpansionState(oldTree.GetExpansionState())
|
||
|
event.Skip()
|
||
|
|
||
|
def GetIndicesOfSelectedItems(self):
|
||
|
tree = self.trees[self.GetSelection()]
|
||
|
if tree.GetSelections():
|
||
|
return [tree.GetIndexOfItem(item) for item in tree.GetSelections()]
|
||
|
else:
|
||
|
return [()]
|
||
|
|
||
|
def RefreshItems(self):
|
||
|
tree = self.trees[self.GetSelection()]
|
||
|
tree.RefreshItems()
|
||
|
tree.UnselectAll()
|
||
|
|
||
|
|
||
|
class TestPanel(wx.Panel):
|
||
|
def __init__(self, parent, log):
|
||
|
self.log = log
|
||
|
super(TestPanel, self).__init__(parent)
|
||
|
self.treemodel = TreeModel()
|
||
|
self.CreateControls()
|
||
|
self.LayoutControls()
|
||
|
|
||
|
def CreateControls(self):
|
||
|
self.notebook = TreeNotebook(self, treemodel=self.treemodel,
|
||
|
log=self.log)
|
||
|
self.label = wx.StaticText(self, label='Number of children: ')
|
||
|
self.childrenCountCtrl = wx.SpinCtrl(self, value='0', max=10000)
|
||
|
self.button = wx.Button(self, label='Update children')
|
||
|
self.button.Bind(wx.EVT_BUTTON, self.OnEnter)
|
||
|
|
||
|
def LayoutControls(self):
|
||
|
hSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||
|
options = dict(flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=2)
|
||
|
hSizer.Add(self.label, **options)
|
||
|
hSizer.Add(self.childrenCountCtrl, 2, **options)
|
||
|
hSizer.Add(self.button, **options)
|
||
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
||
|
sizer.Add(self.notebook, 1, wx.EXPAND)
|
||
|
sizer.Add(hSizer, 0, wx.EXPAND)
|
||
|
self.SetSizer(sizer)
|
||
|
|
||
|
def OnEnter(self, event):
|
||
|
indicesList = self.notebook.GetIndicesOfSelectedItems()
|
||
|
newChildrenCount = self.childrenCountCtrl.GetValue()
|
||
|
for indices in indicesList:
|
||
|
text = self.treemodel.GetText(indices)
|
||
|
oldChildrenCount = self.treemodel.GetChildrenCount(indices)
|
||
|
self.log.write('%s %s now has %d children (was %d)'%(text, indices,
|
||
|
newChildrenCount, oldChildrenCount))
|
||
|
self.treemodel.SetChildrenCount(indices, newChildrenCount)
|
||
|
self.notebook.RefreshItems()
|
||
|
|
||
|
|
||
|
def runTest(frame, nb, log):
|
||
|
win = TestPanel(nb, log)
|
||
|
return win
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
import sys, os, run
|
||
|
run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
|
||
|
|