PageRenderTime 494ms CodeModel.GetById 160ms app.highlight 141ms RepoModel.GetById 188ms app.codeStats 0ms

/Demo/tkinter/guido/mbox.py

http://unladen-swallow.googlecode.com/
Python | 285 lines | 274 code | 8 blank | 3 comment | 0 complexity | 048b443aa03cd70a0d0f4fdd4bd3cc6f MD5 | raw file
  1#! /usr/bin/env python
  2
  3# Scan MH folder, display results in window
  4
  5import os
  6import sys
  7import re
  8import getopt
  9import string
 10import mhlib
 11
 12from Tkinter import *
 13
 14from dialog import dialog
 15
 16mailbox = os.environ['HOME'] + '/Mail'
 17
 18def main():
 19    global root, tk, top, mid, bot
 20    global folderbox, foldermenu, scanbox, scanmenu, viewer
 21    global folder, seq
 22    global mh, mhf
 23
 24    # Parse command line options
 25
 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
 38
 39    # Initialize MH
 40
 41    mh = mhlib.MH()
 42    mhf = mh.openfolder(folder)
 43
 44    # Build widget hierarchy
 45
 46    root = Tk()
 47    tk = root.tk
 48
 49    top = Frame(root)
 50    top.pack({'expand': 1, 'fill': 'both'})
 51
 52    # Build right part: folder list
 53
 54    right = Frame(top)
 55    right.pack({'fill': 'y', 'side': 'right'})
 56
 57    folderbar = Scrollbar(right, {'relief': 'sunken', 'bd': 2})
 58    folderbar.pack({'fill': 'y', 'side': 'right'})
 59
 60    folderbox = Listbox(right, {'exportselection': 0})
 61    folderbox.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
 62
 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)
 72
 73    folderbox['yscrollcommand'] = (folderbar, 'set')
 74    folderbar['command'] = (folderbox, 'yview')
 75    folderbox.bind('<Double-1>', open_folder, 1)
 76    folderbox.bind('<3>', folder_post)
 77
 78    # Build left part: scan list
 79
 80    left = Frame(top)
 81    left.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
 82
 83    scanbar = Scrollbar(left, {'relief': 'sunken', 'bd': 2})
 84    scanbar.pack({'fill': 'y', 'side': 'right'})
 85
 86    scanbox = Listbox(left, {'font': 'fixed'})
 87    scanbox.pack({'expand': 1, 'fill': 'both', 'side': 'left'})
 88
 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)
104
105    scanbox['yscrollcommand'] = (scanbar, 'set')
106    scanbar['command'] = (scanbox, 'yview')
107    scanbox.bind('<Double-1>', open_message)
108    scanbox.bind('<3>', scan_post)
109
110    # Separator between middle and bottom part
111
112    rule2 = Frame(root, {'bg': 'black'})
113    rule2.pack({'fill': 'x'})
114
115    # Build bottom part: current message
116
117    bot = Frame(root)
118    bot.pack({'expand': 1, 'fill': 'both'})
119    #
120    viewer = None
121
122    # Window manager commands
123
124    root.minsize(800, 1) # Make window resizable
125
126    # Fill folderbox with text
127
128    setfolders()
129
130    # Fill scanbox with text
131
132    rescan()
133
134    # Enter mainloop
135
136    root.mainloop()
137
138def folder_post(e):
139    x, y = e.x_root, e.y_root
140    foldermenu.post(x - 10, y - 10)
141    foldermenu.grab_set()
142
143def folder_unpost(e):
144    tk.call('update', 'idletasks')
145    foldermenu.grab_release()
146    foldermenu.unpost()
147    foldermenu.invoke('active')
148
149def scan_post(e):
150    x, y = e.x_root, e.y_root
151    scanmenu.post(x - 10, y - 10)
152    scanmenu.grab_set()
153
154def scan_unpost(e):
155    tk.call('update', 'idletasks')
156    scanmenu.grab_release()
157    scanmenu.unpost()
158    scanmenu.invoke('active')
159
160scanparser = re.compile('^ *([0-9]+)')
161
162def 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()
176
177def 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
201
202def interestingheader(header):
203    return header != 'received'
204
205def 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)
220
221lastrefile = ''
222tofolder = None
223def 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)
252
253def fixfocus(near, itop):
254    n = scanbox.size()
255    for i in range(n):
256        line = scanbox.get(repr(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)
265
266def setfolders():
267    folderbox.delete(0, 'end')
268    for fn in mh.listallfolders():
269        folderbox.insert('end', fn)
270
271def 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)
279
280def scanfolder(folder = 'inbox', sequence = 'all'):
281    return map(
282            lambda line: line[:-1],
283            os.popen('scan +%s %s' % (folder, sequence), 'r').readlines())
284
285main()