| 
									
										
										
										
											2001-02-21 13:54:31 +00:00
										 |  |  | import re | 
					
						
							| 
									
										
										
										
											1999-01-30 22:39:17 +00:00
										 |  |  | import W | 
					
						
							|  |  |  | import macfs | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import MacPrefs | 
					
						
							|  |  |  | import MacOS | 
					
						
							|  |  |  | import string | 
					
						
							| 
									
										
										
										
											2001-12-03 18:11:36 +00:00
										 |  |  | import webbrowser | 
					
						
							| 
									
										
										
										
											2003-01-26 22:15:48 +00:00
										 |  |  | import EasyDialogs | 
					
						
							| 
									
										
										
										
											1999-01-30 22:39:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | app = W.getapplication() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-02-21 13:54:31 +00:00
										 |  |  | _titlepat = re.compile('<title>\([^<]*\)</title>') | 
					
						
							| 
									
										
										
										
											1999-01-30 22:39:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def sucktitle(path): | 
					
						
							|  |  |  | 	f = open(path) | 
					
						
							|  |  |  | 	text = f.read(1024) # assume the title is in the first 1024 bytes | 
					
						
							|  |  |  | 	f.close() | 
					
						
							| 
									
										
										
										
											2001-12-03 18:11:36 +00:00
										 |  |  | 	lowertext = text.lower() | 
					
						
							| 
									
										
										
										
											2001-02-21 13:54:31 +00:00
										 |  |  | 	matcher = _titlepat.search(lowertext) | 
					
						
							|  |  |  | 	if matcher: | 
					
						
							|  |  |  | 		return matcher.group(1) | 
					
						
							| 
									
										
										
										
											1999-01-30 22:39:17 +00:00
										 |  |  | 	return path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def verifydocpath(docpath): | 
					
						
							|  |  |  | 	try: | 
					
						
							|  |  |  | 		tut = os.path.join(docpath, "tut") | 
					
						
							|  |  |  | 		lib = os.path.join(docpath, "lib") | 
					
						
							|  |  |  | 		ref = os.path.join(docpath, "ref") | 
					
						
							|  |  |  | 		for path in [tut, lib, ref]: | 
					
						
							|  |  |  | 			if not os.path.exists(path): | 
					
						
							|  |  |  | 				return 0 | 
					
						
							|  |  |  | 	except: | 
					
						
							|  |  |  | 		return 0 | 
					
						
							|  |  |  | 	return 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _resultscounter = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Results: | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def __init__(self, hits): | 
					
						
							|  |  |  | 		global _resultscounter | 
					
						
							|  |  |  | 		hits = map(lambda (path, hits): (sucktitle(path), path, hits), hits) | 
					
						
							|  |  |  | 		hits.sort() | 
					
						
							|  |  |  | 		self.hits = hits | 
					
						
							|  |  |  | 		nicehits = map( | 
					
						
							|  |  |  | 				lambda (title, path, hits): | 
					
						
							|  |  |  | 				title + '\r' + string.join( | 
					
						
							|  |  |  | 				map(lambda (c, p): "%s (%d)" % (p, c), hits), ', '), hits) | 
					
						
							|  |  |  | 		nicehits.sort() | 
					
						
							|  |  |  | 		self.w = W.Window((440, 300), "Search results %d" % _resultscounter, minsize = (200, 100)) | 
					
						
							| 
									
										
										
										
											2001-12-03 18:11:36 +00:00
										 |  |  | 		self.w.results = W.TwoLineList((-1, -1, 1, -14), nicehits, self.listhit) | 
					
						
							| 
									
										
										
										
											1999-01-30 22:39:17 +00:00
										 |  |  | 		self.w.open() | 
					
						
							|  |  |  | 		self.w.bind('return', self.listhit) | 
					
						
							|  |  |  | 		self.w.bind('enter', self.listhit) | 
					
						
							|  |  |  | 		_resultscounter = _resultscounter + 1 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def listhit(self, isdbl = 1): | 
					
						
							|  |  |  | 		if isdbl: | 
					
						
							|  |  |  | 			for i in self.w.results.getselection(): | 
					
						
							| 
									
										
										
										
											2001-12-03 18:11:36 +00:00
										 |  |  | 				path = self.hits[i][1] | 
					
						
							|  |  |  | 				url = "file://" + "/".join(path.split(":")) | 
					
						
							|  |  |  | 				webbrowser.open(url) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-01-30 22:39:17 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Status: | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def __init__(self): | 
					
						
							| 
									
										
										
										
											2001-06-19 21:37:33 +00:00
										 |  |  | 		self.w = W.Dialog((440, 64), "Searching\xc9") | 
					
						
							| 
									
										
										
										
											2001-12-03 18:11:36 +00:00
										 |  |  | 		self.w.searching = W.TextBox((4, 4, -4, 16), "") | 
					
						
							| 
									
										
										
										
											1999-01-30 22:39:17 +00:00
										 |  |  | 		self.w.hits = W.TextBox((4, 24, -4, 16), "Hits: 0") | 
					
						
							|  |  |  | 		self.w.canceltip = W.TextBox((4, 44, -4, 16), "Type cmd-period (.) to cancel.") | 
					
						
							|  |  |  | 		self.w.open() | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def set(self, path, hits): | 
					
						
							|  |  |  | 		self.w.searching.set(path) | 
					
						
							|  |  |  | 		self.w.hits.set('Hits: ' + `hits`) | 
					
						
							|  |  |  | 		app.breathe() | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def close(self): | 
					
						
							|  |  |  | 		self.w.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def match(text, patterns, all): | 
					
						
							|  |  |  | 	hits = [] | 
					
						
							|  |  |  | 	hitsappend = hits.append | 
					
						
							|  |  |  | 	stringcount = string.count | 
					
						
							|  |  |  | 	for pat in patterns: | 
					
						
							|  |  |  | 		c = stringcount(text, pat) | 
					
						
							|  |  |  | 		if c > 0: | 
					
						
							|  |  |  | 			hitsappend((c, pat)) | 
					
						
							|  |  |  | 		elif all: | 
					
						
							|  |  |  | 			hits[:] = [] | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 	hits.sort() | 
					
						
							|  |  |  | 	hits.reverse() | 
					
						
							|  |  |  | 	return hits | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-12-03 18:11:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-01-30 22:39:17 +00:00
										 |  |  | def dosearch(docpath, searchstring, settings): | 
					
						
							|  |  |  | 	(docpath, kind, case, word, tut, lib, ref, ext, api) = settings | 
					
						
							|  |  |  | 	books = [(tut, 'tut'), (lib, 'lib'), (ref, 'ref'), (ext, 'ext'), (api, 'api')] | 
					
						
							|  |  |  | 	if not case: | 
					
						
							|  |  |  | 		searchstring = string.lower(searchstring) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if kind == 1: | 
					
						
							|  |  |  | 		patterns = string.split(searchstring) | 
					
						
							|  |  |  | 		all = 1 | 
					
						
							|  |  |  | 	elif kind == 2: | 
					
						
							|  |  |  | 		patterns = string.split(searchstring) | 
					
						
							|  |  |  | 		all = 0 | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 		patterns = [searchstring] | 
					
						
							|  |  |  | 		all = 0 # not relevant | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	ospathjoin = os.path.join | 
					
						
							|  |  |  | 	stringlower = string.lower | 
					
						
							|  |  |  | 	status = Status() | 
					
						
							|  |  |  | 	statusset = status.set | 
					
						
							|  |  |  | 	_match = match | 
					
						
							|  |  |  | 	_open = open | 
					
						
							|  |  |  | 	hits = {} | 
					
						
							|  |  |  | 	try: | 
					
						
							| 
									
										
										
										
											2002-01-21 23:00:52 +00:00
										 |  |  | 		if hasattr(MacOS, 'EnableAppswitch'): | 
					
						
							|  |  |  | 			MacOS.EnableAppswitch(0) | 
					
						
							| 
									
										
										
										
											1999-01-30 22:39:17 +00:00
										 |  |  | 		try: | 
					
						
							|  |  |  | 			for do, name in books: | 
					
						
							|  |  |  | 				if not do: | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				bookpath = ospathjoin(docpath, name) | 
					
						
							|  |  |  | 				if not os.path.exists(bookpath): | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				files = os.listdir(bookpath) | 
					
						
							|  |  |  | 				for file in files: | 
					
						
							|  |  |  | 					fullpath = ospathjoin(bookpath, file) | 
					
						
							|  |  |  | 					if fullpath[-5:] <> '.html': | 
					
						
							|  |  |  | 						continue | 
					
						
							|  |  |  | 					statusset(fullpath, len(hits)) | 
					
						
							|  |  |  | 					f = _open(fullpath) | 
					
						
							|  |  |  | 					text = f.read() | 
					
						
							|  |  |  | 					if not case: | 
					
						
							|  |  |  | 						text = stringlower(text) | 
					
						
							|  |  |  | 					f.close() | 
					
						
							|  |  |  | 					filehits = _match(text, patterns, all) | 
					
						
							|  |  |  | 					if filehits: | 
					
						
							|  |  |  | 						hits[fullpath] = filehits | 
					
						
							|  |  |  | 		finally: | 
					
						
							| 
									
										
										
										
											2002-01-21 23:00:52 +00:00
										 |  |  | 			if hasattr(MacOS, 'EnableAppswitch'): | 
					
						
							|  |  |  | 				MacOS.EnableAppswitch(-1) | 
					
						
							| 
									
										
										
										
											1999-01-30 22:39:17 +00:00
										 |  |  | 			status.close() | 
					
						
							|  |  |  | 	except KeyboardInterrupt: | 
					
						
							|  |  |  | 		pass | 
					
						
							|  |  |  | 	hits = hits.items() | 
					
						
							|  |  |  | 	hits.sort() | 
					
						
							|  |  |  | 	return hits | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class PyDocSearch: | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def __init__(self): | 
					
						
							|  |  |  | 		prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath) | 
					
						
							|  |  |  | 		try: | 
					
						
							|  |  |  | 			(docpath, kind, case, word, tut, lib, ref, ext, api) = prefs.docsearchengine | 
					
						
							|  |  |  | 		except: | 
					
						
							|  |  |  | 			(docpath, kind, case, word, tut, lib, ref, ext, api) = prefs.docsearchengine = \ | 
					
						
							|  |  |  | 				("", 0, 0, 0, 1, 1, 0, 0, 0) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		if docpath and not verifydocpath(docpath): | 
					
						
							|  |  |  | 			docpath = "" | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		self.w = W.Window((400, 200), "Search the Python Documentation") | 
					
						
							|  |  |  | 		self.w.searchtext = W.EditText((10, 10, -100, 20), callback = self.checkbuttons) | 
					
						
							|  |  |  | 		self.w.searchbutton = W.Button((-90, 12, 80, 16), "Search", self.search) | 
					
						
							|  |  |  | 		buttons = [] | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		gutter = 10 | 
					
						
							|  |  |  | 		width = 130 | 
					
						
							|  |  |  | 		bookstart = width + 2 * gutter | 
					
						
							|  |  |  | 		self.w.phraseradio = W.RadioButton((10, 38, width, 16), "As a phrase", buttons) | 
					
						
							|  |  |  | 		self.w.allwordsradio = W.RadioButton((10, 58, width, 16), "All words", buttons) | 
					
						
							|  |  |  | 		self.w.anywordsradio = W.RadioButton((10, 78, width, 16), "Any word", buttons) | 
					
						
							|  |  |  | 		self.w.casesens = W.CheckBox((10, 98, width, 16), "Case sensitive") | 
					
						
							|  |  |  | 		self.w.wholewords = W.CheckBox((10, 118, width, 16), "Whole words") | 
					
						
							|  |  |  | 		self.w.tutorial = W.CheckBox((bookstart, 38, -10, 16), "Tutorial") | 
					
						
							|  |  |  | 		self.w.library = W.CheckBox((bookstart, 58, -10, 16), "Library reference") | 
					
						
							|  |  |  | 		self.w.langueref = W.CheckBox((bookstart, 78, -10, 16), "Lanuage reference manual") | 
					
						
							|  |  |  | 		self.w.extending = W.CheckBox((bookstart, 98, -10, 16), "Extending & embedding") | 
					
						
							|  |  |  | 		self.w.api = W.CheckBox((bookstart, 118, -10, 16), "C/C++ API") | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2001-12-03 18:11:36 +00:00
										 |  |  | 		self.w.setdocfolderbutton = W.Button((10, -30, 100, 16), "Set doc folder", self.setdocpath) | 
					
						
							| 
									
										
										
										
											1999-01-30 22:39:17 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		if docpath: | 
					
						
							|  |  |  | 			self.w.setdefaultbutton(self.w.searchbutton) | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			self.w.setdefaultbutton(self.w.setdocfolderbutton) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		self.docpath = docpath | 
					
						
							|  |  |  | 		if not docpath: | 
					
						
							|  |  |  | 			docpath = "(please select the Python html documentation folder)" | 
					
						
							| 
									
										
										
										
											2001-12-03 18:11:36 +00:00
										 |  |  | 		self.w.docfolder = W.TextBox((120, -28, -10, 16), docpath) | 
					
						
							| 
									
										
										
										
											1999-01-30 22:39:17 +00:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		[self.w.phraseradio, self.w.allwordsradio, self.w.anywordsradio][kind].set(1) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		self.w.casesens.set(case) | 
					
						
							|  |  |  | 		self.w.wholewords.set(word) | 
					
						
							|  |  |  | 		self.w.tutorial.set(tut) | 
					
						
							|  |  |  | 		self.w.library.set(lib) | 
					
						
							|  |  |  | 		self.w.langueref.set(ref) | 
					
						
							|  |  |  | 		self.w.extending.set(ext) | 
					
						
							|  |  |  | 		self.w.api.set(api) | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		self.w.open() | 
					
						
							|  |  |  | 		self.w.wholewords.enable(0) | 
					
						
							|  |  |  | 		self.w.bind('<close>', self.close) | 
					
						
							|  |  |  | 		self.w.searchbutton.enable(0) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def search(self): | 
					
						
							|  |  |  | 		hits = dosearch(self.docpath, self.w.searchtext.get(), self.getsettings()) | 
					
						
							|  |  |  | 		if hits: | 
					
						
							|  |  |  | 			Results(hits) | 
					
						
							|  |  |  | 		elif hasattr(MacOS, 'SysBeep'): | 
					
						
							|  |  |  | 			MacOS.SysBeep(0) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def setdocpath(self): | 
					
						
							| 
									
										
										
										
											2003-01-26 22:15:48 +00:00
										 |  |  | 		docpath = EasyDialogs.AskFolder() | 
					
						
							|  |  |  | 		if docpath: | 
					
						
							| 
									
										
										
										
											1999-01-30 22:39:17 +00:00
										 |  |  | 			if not verifydocpath(docpath): | 
					
						
							|  |  |  | 				W.Message("This does not seem to be a Python documentation folder...") | 
					
						
							|  |  |  | 			else: | 
					
						
							|  |  |  | 				self.docpath = docpath | 
					
						
							|  |  |  | 				self.w.docfolder.set(docpath) | 
					
						
							|  |  |  | 				self.w.setdefaultbutton(self.w.searchbutton) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def close(self): | 
					
						
							|  |  |  | 		prefs = MacPrefs.GetPrefs(W.getapplication().preffilepath) | 
					
						
							|  |  |  | 		prefs.docsearchengine = self.getsettings() | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def getsettings(self): | 
					
						
							|  |  |  | 		radiobuttons = [self.w.phraseradio, self.w.allwordsradio, self.w.anywordsradio] | 
					
						
							|  |  |  | 		for i in range(3): | 
					
						
							|  |  |  | 			if radiobuttons[i].get(): | 
					
						
							|  |  |  | 				kind = i | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 		docpath = self.docpath | 
					
						
							|  |  |  | 		case = self.w.casesens.get() | 
					
						
							|  |  |  | 		word = self.w.wholewords.get() | 
					
						
							|  |  |  | 		tut = self.w.tutorial.get() | 
					
						
							|  |  |  | 		lib = self.w.library.get() | 
					
						
							|  |  |  | 		ref = self.w.langueref.get() | 
					
						
							|  |  |  | 		ext = self.w.extending.get() | 
					
						
							|  |  |  | 		api = self.w.api.get() | 
					
						
							|  |  |  | 		return (docpath, kind, case, word, tut, lib, ref, ext, api) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	def checkbuttons(self): | 
					
						
							|  |  |  | 		self.w.searchbutton.enable(not not self.w.searchtext.get()) |