9 closedid
= struct
.pack('h', 468)
10 openid
= struct
.pack('h', 469)
11 closedsolidid
= struct
.pack('h', 470)
12 opensolidid
= struct
.pack('h', 471)
14 arrows
= (nullid
, closedid
, openid
, closedsolidid
, opensolidid
)
16 has_ctlcharsRE
= re
.compile(r
'[\000-\037\177-\377]')
17 def ctlcharsREsearch(str):
18 if has_ctlcharsRE
.search(str) is None:
22 def double_repr(key
, value
, truncvalue
= 0,
23 type = type, StringType
= types
.StringType
,
24 has_ctlchars
= ctlcharsREsearch
, _repr
= repr, str = str):
25 if type(key
) == StringType
and has_ctlchars(key
) < 0:
29 if key
== '__builtins__':
30 value
= "<" + type(value
).__name
__ + " '__builtin__'>"
31 elif key
== '__return__':
32 # bleh, when returning from a class codeblock we get infinite recursion in repr.
33 # Use safe repr instead.
35 value
= repr.repr(value
)
39 '' + value
# test to see if it is a string, in case a __repr__ method is buggy
41 value
= '\xa5\xa5\xa5 exception in repr()'
43 return key
+ '\t' + value
[:255]
44 return key
+ '\t' + value
47 class BrowserWidget(W
.List
):
51 def __init__(self
, possize
, object = None, col
= 100, closechildren
= 0):
52 W
.List
.__init
__(self
, possize
, callback
= self
.listhit
)
55 self
.lastmaxindent
= 0
56 self
.closechildren
= closechildren
60 self
.bind('return', self
.openselection
)
61 self
.bind('enter', self
.openselection
)
62 if object is not None:
65 def set(self
, object):
66 if self
.object[0] is not object:
68 self
[:] = self
.unpack(object, 0)
69 elif self
._parentwindow
is not None and self
._parentwindow
.wid
:
72 def unpack(self
, object, indent
):
73 return unpack_object(object, indent
)
78 self
.setdrawingmode(0)
79 sel
= self
.getselectedobjects()
80 fold
= self
.getunfoldedobjects()
81 topcell
= self
.gettopcell()
82 self
[:] = self
.unpack(self
.object[0], 0)
83 self
.unfoldobjects(fold
)
84 self
.setselectedobjects(sel
)
85 self
.settopcell(topcell
)
86 self
.setdrawingmode(1)
88 def setcolumn(self
, col
):
90 self
.colstr
= struct
.pack('h', col
)
92 sel
= self
.getselection()
93 self
.setitems(self
.items
)
94 self
.setselection(sel
)
96 def key(self
, char
, event
):
97 if char
in (Wkeys
.leftarrowkey
, Wkeys
.rightarrowkey
):
98 sel
= self
.getselection()
100 self
.setdrawingmode(0)
102 self
.fold(index
, char
== Wkeys
.rightarrowkey
)
103 self
.setdrawingmode(1)
105 W
.List
.key(self
, char
, event
)
107 def rollover(self
, (x
, y
), onoff
):
109 if self
.incolumn((x
, y
)):
110 W
.SetCursor('hmover')
114 def inarrow(self
, (x
, y
)):
115 cl
, ct
, cr
, cb
= self
._list
.LRect((0, 0))
116 l
, t
, r
, b
= self
._bounds
119 index
= (y
- ct
) / cellheight
120 if index
< len(self
.items
):
124 def incolumn(self
, (x
, y
)):
125 l
, t
, r
, b
= self
._list
.LRect((0, 0))
126 abscol
= l
+ self
.col
127 return abs(abscol
- x
) < 3
129 def trackcolumn(self
, (x
, y
)):
130 import Qd
, QuickDraw
, Evt
132 l
, t
, r
, b
= self
._bounds
133 bounds
= l
, t
, r
, b
= l
+ 1, t
+ 1, r
- 16, b
- 1
134 abscol
= l
+ self
.col
135 mincol
= l
+ self
.mincol
138 Qd
.PenPat('\000\377\000\377\000\377\000\377')
139 Qd
.PenMode(QuickDraw
.srcXor
)
140 rect
= abscol
- 1, t
, abscol
, b
146 (x
, y
) = Evt
.GetMouse()
147 if (x
, y
) <> lastpoint
:
149 newcol
= max(newcol
, mincol
)
150 newcol
= min(newcol
, maxcol
)
152 rect
= newcol
- 1, t
, newcol
, b
156 Qd
.PenPat(Qd
.qd
.black
)
158 if newcol
> 0 and newcol
<> abscol
:
159 self
.setcolumn(newcol
- l
)
161 def click(self
, point
, modifiers
):
162 if point
== (-1, -1): # gross.
163 W
.List
.click(self
, point
,modifiers
)
165 hit
, index
= self
.inarrow(point
)
167 (key
, value
, arrow
, indent
) = self
.items
[index
]
168 self
.fold(index
, arrow
== 1)
169 elif self
.incolumn(point
):
170 self
.trackcolumn(point
)
172 W
.List
.click(self
, point
, modifiers
)
175 def findmatch(self
, tag
):
181 for i
in range(len(items
)):
182 item
= lower(str(items
[i
][0]))
183 if tag
<= item
< match
:
189 return len(items
) - 1
192 if self
.closechildren
:
193 for window
in self
.children
:
198 def fold(self
, index
, onoff
):
199 (key
, value
, arrow
, indent
) = self
.items
[index
]
200 if arrow
== 0 or (onoff
and arrow
== 2) or (not onoff
and arrow
== 1):
203 topcell
= self
.gettopcell()
205 self
[index
] = (key
, value
, 4, indent
)
206 self
.setdrawingmode(0)
207 self
[index
+1:index
+1] = self
.unpack(value
, indent
+ 1)
208 self
[index
] = (key
, value
, 2, indent
)
210 self
[index
] = (key
, value
, 3, indent
)
211 self
.setdrawingmode(0)
213 for i
in range(index
+ 1, len(self
.items
)):
214 (dummy
, dummy
, dummy
, subindent
) = self
.items
[i
]
215 if subindent
<= indent
:
218 self
[index
+1:index
+1+count
] = []
219 self
[index
] = (key
, value
, 1, indent
)
220 maxindent
= self
.getmaxindent()
221 if maxindent
<> self
.lastmaxindent
:
222 newabsindent
= self
.col
+ (maxindent
- self
.lastmaxindent
) * self
.indent
223 if newabsindent
>= self
.mincol
:
224 self
.setcolumn(newabsindent
)
225 self
.lastmaxindent
= maxindent
226 self
.settopcell(topcell
)
227 self
.setdrawingmode(1)
229 def unfoldobjects(self
, objects
):
232 index
= self
.items
.index(obj
)
238 def getunfoldedobjects(self
):
241 for index
in range(len(self
.items
)):
242 (key
, value
, arrow
, indent
) = self
.items
[index
]
243 if indent
> curindent
:
244 (k
, v
, a
, i
) = self
.items
[index
- 1]
245 objects
.append((k
, v
, 1, i
))
247 elif indent
< curindent
:
251 def listhit(self
, isdbl
):
255 def openselection(self
):
257 sel
= self
.getselection()
259 (key
, value
, arrow
, indent
) = self
[index
]
261 self
.children
.append(Browser(value
))
262 elif type(value
) == types
.StringType
and '\0' not in value
:
263 editor
= self
._parentwindow
.parent
.getscript(value
)
267 elif os
.path
.exists(value
) and os
.path
.isfile(value
):
269 fss
= macfs
.FSSpec(value
)
270 if fss
.GetCreatorType()[1] == 'TEXT':
271 W
.getapplication().openscript(value
)
273 def itemrepr(self
, (key
, value
, arrow
, indent
), str = str, double_repr
= double_repr
,
274 arrows
= arrows
, pack
= struct
.pack
):
275 arrow
= arrows
[arrow
]
276 return arrow
+ pack('h', self
.indent
* indent
) + self
.colstr
+ \
277 double_repr(key
, value
, 1)
279 def getmaxindent(self
, max = max):
281 for item
in self
.items
:
282 maxindent
= max(maxindent
, item
[3])
285 def domenu_copy(self
, *args
):
286 sel
= self
.getselectedobjects()
288 for key
, value
, dummy
, dummy
in sel
:
289 selitems
.append(double_repr(key
, value
))
290 text
= string
.join(selitems
, '\r')
294 Scrap
.PutScrap('TEXT', text
)
299 def __init__(self
, object = None, title
= None, closechildren
= 0):
300 if hasattr(object, '__name__'):
301 name
= object.__name
__
305 title
= 'Object browser'
307 title
= title
+ ': ' + name
308 self
.w
= w
= W
.Window((300, 400), title
, minsize
= (100, 100))
309 w
.info
= W
.TextBox((18, 8, -70, 15))
310 w
.updatebutton
= W
.Button((-64, 4, 50, 16), 'Update', self
.update
)
311 w
.browser
= BrowserWidget((-1, 24, 1, -14), None)
312 w
.bind('cmdu', w
.updatebutton
.push
)
314 self
.set(object, name
)
320 def set(self
, object, name
= ''):
322 tp
= type(object).__name
__
327 if not name
and hasattr(object, '__name__'):
328 name
= object.__name
__
330 info
= name
+ ': ' + tp
335 info
= info
+ ' (%d element)' % length
337 info
= info
+ ' (%d elements)' % length
338 self
.w
.info
.set(info
)
339 self
.w
.browser
.set(object)
342 self
.w
.browser
.update()
360 def unpack_object(object, indent
= 0):
362 if tp
in SIMPLE_TYPES
and tp
is not types
.NoneType
:
363 raise TypeError, "can't browse simple type: %s" % tp
.__name
__
364 elif tp
== types
.DictionaryType
:
365 return unpack_dict(object, indent
)
366 elif tp
in (types
.TupleType
, types
.ListType
):
367 return unpack_sequence(object, indent
)
368 elif tp
== types
.InstanceType
:
369 return unpack_instance(object, indent
)
370 elif tp
== types
.ClassType
:
371 return unpack_class(object, indent
)
372 elif tp
== types
.ModuleType
:
373 return unpack_dict(object.__dict
__, indent
)
375 return unpack_other(object, indent
)
377 def unpack_sequence(seq
, indent
= 0):
378 items
= map(None, range(len(seq
)), seq
)
379 items
= map(lambda (k
, v
), type = type, simp
= SIMPLE_TYPES
, indent
= indent
:
380 (k
, v
, not type(v
) in simp
, indent
), items
)
383 def unpack_dict(dict, indent
= 0):
385 return pack_items(items
, indent
)
387 def unpack_instance(inst
, indent
= 0):
388 if hasattr(inst
, '__pybrowse_unpack__'):
389 return unpack_object(inst
.__pybrowse
_unpack
__(), indent
)
391 items
= [('__class__', inst
.__class
__)] + inst
.__dict
__.items()
392 return pack_items(items
, indent
)
394 def unpack_class(clss
, indent
= 0):
395 items
= [('__bases__', clss
.__bases
__), ('__name__', clss
.__name
__)] + clss
.__dict
__.items()
396 return pack_items(items
, indent
)
398 def unpack_other(object, indent
= 0):
400 if hasattr(object, '__members__'):
401 attrs
= attrs
+ object.__members
__
402 if hasattr(object, '__methods__'):
403 attrs
= attrs
+ object.__methods
__
406 items
.append((attr
, getattr(object, attr
)))
407 return pack_items(items
, indent
)
409 def pack_items(items
, indent
= 0):
410 items
= map(lambda (k
, v
), type = type, simp
= SIMPLE_TYPES
, indent
= indent
:
411 (k
, v
, not type(v
) in simp
, indent
),
413 return tuple_caselesssort(items
)
415 def caselesssort(alist
):
416 """Return a sorted copy of a list. If there are only strings in the list,
417 it will not consider case"""
420 # turn ['FOO', 'aaBc', 'ABcD'] into [('foo', 'FOO'), ('aabc', 'aaBc'), ('abcd', 'ABcD')], if possible
421 tupledlist
= map(lambda item
, lower
= string
.lower
: (lower(item
), item
), alist
)
423 # at least one element in alist is not a string, proceed the normal way...
429 # turn [('aabc', 'aaBc'), ('abcd', 'ABcD'), ('foo', 'FOO')] into ['aaBc', 'ABcD', 'FOO']
430 return map(lambda x
: x
[1], tupledlist
)
432 def tuple_caselesssort(items
):
434 tupledlist
= map(lambda tuple, lower
= string
.lower
: (lower(tuple[0]), tuple), items
)
435 except (AttributeError, TypeError):
441 return map(lambda (low
, tuple): tuple, tupledlist
)