First Checked In.
diff --git a/Mac/Tools/IDE/PyEdit.py b/Mac/Tools/IDE/PyEdit.py
new file mode 100644
index 0000000..f885d04
--- /dev/null
+++ b/Mac/Tools/IDE/PyEdit.py
@@ -0,0 +1,1126 @@
+"""A (less & less) simple Python editor"""
+
+import W
+import Wtraceback
+from Wkeys import *
+
+import macfs
+import MacOS
+import Win
+import Res
+import Evt
+import os
+import imp
+import sys
+import string
+import marshal
+import regex
+
+_scriptuntitledcounter = 1
+_wordchars = string.letters + string.digits + "_"
+
+
+class Editor(W.Window):
+	
+	def __init__(self, path = "", title = ""):
+		defaultfontsettings, defaulttabsettings, defaultwindowsize = geteditorprefs()
+		global _scriptuntitledcounter
+		if not path:
+			if title:
+				self.title = title
+			else:
+				self.title = "Untitled Script " + `_scriptuntitledcounter`
+				_scriptuntitledcounter = _scriptuntitledcounter + 1
+			text = ""
+			self._creator = W._signature
+		elif os.path.exists(path):
+			path = resolvealiases(path)
+			dir, name = os.path.split(path)
+			self.title = name
+			f = open(path, "rb")
+			text = f.read()
+			f.close()
+			fss = macfs.FSSpec(path)
+			self._creator, filetype = fss.GetCreatorType()
+		else:
+			raise IOError, "file '%s' does not exist" % path
+		self.path = path
+		
+		self.settings = {}
+		if self.path:
+			self.readwindowsettings()
+		if self.settings.has_key("windowbounds"):
+			bounds = self.settings["windowbounds"]
+		else:
+			bounds = defaultwindowsize
+		if self.settings.has_key("fontsettings"):
+			self.fontsettings = self.settings["fontsettings"]
+		else:
+			self.fontsettings = defaultfontsettings
+		if self.settings.has_key("tabsize"):
+			try:
+				self.tabsettings = (tabsize, tabmode) = self.settings["tabsize"]
+			except:
+				self.tabsettings = defaulttabsettings
+		else:
+			self.tabsettings = defaulttabsettings
+		W.Window.__init__(self, bounds, self.title, minsize = (330, 120), tabbable = 0)
+		
+		self.setupwidgets(text)
+		if self.settings.has_key("selection"):
+			selstart, selend = self.settings["selection"]
+			self.setselection(selstart, selend)
+		self.open()
+		self.setinfotext()
+		self.globals = {}
+		self._buf = ""  # for write method
+		self.debugging = 0
+		self.profiling = 0
+		if self.settings.has_key("run_as_main"):
+			self.run_as_main = self.settings["run_as_main"]
+		else:
+			self.run_as_main = 0
+	
+	def readwindowsettings(self):
+		try:
+			resref = Res.OpenResFile(self.path)
+		except Res.Error:
+			return
+		try:
+			Res.UseResFile(resref)
+			data = Res.Get1Resource('PyWS', 128)
+			self.settings = marshal.loads(data.data)
+		except:
+			pass
+		Res.CloseResFile(resref)
+		
+	def writewindowsettings(self):
+		try:
+			resref = Res.OpenResFile(self.path)
+		except Res.Error:
+			Res.CreateResFile(self.path)
+			resref = Res.OpenResFile(self.path)
+		try:
+			data = Res.Resource(marshal.dumps(self.settings))
+			Res.UseResFile(resref)
+			try:
+				temp = Res.Get1Resource('PyWS', 128)
+				temp.RemoveResource()
+			except Res.Error:
+				pass
+			data.AddResource('PyWS', 128, "window settings")
+		finally:
+			Res.UpdateResFile(resref)
+			Res.CloseResFile(resref)
+	
+	def getsettings(self):
+		self.settings = {}
+		self.settings["windowbounds"] = self.getbounds()
+		self.settings["selection"] = self.getselection()
+		self.settings["fontsettings"] = self.editgroup.editor.getfontsettings()
+		self.settings["tabsize"] = self.editgroup.editor.gettabsettings()
+		self.settings["run_as_main"] = self.run_as_main
+	
+	def get(self):
+		return self.editgroup.editor.get()
+	
+	def getselection(self):
+		return self.editgroup.editor.ted.WEGetSelection()
+	
+	def setselection(self, selstart, selend):
+		self.editgroup.editor.setselection(selstart, selend)
+	
+	def getfilename(self):
+		if self.path:
+			return self.path
+		return '<%s>' % self.title
+	
+	def setupwidgets(self, text):
+		topbarheight = 24
+		popfieldwidth = 80
+		self.lastlineno = None
+		
+		# make an editor
+		self.editgroup = W.Group((0, topbarheight + 1, 0, 0))
+		editor = W.PyEditor((0, 0, -15,-15), text, 
+				fontsettings = self.fontsettings, 
+				tabsettings = self.tabsettings,
+				file = self.getfilename())
+		
+		# make the widgets
+		self.popfield = ClassFinder((popfieldwidth - 17, -15, 16, 16), [], self.popselectline)
+		self.linefield = W.EditText((-1, -15, popfieldwidth - 15, 16), inset = (6, 1))
+		self.editgroup._barx = W.Scrollbar((popfieldwidth - 2, -15, -14, 16), editor.hscroll, max = 32767)
+		self.editgroup._bary = W.Scrollbar((-15, 14, 16, -14), editor.vscroll, max = 32767)
+		self.editgroup.editor = editor	# add editor *after* scrollbars
+		
+		self.editgroup.optionsmenu = W.PopupMenu((-15, -1, 16, 16), [])
+		self.editgroup.optionsmenu.bind('<click>', self.makeoptionsmenu)
+		
+		self.bevelbox = W.BevelBox((0, 0, 0, topbarheight))
+		self.hline = W.HorizontalLine((0, topbarheight, 0, 0))
+		self.infotext = W.TextBox((175, 6, -4, 14), backgroundcolor = (0xe000, 0xe000, 0xe000))
+		self.runbutton = W.Button((5, 4, 80, 16), "Run all", self.run)
+		self.runselbutton = W.Button((90, 4, 80, 16), "Run selection", self.runselection)
+		
+		# bind some keys
+		editor.bind("cmdr", self.runbutton.push)
+		editor.bind("enter", self.runselbutton.push)
+		editor.bind("cmdj", self.domenu_gotoline)
+		editor.bind("cmdd", self.domenu_toggledebugger)
+		editor.bind("<idle>", self.updateselection)
+		
+		editor.bind("cmde", searchengine.setfindstring)
+		editor.bind("cmdf", searchengine.show)
+		editor.bind("cmdg", searchengine.findnext)
+		editor.bind("cmdshiftr", searchengine.replace)
+		editor.bind("cmdt", searchengine.replacefind)
+		
+		self.linefield.bind("return", self.dolinefield)
+		self.linefield.bind("enter", self.dolinefield)
+		self.linefield.bind("tab", self.dolinefield)
+		
+		# intercept clicks
+		editor.bind("<click>", self.clickeditor)
+		self.linefield.bind("<click>", self.clicklinefield)
+	
+	def makeoptionsmenu(self):
+		menuitems = [('Font settingsÉ', self.domenu_fontsettings), 
+				('\0' + chr(self.run_as_main) + 'Run as __main__', self.domenu_toggle_run_as_main), 
+				('Modularize', self.domenu_modularize),
+				('Browse namespaceÉ', self.domenu_browsenamespace), 
+				'-']
+		if self.profiling:
+			menuitems = menuitems + [('Disable profiler', self.domenu_toggleprofiler)]
+		else:
+			menuitems = menuitems + [('Enable profiler', self.domenu_toggleprofiler)]
+		if self.editgroup.editor._debugger:
+			menuitems = menuitems + [('Disable debugger', self.domenu_toggledebugger),
+				('Clear breakpoints', self.domenu_clearbreakpoints),
+				('Edit breakpointsÉ', self.domenu_editbreakpoints)]
+		else:
+			menuitems = menuitems + [('Enable debugger', self.domenu_toggledebugger)]
+		self.editgroup.optionsmenu.set(menuitems)
+	
+	def domenu_toggle_run_as_main(self):
+		self.run_as_main = not self.run_as_main
+		self.editgroup.editor.selchanged = 1
+	
+	def showbreakpoints(self, onoff):
+		self.editgroup.editor.showbreakpoints(onoff)
+		self.debugging = onoff
+	
+	def domenu_clearbreakpoints(self, *args):
+		self.editgroup.editor.clearbreakpoints()
+	
+	def domenu_editbreakpoints(self, *args):
+		self.editgroup.editor.editbreakpoints()
+	
+	def domenu_toggledebugger(self, *args):
+		if not self.debugging:
+			W.SetCursor('watch')
+		self.debugging = not self.debugging
+		self.editgroup.editor.togglebreakpoints()
+		
+	def domenu_toggleprofiler(self, *args):
+		self.profiling = not self.profiling
+	
+	def domenu_browsenamespace(self, *args):
+		import PyBrowser, W
+		W.SetCursor('watch')
+		globals, file, modname = self.getenvironment()
+		if not modname:
+			modname = self.title
+		PyBrowser.Browser(globals, "Object browser: " + modname)
+	
+	def domenu_modularize(self, *args):
+		modname = _filename_as_modname(self.title)
+		if not modname:
+			raise W.AlertError, 'CanÕt modularize Ò%sÓ' % self.title
+		run_as_main = self.run_as_main
+		self.run_as_main = 0
+		self.run()
+		self.run_as_main = run_as_main
+		if self.path:
+			file = self.path
+		else:
+			file = self.title
+		
+		if self.globals and not sys.modules.has_key(modname):
+			module = imp.new_module(modname)
+			for attr in self.globals.keys():
+				setattr(module,attr,self.globals[attr])
+			sys.modules[modname] = module
+			self.globals = {}
+	
+	def domenu_fontsettings(self, *args):
+		import FontSettings
+		fontsettings = self.editgroup.editor.getfontsettings()
+		tabsettings = self.editgroup.editor.gettabsettings()
+		settings = FontSettings.FontDialog(fontsettings, tabsettings)
+		if settings:
+			fontsettings, tabsettings = settings
+			self.editgroup.editor.setfontsettings(fontsettings)
+			self.editgroup.editor.settabsettings(tabsettings)
+	
+	def clicklinefield(self):
+		if self._currentwidget <> self.linefield:
+			self.linefield.select(1)
+			self.linefield.selectall()
+			return 1
+	
+	def clickeditor(self):
+		if self._currentwidget <> self.editgroup.editor:
+			self.dolinefield()
+			return 1
+	
+	def updateselection(self, force = 0):
+		sel = min(self.editgroup.editor.getselection())
+		lineno = self.editgroup.editor.offsettoline(sel)
+		if lineno <> self.lastlineno or force:
+			self.lastlineno = lineno
+			self.linefield.set(str(lineno + 1))
+			self.linefield.selview()
+	
+	def dolinefield(self):
+		try:
+			lineno = string.atoi(self.linefield.get()) - 1
+			if lineno <> self.lastlineno:
+				self.editgroup.editor.selectline(lineno)
+				self.updateselection(1)
+		except:
+			self.updateselection(1)
+		self.editgroup.editor.select(1)
+	
+	def setinfotext(self):
+		if not hasattr(self, 'infotext'):
+			return
+		if self.path:
+			self.infotext.set(self.path)
+		else:
+			self.infotext.set("")
+	
+	def close(self):
+		if self.editgroup.editor.changed:
+			import EasyDialogs
+			import Qd
+			Qd.InitCursor() # XXX should be done by dialog
+			save = EasyDialogs.AskYesNoCancel('Save window Ò%sÓ before closing?' % self.title, 1)
+			if save > 0:
+				if self.domenu_save():
+					return 1
+			elif save < 0:
+				return 1
+		self.globals = None	     # XXX doesn't help... all globals leak :-(
+		W.Window.close(self)
+	
+	def domenu_close(self, *args):
+		return self.close()
+	
+	def domenu_save(self, *args):
+		if not self.path:
+			# Will call us recursively
+			return self.domenu_save_as()
+		data = self.editgroup.editor.get()
+		fp = open(self.path, 'wb')  # open file in binary mode, data has '\r' line-endings
+		fp.write(data)
+		fp.close()
+		fss = macfs.FSSpec(self.path)
+		fss.SetCreatorType(self._creator, 'TEXT')
+		self.getsettings()
+		self.writewindowsettings()
+		self.editgroup.editor.changed = 0
+		self.editgroup.editor.selchanged = 0
+		import linecache
+		if linecache.cache.has_key(self.path):
+			del linecache.cache[self.path]
+		import macostools
+		macostools.touched(self.path)
+	
+	def can_save(self, menuitem):
+		return self.editgroup.editor.changed or self.editgroup.editor.selchanged
+	
+	def domenu_save_as(self, *args):
+		fss, ok = macfs.StandardPutFile('Save as:', self.title)
+		if not ok: 
+			return 1
+		self.showbreakpoints(0)
+		self.path = fss.as_pathname()
+		self.setinfotext()
+		self.title = os.path.split(self.path)[-1]
+		self.wid.SetWTitle(self.title)
+		self.domenu_save()
+		self.editgroup.editor.setfile(self.getfilename())
+		app = W.getapplication()
+		app.makeopenwindowsmenu()
+		if hasattr(app, 'makescriptsmenu'):
+			app = W.getapplication()
+			fss, fss_changed = app.scriptsfolder.Resolve()
+			path = fss.as_pathname()
+			if path == self.path[:len(path)]:
+				W.getapplication().makescriptsmenu()
+	
+	def domenu_save_as_applet(self, *args):
+		try:
+			import buildtools
+		except ImportError:
+			# only have buildtools in Python >= 1.5.2
+			raise W.AlertError, "ÒSave as AppletÓ is only supported in\rPython 1.5.2 and up."
+		
+		buildtools.DEBUG = 0	# ouch.
+		
+		if self.title[-3:] == ".py":
+			destname = self.title[:-3]
+		else:
+			destname = self.title + ".applet"
+		fss, ok = macfs.StandardPutFile('Save as Applet:', destname)
+		if not ok: 
+			return 1
+		W.SetCursor("watch")
+		destname = fss.as_pathname()
+		if self.path:
+			filename = self.path
+			if filename[-3:] == ".py":
+				rsrcname = filename[:-3] + '.rsrc'
+			else:
+				rsrcname = filename + '.rsrc'
+		else:
+			filename = self.title
+			rsrcname = ""
+		
+		pytext = self.editgroup.editor.get()
+		pytext = string.split(pytext, '\r')
+		pytext = string.join(pytext, '\n') + '\n'
+		try:
+			code = compile(pytext, filename, "exec")
+		except (SyntaxError, EOFError):
+			raise buildtools.BuildError, "Syntax error in script %s" % `filename`
+		
+		# Try removing the output file
+		try:
+			os.remove(destname)
+		except os.error:
+			pass
+		template = buildtools.findtemplate()
+		buildtools.process_common(template, None, code, rsrcname, destname, 0, 1)
+	
+	def domenu_gotoline(self, *args):
+		self.linefield.selectall()
+		self.linefield.select(1)
+		self.linefield.selectall()
+	
+	def domenu_selectline(self, *args):
+		self.editgroup.editor.expandselection()
+	
+	def domenu_find(self, *args):
+		searchengine.show()
+	
+	def domenu_entersearchstring(self, *args):
+		searchengine.setfindstring()
+	
+	def domenu_replace(self, *args):
+		searchengine.replace()
+	
+	def domenu_findnext(self, *args):
+		searchengine.findnext()
+	
+	def domenu_replacefind(self, *args):
+		searchengine.replacefind()
+	
+	def domenu_run(self, *args):
+		self.runbutton.push()
+	
+	def domenu_runselection(self, *args):
+		self.runselbutton.push()
+	
+	def run(self):
+		self._run()
+	
+	def _run(self):
+		pytext = self.editgroup.editor.get()
+		globals, file, modname = self.getenvironment()
+		self.execstring(pytext, globals, globals, file, modname)
+	
+	def runselection(self):
+		self._runselection()
+	
+	def _runselection(self):
+		globals, file, modname = self.getenvironment()
+		locals = globals
+		# select whole lines
+		self.editgroup.editor.expandselection()
+		
+		# get lineno of first selected line
+		selstart, selend = self.editgroup.editor.getselection()
+		selstart, selend = min(selstart, selend), max(selstart, selend)
+		selfirstline = self.editgroup.editor.offsettoline(selstart)
+		alltext = self.editgroup.editor.get()
+		pytext = alltext[selstart:selend]
+		lines = string.split(pytext, '\r')
+		indent = getminindent(lines)
+		if indent == 1:
+			classname = ''
+			alllines = string.split(alltext, '\r')
+			identifieRE_match = _identifieRE.match
+			for i in range(selfirstline - 1, -1, -1):
+				line = alllines[i]
+				if line[:6] == 'class ':
+					classname = string.split(string.strip(line[6:]))[0]
+					classend = identifieRE_match(classname)
+					if classend < 1:
+						raise W.AlertError, 'CanÕt find a class.'
+					classname = classname[:classend]
+					break
+				elif line and line[0] not in '\t#':
+					raise W.AlertError, 'CanÕt find a class.'
+			else:
+				raise W.AlertError, 'CanÕt find a class.'
+			if globals.has_key(classname):
+				locals = globals[classname].__dict__
+			else:
+				raise W.AlertError, 'CanÕt find class Ò%sÓ.' % classname
+			# dedent to top level
+			for i in range(len(lines)):
+				lines[i] = lines[i][1:]
+			pytext = string.join(lines, '\r')
+		elif indent > 0:
+			raise W.AlertError, 'CanÕt run indented code.'
+		
+		# add "newlines" to fool compile/exec: 
+		# now a traceback will give the right line number
+		pytext = selfirstline * '\r' + pytext
+		self.execstring(pytext, globals, locals, file, modname)
+	
+	def execstring(self, pytext, globals, locals, file, modname):
+		tracebackwindow.hide()
+		# update windows
+		W.getapplication().refreshwindows()
+		if self.run_as_main:
+			modname = "__main__"
+		if self.path:
+			dir = os.path.dirname(self.path)
+			savedir = os.getcwd()
+			os.chdir(dir)
+			try:
+				cwdindex = sys.path.index(os.curdir)
+			except ValueError:
+				cwdindex = None
+			else:
+				sys.path[cwdindex] = dir
+		else:
+			cwdindex = None
+		try:
+			execstring(pytext, globals, locals, file, self.debugging, 
+					modname, self.profiling)
+		finally:
+			if self.path:
+				os.chdir(savedir)
+				if cwdindex is not None:
+					sys.path[cwdindex] = os.curdir
+	
+	def getenvironment(self):
+		if self.path:
+			file = self.path
+			dir = os.path.dirname(file)
+			# check if we're part of a package
+			modname = ""
+			while os.path.exists(os.path.join(dir, "__init__.py")):
+				dir, dirname = os.path.split(dir)
+				modname = modname + dirname + '.'
+			subname = _filename_as_modname(self.title)
+			if modname:
+				if subname == "__init__":
+					modname  = modname[:-1]  # strip trailing period
+				else:
+					modname  = modname + subname
+			else:
+				modname = subname
+			if sys.modules.has_key(modname):
+				globals = sys.modules[modname].__dict__
+				self.globals = {}
+			else:
+				globals = self.globals
+		else:
+			file = '<%s>' % self.title
+			globals = self.globals
+			modname = file
+		return globals, file, modname
+	
+	def write(self, stuff):
+		"""for use as stdout"""
+		self._buf = self._buf + stuff
+		if '\n' in self._buf:
+			self.flush()
+	
+	def flush(self):
+		stuff = string.split(self._buf, '\n')
+		stuff = string.join(stuff, '\r')
+		end = self.editgroup.editor.ted.WEGetTextLength()
+		self.editgroup.editor.ted.WESetSelection(end, end)
+		self.editgroup.editor.ted.WEInsert(stuff, None, None)
+		self.editgroup.editor.updatescrollbars()
+		self._buf = ""
+		# ? optional:
+		#self.wid.SelectWindow()
+	
+	def getclasslist(self):
+		from string import find, strip
+		editor = self.editgroup.editor
+		text = editor.get()
+		list = []
+		append = list.append
+		functag = "func"
+		classtag = "class"
+		methodtag = "method"
+		pos = -1
+		if text[:4] == 'def ':
+			append((pos + 4, functag))
+			pos = 4
+		while 1:
+			pos = find(text, '\rdef ', pos + 1)
+			if pos < 0:
+				break
+			append((pos + 5, functag))
+		pos = -1
+		if text[:6] == 'class ':
+			append((pos + 6, classtag))
+			pos = 6
+		while 1:
+			pos = find(text, '\rclass ', pos + 1)
+			if pos < 0:
+				break
+			append((pos + 7, classtag))
+		pos = 0
+		while 1:
+			pos = find(text, '\r\tdef ', pos + 1)
+			if pos < 0:
+				break
+			append((pos + 6, methodtag))
+		list.sort()
+		classlist = []
+		methodlistappend = None
+		offsetToLine = editor.ted.WEOffsetToLine
+		getLineRange = editor.ted.WEGetLineRange
+		append = classlist.append
+		identifieRE_match = _identifieRE.match
+		for pos, tag in list:
+			lineno = offsetToLine(pos)
+			lineStart, lineEnd = getLineRange(lineno)
+			line = strip(text[pos:lineEnd])
+			line = line[:identifieRE_match(line)]
+			if tag is functag:
+				append(("def " + line, lineno + 1))
+				methodlistappend = None
+			elif tag is classtag:
+				append(["class " + line])
+				methodlistappend = classlist[-1].append
+			elif methodlistappend and tag is methodtag:
+				methodlistappend(("def " + line, lineno + 1))
+		return classlist
+	
+	def popselectline(self, lineno):
+		self.editgroup.editor.selectline(lineno - 1)
+	
+	def selectline(self, lineno, charoffset = 0):
+		self.editgroup.editor.selectline(lineno - 1, charoffset)
+
+
+def _escape(where, what) : 
+	return string.join(string.split(where, what), '\\' + what)
+
+def _makewholewordpattern(word):
+	# first, escape special regex chars
+	for esc in "\\[].*^+$?":
+		word = _escape(word, esc)
+	import regex
+	notwordcharspat = '[^' + _wordchars + ']'
+	pattern = '\(' + word + '\)'
+	if word[0] in _wordchars:
+		pattern = notwordcharspat + pattern
+	if word[-1] in _wordchars:
+		pattern = pattern + notwordcharspat
+	return regex.compile(pattern)
+
+class SearchEngine:
+	
+	def __init__(self):
+		self.visible = 0
+		self.w = None
+		self.parms = {  "find": "",
+					"replace": "",
+					"wrap": 1,
+					"casesens": 1,
+					"wholeword": 1
+				}
+		import MacPrefs
+		prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
+		if prefs.searchengine:
+			self.parms["casesens"] = prefs.searchengine.casesens
+			self.parms["wrap"] = prefs.searchengine.wrap
+			self.parms["wholeword"] = prefs.searchengine.wholeword
+	
+	def show(self):
+		self.visible = 1
+		if self.w:
+			self.w.wid.ShowWindow()
+			self.w.wid.SelectWindow()
+			self.w.find.edit.select(1)
+			self.w.find.edit.selectall()
+			return
+		self.w = W.Dialog((420, 150), "Find")
+		
+		self.w.find = TitledEditText((10, 4, 300, 36), "Search for:")
+		self.w.replace = TitledEditText((10, 100, 300, 36), "Replace with:")
+		
+		self.w.boxes = W.Group((10, 50, 300, 40))
+		self.w.boxes.casesens = W.CheckBox((0, 0, 100, 16), "Case sensitive")
+		self.w.boxes.wholeword = W.CheckBox((0, 20, 100, 16), "Whole word")
+		self.w.boxes.wrap = W.CheckBox((110, 0, 100, 16), "Wrap around")
+		
+		self.buttons = [	("Find",		"cmdf",	 self.find), 
+					("Replace",	     "cmdr",	 self.replace), 
+					("Replace all",	 None,   self.replaceall), 
+					("DonÕt find",  "cmdd",	 self.dont), 
+					("Cancel",	      "cmd.",	 self.cancel)
+				]
+		for i in range(len(self.buttons)):
+			bounds = -90, 22 + i * 24, 80, 16
+			title, shortcut, callback = self.buttons[i]
+			self.w[title] = W.Button(bounds, title, callback)
+			if shortcut:
+				self.w.bind(shortcut, self.w[title].push)
+		self.w.setdefaultbutton(self.w["DonÕt find"])
+		self.w.find.edit.bind("<key>", self.key)
+		self.w.bind("<activate>", self.activate)
+		self.w.bind("<close>", self.close)
+		self.w.open()
+		self.setparms()
+		self.w.find.edit.select(1)
+		self.w.find.edit.selectall()
+		self.checkbuttons()
+	
+	def close(self):
+		self.hide()
+		return -1
+	
+	def key(self, char, modifiers):
+		self.w.find.edit.key(char, modifiers)
+		self.checkbuttons()
+		return 1
+	
+	def activate(self, onoff):
+		if onoff:
+			self.checkbuttons()
+	
+	def checkbuttons(self):
+		editor = findeditor(self)
+		if editor:
+			if self.w.find.get():
+				for title, cmd, call in self.buttons[:-2]:
+					self.w[title].enable(1)
+				self.w.setdefaultbutton(self.w["Find"])
+			else:
+				for title, cmd, call in self.buttons[:-2]:
+					self.w[title].enable(0)
+				self.w.setdefaultbutton(self.w["DonÕt find"])
+		else:
+			for title, cmd, call in self.buttons[:-2]:
+				self.w[title].enable(0)
+			self.w.setdefaultbutton(self.w["DonÕt find"])
+	
+	def find(self):
+		self.getparmsfromwindow()
+		if self.findnext():
+			self.hide()
+	
+	def replace(self):
+		editor = findeditor(self)
+		if not editor:
+			return
+		if self.visible:
+			self.getparmsfromwindow()
+		text = editor.getselectedtext()
+		find = self.parms["find"]
+		if not self.parms["casesens"]:
+			find = string.lower(find)
+			text = string.lower(text)
+		if text == find:
+			self.hide()
+			editor.insert(self.parms["replace"])
+	
+	def replaceall(self):
+		editor = findeditor(self)
+		if not editor:
+			return
+		if self.visible:
+			self.getparmsfromwindow()
+		W.SetCursor("watch")
+		find = self.parms["find"]
+		if not find:
+			return
+		findlen = len(find)
+		replace = self.parms["replace"]
+		replacelen = len(replace)
+		Text = editor.get()
+		if not self.parms["casesens"]:
+			find = string.lower(find)
+			text = string.lower(Text)
+		else:
+			text = Text
+		newtext = ""
+		pos = 0
+		counter = 0
+		while 1:
+			if self.parms["wholeword"]:
+				wholewordRE = _makewholewordpattern(find)
+				wholewordRE.search(text, pos)
+				if wholewordRE.regs:
+					pos = wholewordRE.regs[1][0]
+				else:
+					pos = -1
+			else:
+				pos = string.find(text, find, pos)
+			if pos < 0:
+				break
+			counter = counter + 1
+			text = text[:pos] + replace + text[pos + findlen:]
+			Text = Text[:pos] + replace + Text[pos + findlen:]
+			pos = pos + replacelen
+		W.SetCursor("arrow")
+		if counter:
+			self.hide()
+			import EasyDialogs
+			import Res
+			editor.changed = 1
+			editor.selchanged = 1
+			editor.ted.WEUseText(Res.Resource(Text))
+			editor.ted.WECalText()
+			editor.SetPort()
+			Win.InvalRect(editor._bounds)
+			#editor.ted.WEUpdate(self.w.wid.GetWindowPort().visRgn)
+			EasyDialogs.Message("Replaced %d occurrences" % counter)
+	
+	def dont(self):
+		self.getparmsfromwindow()
+		self.hide()
+	
+	def replacefind(self):
+		self.replace()
+		self.findnext()
+	
+	def setfindstring(self):
+		editor = findeditor(self)
+		if not editor:
+			return
+		find = editor.getselectedtext()
+		if not find:
+			return
+		self.parms["find"] = find
+		if self.w:
+			self.w.find.edit.set(self.parms["find"])
+			self.w.find.edit.selectall()
+	
+	def findnext(self):
+		editor = findeditor(self)
+		if not editor:
+			return
+		find = self.parms["find"]
+		if not find:
+			return
+		text = editor.get()
+		if not self.parms["casesens"]:
+			find = string.lower(find)
+			text = string.lower(text)
+		selstart, selend = editor.getselection()
+		selstart, selend = min(selstart, selend), max(selstart, selend)
+		if self.parms["wholeword"]:
+			wholewordRE = _makewholewordpattern(find)
+			wholewordRE.search(text, selend)
+			if wholewordRE.regs:
+				pos = wholewordRE.regs[1][0]
+			else:
+				pos = -1
+		else:
+			pos = string.find(text, find, selend)
+		if pos >= 0:
+			editor.setselection(pos, pos + len(find))
+			return 1
+		elif self.parms["wrap"]:
+			if self.parms["wholeword"]:
+				wholewordRE.search(text, 0)
+				if wholewordRE.regs:
+					pos = wholewordRE.regs[1][0]
+				else:
+					pos = -1
+			else:
+				pos = string.find(text, find)
+			if selstart > pos >= 0:
+				editor.setselection(pos, pos + len(find))
+				return 1
+	
+	def setparms(self):
+		for key, value in self.parms.items():
+			try:
+				self.w[key].set(value)
+			except KeyError:
+				self.w.boxes[key].set(value)
+	
+	def getparmsfromwindow(self):
+		if not self.w:
+			return
+		for key, value in self.parms.items():
+			try:
+				value = self.w[key].get()
+			except KeyError:
+				value = self.w.boxes[key].get()
+			self.parms[key] = value
+	
+	def cancel(self):
+		self.hide()
+		self.setparms()
+	
+	def hide(self):
+		if self.w:
+			self.w.wid.HideWindow()
+			self.visible = 0
+	
+	def writeprefs(self):
+		import MacPrefs
+		self.getparmsfromwindow()
+		prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
+		prefs.searchengine.casesens = self.parms["casesens"]
+		prefs.searchengine.wrap = self.parms["wrap"]
+		prefs.searchengine.wholeword = self.parms["wholeword"]
+		prefs.save()
+	
+
+class TitledEditText(W.Group):
+	
+	def __init__(self, possize, title, text = ""):
+		W.Group.__init__(self, possize)
+		self.title = W.TextBox((0, 0, 0, 16), title)
+		self.edit = W.EditText((0, 16, 0, 0), text)
+	
+	def set(self, value):
+		self.edit.set(value)
+	
+	def get(self):
+		return self.edit.get()
+
+
+class ClassFinder(W.PopupWidget):
+	
+	def click(self, point, modifiers):
+		W.SetCursor("watch")
+		self.set(self._parentwindow.getclasslist())
+		W.PopupWidget.click(self, point, modifiers)
+
+
+def getminindent(lines):
+	indent = -1
+	for line in lines:
+		stripped = string.strip(line)
+		if not stripped or stripped[0] == '#':
+			continue
+		if indent < 0 or line[:indent] <> indent * '\t':
+			indent = 0
+			for c in line:
+				if c <> '\t':
+					break
+				indent = indent + 1
+	return indent
+
+
+def getoptionkey():
+	return not not ord(Evt.GetKeys()[7]) & 0x04
+
+
+def execstring(pytext, globals, locals, filename="<string>", debugging=0, 
+			modname="__main__", profiling=0):
+	if debugging:
+		import PyDebugger, bdb
+		BdbQuit = bdb.BdbQuit
+	else:
+		BdbQuit = 'BdbQuitDummyException'
+	pytext = string.split(pytext, '\r')
+	pytext = string.join(pytext, '\n') + '\n'
+	W.SetCursor("watch")
+	globals['__name__'] = modname
+	globals['__file__'] = filename
+	sys.argv = [filename]
+	try:
+		code = compile(pytext, filename, "exec")
+	except:
+		# XXXX BAAAADDD.... We let tracebackwindow decide to treat SyntaxError 
+		# special. That's wrong because THIS case is special (could be literal 
+		# overflow!) and SyntaxError could mean we need a traceback (syntax error 
+		# in imported module!!!
+		tracebackwindow.traceback(1, filename)
+		return
+	try:
+		if debugging:
+			PyDebugger.startfromhere()
+		else:
+			MacOS.EnableAppswitch(0)
+		try:
+			if profiling:
+				import profile, ProfileBrowser
+				p = profile.Profile()
+				p.set_cmd(filename)
+				try:
+					p.runctx(code, globals, locals)
+				finally:
+					import pstats
+					
+					stats = pstats.Stats(p)
+					ProfileBrowser.ProfileBrowser(stats)
+			else:
+				exec code in globals, locals
+		finally:
+			MacOS.EnableAppswitch(-1)
+	except W.AlertError, detail:
+		raise W.AlertError, detail
+	except (KeyboardInterrupt, BdbQuit):
+		pass
+	except:
+		if debugging:
+			sys.settrace(None)
+			PyDebugger.postmortem(sys.exc_type, sys.exc_value, sys.exc_traceback)
+			return
+		else:
+			tracebackwindow.traceback(1, filename)
+	if debugging:
+		sys.settrace(None)
+		PyDebugger.stop()
+
+
+_identifieRE = regex.compile("[A-Za-z_][A-Za-z_0-9]*")
+
+def _filename_as_modname(fname):
+	if fname[-3:] == '.py':
+		modname = fname[:-3]
+		if _identifieRE.match(modname) == len(modname):
+			return string.join(string.split(modname, '.'), '_')
+
+def findeditor(topwindow, fromtop = 0):
+	wid = Win.FrontWindow()
+	if not fromtop:
+		if topwindow.w and wid == topwindow.w.wid:
+			wid = topwindow.w.wid.GetNextWindow()
+	if not wid:
+		return
+	app = W.getapplication()
+	if app._windows.has_key(wid): # KeyError otherwise can happen in RoboFog :-(
+		window = W.getapplication()._windows[wid]
+	else:
+		return
+	if not isinstance(window, Editor):
+		return
+	return window.editgroup.editor
+
+
+class _EditorDefaultSettings:
+	
+	def __init__(self):
+		self.template = "%s, %d point"
+		self.fontsettings, self.tabsettings, self.windowsize = geteditorprefs()
+		self.w = W.Dialog((328, 120), "Editor default settings")
+		self.w.setfontbutton = W.Button((8, 8, 80, 16), "Set fontÉ", self.dofont)
+		self.w.fonttext = W.TextBox((98, 10, -8, 14), self.template % (self.fontsettings[0], self.fontsettings[2]))
+		
+		self.w.picksizebutton = W.Button((8, 50, 80, 16), "Front window", self.picksize)
+		self.w.xsizelabel = W.TextBox((98, 32, 40, 14), "Width:")
+		self.w.ysizelabel = W.TextBox((148, 32, 40, 14), "Height:")
+		self.w.xsize = W.EditText((98, 48, 40, 20), `self.windowsize[0]`)
+		self.w.ysize = W.EditText((148, 48, 40, 20), `self.windowsize[1]`)
+		
+		self.w.cancelbutton = W.Button((-180, -26, 80, 16), "Cancel", self.cancel)
+		self.w.okbutton = W.Button((-90, -26, 80, 16), "Done", self.ok)
+		self.w.setdefaultbutton(self.w.okbutton)
+		self.w.bind('cmd.', self.w.cancelbutton.push)
+		self.w.open()
+	
+	def picksize(self):
+		app = W.getapplication()
+		editor = findeditor(self)
+		if editor is not None:
+			width, height = editor._parentwindow._bounds[2:]
+			self.w.xsize.set(`width`)
+			self.w.ysize.set(`height`)
+		else:
+			raise W.AlertError, "No edit window found"
+	
+	def dofont(self):
+		import FontSettings
+		settings = FontSettings.FontDialog(self.fontsettings, self.tabsettings)
+		if settings:
+			self.fontsettings, self.tabsettings = settings
+			sys.exc_traceback = None
+			self.w.fonttext.set(self.template % (self.fontsettings[0], self.fontsettings[2]))
+	
+	def close(self):
+		self.w.close()
+		del self.w
+	
+	def cancel(self):
+		self.close()
+	
+	def ok(self):
+		try:
+			width = string.atoi(self.w.xsize.get())
+		except:
+			self.w.xsize.select(1)
+			self.w.xsize.selectall()
+			raise W.AlertError, "Bad number for window width"
+		try:
+			height = string.atoi(self.w.ysize.get())
+		except:
+			self.w.ysize.select(1)
+			self.w.ysize.selectall()
+			raise W.AlertError, "Bad number for window height"
+		self.windowsize = width, height
+		seteditorprefs(self.fontsettings, self.tabsettings, self.windowsize)
+		self.close()
+
+def geteditorprefs():
+	import MacPrefs
+	prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
+	try:
+		fontsettings = prefs.pyedit.fontsettings
+		tabsettings = prefs.pyedit.tabsettings
+		windowsize = prefs.pyedit.windowsize
+	except:
+		fontsettings = prefs.pyedit.fontsettings = ("Python-Sans", 0, 9, (0, 0, 0))
+		tabsettings = prefs.pyedit.tabsettings = (8, 1)
+		windowsize = prefs.pyedit.windowsize = (500, 250)
+		sys.exc_traceback = None
+	return fontsettings, tabsettings, windowsize
+
+def seteditorprefs(fontsettings, tabsettings, windowsize):
+	import MacPrefs
+	prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath)
+	prefs.pyedit.fontsettings = fontsettings
+	prefs.pyedit.tabsettings = tabsettings
+	prefs.pyedit.windowsize = windowsize
+	prefs.save()
+
+_defaultSettingsEditor = None
+
+def EditorDefaultSettings():
+	global _defaultSettingsEditor
+	if _defaultSettingsEditor is None or not hasattr(_defaultSettingsEditor, "w"):
+		_defaultSettingsEditor = _EditorDefaultSettings()
+	else:
+		_defaultSettingsEditor.w.select()
+
+def resolvealiases(path):
+	try:
+		return macfs.ResolveAliasFile(path)[0].as_pathname()
+	except (macfs.error, ValueError), (error, str):
+		if error <> -120:
+			raise
+		dir, file = os.path.split(path)
+		return os.path.join(resolvealiases(dir), file)
+
+searchengine = SearchEngine()
+tracebackwindow = Wtraceback.TraceBack()