Move setting of ioready 'wait' earlier in call chain, to
[python/dscho.git] / Demo / tkinter / guido / mbox.py
blob9aea7ee5b1764f164925ebbda583935d48cd2219
1 #! /usr/bin/env python
3 # Scan MH folder, display results in window
5 import os
6 import sys
7 import regex
8 import getopt
9 import string
10 import mhlib
12 from Tkinter import *
14 from dialog import dialog
16 mailbox = os.environ['HOME'] + '/Mail'
18 def main():
19 global root, tk, top, mid, bot
20 global folderbox, foldermenu, scanbox, scanmenu, viewer
21 global folder, seq
22 global mh, mhf
24 # Parse command line options
26 folder = 'inbox'
27 seq = 'all'
28 try:
29 opts, args = getopt.getopt(sys.argv[1:], '')
30 except getopt.error, msg:
31 print msg
32 sys.exit(2)
33 for arg in args:
34 if arg[:1] == '+':
35 folder = arg[1:]
36 else:
37 seq = arg
39 # Initialize MH
41 mh = mhlib.MH()
42 mhf = mh.openfolder(folder)
44 # Build widget hierarchy
46 root = Tk()
47 tk = root.tk
49 top = Frame(root)
50 top.pack({'expand': 1, 'fill': 'both'})
52 # Build right part: folder list
54 right = Frame(top)
55 right.pack({'fill': 'y', 'side': 'right'})
57 folderbar = Scrollbar(right, {'relief': 'sunken', 'bd': 2})
58 folderbar.pack({'fill': 'y', 'side': 'right'})
60 folderbox = Listbox(right, {'exportselection': 0})
61 folderbox.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
63 foldermenu = Menu(root)
64 foldermenu.add('command',
65 {'label': 'Open Folder',
66 'command': open_folder})
67 foldermenu.add('separator')
68 foldermenu.add('command',
69 {'label': 'Quit',
70 'command': 'exit'})
71 foldermenu.bind('<ButtonRelease-3>', folder_unpost)
73 folderbox['yscrollcommand'] = (folderbar, 'set')
74 folderbar['command'] = (folderbox, 'yview')
75 folderbox.bind('<Double-1>', open_folder, 1)
76 folderbox.bind('<3>', folder_post)
78 # Build left part: scan list
80 left = Frame(top)
81 left.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
83 scanbar = Scrollbar(left, {'relief': 'sunken', 'bd': 2})
84 scanbar.pack({'fill': 'y', 'side': 'right'})
86 scanbox = Listbox(left, {'font': 'fixed'})
87 scanbox.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
89 scanmenu = Menu(root)
90 scanmenu.add('command',
91 {'label': 'Open Message',
92 'command': open_message})
93 scanmenu.add('command',
94 {'label': 'Remove Message',
95 'command': remove_message})
96 scanmenu.add('command',
97 {'label': 'Refile Message',
98 'command': refile_message})
99 scanmenu.add('separator')
100 scanmenu.add('command',
101 {'label': 'Quit',
102 'command': 'exit'})
103 scanmenu.bind('<ButtonRelease-3>', scan_unpost)
105 scanbox['yscrollcommand'] = (scanbar, 'set')
106 scanbar['command'] = (scanbox, 'yview')
107 scanbox.bind('<Double-1>', open_message)
108 scanbox.bind('<3>', scan_post)
110 # Separator between middle and bottom part
112 rule2 = Frame(root, {'bg': 'black'})
113 rule2.pack({'fill': 'x'})
115 # Build bottom part: current message
117 bot = Frame(root)
118 bot.pack({'expand': 1, 'fill': 'both'})
120 viewer = None
122 # Window manager commands
124 root.minsize(800, 1) # Make window resizable
126 # Fill folderbox with text
128 setfolders()
130 # Fill scanbox with text
132 rescan()
134 # Enter mainloop
136 root.mainloop()
138 def folder_post(e):
139 x, y = e.x_root, e.y_root
140 foldermenu.post(x - 10, y - 10)
141 foldermenu.grab_set()
143 def folder_unpost(e):
144 tk.call('update', 'idletasks')
145 foldermenu.grab_release()
146 foldermenu.unpost()
147 foldermenu.invoke('active')
149 def scan_post(e):
150 x, y = e.x_root, e.y_root
151 scanmenu.post(x - 10, y - 10)
152 scanmenu.grab_set()
154 def scan_unpost(e):
155 tk.call('update', 'idletasks')
156 scanmenu.grab_release()
157 scanmenu.unpost()
158 scanmenu.invoke('active')
160 scanparser = regex.compile('^ *\([0-9]+\)')
162 def open_folder(e=None):
163 global folder, mhf
164 sel = folderbox.curselection()
165 if len(sel) != 1:
166 if len(sel) > 1:
167 msg = "Please open one folder at a time"
168 else:
169 msg = "Please select a folder to open"
170 dialog(root, "Can't Open Folder", msg, "", 0, "OK")
171 return
172 i = sel[0]
173 folder = folderbox.get(i)
174 mhf = mh.openfolder(folder)
175 rescan()
177 def open_message(e=None):
178 global viewer
179 sel = scanbox.curselection()
180 if len(sel) != 1:
181 if len(sel) > 1:
182 msg = "Please open one message at a time"
183 else:
184 msg = "Please select a message to open"
185 dialog(root, "Can't Open Message", msg, "", 0, "OK")
186 return
187 cursor = scanbox['cursor']
188 scanbox['cursor'] = 'watch'
189 tk.call('update', 'idletasks')
190 i = sel[0]
191 line = scanbox.get(i)
192 if scanparser.match(line) >= 0:
193 num = string.atoi(scanparser.group(1))
194 m = mhf.openmessage(num)
195 if viewer: viewer.destroy()
196 from MimeViewer import MimeViewer
197 viewer = MimeViewer(bot, '+%s/%d' % (folder, num), m)
198 viewer.pack()
199 viewer.show()
200 scanbox['cursor'] = cursor
202 def interestingheader(header):
203 return header != 'received'
205 def remove_message(e=None):
206 itop = scanbox.nearest(0)
207 sel = scanbox.curselection()
208 if not sel:
209 dialog(root, "No Message To Remove",
210 "Please select a message to remove", "", 0, "OK")
211 return
212 todo = []
213 for i in sel:
214 line = scanbox.get(i)
215 if scanparser.match(line) >= 0:
216 todo.append(string.atoi(scanparser.group(1)))
217 mhf.removemessages(todo)
218 rescan()
219 fixfocus(min(todo), itop)
221 lastrefile = ''
222 tofolder = None
223 def refile_message(e=None):
224 global lastrefile, tofolder
225 itop = scanbox.nearest(0)
226 sel = scanbox.curselection()
227 if not sel:
228 dialog(root, "No Message To Refile",
229 "Please select a message to refile", "", 0, "OK")
230 return
231 foldersel = folderbox.curselection()
232 if len(foldersel) != 1:
233 if not foldersel:
234 msg = "Please select a folder to refile to"
235 else:
236 msg = "Please select exactly one folder to refile to"
237 dialog(root, "No Folder To Refile", msg, "", 0, "OK")
238 return
239 refileto = folderbox.get(foldersel[0])
240 todo = []
241 for i in sel:
242 line = scanbox.get(i)
243 if scanparser.match(line) >= 0:
244 todo.append(string.atoi(scanparser.group(1)))
245 if lastrefile != refileto or not tofolder:
246 lastrefile = refileto
247 tofolder = None
248 tofolder = mh.openfolder(lastrefile)
249 mhf.refilemessages(todo, tofolder)
250 rescan()
251 fixfocus(min(todo), itop)
253 def fixfocus(near, itop):
254 n = scanbox.size()
255 for i in range(n):
256 line = scanbox.get(`i`)
257 if scanparser.match(line) >= 0:
258 num = string.atoi(scanparser.group(1))
259 if num >= near:
260 break
261 else:
262 i = 'end'
263 scanbox.select_from(i)
264 scanbox.yview(itop)
266 def setfolders():
267 folderbox.delete(0, 'end')
268 for fn in mh.listallfolders():
269 folderbox.insert('end', fn)
271 def rescan():
272 global viewer
273 if viewer:
274 viewer.destroy()
275 viewer = None
276 scanbox.delete(0, 'end')
277 for line in scanfolder(folder, seq):
278 scanbox.insert('end', line)
280 def scanfolder(folder = 'inbox', sequence = 'all'):
281 return map(
282 lambda line: line[:-1],
283 os.popen('scan +%s %s' % (folder, sequence), 'r').readlines())
285 main()