1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 import os, sys, re, string, types
39 import htmllib, formatter
40 import Tkinter
41
42
43 from mfxutil import Struct, openURL
44 from util import PACKAGE
45
46
47 from tkutil import bind, unbind_destroy, loadImage
48 from tkwidget import MfxDialog
49
50
51
52
53
54
57 fcnf = {}
58 for k in cnf.keys():
59 if type(k) is types.ClassType or k == "name":
60 fcnf[k] = cnf[k]
61 del cnf[k]
62 if cnf.has_key("bg"):
63 fcnf["bg"] = cnf["bg"]
64 self.frame = apply(Tkinter.Frame, (parent,), fcnf)
65 self.vbar = Tkinter.Scrollbar(self.frame, name="vbar")
66 self.vbar.pack(side=Tkinter.RIGHT, fill=Tkinter.Y)
67 cnf["name"] = "text"
68 apply(Tkinter.Text.__init__, (self, self.frame), cnf)
69 self.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH, expand=1)
70 self["yscrollcommand"] = self.vbar.set
71 self.vbar["command"] = self.yview
72
73
74 for m in Tkinter.Pack.__dict__.keys():
75 if m[0] != "_" and m != "config" and m != "configure":
76
77 setattr(self, m, getattr(self.frame, m))
78
79 self.frame["highlightthickness"] = 0
80 self.vbar["highlightthickness"] = 0
81
82
83
85 return self.tk.call(self._w, "xview", "moveto", fraction)
87 return self.tk.call(self._w, "xview", "scroll", number, what)
89 return self.tk.call(self._w, "yview", "moveto", fraction)
91 return self.tk.call(self._w, "yview", "scroll", number, what)
92
93
96 apply(MfxScrolledText.__init__, (self, parent), cnf)
97 self.config(state="disabled", insertofftime=0)
98 self.frame.config(takefocus=0)
99 self.config(takefocus=0)
100 self.vbar.config(takefocus=0)
101
102
103
104
105
106
109 formatter.DumbWriter.__init__(self, self, maxcol=9999)
110
111 self.text = text
112 self.viewer = viewer
113
114 font, size = "Helvetica", 12
115 f = self.text["font"]
116 if f[0] == "{":
117 m = re.search(r"^\{([^\}]+)\}\s*(-?\d+)", f)
118 if m:
119 font, size = m.group(1), int(m.group(2))
120 else:
121 f = string.split(f)
122 font, size = f[0], int(f[1])
123
124 font, size = "Helvetica", -14
125 fixed = ("Courier", -14)
126 if os.name == "nt":
127 font, size = "Helvetica", 12
128 fixed = ("Courier New", 10)
129
130 sign = 1
131 if size < 0: sign = -1
132
133 self.fontmap = {
134 "h1" : (font, size + 12*sign, "bold"),
135 "h2" : (font, size + 8*sign, "bold"),
136 "h3" : (font, size + 6*sign, "bold"),
137 "h4" : (font, size + 4*sign, "bold"),
138 "h5" : (font, size + 2*sign, "bold"),
139 "h6" : (font, size + 1*sign, "bold"),
140 "bold" : (font, size, "bold"),
141 "italic" : (font, size, "italic"),
142 "pre" : (fixed),
143 }
144
145 self.text.config(cursor=self.viewer.defcursor)
146 for f in self.fontmap.keys():
147 self.text.tag_config(f, font=self.fontmap[f])
148
149 self.anchor = None
150 self.anchor_mark = None
151 self.font = None
152 self.font_mark = None
153 self.indent = ""
154
156 class Functor:
157 def __init__(self, viewer, arg):
158 self.viewer = viewer
159 self.arg = arg
160 def __call__(self, *args):
161 self.viewer.updateHistoryXYView()
162 return self.viewer.display(self.arg)
163 return Functor(self.viewer, href)
164
170
173
175 if href:
176
177 self.anchor = (href, name, type)
178 self.anchor_mark = self.text.index("insert")
179
181 if self.anchor:
182 url = self.anchor[0]
183 tag = "href_" + url
184 self.text.tag_add(tag, self.anchor_mark, "insert")
185 self.text.tag_bind(tag, "<ButtonPress>", self.createCallback(url))
186 self.text.tag_bind(tag, "<Enter>", self.anchor_enter)
187 self.text.tag_bind(tag, "<Leave>", self.anchor_leave)
188 self.text.tag_config(tag, foreground="blue", underline=1)
189 self.anchor = None
190
192 self.text.config(cursor = self.viewer.handcursor)
193
195 self.text.config(cursor = self.viewer.defcursor)
196
198
199 if self.font:
200
201 self.text.tag_add(self.font, self.font_mark, "insert")
202 self.font = None
203
204 if font:
205
206 self.font_mark = self.text.index("insert")
207 if self.fontmap.has_key(font[0]):
208 self.font = font[0]
209 elif font[3]:
210 self.font = "pre"
211 elif font[2]:
212 self.font = "bold"
213 elif font[1]:
214 self.font = "italic"
215 else:
216 self.font = None
217
220
223
225 if self.col > 0:
226 self.__write("\n")
227 if blankline > 0:
228 self.__write("\n" * blankline)
229 self.col = 0
230 self.atbreak = 0
231
238
239
240
241
242
243
246 htmllib.HTMLParser.anchor_bgn(self, href, name, type)
247 self.formatter.writer.anchor_bgn(href, name, type)
248
250 if self.anchor:
251 self.anchor = None
252 self.formatter.writer.anchor_end()
253
255 self.formatter.end_paragraph(1)
256 self.ddpop()
257
258 - def handle_image(self, src, alt, ismap, align, width, height):
260
261
262
263
264
265
268 self.parent = parent
269 self.home = None
270 self.url = None
271 self.history = Struct(
272 list = [],
273 index = 0,
274 )
275 self.images = []
276 self.defcursor = parent["cursor"]
277 self.handcursor = "hand2"
278
279
280 frame = self.frame = Tkinter.Frame(parent)
281 frame.pack(side="bottom", fill="x")
282 self.homeButton = Tkinter.Button(frame, text="Index",
283 command=self.goHome)
284 self.homeButton.pack(side="left")
285 self.backButton = Tkinter.Button(frame, text="Back",
286 command=self.goBack)
287 self.backButton.pack(side="left")
288 self.forwardButton = Tkinter.Button(frame, text="Forward",
289 command=self.goForward)
290 self.forwardButton.pack(side="left")
291
292
293
294
295
296 basefont = ("Helvetica", 12)
297 if os.name == "nt":
298
299
300
301 basefont = ("Times New Roman", 12)
302 self.text = MfxReadonlyScrolledText(parent,
303 fg="#000000", bg="#f7f3ff",
304 cursor=self.defcursor,
305 font=basefont, wrap="word",
306 padx=20, pady=20)
307 self.text.pack(side="top", fill="both", expand=1)
308 self.initBindings()
309
311 w = self.parent
312 if isinstance(w,Tkinter.Toplevel):
313 bind(w, "WM_DELETE_WINDOW", self.destroy)
314 bind(w, "<Escape>", self.destroy)
315 bind(w, "<KeyPress-Prior>", self.page_up)
316 bind(w, "<KeyPress-Next>", self.page_down)
317 bind(w, "<KeyPress-Up>", self.unit_up)
318 bind(w, "<KeyPress-Down>", self.unit_down)
319 bind(w, "<KeyPress-Begin>", self.scroll_top)
320 bind(w, "<KeyPress-Home>", self.scroll_top)
321 bind(w, "<KeyPress-End>", self.scroll_bottom)
322 bind(w, "<KeyPress-BackSpace>", self.goBack)
323
333
334 - def page_up(self, *event):
335 self.text.yview_scroll(-1, "page")
336 return "break"
337 - def page_down(self, *event):
338 self.text.yview_scroll(1, "page")
339 return "break"
352
353
354 - def basejoin(self, url, baseurl=None, relpath=1):
355 if baseurl is None:
356 baseurl = self.url
357 if 0:
358 import urllib
359 url = urllib.pathname2url(url)
360 if relpath and self.url:
361 url = urllib.basejoin(baseurl, url)
362 else:
363 url = os.path.normpath(url)
364 if relpath and baseurl and not os.path.isabs(url):
365 h1, t1 = os.path.split(url)
366 h2, t2 = os.path.split(baseurl)
367 if cmp(h1, h2) != 0:
368 url = os.path.join(h2, h1, t1)
369 url = os.path.normpath(url)
370 return url
371
373 if url[-1:] == "/" or os.path.isdir(url):
374 url = os.path.join(url, "index.html")
375 url = os.path.normpath(url)
376 return open(url, "rb"), url
377
378 - def display(self, url, add=1, relpath=1, xview=0, yview=0):
379
380
381 if self.__dict__.get("app"):
382 if self.app and self.app.game:
383 self.app.game._cancelDrag()
384
385
386
387 for p in ("ftp:", "gopher:", "http:", "mailto:", "news:", "telnet:"):
388 if string.find(url, p) != -1:
389 if not openURL(url):
390 self.errorDialog(PACKAGE + " HTML limitation:\n" +
391 "The " + p + " protocol is not supported yet.\n\n" +
392 "Please use your standard web browser\n" +
393 "to open the following URL:\n\n" + url)
394 return
395
396
397 url = self.basejoin(url, relpath=relpath)
398
399
400 try:
401 file = None
402 if 0:
403 import urllib
404 file = urllib.urlopen(url)
405 else:
406 file, url = self.openfile(url)
407 data = file.read()
408 file.close()
409 file = None
410 except Exception, ex:
411 if file: file.close()
412 self.errorDialog("Unable to service request:\n" + url + "\n\n" + str(ex))
413 return
414 except:
415 if file: file.close()
416 self.errorDialog("Unable to service request:\n" + url)
417 return
418
419 self.url = url
420 if self.home is None:
421 self.home = self.url
422 if add:
423 self.addHistory(self.url, xview=xview, yview=yview)
424
425
426 if self.history.index > 1:
427 self.backButton.config(state="normal")
428 else:
429 self.backButton.config(state="disabled")
430 if self.history.index < len(self.history.list):
431 self.forwardButton.config(state="normal")
432 else:
433 self.forwardButton.config(state="disabled")
434
435 old_c1, old_c2 = self.defcursor, self.handcursor
436 self.defcursor = self.handcursor = "watch"
437 self.text.config(cursor=self.defcursor)
438 self.text.update_idletasks()
439 self.frame.config(cursor=self.defcursor)
440 self.frame.update_idletasks()
441 self.text.config(state="normal")
442 self.text.delete("1.0", "end")
443 self.images = []
444 writer = tkHTMLWriter(self.text, self)
445 fmt = formatter.AbstractFormatter(writer)
446 parser = tkHTMLParser(fmt)
447 parser.feed(data)
448 parser.close()
449 self.text.config(state="disabled")
450 if 0.0 <= xview <= 1.0:
451 self.text.xview_moveto(xview)
452 if 0.0 <= yview <= 1.0:
453 self.text.yview_moveto(yview)
454 if isinstance(self.parent,Tkinter.Toplevel):
455 self.parent.wm_title(parser.title)
456 self.parent.wm_iconname(parser.title)
457 self.defcursor, self.handcursor = old_c1, old_c2
458 self.text.config(cursor=self.defcursor)
459 self.frame.config(cursor=self.defcursor)
460
461 - def addHistory(self, url, xview=0, yview=0):
462 if self.history.index > 0:
463 u, xv, yv = self.history.list[self.history.index-1]
464 if cmp(u, url) == 0:
465 self.updateHistoryXYView()
466 return
467 del self.history.list[self.history.index : ]
468 self.history.list.append((url, xview, yview))
469 self.history.index = self.history.index + 1
470
472 if self.history.index > 0:
473 url, xview, yview = self.history.list[self.history.index-1]
474 xview = self.text.xview()[0]
475 yview = self.text.yview()[0]
476 self.history.list[self.history.index-1] = (url, xview, yview)
477
484
491
496
501
502 - def showImage(self, src, alt, ismap, align, width, height):
516
517
518
519
520
521
522
523 -def tkhtml_main(args):
524 try:
525 url = args[1]
526 except:
527
528 url = "index.html"
529 top = Tkinter.Tk()
530 top.wm_minsize(400, 200)
531 viewer = tkHTMLViewer(top)
532 viewer.display(url)
533 top.mainloop()
534 return 0
535
536 if __name__ == "__main__":
537 sys.exit(tkhtml_main(sys.argv))
538