Improved some error messages for command line processing.
[python/dscho.git] / Demo / tkinter / www / www13.py
blob90de01633dcacb2efa62518de8f0aeb64570d2f5
1 #! /usr/bin/env python
3 # www13.py -- display the contents of a URL in a Text widget
4 # - set window title
5 # - make window resizable
6 # - update display while reading
7 # - vertical scroll bar
8 # - rewritten as class
9 # - editable url entry and reload button
10 # - error dialog
11 # - menu bar; added 'master' option to constructor
12 # - Added HTML parser
14 import sys
15 import urllib
16 from Tkinter import *
17 import Dialog
18 import tkfmt
19 import htmllib
21 def main():
22 if len(sys.argv) != 2 or sys.argv[1][:1] == '-':
23 print "Usage:", sys.argv[0], "url"
24 sys.exit(2)
25 url = sys.argv[1]
26 tk = Tk()
27 tk.withdraw()
28 viewer = Viewer(tk)
29 viewer.load(url)
30 viewer.go()
32 class Viewer:
34 def __init__(self, master = None):
35 # Create root window
36 if master is None:
37 self.root = self.master = Tk()
38 else:
39 self.master = master
40 self.root = Toplevel(self.master)
41 self.root.minsize(1, 1)
43 # Create menu bar
44 self.mbar = Frame(self.root,
45 {'relief': 'raised',
46 'border': 2})
47 self.mbar.pack({'fill': 'x'})
49 # Create File menu
50 self.filebutton = Menubutton(self.mbar, {'text': 'File'})
51 self.filebutton.pack({'side': 'left'})
53 self.filemenu = Menu(self.filebutton)
54 self.filebutton['menu'] = self.filemenu
56 # Create Edit menu
57 self.editbutton = Menubutton(self.mbar, {'text': 'Edit'})
58 self.editbutton.pack({'side': 'left'})
60 self.editmenu = Menu(self.editbutton)
61 self.editbutton['menu'] = self.editmenu
63 # Magic so you can swipe from one button to the next
64 self.mbar.tk_menuBar(self.filebutton, self.editbutton)
66 # Populate File menu
67 self.filemenu.add('command', {'label': 'New',
68 'command': self.new_command})
69 self.filemenu.add('command', {'label': 'Open...',
70 'command': self.open_command})
71 self.filemenu.add('command', {'label': 'Clone',
72 'command': self.clone_command})
73 self.filemenu.add('separator')
74 self.filemenu.add('command', {'label': 'Close',
75 'command': self.close_command})
76 self.filemenu.add('command', {'label': 'Quit',
77 'command': self.quit_command})
79 # Populate Edit menu
80 pass
82 # Create topframe for the entry and button
83 self.topframe = Frame(self.root)
84 self.topframe.pack({'fill': 'x'})
86 # Create a label in front of the entry
87 self.urllabel = Label(self.topframe, {'text': 'URL:'})
88 self.urllabel.pack({'side': 'left'})
90 # Create the entry containing the URL
91 self.entry = Entry(self.topframe,
92 {'relief': 'sunken', 'border': 2})
93 self.entry.pack({'side': 'left', 'fill': 'x', 'expand': 1})
94 self.entry.bind('<Return>', self.loadit)
96 # Create the button
97 self.reload = Button(self.topframe,
98 {'text': 'Reload',
99 'command': self.reload})
100 self.reload.pack({'side': 'right'})
102 # Create botframe for the text and scrollbar
103 self.botframe = Frame(self.root)
104 self.botframe.pack({'fill': 'both', 'expand': 1})
106 # The Scrollbar *must* be created first
107 self.vbar = Scrollbar(self.botframe)
108 self.vbar.pack({'fill': 'y', 'side': 'right'})
109 self.text = Text(self.botframe)
110 self.text.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
112 # Link Text widget and Scrollbar
113 self.text['yscrollcommand'] = (self.vbar, 'set')
114 self.vbar['command'] = (self.text, 'yview')
116 self.url = None
118 def load(self, url):
119 # Load a new URL into the window
120 fp, url = self.urlopen(url)
121 if not fp:
122 return
124 self.url = url
126 self.root.title(url)
128 self.entry.delete('0', 'end')
129 self.entry.insert('end', url)
131 self.text.delete('0.0', 'end')
133 f = tkfmt.TkFormatter(self.text)
134 p = htmllib.FormattingParser(f, htmllib.X11Stylesheet)
136 while 1:
137 line = fp.readline()
138 if not line: break
139 if line[-2:] == '\r\n': line = line[:-2] + '\n'
140 p.feed(line)
141 self.root.update_idletasks()
143 p.close()
145 fp.close()
147 def urlopen(self, url):
148 # Open a URL --
149 # return (fp, url) if successful
150 # display dialog and return (None, url) for errors
151 try:
152 fp = urllib.urlopen(url)
153 except IOError, msg:
154 import types
155 if type(msg) == types.TupleType and len(msg) == 4:
156 if msg[1] == 302:
157 m = msg[3]
158 if m.has_key('location'):
159 url = m['location']
160 return self.urlopen(url)
161 elif m.has_key('uri'):
162 url = m['uri']
163 return self.urlopen(url)
164 self.errordialog(IOError, msg)
165 fp = None
166 return fp, url
168 def errordialog(self, exc, msg):
169 # Display an error dialog -- return when the user clicks OK
170 Dialog.Dialog(self.root, {
171 'text': str(msg),
172 'title': exc,
173 'bitmap': 'error',
174 'default': 0,
175 'strings': ('OK',),
178 def go(self):
179 # Start Tk main loop
180 self.root.mainloop()
182 def reload(self, *args):
183 # Callback for Reload button
184 if self.url:
185 self.load(self.url)
187 def loadit(self, *args):
188 # Callback for <Return> event in entry
189 self.load(self.entry.get())
191 def new_command(self):
192 # File/New...
193 Viewer(self.master)
195 def clone_command(self):
196 # File/Clone
197 v = Viewer(self.master)
198 v.load(self.url)
200 def open_command(self):
201 # File/Open...
202 print "File/Open...: Not implemented"
204 def close_command(self):
205 # File/Close
206 self.destroy()
208 def quit_command(self):
209 # File/Quit
210 self.root.quit()
212 def destroy(self):
213 # Destroy this window
214 self.root.destroy()
215 if self.master is not self.root and not self.master.children:
216 self.master.quit()
218 main()