Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 1 | import W |
| 2 | import Wkeys |
| 3 | import struct |
| 4 | import string |
| 5 | import types |
Jack Jansen | 9ad2752 | 2001-02-21 13:54:31 +0000 | [diff] [blame] | 6 | import re |
Just van Rossum | 4e6d13c | 2002-03-26 12:06:11 +0000 | [diff] [blame] | 7 | from Carbon import Qd, Icn, Fm, QuickDraw |
Just van Rossum | 4e6d13c | 2002-03-26 12:06:11 +0000 | [diff] [blame] | 8 | from Carbon.QuickDraw import hilitetransfermode |
| 9 | |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 10 | |
| 11 | nullid = '\0\0' |
| 12 | closedid = struct.pack('h', 468) |
| 13 | openid = struct.pack('h', 469) |
| 14 | closedsolidid = struct.pack('h', 470) |
| 15 | opensolidid = struct.pack('h', 471) |
| 16 | |
| 17 | arrows = (nullid, closedid, openid, closedsolidid, opensolidid) |
| 18 | |
Just van Rossum | 3eec762 | 2001-07-10 19:25:40 +0000 | [diff] [blame] | 19 | has_ctlcharsRE = re.compile(r'[\000-\037\177-\377]') |
Jack Jansen | 9ad2752 | 2001-02-21 13:54:31 +0000 | [diff] [blame] | 20 | def ctlcharsREsearch(str): |
Jack Jansen | dbd0c3a | 2001-03-01 23:15:54 +0000 | [diff] [blame] | 21 | if has_ctlcharsRE.search(str) is None: |
Jack Jansen | 9ad2752 | 2001-02-21 13:54:31 +0000 | [diff] [blame] | 22 | return -1 |
| 23 | return 1 |
| 24 | |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 25 | def double_repr(key, value, truncvalue = 0, |
| 26 | type = type, StringType = types.StringType, |
Jack Jansen | 9ad2752 | 2001-02-21 13:54:31 +0000 | [diff] [blame] | 27 | has_ctlchars = ctlcharsREsearch, _repr = repr, str = str): |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 28 | if type(key) == StringType and has_ctlchars(key) < 0: |
| 29 | key = str(key) |
| 30 | else: |
| 31 | key = _repr(key) |
Just van Rossum | 460ff20 | 1999-10-30 11:43:25 +0000 | [diff] [blame] | 32 | if key == '__builtins__': |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 33 | value = "<" + type(value).__name__ + " '__builtin__'>" |
| 34 | elif key == '__return__': |
| 35 | # bleh, when returning from a class codeblock we get infinite recursion in repr. |
| 36 | # Use safe repr instead. |
| 37 | import repr |
| 38 | value = repr.repr(value) |
| 39 | else: |
| 40 | try: |
| 41 | value = _repr(value) |
| 42 | '' + value # test to see if it is a string, in case a __repr__ method is buggy |
| 43 | except: |
Just van Rossum | dc3c617 | 2001-06-19 21:37:33 +0000 | [diff] [blame] | 44 | value = '\xa5\xa5\xa5 exception in repr()' |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 45 | if truncvalue: |
| 46 | return key + '\t' + value[:255] |
| 47 | return key + '\t' + value |
| 48 | |
| 49 | |
Just van Rossum | 4e6d13c | 2002-03-26 12:06:11 +0000 | [diff] [blame] | 50 | def truncString(s, maxwid): |
| 51 | if maxwid < 1: |
| 52 | return 1, "" |
| 53 | strlen = len(s) |
| 54 | strwid = Qd.TextWidth(s, 0, strlen); |
| 55 | if strwid <= maxwid: |
| 56 | return 0, s |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 57 | |
Just van Rossum | 4e6d13c | 2002-03-26 12:06:11 +0000 | [diff] [blame] | 58 | Qd.TextFace(QuickDraw.condense) |
| 59 | strwid = Qd.TextWidth(s, 0, strlen) |
| 60 | ellipsis = Qd.StringWidth('\xc9') |
| 61 | |
| 62 | if strwid <= maxwid: |
| 63 | Qd.TextFace(0) |
| 64 | return 1, s |
| 65 | if strwid < 1: |
| 66 | Qd.TextFace(0) |
| 67 | return 1, "" |
| 68 | |
| 69 | mid = int(strlen * maxwid / strwid) |
| 70 | while 1: |
| 71 | if mid <= 0: |
| 72 | mid = 0 |
| 73 | break |
| 74 | strwid = Qd.TextWidth(s, 0, mid) + ellipsis |
| 75 | strwid2 = Qd.TextWidth(s, 0, mid + 1) + ellipsis |
| 76 | if strwid <= maxwid and maxwid <= strwid2: |
| 77 | if maxwid == strwid2: |
| 78 | mid += 1 |
| 79 | break |
| 80 | if strwid > maxwid: |
| 81 | mid -= 1 |
| 82 | if mid <= 0: |
| 83 | mid = 0 |
| 84 | break |
| 85 | elif strwid2 < maxwid: |
| 86 | mid += 1 |
| 87 | Qd.TextFace(0) |
| 88 | return 1, s[:mid] + '\xc9' |
| 89 | |
| 90 | |
| 91 | def drawTextCell(text, cellRect, ascent, theList): |
| 92 | l, t, r, b = cellRect |
| 93 | cellwidth = r - l |
Jack Jansen | a359a3d | 2003-02-12 15:39:16 +0000 | [diff] [blame] | 94 | Qd.MoveTo(int(l + 2), int(t + ascent)) |
Just van Rossum | 4e6d13c | 2002-03-26 12:06:11 +0000 | [diff] [blame] | 95 | condense, text = truncString(text, cellwidth - 3) |
| 96 | if condense: |
| 97 | Qd.TextFace(QuickDraw.condense) |
| 98 | Qd.DrawText(text, 0, len(text)) |
| 99 | Qd.TextFace(0) |
| 100 | |
| 101 | |
| 102 | PICTWIDTH = 16 |
| 103 | |
| 104 | |
| 105 | class BrowserWidget(W.CustomList): |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 106 | |
| 107 | def __init__(self, possize, object = None, col = 100, closechildren = 0): |
| 108 | W.List.__init__(self, possize, callback = self.listhit) |
| 109 | self.object = (None,) |
| 110 | self.indent = 16 |
| 111 | self.lastmaxindent = 0 |
| 112 | self.closechildren = closechildren |
| 113 | self.children = [] |
| 114 | self.mincol = 64 |
| 115 | self.setcolumn(col) |
| 116 | self.bind('return', self.openselection) |
| 117 | self.bind('enter', self.openselection) |
| 118 | if object is not None: |
| 119 | self.set(object) |
| 120 | |
| 121 | def set(self, object): |
| 122 | if self.object[0] is not object: |
| 123 | self.object = object, |
| 124 | self[:] = self.unpack(object, 0) |
| 125 | elif self._parentwindow is not None and self._parentwindow.wid: |
| 126 | self.update() |
| 127 | |
| 128 | def unpack(self, object, indent): |
| 129 | return unpack_object(object, indent) |
| 130 | |
| 131 | def update(self): |
| 132 | # for now... |
| 133 | W.SetCursor('watch') |
| 134 | self.setdrawingmode(0) |
| 135 | sel = self.getselectedobjects() |
| 136 | fold = self.getunfoldedobjects() |
| 137 | topcell = self.gettopcell() |
| 138 | self[:] = self.unpack(self.object[0], 0) |
| 139 | self.unfoldobjects(fold) |
| 140 | self.setselectedobjects(sel) |
| 141 | self.settopcell(topcell) |
| 142 | self.setdrawingmode(1) |
| 143 | |
| 144 | def setcolumn(self, col): |
| 145 | self.col = col |
| 146 | self.colstr = struct.pack('h', col) |
| 147 | if self._list: |
| 148 | sel = self.getselection() |
| 149 | self.setitems(self.items) |
| 150 | self.setselection(sel) |
| 151 | |
| 152 | def key(self, char, event): |
| 153 | if char in (Wkeys.leftarrowkey, Wkeys.rightarrowkey): |
| 154 | sel = self.getselection() |
| 155 | sel.reverse() |
| 156 | self.setdrawingmode(0) |
| 157 | for index in sel: |
| 158 | self.fold(index, char == Wkeys.rightarrowkey) |
| 159 | self.setdrawingmode(1) |
| 160 | else: |
| 161 | W.List.key(self, char, event) |
| 162 | |
| 163 | def rollover(self, (x, y), onoff): |
| 164 | if onoff: |
| 165 | if self.incolumn((x, y)): |
| 166 | W.SetCursor('hmover') |
| 167 | else: |
| 168 | W.SetCursor('arrow') |
| 169 | |
| 170 | def inarrow(self, (x, y)): |
| 171 | cl, ct, cr, cb = self._list.LRect((0, 0)) |
| 172 | l, t, r, b = self._bounds |
| 173 | if (x - cl) < 16: |
| 174 | cellheight = cb - ct |
| 175 | index = (y - ct) / cellheight |
| 176 | if index < len(self.items): |
| 177 | return 1, index |
| 178 | return None, None |
| 179 | |
| 180 | def incolumn(self, (x, y)): |
| 181 | l, t, r, b = self._list.LRect((0, 0)) |
| 182 | abscol = l + self.col |
| 183 | return abs(abscol - x) < 3 |
| 184 | |
| 185 | def trackcolumn(self, (x, y)): |
Jack Jansen | 5a6fdcd | 2001-08-25 12:15:04 +0000 | [diff] [blame] | 186 | from Carbon import Qd, QuickDraw, Evt |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 187 | self.SetPort() |
| 188 | l, t, r, b = self._bounds |
| 189 | bounds = l, t, r, b = l + 1, t + 1, r - 16, b - 1 |
| 190 | abscol = l + self.col |
| 191 | mincol = l + self.mincol |
| 192 | maxcol = r - 10 |
| 193 | diff = abscol - x |
| 194 | Qd.PenPat('\000\377\000\377\000\377\000\377') |
| 195 | Qd.PenMode(QuickDraw.srcXor) |
| 196 | rect = abscol - 1, t, abscol, b |
| 197 | Qd.PaintRect(rect) |
| 198 | lastpoint = (x, y) |
| 199 | newcol = -1 |
| 200 | #W.SetCursor('fist') |
| 201 | while Evt.Button(): |
Just van Rossum | f376ef0 | 2001-11-18 14:12:43 +0000 | [diff] [blame] | 202 | Evt.WaitNextEvent(0, 1, None) # needed for OSX |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 203 | (x, y) = Evt.GetMouse() |
| 204 | if (x, y) <> lastpoint: |
| 205 | newcol = x + diff |
| 206 | newcol = max(newcol, mincol) |
| 207 | newcol = min(newcol, maxcol) |
| 208 | Qd.PaintRect(rect) |
| 209 | rect = newcol - 1, t, newcol, b |
| 210 | Qd.PaintRect(rect) |
| 211 | lastpoint = (x, y) |
| 212 | Qd.PaintRect(rect) |
Jack Jansen | 362c7cd0 | 2002-11-30 00:01:29 +0000 | [diff] [blame] | 213 | Qd.PenPat(Qd.GetQDGlobalsBlack()) |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 214 | Qd.PenNormal() |
| 215 | if newcol > 0 and newcol <> abscol: |
| 216 | self.setcolumn(newcol - l) |
| 217 | |
| 218 | def click(self, point, modifiers): |
| 219 | if point == (-1, -1): # gross. |
| 220 | W.List.click(self, point ,modifiers) |
| 221 | return |
| 222 | hit, index = self.inarrow(point) |
| 223 | if hit: |
| 224 | (key, value, arrow, indent) = self.items[index] |
| 225 | self.fold(index, arrow == 1) |
| 226 | elif self.incolumn(point): |
| 227 | self.trackcolumn(point) |
| 228 | else: |
| 229 | W.List.click(self, point, modifiers) |
| 230 | |
| 231 | # for W.List.key |
| 232 | def findmatch(self, tag): |
| 233 | lower = string.lower |
| 234 | items = self.items |
| 235 | taglen = len(tag) |
| 236 | match = '\377' * 100 |
| 237 | match_i = -1 |
| 238 | for i in range(len(items)): |
| 239 | item = lower(str(items[i][0])) |
| 240 | if tag <= item < match: |
| 241 | match = item |
| 242 | match_i = i |
| 243 | if match_i >= 0: |
| 244 | return match_i |
| 245 | else: |
| 246 | return len(items) - 1 |
| 247 | |
| 248 | def close(self): |
| 249 | if self.closechildren: |
| 250 | for window in self.children: |
| 251 | window.close() |
| 252 | self.children = [] |
| 253 | W.List.close(self) |
| 254 | |
| 255 | def fold(self, index, onoff): |
| 256 | (key, value, arrow, indent) = self.items[index] |
| 257 | if arrow == 0 or (onoff and arrow == 2) or (not onoff and arrow == 1): |
| 258 | return |
| 259 | W.SetCursor('watch') |
| 260 | topcell = self.gettopcell() |
| 261 | if onoff: |
| 262 | self[index] = (key, value, 4, indent) |
| 263 | self.setdrawingmode(0) |
| 264 | self[index+1:index+1] = self.unpack(value, indent + 1) |
| 265 | self[index] = (key, value, 2, indent) |
| 266 | else: |
| 267 | self[index] = (key, value, 3, indent) |
| 268 | self.setdrawingmode(0) |
| 269 | count = 0 |
| 270 | for i in range(index + 1, len(self.items)): |
| 271 | (dummy, dummy, dummy, subindent) = self.items[i] |
| 272 | if subindent <= indent: |
| 273 | break |
| 274 | count = count + 1 |
| 275 | self[index+1:index+1+count] = [] |
| 276 | self[index] = (key, value, 1, indent) |
| 277 | maxindent = self.getmaxindent() |
| 278 | if maxindent <> self.lastmaxindent: |
| 279 | newabsindent = self.col + (maxindent - self.lastmaxindent) * self.indent |
| 280 | if newabsindent >= self.mincol: |
| 281 | self.setcolumn(newabsindent) |
| 282 | self.lastmaxindent = maxindent |
| 283 | self.settopcell(topcell) |
| 284 | self.setdrawingmode(1) |
| 285 | |
| 286 | def unfoldobjects(self, objects): |
| 287 | for obj in objects: |
| 288 | try: |
| 289 | index = self.items.index(obj) |
| 290 | except ValueError: |
| 291 | pass |
| 292 | else: |
| 293 | self.fold(index, 1) |
| 294 | |
| 295 | def getunfoldedobjects(self): |
| 296 | curindent = 0 |
| 297 | objects = [] |
| 298 | for index in range(len(self.items)): |
| 299 | (key, value, arrow, indent) = self.items[index] |
| 300 | if indent > curindent: |
| 301 | (k, v, a, i) = self.items[index - 1] |
| 302 | objects.append((k, v, 1, i)) |
| 303 | curindent = indent |
| 304 | elif indent < curindent: |
| 305 | curindent = indent |
| 306 | return objects |
| 307 | |
| 308 | def listhit(self, isdbl): |
| 309 | if isdbl: |
| 310 | self.openselection() |
| 311 | |
| 312 | def openselection(self): |
| 313 | import os |
| 314 | sel = self.getselection() |
| 315 | for index in sel: |
| 316 | (key, value, arrow, indent) = self[index] |
| 317 | if arrow: |
| 318 | self.children.append(Browser(value)) |
| 319 | elif type(value) == types.StringType and '\0' not in value: |
| 320 | editor = self._parentwindow.parent.getscript(value) |
| 321 | if editor: |
| 322 | editor.select() |
| 323 | return |
| 324 | elif os.path.exists(value) and os.path.isfile(value): |
Jack Jansen | e7ee17c | 2003-02-06 22:32:35 +0000 | [diff] [blame] | 325 | if MacOS.GetCreatorAndType(value)[1] in ('TEXT', '\0\0\0\0'): |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 326 | W.getapplication().openscript(value) |
| 327 | |
| 328 | def itemrepr(self, (key, value, arrow, indent), str = str, double_repr = double_repr, |
| 329 | arrows = arrows, pack = struct.pack): |
| 330 | arrow = arrows[arrow] |
| 331 | return arrow + pack('h', self.indent * indent) + self.colstr + \ |
| 332 | double_repr(key, value, 1) |
| 333 | |
| 334 | def getmaxindent(self, max = max): |
| 335 | maxindent = 0 |
| 336 | for item in self.items: |
| 337 | maxindent = max(maxindent, item[3]) |
| 338 | return maxindent |
| 339 | |
| 340 | def domenu_copy(self, *args): |
| 341 | sel = self.getselectedobjects() |
| 342 | selitems = [] |
| 343 | for key, value, dummy, dummy in sel: |
| 344 | selitems.append(double_repr(key, value)) |
| 345 | text = string.join(selitems, '\r') |
| 346 | if text: |
Just van Rossum | 01c9805 | 2001-11-02 19:21:34 +0000 | [diff] [blame] | 347 | from Carbon import Scrap |
Jack Jansen | 6529368 | 2001-12-31 15:08:04 +0000 | [diff] [blame] | 348 | if hasattr(Scrap, 'PutScrap'): |
| 349 | Scrap.ZeroScrap() |
| 350 | Scrap.PutScrap('TEXT', text) |
| 351 | else: |
| 352 | Scrap.ClearCurrentScrap() |
| 353 | sc = Scrap.GetCurrentScrap() |
| 354 | sc.PutScrapFlavor('TEXT', 0, text) |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 355 | |
Just van Rossum | 4e6d13c | 2002-03-26 12:06:11 +0000 | [diff] [blame] | 356 | def listDefDraw(self, selected, cellRect, theCell, |
| 357 | dataOffset, dataLen, theList): |
| 358 | self.myDrawCell(0, selected, cellRect, theCell, |
| 359 | dataOffset, dataLen, theList) |
| 360 | |
| 361 | def listDefHighlight(self, selected, cellRect, theCell, |
| 362 | dataOffset, dataLen, theList): |
| 363 | self.myDrawCell(1, selected, cellRect, theCell, |
| 364 | dataOffset, dataLen, theList) |
| 365 | |
| 366 | def myDrawCell(self, onlyHilite, selected, cellRect, theCell, |
| 367 | dataOffset, dataLen, theList): |
| 368 | savedPort = Qd.GetPort() |
Jack Jansen | 362c7cd0 | 2002-11-30 00:01:29 +0000 | [diff] [blame] | 369 | Qd.SetPort(theList.GetListPort()) |
Just van Rossum | 4e6d13c | 2002-03-26 12:06:11 +0000 | [diff] [blame] | 370 | savedClip = Qd.NewRgn() |
| 371 | Qd.GetClip(savedClip) |
| 372 | Qd.ClipRect(cellRect) |
| 373 | savedPenState = Qd.GetPenState() |
| 374 | Qd.PenNormal() |
| 375 | |
| 376 | l, t, r, b = cellRect |
| 377 | |
| 378 | if not onlyHilite: |
| 379 | Qd.EraseRect(cellRect) |
| 380 | |
| 381 | ascent, descent, leading, size, hm = Fm.FontMetrics() |
| 382 | linefeed = ascent + descent + leading |
| 383 | |
| 384 | if dataLen >= 6: |
| 385 | data = theList.LGetCell(dataLen, theCell) |
| 386 | iconId, indent, tab = struct.unpack("hhh", data[:6]) |
Just van Rossum | 3c4dee4 | 2002-09-16 21:18:49 +0000 | [diff] [blame] | 387 | try: |
| 388 | key, value = data[6:].split("\t", 1) |
| 389 | except ValueError: |
| 390 | # bogus data, at least don't crash. |
| 391 | indent = 0 |
| 392 | tab = 0 |
| 393 | iconId = 0 |
| 394 | key = "" |
| 395 | value = data[6:] |
Just van Rossum | 4e6d13c | 2002-03-26 12:06:11 +0000 | [diff] [blame] | 396 | |
| 397 | if iconId: |
Just van Rossum | 3c4dee4 | 2002-09-16 21:18:49 +0000 | [diff] [blame] | 398 | try: |
| 399 | theIcon = Icn.GetCIcon(iconId) |
| 400 | except Icn.Error: |
| 401 | pass |
| 402 | else: |
| 403 | rect = (0, 0, 16, 16) |
| 404 | rect = Qd.OffsetRect(rect, l, t) |
| 405 | rect = Qd.OffsetRect(rect, 0, (theList.cellSize[1] - (rect[3] - rect[1])) / 2) |
| 406 | Icn.PlotCIcon(rect, theIcon) |
Just van Rossum | 4e6d13c | 2002-03-26 12:06:11 +0000 | [diff] [blame] | 407 | |
| 408 | if len(key) >= 0: |
| 409 | cl, ct, cr, cb = cellRect |
| 410 | vl, vt, vr, vb = self._viewbounds |
| 411 | cl = vl + PICTWIDTH + indent |
| 412 | cr = vl + tab |
| 413 | if cr > vr: |
| 414 | cr = vr |
| 415 | if cl < cr: |
| 416 | drawTextCell(key, (cl, ct, cr, cb), ascent, theList) |
| 417 | cl = vl + tab |
| 418 | cr = vr |
| 419 | if cl < cr: |
| 420 | drawTextCell(value, (cl, ct, cr, cb), ascent, theList) |
| 421 | #elif dataLen != 0: |
| 422 | # drawTextCell("???", 3, cellRect, ascent, theList) |
Just van Rossum | 3c4dee4 | 2002-09-16 21:18:49 +0000 | [diff] [blame] | 423 | else: |
| 424 | return # we have bogus data |
Just van Rossum | 4e6d13c | 2002-03-26 12:06:11 +0000 | [diff] [blame] | 425 | |
| 426 | # draw nice dotted line |
| 427 | l, t, r, b = cellRect |
| 428 | l = self._viewbounds[0] + tab |
| 429 | r = l + 1; |
| 430 | if not (theList.cellSize[1] & 0x01) or (t & 0x01): |
| 431 | myPat = "\xff\x00\xff\x00\xff\x00\xff\x00" |
| 432 | else: |
| 433 | myPat = "\x00\xff\x00\xff\x00\xff\x00\xff" |
| 434 | Qd.PenPat(myPat) |
| 435 | Qd.PenMode(QuickDraw.srcCopy) |
| 436 | Qd.PaintRect((l, t, r, b)) |
| 437 | Qd.PenNormal() |
| 438 | |
| 439 | if selected or onlyHilite: |
| 440 | l, t, r, b = cellRect |
| 441 | l = self._viewbounds[0] + PICTWIDTH |
| 442 | r = self._viewbounds[2] |
| 443 | Qd.PenMode(hilitetransfermode) |
| 444 | Qd.PaintRect((l, t, r, b)) |
| 445 | |
| 446 | # restore graphics environment |
| 447 | Qd.SetPort(savedPort) |
| 448 | Qd.SetClip(savedClip) |
| 449 | Qd.DisposeRgn(savedClip) |
| 450 | Qd.SetPenState(savedPenState) |
| 451 | |
| 452 | |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 453 | |
| 454 | class Browser: |
| 455 | |
| 456 | def __init__(self, object = None, title = None, closechildren = 0): |
| 457 | if hasattr(object, '__name__'): |
| 458 | name = object.__name__ |
| 459 | else: |
| 460 | name = '' |
| 461 | if title is None: |
| 462 | title = 'Object browser' |
| 463 | if name: |
| 464 | title = title + ': ' + name |
| 465 | self.w = w = W.Window((300, 400), title, minsize = (100, 100)) |
| 466 | w.info = W.TextBox((18, 8, -70, 15)) |
Just van Rossum | f376ef0 | 2001-11-18 14:12:43 +0000 | [diff] [blame] | 467 | w.updatebutton = W.BevelButton((-64, 4, 50, 16), 'Update', self.update) |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 468 | w.browser = BrowserWidget((-1, 24, 1, -14), None) |
| 469 | w.bind('cmdu', w.updatebutton.push) |
| 470 | w.open() |
| 471 | self.set(object, name) |
| 472 | |
| 473 | def close(self): |
| 474 | if self.w.wid: |
| 475 | self.w.close() |
| 476 | |
| 477 | def set(self, object, name = ''): |
| 478 | W.SetCursor('watch') |
| 479 | tp = type(object).__name__ |
| 480 | try: |
| 481 | length = len(object) |
| 482 | except: |
| 483 | length = -1 |
| 484 | if not name and hasattr(object, '__name__'): |
| 485 | name = object.__name__ |
| 486 | if name: |
| 487 | info = name + ': ' + tp |
| 488 | else: |
| 489 | info = tp |
| 490 | if length >= 0: |
| 491 | if length == 1: |
| 492 | info = info + ' (%d element)' % length |
| 493 | else: |
| 494 | info = info + ' (%d elements)' % length |
| 495 | self.w.info.set(info) |
| 496 | self.w.browser.set(object) |
| 497 | |
| 498 | def update(self): |
| 499 | self.w.browser.update() |
| 500 | |
| 501 | |
| 502 | SIMPLE_TYPES = ( |
Just van Rossum | 927bc45 | 2002-12-01 22:10:36 +0000 | [diff] [blame] | 503 | type(None), |
| 504 | int, |
| 505 | long, |
| 506 | float, |
| 507 | complex, |
| 508 | str, |
| 509 | unicode, |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 510 | ) |
| 511 | |
Just van Rossum | 927bc45 | 2002-12-01 22:10:36 +0000 | [diff] [blame] | 512 | def get_ivars(obj): |
| 513 | """Return a list the names of all (potential) instance variables.""" |
| 514 | # __mro__ recipe from Guido |
| 515 | slots = {} |
| 516 | # old-style C objects |
| 517 | if hasattr(obj, "__members__"): |
| 518 | for name in obj.__members__: |
| 519 | slots[name] = None |
| 520 | if hasattr(obj, "__methods__"): |
| 521 | for name in obj.__methods__: |
| 522 | slots[name] = None |
| 523 | # generic type |
| 524 | if hasattr(obj, "__dict__"): |
| 525 | slots.update(obj.__dict__) |
| 526 | cls = type(obj) |
| 527 | if hasattr(cls, "__mro__"): |
| 528 | # new-style class, use descriptors |
| 529 | for base in cls.__mro__: |
| 530 | for name, value in base.__dict__.items(): |
| 531 | # XXX using callable() is a heuristic which isn't 100% |
| 532 | # foolproof. |
| 533 | if hasattr(value, "__get__") and not callable(value): |
| 534 | slots[name] = None |
| 535 | if "__dict__" in slots: |
| 536 | del slots["__dict__"] |
| 537 | slots = slots.keys() |
| 538 | slots.sort() |
| 539 | return slots |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 540 | |
| 541 | def unpack_object(object, indent = 0): |
| 542 | tp = type(object) |
Just van Rossum | 927bc45 | 2002-12-01 22:10:36 +0000 | [diff] [blame] | 543 | if isinstance(object, SIMPLE_TYPES) and object is not None: |
Just van Rossum | dc3c617 | 2001-06-19 21:37:33 +0000 | [diff] [blame] | 544 | raise TypeError, "can't browse simple type: %s" % tp.__name__ |
Just van Rossum | 927bc45 | 2002-12-01 22:10:36 +0000 | [diff] [blame] | 545 | elif isinstance(object, dict): |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 546 | return unpack_dict(object, indent) |
Just van Rossum | 927bc45 | 2002-12-01 22:10:36 +0000 | [diff] [blame] | 547 | elif isinstance(object, (tuple, list)): |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 548 | return unpack_sequence(object, indent) |
Just van Rossum | 927bc45 | 2002-12-01 22:10:36 +0000 | [diff] [blame] | 549 | elif isinstance(object, types.ModuleType): |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 550 | return unpack_dict(object.__dict__, indent) |
| 551 | else: |
| 552 | return unpack_other(object, indent) |
| 553 | |
| 554 | def unpack_sequence(seq, indent = 0): |
Just van Rossum | 71fd01c | 2002-12-13 11:07:20 +0000 | [diff] [blame] | 555 | return [(i, v, not isinstance(v, SIMPLE_TYPES), indent) |
| 556 | for i, v in enumerate(seq)] |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 557 | |
| 558 | def unpack_dict(dict, indent = 0): |
| 559 | items = dict.items() |
| 560 | return pack_items(items, indent) |
| 561 | |
| 562 | def unpack_instance(inst, indent = 0): |
| 563 | if hasattr(inst, '__pybrowse_unpack__'): |
| 564 | return unpack_object(inst.__pybrowse_unpack__(), indent) |
| 565 | else: |
| 566 | items = [('__class__', inst.__class__)] + inst.__dict__.items() |
| 567 | return pack_items(items, indent) |
| 568 | |
| 569 | def unpack_class(clss, indent = 0): |
| 570 | items = [('__bases__', clss.__bases__), ('__name__', clss.__name__)] + clss.__dict__.items() |
| 571 | return pack_items(items, indent) |
| 572 | |
| 573 | def unpack_other(object, indent = 0): |
Just van Rossum | 927bc45 | 2002-12-01 22:10:36 +0000 | [diff] [blame] | 574 | attrs = get_ivars(object) |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 575 | items = [] |
| 576 | for attr in attrs: |
Just van Rossum | 927bc45 | 2002-12-01 22:10:36 +0000 | [diff] [blame] | 577 | try: |
| 578 | value = getattr(object, attr) |
| 579 | except: |
| 580 | pass |
| 581 | else: |
| 582 | items.append((attr, value)) |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 583 | return pack_items(items, indent) |
| 584 | |
| 585 | def pack_items(items, indent = 0): |
Just van Rossum | feddf77 | 2002-12-13 15:14:22 +0000 | [diff] [blame] | 586 | items = [(k, v, not isinstance(v, SIMPLE_TYPES), indent) |
| 587 | for k, v in items] |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 588 | return tuple_caselesssort(items) |
| 589 | |
| 590 | def caselesssort(alist): |
| 591 | """Return a sorted copy of a list. If there are only strings in the list, |
| 592 | it will not consider case""" |
| 593 | |
| 594 | try: |
| 595 | # turn ['FOO', 'aaBc', 'ABcD'] into [('foo', 'FOO'), ('aabc', 'aaBc'), ('abcd', 'ABcD')], if possible |
| 596 | tupledlist = map(lambda item, lower = string.lower: (lower(item), item), alist) |
| 597 | except TypeError: |
| 598 | # at least one element in alist is not a string, proceed the normal way... |
| 599 | alist = alist[:] |
| 600 | alist.sort() |
| 601 | return alist |
| 602 | else: |
| 603 | tupledlist.sort() |
| 604 | # turn [('aabc', 'aaBc'), ('abcd', 'ABcD'), ('foo', 'FOO')] into ['aaBc', 'ABcD', 'FOO'] |
| 605 | return map(lambda x: x[1], tupledlist) |
| 606 | |
| 607 | def tuple_caselesssort(items): |
| 608 | try: |
| 609 | tupledlist = map(lambda tuple, lower = string.lower: (lower(tuple[0]), tuple), items) |
Just van Rossum | 6508c7c | 2000-10-20 06:34:57 +0000 | [diff] [blame] | 610 | except (AttributeError, TypeError): |
Just van Rossum | 40f9b7b | 1999-01-30 22:39:17 +0000 | [diff] [blame] | 611 | items = items[:] |
| 612 | items.sort() |
| 613 | return items |
| 614 | else: |
| 615 | tupledlist.sort() |
| 616 | return map(lambda (low, tuple): tuple, tupledlist) |
| 617 | |