Update of /cvsroot/tmda/tmda/bin
In directory sc8-pr-cvs1:/tmp/cvs-serv11363/bin

Modified Files:
        tmda-gui 
Log Message:
Massive rewrite of some parts of the interface.

. the pending message list loading doesn't freeze anymore the interface
. a progress bar has been added, and that speeds up the loading by ten
  (psychologically, that is ;)
. Pending and Address now in the same window (kinda tabbed)
. Splitters are now MultiSplitters(TM), which means we can load an
  arbitrary number of terse headers (columns). Yet to implement though.



Index: tmda-gui
===================================================================
RCS file: /cvsroot/tmda/tmda/bin/tmda-gui,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- tmda-gui    7 Dec 2002 11:08:28 -0000       1.12
+++ tmda-gui    11 Dec 2002 23:18:48 -0000      1.13
@@ -39,7 +39,6 @@
         . you can resize the list columns width
         . you can resize the height of the list
         . double-click on a message and you'll see it's content
-        . W & B buttons are resp. whilelist and blacklist (need some icons...)
         . the list is refreshed every 5 mins by default but you can
           change it in Edit/Settings... (not memorized between runs yet)
 
@@ -101,8 +100,14 @@
 
     return '\n'.join(status)
 
+MessageError = "Message Error"
 def lib_processMessage(msgid, command, **args):
-    msg = Pending.Message(msgid)
+    try:
+        msg = Pending.Message(msgid)
+    except Errors.MessageError:
+        raise MessageError
+    if command not in ('terse', 'show'):
+        msg.initMessage()
     try:
         try:
             data = getattr(msg, command)(args)
@@ -112,13 +117,14 @@
         if type(data) == str:
             return data
         else:
-            print "Debug: type of data in lib_processMessage -> " + str(type(data))
+            if command == 'show':
+                print "Debug: type of data in lib_processMessage -> " + 
+str(type(data))
             try:
                 return '\n'.join(data)
             except TypeError:
                 return str(data)
     except AttributeError:
-        return None
+        raise MessageError
 
 def lib_processPending(command, **args):
     Q = Pending.Queue(descending=1).initQueue()
@@ -132,6 +138,8 @@
 sin = None
 sout = None
 
+ProtoError = "Protocole Error"
+
 def connectToServer(host, auth):
     global sock, sin, sout
     if sock:
@@ -179,9 +187,7 @@
     except ProtoError, msg:
         print "%s: %s" % (ProtoError, msg)
         
-    return ''
-
-ProtoError = "Protocole Error"
+    raise MessageError
 
 def net_processPending(command, **args):
     if command == 'list':
@@ -201,6 +207,7 @@
     from TMDA import Version
     from TMDA import Address
     from TMDA import Pending
+    from TMDA import Errors
 
     using_network = 0
     getAddress = lib_getAddress
@@ -295,42 +302,124 @@
     processPending = net_processPending
 
 
+##############################################
+##  Some helper widgets                     ##
+##############################################
 
-class HSplitterFrame(Frame):
+class ProgressBar(Frame):
+    def __init__(self, master=None, **args):
+        Frame.__init__(self, master, args)
+        self.pack(fill=BOTH, expand=YES)
+        self.cursor = None
+    
+    def Show(self, max=100, step=1):
+        self.Hide()
+        self.cursor = Scale(self, showvalue=NO, orient=HORIZONTAL)
+        self.cursor.pack(fill=BOTH, expand=YES)
+        self.value = 0
+        self.max = max
+        self.cursor.configure(to=max)
+        self.step = step
+        self.update()
+
+    def Inc(self):
+        self.Update(self.value + self.step)
+        
+    def Update(self, value=-1):
+        if value < 0:
+            value = (self.value + self.step)
+            print value
+            if value > self.max or value < 0:
+                self.step *= -1
+                print self.step
+                value = (value + 2 * self.step)
+
+        self.value = value
+        self.cursor.set(value)
+        self.update()
+        
+    def Hide(self):
+        if self.cursor:
+            self.cursor.destroy()
+
+class StatusBar(Frame):
     def __init__(self, master, **args):
         Frame.__init__(self, master, args)
+        self.message = Label(self, bd=1, relief=SUNKEN)
+        self.message.pack(side=LEFT, fill=X)
+
+        self.progress = ProgressBar(self)
+        self.progress.pack(side=RIGHT, fill=X)
+
+    def Set(self, text, **args):
+        args['text'] = ' ' + str(text) + ' '
+        self.message.configure(args)
+        self.update()
 
-        self.one = Frame(self, bd=1, relief=SUNKEN)
-        self.two = Frame(self, bd=1, relief=SUNKEN)
-        self.split = 0.5
-        self.one.place(rely=0, relheight=self.split, relwidth=1)
-        self.two.place(rely=self.split, relheight=1.0-self.split, relwidth=1)
-
-        self.sep = Frame(self, bd=2, relief=RAISED, width=8, height=2,
-                         cursor="sb_v_double_arrow")
-        self.sep.place(relx=0, rely=self.split, anchor=W, relwidth=1)
-        self.sep.bind('<ButtonPress>', self.Start)
-        self.sep.bind('<ButtonRelease>', self.Stop)
+
+class HMultiSplitter(Frame):
+    def __init__(self, master, number, **args):
+        Frame.__init__(self, master, args)
+
+        self.frames = [ Frame(self, bd=0, relief=SUNKEN) for x in range(number) ]
+        
+        max = len(self.frames)
+        step = 1.0 / max
+        y = 0
+        for f in self.frames:
+            f.place(rely=y, relheight=step, relwidth=1)
+            if y > 0:
+                sep = Frame(self, bd=2, relief=RAISED, width=8, height=2,
+                                  cursor="sb_v_double_arrow")
+                sep.place(relx=0, rely=y, anchor=W, relwidth=1)
+                sep.bind('<ButtonPress>', self.Start)
+                sep.bind('<ButtonRelease>', self.Stop)
+                sep.split = y
+                sep.fprev = fprev
+                fprev.snext = sep
+                sep.fnext = f
+                f.sprev = sep
+            y += step
+            fprev = f
 
     def Start(self, ev):
-        self.splitpx = int(self.split * self.winfo_height())
-        self.rsz = self.splitpx
-        self.sep.bind('<B1-Motion>', self.Move)
-        self.sep.place(relx=2) # hide the splitter during the move
+        s = ev.widget
+        s.splitpx = int(s.split * self.winfo_height())
+        s.rsz = s.splitpx
+        s.bind('<B1-Motion>', self.Move)
+        s.place(relx=2) # hide the splitter during the move
         
     def Move(self, ev):
-        self.splitpx = self.rsz + ev.y
-        self.split = (1.0 * self.splitpx) / self.winfo_height()
-        self.one.place(relheight=self.split)
-        self.two.place(rely=self.split, relheight=1.0-self.split)
+        s = ev.widget
+        s.splitpx = s.rsz + ev.y
+        s.split = (1.0 * s.splitpx) / self.winfo_height()
+        try:
+            if s.split < s.fprev.sprev.split:
+                s.split = s.fprev.sprev.split
+        except AttributeError:
+            pass
+        try:
+            if s.split > s.fnext.snext.split:
+                s.split = s.fnext.snext.split
+        except AttributeError:
+            pass
+        try:
+            s.fprev.place(relheight=s.split - s.fprev.sprev.split)
+        except AttributeError:
+            s.fprev.place(relheight=s.split)
+        try:
+            s.fnext.place(rely=s.split, relheight=s.fnext.snext.split-s.split)
+        except AttributeError:
+            s.fnext.place(rely=s.split, relheight=1.0-s.split)
 
     def Stop(self, ev):
-        self.bind('<B1-Motion>', lambda e: "break")
-        self.sep.place(relx=0, rely=self.split, anchor=W)
+        s = ev.widget
+        s.bind('<B1-Motion>', lambda e: "break")
+        s.place(relx=0, rely=s.split, anchor=W)
 
 
-class VSplitterFrame(Frame):
-    def __init__(self, master, **args):
+class VMultiSplitter(Frame):
+    def __init__(self, master, number, **args):
         try:
             self.split = args['split']
             del args['split']
@@ -338,70 +427,87 @@
             self.split = 0.5
         
         Frame.__init__(self, master, args)
-        self.one = Frame(self, bd=1, relief=SUNKEN)
-        self.two = Frame(self, bd=1, relief=SUNKEN)
-        self.one.place(relx=0, relwidth=self.split, relheight=1)
-        self.two.place(relx=self.split, relwidth=1.0-self.split, relheight=1)
-
-        self.sep = Frame(self, bd=2, relief=RAISED, height=8, width=2,
-                         cursor="sb_h_double_arrow")
-        self.sep.place(rely=0, relx=self.split, anchor=N, relheight=1)
-        self.sep.bind('<ButtonPress>', self.Start)
-        self.sep.bind('<ButtonRelease>', self.Stop)
+
+        self.frames = [ Frame(self, bd=0, relief=SUNKEN) for x in range(number) ]
+        
+        max = len(self.frames)
+        step = 1.0 / max
+        x = 0
+        for f in self.frames:
+            f.place(relx=x, relwidth=step, relheight=1)
+            if x > 0:
+                sep = Frame(self, bd=2, relief=RAISED, height=8, width=2,
+                                  cursor="sb_h_double_arrow")
+                sep.place(rely=0, relx=x, anchor=N, relheight=1)
+                sep.bind('<ButtonPress>', self.Start)
+                sep.bind('<ButtonRelease>', self.Stop)
+                sep.split = x
+                sep.fprev = fprev
+                fprev.snext = sep
+                sep.fnext = f
+                f.sprev = sep
+            x += step
+            fprev = f
 
     def Start(self, ev):
-        self.splitpx = int(self.split * self.winfo_width())
-        self.rsz = self.splitpx
-        self.sep.bind('<B1-Motion>', self.Move)
-        self.sep.place(rely=2) # hide the splitter during the move
+        s = ev.widget
+        s.splitpx = int(s.split * self.winfo_width())
+        s.rsz = s.splitpx
+        s.bind('<B1-Motion>', self.Move)
+        s.place(rely=2) # hide the splitter during the move
         
     def Move(self, ev):
-        self.splitpx = self.rsz + ev.x
-        self.split = (1.0 * self.splitpx) / self.winfo_width()
-        self.one.place(relwidth=self.split)
-        self.two.place(relx=self.split, relwidth=1.0-self.split)
+        s = ev.widget
+        s.splitpx = s.rsz + ev.x
+        s.split = (1.0 * s.splitpx) / self.winfo_width()
+        try:
+            if s.split < s.fprev.sprev.split:
+                s.split = s.fprev.sprev.split
+        except AttributeError:
+            pass
+        try:
+            if s.split > s.fnext.snext.split:
+                s.split = s.fnext.snext.split
+        except AttributeError:
+            pass
+        try:
+            s.fprev.place(relwidth=s.split - s.fprev.sprev.split)
+        except AttributeError:
+            s.fprev.place(relwidth=s.split)
+        try:
+            s.fnext.place(relx=s.split, relwidth=s.fnext.snext.split-s.split)
+        except AttributeError:
+            s.fnext.place(relx=s.split, relwidth=1.0-s.split)
 
     def Stop(self, ev):
-        self.bind('<B1-Motion>', lambda e: "break")
-        self.sep.place(rely=0, relx=self.split, anchor=N)
+        s = ev.widget
+        s.bind('<B1-Motion>', lambda e: "break")
+        s.place(rely=0, relx=s.split, anchor=N)
 
 
 class MessageList(Frame):
-    def __init__(self, master, **args):
+    def __init__(self, master, statusbar=None, **args):
         Frame.__init__(self, master, args)
+        self.statusbar = statusbar
         self._sb = Scrollbar(self, orient=VERTICAL)
         self._sb.config(command=self._yview)
         
         self._colnames = [ 'msgid', 'from_name', 'subject' ]
+        self._collabels = { 'msgid': 'Date', 'from_name': 'From', 'subject': 
+'Subject', } 
 
         self._cols = []
 
-        fo = VSplitterFrame(self, split=0.25)
-        fi = VSplitterFrame(fo.two, split=0.33)
-        
-        f = Label(fo.one, text="Date", bd=1, relief=RAISED)
-        f.pack(side=TOP, fill=X)
-        l = Listbox(fo.one, yscrollcommand=self._set, bd=0)
-        l.pack(side=LEFT, fill=BOTH, expand=YES)
-        self._cols.append(l)
-
-        f = Label(fi.one, text="From", bd=1, relief=RAISED)
-        f.pack(side=TOP, fill=X)
-        l = Listbox(fi.one, yscrollcommand=self._set, bd=0)
-        l.pack(side=LEFT, fill=BOTH, expand=YES)
-        self._cols.append(l)
-
-        f = Label(fi.two, text="Subject", bd=1, relief=RAISED)
-        f.pack(side=TOP, fill=X)
-        l = Listbox(fi.two, yscrollcommand=self._set, bd=0)
-        l.pack(side=LEFT, fill=BOTH, expand=YES)
-        self._cols.append(l)
-
-        fi.pack(fill=BOTH, expand=YES)
-        fo.pack(side=LEFT, fill=BOTH, expand=YES)
+        f = VMultiSplitter(self, len(self._colnames))
+        f.pack(side=LEFT, fill=BOTH, expand=YES)
+    
+        for i in range(len(self._colnames)):
+            Label(f.frames[i], text=self._collabels[self._colnames[i]],
+                      bd=1, relief=RAISED).pack(side=TOP, fill=X)
+            l = Listbox(f.frames[i], yscrollcommand=self._set, bd=0)
+            l.pack(side=LEFT, fill=BOTH, expand=YES)
+            self._cols.append(l)
         self._sb.pack(side=RIGHT, fill=Y)
-
-        
+    
     def curselection(self):
         for col in self._cols:
             selindex = col.curselection()
@@ -471,26 +577,41 @@
             return ('', '')
         
     def Refresh(self):
-        for col in self._cols:
-            col.delete(0, END)
-        self.msgs = []
-        lst = processPending('list')
-        for item in lst:
-            self.msgs.append(item)
-            msg = processMessage(item, command='terse', date=1).split('\n')
-            i = 0
+        try:
             for col in self._cols:
-                col.insert(END, msg[i])
-                i = i + 1
+                col.delete(0, END)
+            self.msgs = []
+            lst = processPending('list')
+            self.statusbar.Set('Please wait, loading message list...')
+            self.statusbar.progress.Show(len(lst))
+            x = 0
+            for item in lst:
+                self.statusbar.progress.Inc()
+                try:
+                    msg = processMessage(item, command='terse', date=1).split('\n')
+                except MessageError:
+                    # no such message
+                    continue
+                self.msgs.append(item)
+                i = 0
+                for col in self._cols:
+                    col.insert(END, msg[i])
+                    i = i + 1
+            self.statusbar.progress.Hide()
+        except TclError: # Refresh is probably aborted by user
+            pass
 
 class PendingGUI(Frame):
     AppName = "tmda-gui"
     refresh_interval = 300
-    def __init__(self, master=None, **args):
-        if master:
+    def __init__(self, master=None, statusbar=None, **args):
+        if 0 and master:
             master.title(self.AppName)
             master.protocol("WM_DELETE_WINDOW", self.FileQuit)
 
+        Frame.__init__(self, master, args)
+        self.statusbar = statusbar
+
         self.menudef = [
             [
                 { 'text': 'File', },
@@ -534,9 +655,8 @@
             ],
         ]
         self.master=master
-        Frame.__init__(self, master, args)
         self.createWidgets()
-        self.counter = 0
+        self.counter = self.refresh_interval - 1
         self.poll()
 
     def FileOpen(self):
@@ -615,8 +735,8 @@
             self.menu.buttons.append(m)
 
     def MessageRefresh(self, ev=None):
-        self.listbox.Refresh()
         self.message.text.delete(1.0, END)
+        self.listbox.Refresh()
         self.updateStatus()
 
     def MessageShow(self, ev=None):
@@ -637,7 +757,7 @@
         self.listbox.BlacklistSelectedMessage()
 
     def MessageRelease(self, ev=None):
-        self.MessageShow()
+        self.message.text.delete(1.0, END)
         self.listbox.ReleaseSelectedMessage()
         self.updateStatus()
 
@@ -647,7 +767,7 @@
         self.updateStatus()
 
     def createWidgets(self):
-        self.createMenu()
+        #self.createMenu()
 
         self.toolbar = Frame(self, relief=GROOVE)
 
@@ -669,20 +789,27 @@
         b = Button(self.toolbar, text="Delete", bd=1,
                    command=self.MessageDelete)
         b.pack(side=LEFT, padx=0, pady=0)
-        b = Button(self.toolbar, text="Quit", bd=1,
-                   command=self.FileQuit)
-        b.pack(side=RIGHT, padx=0, pady=0)
+#        b = Button(self.toolbar, text="Quit", bd=1,
+#                   command=self.FileQuit)
+#        b.pack(side=RIGHT, padx=0, pady=0)
         self.toolbar.pack(side=TOP, fill=X)
         
-        self.split = HSplitterFrame(self, width=600, height=400,
+        self.split = HMultiSplitter(self, 2, width=600, height=400,
                                     relief=GROOVE)
+
+        self.split.one = self.split.frames[0]
+        self.split.two = self.split.frames[1]
+    
         self.split.pack(fill=BOTH, expand=YES)
 
-        self.listbox = MessageList(self.split.one)
+        if not self.statusbar:
+            self.statusbar = StatusBar(self)
+            self.statusbar.pack(side=BOTTOM, fill=X)
+
+        self.listbox = MessageList(self.split.one, statusbar=self.statusbar)
         self.listbox.bind("<Double-Button-1>", self.MessageShow)
         self.listbox.pack(fill=BOTH, expand=YES)
 
-
         self.message = self.split.two
         self.message.text = Text(self.message, bd=1, relief=GROOVE)#, anchor=W)
         scrollbar = Scrollbar(self.message, orient=VERTICAL)
@@ -693,15 +820,10 @@
         self.message.text.bind('<Key>', lambda ev: 'break')
         self.message.text.pack(fill=BOTH, expand=YES)
 
-        self.status = Frame(self)
-        self.status.label = Label(self.status, bd=1, relief=SUNKEN)#, anchor=W)
-        self.status.label.pack(side=LEFT, fill=X)
-        self.status.pack(side=BOTTOM, fill=X)
-        self.MessageRefresh()
 
     def updateStatus(self, ev=None):
-        self.status.label['text'] = "%d messages in pending queue" \
-                                    % len(self.listbox.msgs)
+        self.statusbar.Set("%d messages in pending queue..." \
+                                    % len(self.listbox.msgs))
 
     def poll(self):
         self.counter += 1
@@ -763,10 +885,7 @@
         R += 1
         f = Frame(self)
         f.grid(row=R, columnspan=3)
-        Button(f, text="Calc", command=self.Calc).grid(row=0, column=0)
-        Button(f, text="Pending",
-               command=self.LaunchPending).grid(row=0, column=1)
-        Button(f, text="Exit", command=master.destroy).grid(row=0, column=2)
+        Button(f, text="Create / Check Address", command=self.Calc).grid(row=0, 
+column=0, columnspan=3)
 
         R += 1
         Label(self, text="Check:").grid(row=R, sticky=W)
@@ -820,11 +939,85 @@
             status = "Enter an address to check"
         self.r_check.configure(text=status)
 
+class About(Frame):
+    def __init__(self, master, AppName, **args):
+        if not master:
+            master = Toplevel()
+        Frame.__init__(self, master, args)
 
-    def LaunchPending(self):
-        p = PendingGUI(Toplevel(self)).pack(fill=BOTH, expand=YES)
+        abouttxt = """Copyright 2002 David Guerizec <[EMAIL PROTECTED]>\n""" + \
+                   """Copyright 2002 TMDA Project http://www.tmda.net/""";
+        print abouttxt
+        try:
+            self.title("About %s" % AppName)
+            self.ok = Button(f, text="OK", command=self.destroy, relief=GROOVE)
+            self.ok.pack(side=TOP)
+        except AttributeError:
+            pass
+        f = Frame(self, bd=15, relief=FLAT)
+        f.pack(side=TOP, fill=BOTH, expand=1)
+        self.txt = Label(f, text=abouttxt, relief=GROOVE, padx=15, pady=15)
+        self.txt.pack(side=TOP, fill=BOTH, expand=1)
+        f = Frame(self, bd=10, relief=FLAT)
+        f.pack(side=TOP, fill=BOTH, expand=1)
         
 
+class TMDAGUI(Frame):
+    AppName = "tmda-gui"
+    def __init__(self, master=None, **args):
+        if master:
+            master.title(self.AppName)
+            master.protocol("WM_DELETE_WINDOW", self.Quit)
+        self.master = master
+        Frame.__init__(self, master, args)
+        self.tabs = Frame(master=self)
+        self.tabs.pack(side=TOP, fill=X)
+        self.baddress = Button(self.tabs, text='Address', command=self.displayAddress)
+        self.baddress.pack(side=LEFT)
+        self.bpending = Button(self.tabs, text='Pending', command=self.displayPending)
+        self.bpending.pack(side=LEFT)
+        self.bquit = Button(self.tabs, text='Quit', command=self.Quit)
+        self.bquit.pack(side=RIGHT)
+        self.babout = Button(self.tabs, text='About', command=self.displayAbout)
+        self.babout.pack(side=RIGHT)
+        self.statusbar = StatusBar(self)
+        self.statusbar.pack(side=BOTTOM, fill=X)
+        self.displayAddress()
+        
+    def displayAddress(self):
+        try:
+            self.panel.destroy()
+        except AttributeError:
+            pass
+        self.statusbar.Set('Tagged address center')
+        self.panel = AddressGUI(master=self)
+        self.panel.pack(fill=BOTH, expand=YES)
+        self.statusbar.progress.Hide()
+
+    def displayPending(self):
+        try:
+            self.panel.destroy()
+        except AttributeError:
+            pass
+        self.bpending.update()
+        self.statusbar.Set('Pending messages center')
+        self.panel = PendingGUI(master=self, statusbar=self.statusbar)
+        self.panel.pack(fill=BOTH, expand=YES)
+        self.statusbar.progress.Hide()
+
+    def displayAbout(self):
+        try:
+            self.panel.destroy()
+        except AttributeError:
+            pass
+        self.statusbar.Set('Welcome to a SPAM free world!', anchor=CENTER)
+        self.panel = About(master=self, AppName=self.AppName)
+        self.panel.pack(fill=BOTH, expand=YES)
+        self.statusbar.progress.Hide()
+
+    def Quit(self):
+        self.master.destroy()
+
 def main():
     root = Tk()
     if using_network:
@@ -834,7 +1027,7 @@
     if pending_first:
         PendingGUI(root).pack(fill=BOTH, expand=YES)
     else:
-        AddressGUI(root).pack(fill=BOTH, expand=YES)
+        TMDAGUI(root, width=800, height=600).pack(fill=BOTH, expand=YES)
     root.mainloop()
 
 if __name__ == '__main__':

_______________________________________
tmda-cvs mailing list
http://tmda.net/lists/listinfo/tmda-cvs

Reply via email to