]>
Commit | Line | Data |
---|---|---|
8fa876ca RD |
1 | # 11/13/2003 - Jeff Grimmett (grimmtooth@softhome.net) |
2 | # | |
3 | # o Updated for wx namespace | |
4 | # | |
5 | ||
cf694132 RD |
6 | """ |
7 | Hello, and welcome to this test of the wxTreeItemData | |
8 | class. | |
9 | ||
10 | The wxTreeItemData class can be used to associate a python | |
11 | object with a wxTreeCtrl item. In this sample, its use is | |
12 | demonstrated via a tree control that shows the contents of a | |
13 | python namespace according to the standard dir() | |
14 | command. Every item in the tree has its label taken from the | |
15 | dir() output, and 'behind it' a reference to the python | |
16 | object is stored in a wxTreeItemData object. | |
17 | ||
18 | As you may have guessed by now, this sample automatically | |
19 | displays '__doc__' strings if the selected python object | |
20 | happens to have one. Please expand the pyTree object to | |
21 | learn more about the implementation. | |
22 | ||
23 | Version 1.0, April 4 1999. | |
24 | Harm van der Heijden (H.v.d.Heijden@phys.tue.nl) | |
25 | ||
26 | P.S. Check out the string module. It's imported in this | |
27 | sample not because it's used, but because it's so | |
28 | beautifully documented... | |
29 | """ | |
30 | ||
8fa876ca RD |
31 | import string # Used for demo purposes, nothing more. :-) |
32 | import sys | |
33 | ||
34 | import wx | |
cf694132 RD |
35 | |
36 | #---------------------------------------------------------------------- | |
37 | ||
38 | def _getindent(line): | |
39 | """Returns the indentation level of the given line.""" | |
40 | indent = 0 | |
41 | for c in line: | |
42 | if c == ' ': indent = indent + 1 | |
43 | elif c == '\t': indent = indent + 8 | |
44 | else: break | |
45 | return indent | |
46 | ||
47 | def _sourcefinder(func): | |
48 | """Given a func_code object, this function tries to find and return | |
49 | the python source code of the function.""" | |
50 | try: | |
51 | f = open(func.co_filename,"r") | |
52 | except: | |
53 | return "(could not open file %s)" % (func.co_filename,) | |
54 | ||
55 | for i in range(func.co_firstlineno): | |
56 | line = f.readline() | |
8fa876ca | 57 | |
cf694132 RD |
58 | ind = _getindent(line) |
59 | msg = "" | |
8fa876ca | 60 | |
cf694132 RD |
61 | while line: |
62 | msg = msg + line | |
63 | line = f.readline() | |
64 | # the following should be <= ind, but then we get | |
65 | # confused by multiline docstrings. Using == works most of | |
66 | # the time... but not always! | |
67 | if _getindent(line) == ind: break | |
8fa876ca | 68 | |
cf694132 RD |
69 | return msg |
70 | ||
71 | #---------------------------------------------------------------------- | |
72 | ||
8fa876ca | 73 | class pyTree(wx.TreeCtrl): |
cf694132 | 74 | """ |
8fa876ca | 75 | This wx.TreeCtrl derivative displays a tree view of a Python namespace. |
cf694132 RD |
76 | Anything from which the dir() command returns a non-empty list is a branch |
77 | in this tree. | |
78 | """ | |
79 | ||
80 | def __init__(self, parent, id, root): | |
81 | """ | |
82 | Initialize function; because we insert branches into the tree | |
83 | as needed, we use the ITEM_EXPANDING event handler. The | |
84 | ITEM_COLLAPSED handler removes the stuff afterwards. The | |
85 | SEL_CHANGED handler attempts to display interesting | |
86 | information about the selected object. | |
87 | """ | |
8fa876ca RD |
88 | wx.TreeCtrl.__init__(self, parent, id) |
89 | self.root = self.AddRoot(str(root), -1, -1, wx.TreeItemData(root)) | |
90 | ||
cf694132 | 91 | if dir(root): |
8fa876ca RD |
92 | self.SetItemHasChildren(self.root, True) |
93 | ||
94 | self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnItemExpanding, id=self.GetId()) | |
95 | self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed, id=self.GetId()) | |
96 | self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, id=self.GetId()) | |
97 | ||
cf694132 | 98 | self.output = None |
493f1553 | 99 | self.Expand(self.root) |
cf694132 RD |
100 | |
101 | ||
102 | def SetOutput(self, output): | |
103 | """ | |
104 | Set output function (accepts single string). Used to display string | |
105 | representation of the selected object by OnSelChanged. | |
106 | """ | |
107 | self.output = output | |
108 | ||
109 | ||
110 | def OnItemExpanding(self,event): | |
111 | """ | |
112 | The real workhorse of this class. First we retrieve the object | |
113 | (parent) belonging to the branch that is to be expanded. This | |
114 | is done by calling GetPyData(parent), which is a short-cut for | |
115 | GetPyItemData(parent).Get(). | |
116 | ||
117 | Then we get the dir() list of that object. For each item in | |
118 | this list, a tree item is created with associated | |
119 | wxTreeItemData referencing the child object. We get this | |
120 | object using child = getattr(parent, item). | |
121 | ||
122 | Finally, we check wether the child returns a non-empty dir() | |
123 | list. If so, it is labeled as 'having children', so that it | |
124 | may be expanded. When it actually is expanded, this function | |
125 | will again figure out what the offspring is. | |
126 | """ | |
127 | item = event.GetItem() | |
8fa876ca | 128 | |
493f1553 RD |
129 | if self.IsExpanded(item): # This event can happen twice in the self.Expand call |
130 | return | |
8fa876ca | 131 | |
cf694132 RD |
132 | obj = self.GetPyData( item ) |
133 | lst = dir(obj) | |
8fa876ca | 134 | |
cf694132 RD |
135 | for key in lst: |
136 | new_obj = getattr(obj,key) | |
137 | new_item = self.AppendItem( item, key, -1, -1, | |
8fa876ca RD |
138 | wx.TreeItemData(new_obj) ) |
139 | ||
cf694132 | 140 | if dir(new_obj): |
8fa876ca | 141 | self.SetItemHasChildren(new_item, True) |
cf694132 RD |
142 | |
143 | def OnItemCollapsed(self, event): | |
144 | """ | |
145 | We need to remove all children here, otherwise we'll see all | |
146 | that old rubbish again after the next expansion. | |
147 | """ | |
148 | item = event.GetItem() | |
149 | self.DeleteChildren(item) | |
150 | ||
151 | def OnSelChanged(self, event): | |
152 | """ | |
153 | If an output function is defined, we try to print some | |
154 | informative, interesting and thought-provoking stuff to it. | |
155 | If it has a __doc__ string, we print it. If it's a function or | |
156 | unbound class method, we attempt to find the python source. | |
157 | """ | |
158 | if not self.output: | |
159 | return | |
8fa876ca | 160 | |
cf694132 RD |
161 | obj = self.GetPyData( event.GetItem() ) |
162 | msg = str(obj) | |
8fa876ca | 163 | |
cf694132 RD |
164 | if hasattr(obj, '__doc__'): |
165 | msg = msg+"\n\nDocumentation string:\n\n%s" % ( getattr(obj, '__doc__'),) | |
8fa876ca | 166 | |
cf694132 RD |
167 | # Is it a function? |
168 | func = None | |
8fa876ca | 169 | |
cf694132 RD |
170 | if hasattr(obj, "func_code"): # normal function |
171 | func = getattr(obj, "func_code") | |
8fa876ca | 172 | |
cf694132 RD |
173 | elif hasattr(obj, "im_func"): # unbound class method |
174 | func = getattr(getattr(obj, "im_func"), "func_code") | |
8fa876ca | 175 | |
cf694132 RD |
176 | if func: # if we found one, let's try to print the source |
177 | msg = msg+"\n\nFunction source:\n\n" + _sourcefinder(func) | |
178 | ||
179 | apply(self.output, (msg,)) | |
180 | ||
181 | #---------------------------------------------------------------------- | |
182 | ||
183 | overview = __doc__ | |
184 | ||
185 | def runTest(frame, nb, log): | |
186 | """ | |
187 | This method is used by the wxPython Demo Framework for integrating | |
188 | this demo with the rest. | |
189 | """ | |
96bfd053 | 190 | thisModule = sys.modules[__name__] |
8fa876ca RD |
191 | win = wx.Frame(frame, -1, "PyTreeItemData Test") |
192 | split = wx.SplitterWindow(win, -1) | |
cf694132 | 193 | tree = pyTree(split, -1, thisModule) |
8fa876ca | 194 | text = wx.TextCtrl(split, -1, "", style=wx.TE_MULTILINE) |
cf694132 RD |
195 | split.SplitVertically(tree, text, 200) |
196 | tree.SetOutput(text.SetValue) | |
197 | tree.SelectItem(tree.root) | |
8fa876ca | 198 | win.SetSize((800,500)) |
cf694132 RD |
199 | frame.otherWin = win |
200 | win.Show(1) | |
201 | ||
202 | ||
203 | ||
204 | #---------------------------------------------------------------------- | |
205 | if __name__ == '__main__': | |
206 | ||
8fa876ca | 207 | class MyFrame(wx.Frame): |
cf694132 RD |
208 | """Very standard Frame class. Nothing special here!""" |
209 | ||
210 | def __init__(self): | |
211 | """Make a splitter window; left a tree, right a textctrl. Wow.""" | |
212 | import __main__ | |
8fa876ca RD |
213 | wx.Frame.__init__(self, None, -1, "PyTreeItemData Test", size=(800,500)) |
214 | split = wx.SplitterWindow(self, -1) | |
cf694132 | 215 | tree = pyTree(split, -1, __main__) |
8fa876ca | 216 | text = wx.TextCtrl(split, -1, "", style=wx.TE_MULTILINE) |
cf694132 RD |
217 | split.SplitVertically(tree, text, 200) |
218 | tree.SetOutput(text.SetValue) | |
219 | tree.SelectItem(tree.root) | |
220 | ||
8fa876ca | 221 | class MyApp(wx.App): |
cf694132 RD |
222 | """This class is even less interesting than MyFrame.""" |
223 | ||
224 | def OnInit(self): | |
225 | """OnInit. Boring, boring, boring!""" | |
226 | frame = MyFrame() | |
8fa876ca | 227 | frame.Show(True) |
cf694132 | 228 | self.SetTopWindow(frame) |
8fa876ca | 229 | return True |
cf694132 | 230 | |
8fa876ca | 231 | app = MyApp(False) |
cf694132 RD |
232 | app.MainLoop() |
233 | ||
234 |