blob: be606506dc6122fe814e5b91d1a51092b4eb3e5a [file] [log] [blame]
Guido van Rossume3bd8211998-06-15 12:35:19 +00001#! /usr/bin/env python
2
3"""Tkinter-based GUI for websucker.
4
5Easy use: type or paste source URL and destination directory in
6their respective text boxes, click GO or hit return, and presto.
7"""
8
9from Tkinter import *
10import Tkinter
11import string
12import websucker
13import sys
14import os
Guido van Rossumb77a68e1998-07-08 03:05:22 +000015import threading
16import Queue
17import time
Guido van Rossume3bd8211998-06-15 12:35:19 +000018
Guido van Rossumb77a68e1998-07-08 03:05:22 +000019VERBOSE = 2
Guido van Rossume3bd8211998-06-15 12:35:19 +000020
21
22try:
23 class Canceled(Exception):
24 "Exception used to cancel run()."
25except:
26 Canceled = __name__ + ".Canceled"
27
28
Guido van Rossumb77a68e1998-07-08 03:05:22 +000029class SuckerThread(websucker.Sucker):
Guido van Rossume3bd8211998-06-15 12:35:19 +000030
Guido van Rossumb77a68e1998-07-08 03:05:22 +000031 stopit = 0
32 savedir = None
33 rootdir = None
34
35 def __init__(self, msgq):
36 self.msgq = msgq
Guido van Rossume3bd8211998-06-15 12:35:19 +000037 websucker.Sucker.__init__(self)
38 self.setflags(verbose=VERBOSE)
39 self.urlopener.addheaders = [
40 ('User-agent', 'websucker/%s' % websucker.__version__),
Guido van Rossume3bd8211998-06-15 12:35:19 +000041 ]
Guido van Rossumb77a68e1998-07-08 03:05:22 +000042
43 def message(self, format, *args):
44 if args:
45 format = format%args
46 ##print format
47 self.msgq.put(format)
Guido van Rossume3bd8211998-06-15 12:35:19 +000048
Guido van Rossumb77a68e1998-07-08 03:05:22 +000049 def run1(self, url):
50 try:
51 try:
52 self.reset()
53 self.addroot(url)
54 self.run()
55 except Canceled:
56 self.message("[canceled]")
57 else:
58 self.message("[done]")
59 finally:
60 self.msgq.put(None)
61
62 def savefile(self, text, path):
63 if self.stopit:
64 raise Canceled
65 websucker.Sucker.savefile(self, text, path)
66
67 def getpage(self, url):
68 if self.stopit:
69 raise Canceled
70 return websucker.Sucker.getpage(self, url)
71
72 def savefilename(self, url):
73 path = websucker.Sucker.savefilename(self, url)
74 if self.savedir:
75 n = len(self.rootdir)
76 if path[:n] == self.rootdir:
77 path = path[n:]
78 while path[:1] == os.sep:
79 path = path[1:]
80 path = os.path.join(self.savedir, path)
81 return path
82
83 def XXXaddrobot(self, *args):
84 pass
85
86 def XXXisallowed(self, *args):
87 return 1
88
89
90
91class App:
92
93 sucker = None
94 msgq = None
95
96 def __init__(self, top):
Guido van Rossume3bd8211998-06-15 12:35:19 +000097 self.top = top
98 top.columnconfigure(99, weight=1)
99 self.url_label = Label(top, text="URL:")
100 self.url_label.grid(row=0, column=0, sticky='e')
Guido van Rossum0a13f7f1998-06-15 14:49:16 +0000101 self.url_entry = Entry(top, width=60, exportselection=0)
102 self.url_entry.grid(row=0, column=1, sticky='we',
103 columnspan=99)
104 self.url_entry.focus_set()
Guido van Rossumb77a68e1998-07-08 03:05:22 +0000105 self.url_entry.bind("<Key-Return>", self.go)
Guido van Rossume3bd8211998-06-15 12:35:19 +0000106 self.dir_label = Label(top, text="Directory:")
107 self.dir_label.grid(row=1, column=0, sticky='e')
108 self.dir_entry = Entry(top)
Guido van Rossum0a13f7f1998-06-15 14:49:16 +0000109 self.dir_entry.grid(row=1, column=1, sticky='we',
110 columnspan=99)
Guido van Rossume3bd8211998-06-15 12:35:19 +0000111 self.go_button = Button(top, text="Go", command=self.go)
112 self.go_button.grid(row=2, column=1, sticky='w')
Guido van Rossum0a13f7f1998-06-15 14:49:16 +0000113 self.cancel_button = Button(top, text="Cancel",
114 command=self.cancel,
Guido van Rossume3bd8211998-06-15 12:35:19 +0000115 state=DISABLED)
116 self.cancel_button.grid(row=2, column=2, sticky='w')
Guido van Rossum0a13f7f1998-06-15 14:49:16 +0000117 self.auto_button = Button(top, text="Paste+Go",
118 command=self.auto)
Guido van Rossume3bd8211998-06-15 12:35:19 +0000119 self.auto_button.grid(row=2, column=3, sticky='w')
120 self.status_label = Label(top, text="[idle]")
121 self.status_label.grid(row=2, column=4, sticky='w')
Guido van Rossume3bd8211998-06-15 12:35:19 +0000122 self.top.update_idletasks()
123 self.top.grid_propagate(0)
Guido van Rossum0a13f7f1998-06-15 14:49:16 +0000124
Guido van Rossume3bd8211998-06-15 12:35:19 +0000125 def message(self, text, *args):
126 if args:
127 text = text % args
Guido van Rossumb77a68e1998-07-08 03:05:22 +0000128 self.status_label.config(text=text)
Guido van Rossume3bd8211998-06-15 12:35:19 +0000129
Guido van Rossumb77a68e1998-07-08 03:05:22 +0000130 def check_msgq(self):
131 while not self.msgq.empty():
132 msg = self.msgq.get()
133 if msg is None:
134 self.go_button.configure(state=NORMAL)
135 self.auto_button.configure(state=NORMAL)
136 self.cancel_button.configure(state=DISABLED)
137 if self.sucker:
138 self.sucker.stopit = 0
139 self.top.bell()
140 else:
141 self.message(msg)
142 self.top.after(100, self.check_msgq)
143
144 def go(self, event=None):
145 if not self.msgq:
146 self.msgq = Queue.Queue(0)
147 self.check_msgq()
148 if not self.sucker:
149 self.sucker = SuckerThread(self.msgq)
150 if self.sucker.stopit:
Guido van Rossume3bd8211998-06-15 12:35:19 +0000151 return
152 self.url_entry.selection_range(0, END)
153 url = self.url_entry.get()
154 url = string.strip(url)
155 if not url:
156 self.top.bell()
157 self.message("[Error: No URL entered]")
158 return
159 self.rooturl = url
160 dir = string.strip(self.dir_entry.get())
161 if not dir:
Guido van Rossumb77a68e1998-07-08 03:05:22 +0000162 self.sucker.savedir = None
Guido van Rossume3bd8211998-06-15 12:35:19 +0000163 else:
Guido van Rossumb77a68e1998-07-08 03:05:22 +0000164 self.sucker.savedir = dir
165 self.sucker.rootdir = os.path.dirname(
Guido van Rossume3bd8211998-06-15 12:35:19 +0000166 websucker.Sucker.savefilename(self, url))
167 self.go_button.configure(state=DISABLED)
168 self.auto_button.configure(state=DISABLED)
169 self.cancel_button.configure(state=NORMAL)
Guido van Rossumb77a68e1998-07-08 03:05:22 +0000170 self.message( '[running...]')
171 self.sucker.stopit = 0
172 t = threading.Thread(target=self.sucker.run1, args=(url,))
173 t.start()
Guido van Rossume3bd8211998-06-15 12:35:19 +0000174
175 def cancel(self):
Guido van Rossumb77a68e1998-07-08 03:05:22 +0000176 if self.sucker:
177 self.sucker.stopit = 1
Guido van Rossume3bd8211998-06-15 12:35:19 +0000178 self.message("[canceling...]")
179
180 def auto(self):
Guido van Rossum0a13f7f1998-06-15 14:49:16 +0000181 tries = ['PRIMARY', 'CLIPBOARD']
182 text = ""
183 for t in tries:
184 try:
185 text = self.top.selection_get(selection=t)
186 except TclError:
187 continue
188 text = string.strip(text)
189 if text:
190 break
Guido van Rossume3bd8211998-06-15 12:35:19 +0000191 if not text:
192 self.top.bell()
193 self.message("[Error: clipboard is empty]")
194 return
195 self.url_entry.delete(0, END)
196 self.url_entry.insert(0, text)
Guido van Rossume3bd8211998-06-15 12:35:19 +0000197 self.go()
Guido van Rossume3bd8211998-06-15 12:35:19 +0000198
199
Guido van Rossumb77a68e1998-07-08 03:05:22 +0000200class AppArray:
201
202 def __init__(self, top=None):
203 if not top:
204 top = Tk()
205 top.title("websucker GUI")
206 top.iconname("wsgui")
207 top.wm_protocol('WM_DELETE_WINDOW', self.exit)
208 self.top = top
209 self.appframe = Frame(self.top)
210 self.appframe.pack(fill='both')
211 self.applist = []
212 self.exit_button = Button(top, text="Exit", command=self.exit)
213 self.exit_button.pack(side=RIGHT)
214 self.new_button = Button(top, text="New", command=self.addsucker)
215 self.new_button.pack(side=LEFT)
216 self.addsucker()
217 ##self.applist[0].url_entry.insert(END, "http://www.python.org/doc/essays/")
218
219 def addsucker(self):
220 self.top.geometry("")
221 frame = Frame(self.appframe, borderwidth=2, relief=GROOVE)
222 frame.pack(fill='x')
223 app = App(frame)
224 self.applist.append(app)
225
226 done = 0
227
228 def mainloop(self):
229 while not self.done:
230 time.sleep(0.1)
231 self.top.update()
232
233 def exit(self):
234 for app in self.applist:
235 app.cancel()
236 app.message("[exiting...]")
237 self.done = 1
238
239
240def main():
241 AppArray().mainloop()
242
Guido van Rossume3bd8211998-06-15 12:35:19 +0000243if __name__ == '__main__':
Guido van Rossumb77a68e1998-07-08 03:05:22 +0000244 main()