diff --git a/head/offlineimap.py b/head/offlineimap.py index dec3bb2..851dd84 100644 --- a/head/offlineimap.py +++ b/head/offlineimap.py @@ -234,6 +234,11 @@ def sync_with_timer(): def threadexited(thread): if thread.getExitCause() == 'EXCEPTION': + if isinstance(thread.getExitException(), SystemExit): + # Bring a SystemExit into the main thread. + # Do not send it back to UI layer right now. + # Maybe later send it to ui.terminate? + raise SystemExit ui.threadException(thread) # Expected to terminate sys.exit(100) # Just in case... os._exit(100) @@ -246,7 +251,8 @@ def threadexited(thread): ui.threadExited(thread) threadutil.initexitnotify() -t = ExitNotifyThread(target=sync_with_timer, name='sync_with_timer') +t = ExitNotifyThread(target=sync_with_timer, + name='Sync Runner') t.setDaemon(1) t.start() try: @@ -255,6 +261,3 @@ except SystemExit: raise except: ui.mainException() # Also expected to terminate. - - - diff --git a/head/offlineimap/ui/Tk.py b/head/offlineimap/ui/Tk.py index 3872ffd..f8538ce 100644 --- a/head/offlineimap/ui/Tk.py +++ b/head/offlineimap/ui/Tk.py @@ -54,8 +54,11 @@ class PasswordDialog: return self.password class TextOKDialog: - def __init__(self, title, message): - self.top = Tk() + def __init__(self, title, message, blocking = 1, master = None): + if not master: + self.top = Tk() + else: + self.top = Toplevel(master) self.top.title(title) self.text = ScrolledText(self.top, font = "Courier 10") self.text.pack() @@ -64,7 +67,8 @@ class TextOKDialog: self.button = Button(self.top, text = "OK", command=self.ok) self.button.pack() - self.top.wait_window(self.button) + if blocking: + self.top.wait_window(self.button) def ok(self): self.top.destroy() @@ -111,8 +115,9 @@ class ThreadFrame(Frame): def getthreadextraframe(self): if self.threadextraframe: return self.threadextraframe - self.threadextraframe = Frame() + self.threadextraframe = Frame(self) self.threadextraframe.pack(fill = 'x') + return self.threadextraframe def setaccount(self, account): self.account = account @@ -153,7 +158,6 @@ class TkUI(UIBase): name = "Tk idle vacuum") t.setDaemon(1) t.start() - print "TkUI mainloop started." def runmainloop(s): s.top.mainloop() @@ -184,10 +188,8 @@ class TkUI(UIBase): def threadExited(s, thread): threadid = thread.threadid - print "Thread %d exited" % threadid s.tflock.acquire() if threadid in s.threadframes: - print "Removing thread %d" % threadid tf = s.threadframes[threadid] tf.setthread(None) tf.setaccount("Unknown") @@ -211,6 +213,7 @@ class TkUI(UIBase): print msg s.top.destroy() + s.top = None TextOKDialog("Thread Exception", msg) s.terminate(100) @@ -221,12 +224,51 @@ class TkUI(UIBase): print msg s.top.destroy() + s.top = None TextOKDialog("Main Program Exception", msg) + def init_banner(s): + s._msg(version.productname + " " + version.versionstr + ", " +\ + version.copyright) + tf = s.gettf().getthreadextraframe() + + def showlicense(): + TextOKDialog(version.productname + " License", + version.bigcopyright + "\n" + + version.homepage + "\n\n" + version.license, + blocking = 0, master = tf) + b = Button(tf, text = "About", command = showlicense) + b.pack(side = LEFT) + + b = Button(tf, text = "Exit", command = s.terminate) + b.pack(side = RIGHT) + def deletingmessages(s, uidlist, destlist): ds = s.folderlist(destlist) s._msg("Deleting %d messages in %s" % (len(uidlist), ds)) + def _sleep_cancel(s, args = None): + s.sleeping_abort = 1 + + def sleep(s, sleepsecs): + s.sleeping_abort = 0 + tf = s.gettf().getthreadextraframe() + + sleepbut = Button(tf, text = 'Sync immediately', + command = s._sleep_cancel) + sleepbut.pack() + UIBase.sleep(s, sleepsecs) + + def sleeping(s, sleepsecs, remainingsecs): + if remainingsecs: + s._msg("Next sync in %d:%02d" % (remainingsecs / 60, + remainingsecs % 60)) + else: + s._msg("Wait done; synchronizing now.") + s.gettf().destroythreadextraframe() + time.sleep(sleepsecs) + return s.sleeping_abort + ################################################## Copied from TTY def syncingmessages(s, sr, sf, dr, df): diff --git a/head/offlineimap/version.py b/head/offlineimap/version.py index 3650598..56ac04f 100644 --- a/head/offlineimap/version.py +++ b/head/offlineimap/version.py @@ -9,11 +9,12 @@ copyright = "Copyright (C) 2002 John Goerzen" author = "John Goerzen" author_email = "jgoerzen@complete.org" description = "Disconnected Universal IMAP Mail Synchronization/Reader Support" +bigcopyright = "%(productname)s %(versionstr)s, %(copyright)s <%(author_email)s>" % locals() -banner = """%(productname)s %(versionstr)s, %(copyright)s <%(author_email)s> +banner = bigcopyright + """ This software comes with ABSOLUTELY NO WARRANTY; see the file COPYING for details. This is free software, and you are welcome -to distribute it under the conditions laid out in COPYING.""" % locals() +to distribute it under the conditions laid out in COPYING.""" homepage = "http://www.quux.org/devel/offlineimap" homegopher = "gopher://quux.org/1/devel/offlineimap"