mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			440 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			440 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import W
 | 
						|
import Wkeys
 | 
						|
import struct
 | 
						|
import string
 | 
						|
import types
 | 
						|
import regex
 | 
						|
 | 
						|
nullid = '\0\0'
 | 
						|
closedid = struct.pack('h', 468)
 | 
						|
openid = struct.pack('h', 469)
 | 
						|
closedsolidid = struct.pack('h', 470)
 | 
						|
opensolidid = struct.pack('h', 471)
 | 
						|
 | 
						|
arrows = (nullid, closedid, openid, closedsolidid, opensolidid)
 | 
						|
 | 
						|
has_ctlcharsRE = regex.compile('[\000-\037\177-\377]')
 | 
						|
 | 
						|
def double_repr(key, value, truncvalue = 0, 
 | 
						|
			type = type, StringType = types.StringType,
 | 
						|
			has_ctlchars = has_ctlcharsRE.search, _repr = repr, str = str):
 | 
						|
	if type(key) == StringType and has_ctlchars(key) < 0:
 | 
						|
		key = str(key)
 | 
						|
	else:
 | 
						|
		key = _repr(key)
 | 
						|
	if type(value) == StringType and has_ctlchars(value) < 0:
 | 
						|
		value = str(value)
 | 
						|
	elif key == '__builtins__':
 | 
						|
		value = "<" + type(value).__name__ + " '__builtin__'>"
 | 
						|
	elif key == '__return__':
 | 
						|
		# bleh, when returning from a class codeblock we get infinite recursion in repr. 
 | 
						|
		# Use safe repr instead.
 | 
						|
		import repr
 | 
						|
		value = repr.repr(value)
 | 
						|
	else:
 | 
						|
		try:
 | 
						|
			value = _repr(value)
 | 
						|
			'' + value	# test to see if it is a string, in case a __repr__ method is buggy
 | 
						|
		except:
 | 
						|
			value = '€€€ exception in repr()'
 | 
						|
	if truncvalue:
 | 
						|
		return key + '\t' + value[:255]
 | 
						|
	return key + '\t' + value
 | 
						|
 | 
						|
 | 
						|
class BrowserWidget(W.List):
 | 
						|
	
 | 
						|
	LDEF_ID = 471
 | 
						|
	
 | 
						|
	def __init__(self, possize, object = None, col = 100, closechildren = 0):
 | 
						|
		W.List.__init__(self, possize, callback = self.listhit)
 | 
						|
		self.object = (None,)
 | 
						|
		self.indent = 16
 | 
						|
		self.lastmaxindent = 0
 | 
						|
		self.closechildren = closechildren
 | 
						|
		self.children = []
 | 
						|
		self.mincol = 64
 | 
						|
		self.setcolumn(col)
 | 
						|
		self.bind('return', self.openselection)
 | 
						|
		self.bind('enter', self.openselection)
 | 
						|
		if object is not None:
 | 
						|
			self.set(object)
 | 
						|
	
 | 
						|
	def set(self, object):
 | 
						|
		if self.object[0] is not object:
 | 
						|
			self.object = object,
 | 
						|
			self[:] = self.unpack(object, 0)
 | 
						|
		elif self._parentwindow is not None and self._parentwindow.wid:
 | 
						|
			self.update()
 | 
						|
	
 | 
						|
	def unpack(self, object, indent):
 | 
						|
		return unpack_object(object, indent)
 | 
						|
	
 | 
						|
	def update(self):
 | 
						|
		# for now...
 | 
						|
		W.SetCursor('watch')
 | 
						|
		self.setdrawingmode(0)
 | 
						|
		sel = self.getselectedobjects()
 | 
						|
		fold = self.getunfoldedobjects()
 | 
						|
		topcell = self.gettopcell()
 | 
						|
		self[:] = self.unpack(self.object[0], 0)
 | 
						|
		self.unfoldobjects(fold)
 | 
						|
		self.setselectedobjects(sel)
 | 
						|
		self.settopcell(topcell)
 | 
						|
		self.setdrawingmode(1)
 | 
						|
	
 | 
						|
	def setcolumn(self, col):
 | 
						|
		self.col = col
 | 
						|
		self.colstr = struct.pack('h', col)
 | 
						|
		if self._list:
 | 
						|
			sel = self.getselection()
 | 
						|
			self.setitems(self.items)
 | 
						|
			self.setselection(sel)
 | 
						|
	
 | 
						|
	def key(self, char, event):
 | 
						|
		if char in (Wkeys.leftarrowkey, Wkeys.rightarrowkey):
 | 
						|
			sel = self.getselection()
 | 
						|
			sel.reverse()
 | 
						|
			self.setdrawingmode(0)
 | 
						|
			for index in sel:
 | 
						|
				self.fold(index, char == Wkeys.rightarrowkey)
 | 
						|
			self.setdrawingmode(1)
 | 
						|
		else:
 | 
						|
			W.List.key(self, char, event)
 | 
						|
	
 | 
						|
	def rollover(self, (x, y), onoff):
 | 
						|
		if onoff:
 | 
						|
			if self.incolumn((x, y)):
 | 
						|
				W.SetCursor('hmover')
 | 
						|
			else:
 | 
						|
				W.SetCursor('arrow')
 | 
						|
	
 | 
						|
	def inarrow(self, (x, y)):
 | 
						|
		cl, ct, cr, cb = self._list.LRect((0, 0))
 | 
						|
		l, t, r, b = self._bounds
 | 
						|
		if (x - cl) < 16:
 | 
						|
			cellheight = cb - ct
 | 
						|
			index = (y - ct) / cellheight
 | 
						|
			if index < len(self.items):
 | 
						|
				return 1, index
 | 
						|
		return None, None
 | 
						|
	
 | 
						|
	def incolumn(self, (x, y)):
 | 
						|
		l, t, r, b = self._list.LRect((0, 0))
 | 
						|
		abscol = l + self.col
 | 
						|
		return abs(abscol - x) < 3
 | 
						|
	
 | 
						|
	def trackcolumn(self, (x, y)):
 | 
						|
		import Qd, QuickDraw, Evt
 | 
						|
		self.SetPort()
 | 
						|
		l, t, r, b = self._bounds
 | 
						|
		bounds = l, t, r, b = l + 1, t + 1, r - 16, b - 1
 | 
						|
		abscol = l + self.col
 | 
						|
		mincol = l + self.mincol
 | 
						|
		maxcol = r - 10
 | 
						|
		diff = abscol - x
 | 
						|
		Qd.PenPat('\000\377\000\377\000\377\000\377')
 | 
						|
		Qd.PenMode(QuickDraw.srcXor)
 | 
						|
		rect = abscol - 1, t, abscol, b
 | 
						|
		Qd.PaintRect(rect)
 | 
						|
		lastpoint = (x, y)
 | 
						|
		newcol = -1
 | 
						|
		#W.SetCursor('fist')
 | 
						|
		while Evt.Button():
 | 
						|
			(x, y) = Evt.GetMouse()
 | 
						|
			if (x, y) <> lastpoint:
 | 
						|
				newcol = x + diff
 | 
						|
				newcol = max(newcol, mincol)
 | 
						|
				newcol = min(newcol, maxcol)
 | 
						|
				Qd.PaintRect(rect)
 | 
						|
				rect = newcol - 1, t, newcol, b
 | 
						|
				Qd.PaintRect(rect)
 | 
						|
				lastpoint = (x, y)
 | 
						|
		Qd.PaintRect(rect)
 | 
						|
		Qd.PenPat(Qd.qd.black)
 | 
						|
		Qd.PenNormal()
 | 
						|
		if newcol > 0 and newcol <> abscol:
 | 
						|
			self.setcolumn(newcol - l)
 | 
						|
	
 | 
						|
	def click(self, point, modifiers):
 | 
						|
		if point == (-1, -1):	# gross.
 | 
						|
			W.List.click(self, point ,modifiers)
 | 
						|
			return
 | 
						|
		hit, index = self.inarrow(point)
 | 
						|
		if hit:
 | 
						|
			(key, value, arrow, indent) = self.items[index]
 | 
						|
			self.fold(index, arrow == 1)
 | 
						|
		elif self.incolumn(point):
 | 
						|
			self.trackcolumn(point)
 | 
						|
		else:
 | 
						|
			W.List.click(self, point, modifiers)
 | 
						|
	
 | 
						|
	# for W.List.key
 | 
						|
	def findmatch(self, tag):
 | 
						|
		lower = string.lower
 | 
						|
		items = self.items
 | 
						|
		taglen = len(tag)
 | 
						|
		match = '\377' * 100
 | 
						|
		match_i = -1
 | 
						|
		for i in range(len(items)):
 | 
						|
			item = lower(str(items[i][0]))
 | 
						|
			if tag <= item < match:
 | 
						|
				match = item
 | 
						|
				match_i = i
 | 
						|
		if match_i >= 0:
 | 
						|
			return match_i
 | 
						|
		else:
 | 
						|
			return len(items) - 1
 | 
						|
	
 | 
						|
	def close(self):
 | 
						|
		if self.closechildren:
 | 
						|
			for window in self.children:
 | 
						|
				window.close()
 | 
						|
		self.children = []
 | 
						|
		W.List.close(self)
 | 
						|
	
 | 
						|
	def fold(self, index, onoff):
 | 
						|
		(key, value, arrow, indent) = self.items[index]
 | 
						|
		if arrow == 0 or (onoff and arrow == 2) or (not onoff and arrow == 1):
 | 
						|
			return
 | 
						|
		W.SetCursor('watch')
 | 
						|
		topcell = self.gettopcell()
 | 
						|
		if onoff:
 | 
						|
			self[index] = (key, value, 4, indent)
 | 
						|
			self.setdrawingmode(0)
 | 
						|
			self[index+1:index+1] = self.unpack(value, indent + 1)
 | 
						|
			self[index] = (key, value, 2, indent)
 | 
						|
		else:
 | 
						|
			self[index] = (key, value, 3, indent)
 | 
						|
			self.setdrawingmode(0)
 | 
						|
			count = 0
 | 
						|
			for i in range(index + 1, len(self.items)):
 | 
						|
				(dummy, dummy, dummy, subindent) = self.items[i]
 | 
						|
				if subindent <= indent:
 | 
						|
					break
 | 
						|
				count = count + 1
 | 
						|
			self[index+1:index+1+count] = []
 | 
						|
			self[index] = (key, value, 1, indent)
 | 
						|
		maxindent = self.getmaxindent()
 | 
						|
		if maxindent <> self.lastmaxindent:
 | 
						|
			newabsindent = self.col + (maxindent - self.lastmaxindent) * self.indent
 | 
						|
			if newabsindent >= self.mincol:
 | 
						|
				self.setcolumn(newabsindent)
 | 
						|
			self.lastmaxindent = maxindent
 | 
						|
		self.settopcell(topcell)
 | 
						|
		self.setdrawingmode(1)
 | 
						|
	
 | 
						|
	def unfoldobjects(self, objects):
 | 
						|
		for obj in objects:
 | 
						|
			try:
 | 
						|
				index = self.items.index(obj)
 | 
						|
			except ValueError:
 | 
						|
				pass
 | 
						|
			else:
 | 
						|
				self.fold(index, 1)
 | 
						|
	
 | 
						|
	def getunfoldedobjects(self):
 | 
						|
		curindent = 0
 | 
						|
		objects = []
 | 
						|
		for index in range(len(self.items)):
 | 
						|
			(key, value, arrow, indent) = self.items[index]
 | 
						|
			if indent > curindent:
 | 
						|
				(k, v, a, i) = self.items[index - 1]
 | 
						|
				objects.append((k, v, 1, i))
 | 
						|
				curindent = indent
 | 
						|
			elif indent < curindent:
 | 
						|
				curindent = indent
 | 
						|
		return objects
 | 
						|
	
 | 
						|
	def listhit(self, isdbl):
 | 
						|
		if isdbl:
 | 
						|
			self.openselection()
 | 
						|
	
 | 
						|
	def openselection(self):
 | 
						|
		import os
 | 
						|
		sel = self.getselection()
 | 
						|
		for index in sel:
 | 
						|
			(key, value, arrow, indent) = self[index]
 | 
						|
			if arrow:
 | 
						|
				self.children.append(Browser(value))
 | 
						|
			elif type(value) == types.StringType and '\0' not in value:
 | 
						|
				editor = self._parentwindow.parent.getscript(value)
 | 
						|
				if editor:
 | 
						|
					editor.select()
 | 
						|
					return
 | 
						|
				elif os.path.exists(value) and os.path.isfile(value):
 | 
						|
					import macfs
 | 
						|
					fss = macfs.FSSpec(value)
 | 
						|
					if fss.GetCreatorType()[1] == 'TEXT':
 | 
						|
						W.getapplication().openscript(value)
 | 
						|
	
 | 
						|
	def itemrepr(self, (key, value, arrow, indent), str = str, double_repr = double_repr, 
 | 
						|
			arrows = arrows, pack = struct.pack):
 | 
						|
		arrow = arrows[arrow]
 | 
						|
		return arrow + pack('h', self.indent * indent) + self.colstr + \
 | 
						|
				double_repr(key, value, 1)
 | 
						|
	
 | 
						|
	def getmaxindent(self, max = max):
 | 
						|
		maxindent = 0
 | 
						|
		for item in self.items:
 | 
						|
			maxindent = max(maxindent, item[3])
 | 
						|
		return maxindent
 | 
						|
	
 | 
						|
	def domenu_copy(self, *args):
 | 
						|
		sel = self.getselectedobjects()
 | 
						|
		selitems = []
 | 
						|
		for key, value, dummy, dummy in sel:
 | 
						|
			selitems.append(double_repr(key, value))
 | 
						|
		text = string.join(selitems, '\r')
 | 
						|
		if text:
 | 
						|
			import Scrap
 | 
						|
			Scrap.ZeroScrap()
 | 
						|
			Scrap.PutScrap('TEXT', text)
 | 
						|
 | 
						|
 | 
						|
class Browser:
 | 
						|
	
 | 
						|
	def __init__(self, object = None, title = None, closechildren = 0):
 | 
						|
		if hasattr(object, '__name__'):
 | 
						|
			name = object.__name__
 | 
						|
		else:
 | 
						|
			name = ''
 | 
						|
		if title is None:
 | 
						|
			title = 'Object browser'
 | 
						|
			if name:
 | 
						|
				title = title + ': ' + name
 | 
						|
		self.w = w = W.Window((300, 400), title, minsize = (100, 100))
 | 
						|
		w.info = W.TextBox((18, 8, -70, 15))
 | 
						|
		w.updatebutton = W.Button((-64, 4, 50, 16), 'Update', self.update)
 | 
						|
		w.browser = BrowserWidget((-1, 24, 1, -14), None)
 | 
						|
		w.bind('cmdu', w.updatebutton.push)
 | 
						|
		w.open()
 | 
						|
		self.set(object, name)
 | 
						|
	
 | 
						|
	def close(self):
 | 
						|
		if self.w.wid:
 | 
						|
			self.w.close()
 | 
						|
	
 | 
						|
	def set(self, object, name = ''):
 | 
						|
		W.SetCursor('watch')
 | 
						|
		tp = type(object).__name__
 | 
						|
		try:
 | 
						|
			length = len(object)
 | 
						|
		except:
 | 
						|
			length = -1
 | 
						|
		if not name and hasattr(object, '__name__'):
 | 
						|
			name = object.__name__
 | 
						|
		if name:
 | 
						|
			info = name + ': ' + tp
 | 
						|
		else:
 | 
						|
			info = tp
 | 
						|
		if length >= 0:
 | 
						|
			if length == 1:
 | 
						|
				info = info + ' (%d element)' % length
 | 
						|
			else:
 | 
						|
				info = info + ' (%d elements)' % length
 | 
						|
		self.w.info.set(info)
 | 
						|
		self.w.browser.set(object)
 | 
						|
	
 | 
						|
	def update(self):
 | 
						|
		self.w.browser.update()
 | 
						|
 | 
						|
 | 
						|
SIMPLE_TYPES = (
 | 
						|
	types.NoneType,
 | 
						|
	types.IntType,
 | 
						|
	types.LongType,
 | 
						|
	types.FloatType,
 | 
						|
	types.ComplexType,
 | 
						|
	types.StringType
 | 
						|
)
 | 
						|
 | 
						|
INDEXING_TYPES = (
 | 
						|
	types.TupleType,
 | 
						|
	types.ListType,
 | 
						|
	types.DictionaryType
 | 
						|
)
 | 
						|
 | 
						|
def unpack_object(object, indent = 0):
 | 
						|
	tp = type(object)
 | 
						|
	if tp in SIMPLE_TYPES and tp is not types.NoneType:
 | 
						|
		raise TypeError, 'can¹t browse simple type: %s' % tp.__name__
 | 
						|
	elif tp == types.DictionaryType:
 | 
						|
		return unpack_dict(object, indent)
 | 
						|
	elif tp in (types.TupleType, types.ListType):
 | 
						|
		return unpack_sequence(object, indent)
 | 
						|
	elif tp == types.InstanceType:
 | 
						|
		return unpack_instance(object, indent)
 | 
						|
	elif tp == types.ClassType:
 | 
						|
		return unpack_class(object, indent)
 | 
						|
	elif tp == types.ModuleType:
 | 
						|
		return unpack_dict(object.__dict__, indent)
 | 
						|
	else:
 | 
						|
		return unpack_other(object, indent)
 | 
						|
 | 
						|
def unpack_sequence(seq, indent = 0):
 | 
						|
	items = map(None, range(len(seq)), seq)
 | 
						|
	items = map(lambda (k, v), type = type, simp = SIMPLE_TYPES, indent = indent: 
 | 
						|
				(k, v, not type(v) in simp, indent), items)
 | 
						|
	return items
 | 
						|
 | 
						|
def unpack_dict(dict, indent = 0):
 | 
						|
	items = dict.items()
 | 
						|
	return pack_items(items, indent)
 | 
						|
 | 
						|
def unpack_instance(inst, indent = 0):
 | 
						|
	if hasattr(inst, '__pybrowse_unpack__'):
 | 
						|
		return unpack_object(inst.__pybrowse_unpack__(), indent)
 | 
						|
	else:
 | 
						|
		items = [('__class__', inst.__class__)] + inst.__dict__.items()
 | 
						|
		return pack_items(items, indent)
 | 
						|
 | 
						|
def unpack_class(clss, indent = 0):
 | 
						|
	items = [('__bases__', clss.__bases__), ('__name__', clss.__name__)] + clss.__dict__.items()
 | 
						|
	return pack_items(items, indent)
 | 
						|
 | 
						|
def unpack_other(object, indent = 0):
 | 
						|
	attrs = []
 | 
						|
	if hasattr(object, '__members__'):
 | 
						|
		attrs = attrs + object.__members__
 | 
						|
	if hasattr(object, '__methods__'):
 | 
						|
		attrs = attrs + object.__methods__
 | 
						|
	items = []
 | 
						|
	for attr in attrs:
 | 
						|
		items.append((attr, getattr(object, attr)))
 | 
						|
	return pack_items(items, indent)
 | 
						|
 | 
						|
def pack_items(items, indent = 0):
 | 
						|
	items = map(lambda (k, v), type = type, simp = SIMPLE_TYPES, indent = indent: 
 | 
						|
				(k, v, not type(v) in simp, indent), 
 | 
						|
			items)
 | 
						|
	return tuple_caselesssort(items)
 | 
						|
 | 
						|
def caselesssort(alist):
 | 
						|
	"""Return a sorted copy of a list. If there are only strings in the list, 
 | 
						|
	it will not consider case"""
 | 
						|
	
 | 
						|
	try:
 | 
						|
		# turn ['FOO',  'aaBc', 'ABcD'] into [('foo', 'FOO'), ('aabc', 'aaBc'), ('abcd', 'ABcD')], if possible
 | 
						|
		tupledlist = map(lambda item, lower = string.lower: (lower(item), item), alist)
 | 
						|
	except TypeError:
 | 
						|
		# at least one element in alist is not a string, proceed the normal way...
 | 
						|
		alist = alist[:]
 | 
						|
		alist.sort()
 | 
						|
		return alist
 | 
						|
	else:
 | 
						|
		tupledlist.sort()
 | 
						|
		# turn [('aabc', 'aaBc'), ('abcd', 'ABcD'), ('foo', 'FOO')] into ['aaBc', 'ABcD', 'FOO']
 | 
						|
		return map(lambda x: x[1], tupledlist)
 | 
						|
 | 
						|
def tuple_caselesssort(items):
 | 
						|
	try:
 | 
						|
		tupledlist = map(lambda tuple, lower = string.lower: (lower(tuple[0]), tuple), items)
 | 
						|
	except TypeError:
 | 
						|
		items = items[:]
 | 
						|
		items.sort()
 | 
						|
		return items
 | 
						|
	else:
 | 
						|
		tupledlist.sort()
 | 
						|
		return map(lambda (low, tuple): tuple, tupledlist)
 | 
						|
 |