'''HELP: A newbie's failed attempt at drag n drop with wxTreeCtrl
Having shamelessly plagiarized the demo code and XMLTreeview, I am currently
stuck, trying without a great deal of success to implement drag-n-drop
functionality within a wxTreeCtrl
Problem 1:
Objective: I would like to be able to reorganize a rendered xml tree by
arbitrarily moving nodes around.
e.g In the dummy xml string below I would like to move a news channels (e.g.
CNN)
using drag and drop to the 'Favourites' branch which currently only
contains slashdot
I'm stuck however:
+ EVT_TREE_END_DRAG is in the documentation but doesn't
seems to be implemented in wxPython 2.2.5
+ do I implement some conditional logic which turns every branch
into a wxDropTarget and every leaf into a wxDropSource?
I know I'm way off but even a hit at the proper trajectory would go a long
way...
Problem 2:
Is there a generic method for expanding all nodes in a wxTreeCtrl?
Many thanks for any help....
Sam Anderson
sa@bayt.net
'''
import string, webbrowser
from wxPython.wx import *
from xml.parsers import expat
__title__ = 'wxTreeCtrl DragNDrop Test'
# dummy xml file
xml='''<?xml version="1.0" encoding="UTF-8"?>
<Test title="Channels">
<Channels title="Favourites">
<Channel type="channel" title="Slashdot" uri="http://slashdot.org"/>
</Channels>
<Channels title="News">
<Channel title="CNN" uri="http://cnn.com"/>
<Channel title="BBC" uri="http://bbc.co.uk"/>
<Channel title="The Economist" uri="http://economist.com"/>
<Channel title="MSNB" uri="http://msnbc.com"/>
</Channels>
<Channels title="Sports">
<Channel type="channel" title="ESPN" uri="http://espn.com"/>
</Channels>
<Trash title="Trash"/>
</Test>'''
class TestApp(wxApp):
def OnInit(self):
# create navigation frame
frame = NavFrame(NULL, -1, __title__)
tree = frame.tree
# expand a few nodes
# NOTE: I know this is pathetic but I couldn't figure out how
# to walk through and expand all nodes
root = tree.nodeStack[0]
child, cookie = tree.GetFirstChild(root, 0)
nchild, cookie = tree.GetFirstChild(child, 0)
tree.Expand(root)
tree.Expand(child)
tree.Expand(nchild)
# display navigation frame
frame.Show(true)
self.SetTopWindow(frame)
return true
class NavFrame(wxFrame):
def __init__(self, parent, ID, title):
wxFrame.__init__(self, parent, ID, title,
wxDefaultPosition,
wxSize(270,500))
# give the tree a unique id
tID = NewId()
# call the tree
self.tree = XMLTree(self, tID, wxDefaultPosition, wxSize(270,490),
wxTR_HAS_BUTTONS | wxTR_EDIT_LABELS)
# Load XML into tree
self.tree.LoadXML()
# tree events
EVT_TREE_ITEM_EXPANDED (self.tree, tID, self.OnItemExpanded)
EVT_TREE_ITEM_COLLAPSED (self.tree, tID, self.OnItemCollapsed)
EVT_TREE_SEL_CHANGED (self.tree, tID, self.OnSelChanged)
EVT_LEFT_DOWN (self.tree, self.OnTreeLeftDown)
#-------------Drag-N-Drop Event Handlers
EVT_TREE_BEGIN_DRAG(self.tree, tID, self.OnBeginDrag)
#EVT_TREE_END_DRAG(self.tree, tID, self.OnEndDrag)
# other events
EVT_CLOSE(self, self.OnCloseWindow)
def OnSelChanged(self, event):
# item is the node selected
item = event.GetItem()
# gets item text for selected node
itemText = self.tree.GetItemText(item)
# get dictionary of attributed for node
attrs = self.tree.GetPyData(item)
# if attribute 'uri' exists, open specified value with browser
if attrs.has_key('uri'):
uri = attrs['uri']
webbrowser.open(uri)
def OnItemExpanded(self, event):
item = event.GetItem()
event.Skip()
def OnBeginDrag(self, event):
event.Allow()
item = event.GetItem()
event.Skip()
def OnItemCollapsed(self, event):
item = event.GetItem()
event.Skip()
def OnTreeLeftDown(self, event):
pt = event.GetPosition();
item, flags = self.tree.HitTest(pt)
if item == self.tree.GetSelection():
print 'LeftDown'
else:
event.Skip()
def OnCloseWindow(self, event):
self.Destroy()
class XMLTree(wxTreeCtrl):
def __init__(self, parent, id, pos, size, style):
wxTreeCtrl.__init__(self, parent, id, pos, size, style)
# create nodeStack and add root node
self.nodeStack = [self.AddRoot("My InfoSpace")]
def StartElement(self, name, attrs ):
name = name.encode()
id = self.AppendItem(self.nodeStack[-1], name)
# for each element map xml attributes to an associated dictionary
self.SetPyData(id, attrs)
# set title of tree node based on element title attribute
if attrs.has_key('title'):
title = attrs['title']
self.SetItemText(id, str(title))
# add element to tree
self.nodeStack.append(id)
def EndElement(self, name ):
self.nodeStack = self.nodeStack[:-1]
def CharacterData(self, data ):
if string.strip(data):
data = data.encode()
self.AppendItem(self.nodeStack[-1], data)
def LoadXML(self):
Parser = expat.ParserCreate()
Parser.StartElementHandler = self.StartElement
Parser.EndElementHandler = self.EndElement
Parser.CharacterDataHandler = self.CharacterData
ParserStatus = Parser.Parse(xml, 1)
if __name__ == '__main__':
app = TestApp(0)
app.MainLoop()