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
166
167
168
169 self.text.insert("insert", data)
170
172 self.text.insert("insert", data)
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
219 self.indent = " " * level
220
222 self.__write(self.indent + data + " ")
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
233 width = int(int(self.text["width"]) * 0.9)
234 self.__write("_" * width)
235 self.__write("\n")
236 self.col = 0
237 self.atbreak = 0
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):
259 self.formatter.writer.viewer.showImage(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 self.closeButton = Tkinter.Button(frame, text="Close",
292 command=self.destroy)
293 self.closeButton.pack(side="right")
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 bind(w, "WM_DELETE_WINDOW", self.destroy)
313 bind(w, "<Escape>", self.destroy)
314 bind(w, "<KeyPress-Prior>", self.page_up)
315 bind(w, "<KeyPress-Next>", self.page_down)
316 bind(w, "<KeyPress-Up>", self.unit_up)
317 bind(w, "<KeyPress-Down>", self.unit_down)
318 bind(w, "<KeyPress-Begin>", self.scroll_top)
319 bind(w, "<KeyPress-Home>", self.scroll_top)
320 bind(w, "<KeyPress-End>", self.scroll_bottom)
321 bind(w, "<KeyPress-BackSpace>", self.goBack)
322
324 unbind_destroy(self.parent)
325 try:
326 self.parent.wm_withdraw()
327 except: pass
328 try:
329 self.parent.destroy()
330 except: pass
331 self.parent = None
332
333 - def page_up(self, *event):
334 self.text.yview_scroll(-1, "page")
335 return "break"
336 - def page_down(self, *event):
337 self.text.yview_scroll(1, "page")
338 return "break"
351
352
353 - def basejoin(self, url, baseurl=None, relpath=1):
354 if baseurl is None:
355 baseurl = self.url
356 if 0:
357 import urllib
358 url = urllib.pathname2url(url)
359 if relpath and self.url:
360 url = urllib.basejoin(baseurl, url)
361 else:
362 url = os.path.normpath(url)
363 if relpath and baseurl and not os.path.isabs(url):
364 h1, t1 = os.path.split(url)
365 h2, t2 = os.path.split(baseurl)
366 if cmp(h1, h2) != 0:
367 url = os.path.join(h2, h1, t1)
368 url = os.path.normpath(url)
369 return url
370
372 if url[-1:] == "/" or os.path.isdir(url):
373 url = os.path.join(url, "index.html")
374 url = os.path.normpath(url)
375 return open(url, "rb"), url
376
377 - def display(self, url, add=1, relpath=1, xview=0, yview=0):
378
379
380 if self.__dict__.get("app"):
381 if self.app and self.app.game:
382 self.app.game._cancelDrag()
383
384
385
386 for p in ("ftp:", "gopher:", "http:", "mailto:", "news:", "telnet:"):
387 if string.find(url, p) != -1:
388 if not openURL(url):
389 self.errorDialog(PACKAGE + " HTML limitation:\n" +
390 "The " + p + " protocol is not supported yet.\n\n" +
391 "Please use your standard web browser\n" +
392 "to open the following URL:\n\n" + url)
393 return
394
395
396 url = self.basejoin(url, relpath=relpath)
397
398
399 try:
400 file = None
401 if 0:
402 import urllib
403 file = urllib.urlopen(url)
404 else:
405 file, url = self.openfile(url)
406 data = file.read()
407 file.close()
408 file = None
409 except Exception, ex:
410 if file: file.close()
411 self.errorDialog("Unable to service request:\n" + url + "\n\n" + str(ex))
412 return
413 except:
414 if file: file.close()
415 self.errorDialog("Unable to service request:\n" + url)
416 return
417
418 self.url = url
419 if self.home is None:
420 self.home = self.url
421 if add:
422 self.addHistory(self.url, xview=xview, yview=yview)
423
424
425 if self.history.index > 1:
426 self.backButton.config(state="normal")
427 else:
428 self.backButton.config(state="disabled")
429 if self.history.index < len(self.history.list):
430 self.forwardButton.config(state="normal")
431 else:
432 self.forwardButton.config(state="disabled")
433
434 old_c1, old_c2 = self.defcursor, self.handcursor
435 self.defcursor = self.handcursor = "watch"
436 self.text.config(cursor=self.defcursor)
437 self.text.update_idletasks()
438 self.frame.config(cursor=self.defcursor)
439 self.frame.update_idletasks()
440 self.text.config(state="normal")
441 self.text.delete("1.0", "end")
442 self.images = []
443 writer = tkHTMLWriter(self.text, self)
444 fmt = formatter.AbstractFormatter(writer)
445 parser = tkHTMLParser(fmt)
446 parser.feed(data)
447 parser.close()
448 self.text.config(state="disabled")
449 if 0.0 <= xview <= 1.0:
450 self.text.xview_moveto(xview)
451 if 0.0 <= yview <= 1.0:
452 self.text.yview_moveto(yview)
453 self.parent.wm_title(parser.title)
454 self.parent.wm_iconname(parser.title)
455 self.defcursor, self.handcursor = old_c1, old_c2
456 self.text.config(cursor=self.defcursor)
457 self.frame.config(cursor=self.defcursor)
458
459 - def addHistory(self, url, xview=0, yview=0):
460 if self.history.index > 0:
461 u, xv, yv = self.history.list[self.history.index-1]
462 if cmp(u, url) == 0:
463 self.updateHistoryXYView()
464 return
465 del self.history.list[self.history.index : ]
466 self.history.list.append((url, xview, yview))
467 self.history.index = self.history.index + 1
468
470 if self.history.index > 0:
471 url, xview, yview = self.history.list[self.history.index-1]
472 xview = self.text.xview()[0]
473 yview = self.text.yview()[0]
474 self.history.list[self.history.index-1] = (url, xview, yview)
475
477 if self.history.index > 1:
478 self.updateHistoryXYView()
479 self.history.index = self.history.index - 1
480 url, xview, yview = self.history.list[self.history.index-1]
481 self.display(url, add=0, relpath=0, xview=xview, yview=yview)
482
484 if self.history.index < len(self.history.list):
485 self.updateHistoryXYView()
486 url, xview, yview = self.history.list[self.history.index]
487 self.history.index = self.history.index + 1
488 self.display(url, add=0, relpath=0, xview=xview, yview=yview)
489
494
496 d = MfxDialog(self.parent, title=PACKAGE+" HTML Problem",
497 text=msg, bitmap="warning",
498 strings=("OK",), default=0)
499
500 - def showImage(self, src, alt, ismap, align, width, height):
501 url = self.basejoin(src)
502
503 try:
504 img = loadImage(file=url)
505 except:
506 img = None
507 if img:
508 padx, pady = 10, 10
509 padx, pady = 0, 20
510 if string.lower(align) == "left":
511 padx = 0
512 self.text.image_create(index="insert", image=img, padx=padx, pady=pady)
513 self.images.append(img)
514
515
516
517
518
519
520
521 -def tkhtml_main(args):
522 try:
523 url = args[1]
524 except:
525 url = os.path.abspath(os.path.join("HTML","node60.html"))
526 top = Tkinter.Tk()
527 top.wm_minsize(400, 200)
528 viewer = tkHTMLViewer(top)
529 viewer.display(url)
530 top.mainloop()
531 return 0
532
533 if __name__ == "__main__":
534 sys.exit(tkhtml_main(sys.argv))
535