blob: 2e870c47832c8f4e2caf697d443c4aa3fd149d0c [file] [log] [blame]
Guido van Rossumdfa70a91995-01-10 17:05:37 +00001#! /usr/local/bin/python
2
3# www12.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
13import sys
14import urllib
15from Tkinter import *
16import Dialog
17
18def main():
19 if len(sys.argv) != 2 or sys.argv[1][:1] == '-':
20 print "Usage:", sys.argv[0], "url"
21 sys.exit(2)
22 url = sys.argv[1]
23 tk = Tk()
24 tk.withdraw()
25 viewer = Viewer(tk)
26 viewer.load(url)
27 viewer.go()
28
29class Viewer:
30
31 def __init__(self, master = None):
32 # Create root window
33 if master is None:
34 self.root = self.master = Tk()
35 else:
36 self.master = master
37 self.root = Toplevel(self.master)
38 self.root.minsize(1, 1)
39
40 # Create menu bar
41 self.mbar = Frame(self.root,
42 {'relief': 'raised',
43 'border': 2})
44 self.mbar.pack({'fill': 'x'})
45
46 # Create File menu
47 self.filebutton = Menubutton(self.mbar, {'text': 'File'})
48 self.filebutton.pack({'side': 'left'})
49
50 self.filemenu = Menu(self.filebutton)
51 self.filebutton['menu'] = self.filemenu
52
53 # Create Edit menu
54 self.editbutton = Menubutton(self.mbar, {'text': 'Edit'})
55 self.editbutton.pack({'side': 'left'})
56
57 self.editmenu = Menu(self.editbutton)
58 self.editbutton['menu'] = self.editmenu
59
60 # Magic so you can swipe from one button to the next
61 self.mbar.tk_menuBar(self.filebutton, self.editbutton)
62
63 # Populate File menu
64 self.filemenu.add('command', {'label': 'New',
65 'command': self.new_command})
66 self.filemenu.add('command', {'label': 'Open...',
67 'command': self.open_command})
68 self.filemenu.add('command', {'label': 'Clone',
69 'command': self.clone_command})
70 self.filemenu.add('separator')
71 self.filemenu.add('command', {'label': 'Close',
72 'command': self.close_command})
73 self.filemenu.add('command', {'label': 'Quit',
74 'command': self.quit_command})
75
76 # Populate Edit menu
77 pass
78
79 # Create topframe for the entry and button
80 self.topframe = Frame(self.root)
81 self.topframe.pack({'fill': 'x'})
82
83 # Create a label in front of the entry
84 self.urllabel = Label(self.topframe, {'text': 'URL:'})
85 self.urllabel.pack({'side': 'left'})
86
87 # Create the entry containing the URL
88 self.entry = Entry(self.topframe,
89 {'relief': 'sunken', 'border': 2})
90 self.entry.pack({'side': 'left', 'fill': 'x', 'expand': 1})
91 self.entry.bind('<Return>', self.loadit)
92
93 # Create the button
94 self.reload = Button(self.topframe,
95 {'text': 'Reload',
96 'command': self.reload})
97 self.reload.pack({'side': 'right'})
98
99 # Create botframe for the text and scrollbar
100 self.botframe = Frame(self.root)
101 self.botframe.pack({'fill': 'both', 'expand': 1})
102
103 # The Scrollbar *must* be created first
104 self.vbar = Scrollbar(self.botframe)
105 self.vbar.pack({'fill': 'y', 'side': 'right'})
106 self.text = Text(self.botframe)
107 self.text.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
108
109 # Link Text widget and Scrollbar
110 self.text['yscrollcommand'] = (self.vbar, 'set')
111 self.vbar['command'] = (self.text, 'yview')
112
113 self.url = None
114
115 def load(self, url):
116 # Load a new URL into the window
117 fp, url = self.urlopen(url)
118 if not fp:
119 return
120
121 self.url = url
122
123 self.root.title(url)
124
125 self.entry.delete('0', 'end')
126 self.entry.insert('end', url)
127
128 self.text.delete('0.0', 'end')
129
130 while 1:
131 line = fp.readline()
132 if not line: break
133 if line[-2:] == '\r\n': line = line[:-2] + '\n'
134 self.text.insert('end', line)
135 self.root.update_idletasks()
136
137 fp.close()
138
139 def urlopen(self, url):
140 # Open a URL --
141 # return (fp, url) if successful
142 # display dialog and return (None, url) for errors
143 try:
144 fp = urllib.urlopen(url)
145 except IOError, msg:
146 import types
147 if type(msg) == types.TupleType and len(msg) == 4:
148 if msg[1] == 302:
149 m = msg[3]
150 if m.has_key('location'):
151 url = m['location']
152 return self.urlopen(url)
153 elif m.has_key('uri'):
154 url = m['uri']
155 return self.urlopen(url)
156 self.errordialog(IOError, msg)
157 fp = None
158 return fp, url
159
160 def errordialog(self, exc, msg):
161 # Display an error dialog -- return when the user clicks OK
162 Dialog.Dialog(self.root, {
163 'text': str(msg),
164 'title': exc,
165 'bitmap': 'error',
166 'default': 0,
167 'strings': ('OK',),
168 })
169
170 def go(self):
171 # Start Tk main loop
172 self.root.mainloop()
173
174 def reload(self, *args):
175 # Callback for Reload button
176 if self.url:
177 self.load(self.url)
178
179 def loadit(self, *args):
180 # Callback for <Return> event in entry
181 self.load(self.entry.get())
182
183 def new_command(self):
184 # File/New...
185 Viewer(self.master)
186
187 def clone_command(self):
188 # File/Clone
189 v = Viewer(self.master)
190 v.load(self.url)
191
192 def open_command(self):
193 # File/Open...
194 print "File/Open...: Not implemented"
195
196 def close_command(self):
197 # File/Close
198 self.destroy()
199
200 def quit_command(self):
201 # File/Quit
202 self.root.quit()
203
204 def destroy(self):
205 # Destroy this window
206 self.root.destroy()
207 if self.master is not self.root and not self.master.children:
208 self.master.quit()
209
210main()