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

Added Files:
        tmda-gui 
Log Message:
tmda-gui: Tkinter interface to TMDA

Usage:
    tmda-gui
        gives a (yet) non fonctionnal Address generator interface.
        
    tmda-gui -p
        gives a functionnal (but yet to finish) Pending queue graphical
        interface.
        Tricks:
        . 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)


NOTE: This is early alpha software, so please try it, and send your
comments on the tmda-gui or tmda-workers list.
Please don't use it yet in a production environment.




--- NEW FILE ---
#!/usr/bin/python

import os, sys

from Tkinter import *

try:
    import paths
except ImportError:
    # Prepend /usr/lib/python2.x/site-packages/TMDA/pythonlib
    sitedir = os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3],
                           'site-packages', 'TMDA', 'pythonlib')
    sys.path.insert(0, sitedir)

import email


class HSplitterFrame(Frame):
    def __init__(self, master, **args):
        Frame.__init__(self, master, args)

        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)

    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
        
    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)

    def Stop(self, ev):
        self.bind('<B1-Motion>', lambda e: "break")
        self.sep.place(relx=0, rely=self.split, anchor=W)


class VSplitterFrame(Frame):
    def __init__(self, master, **args):
        try:
            self.split = args['split']
            del args['split']
        except KeyError:
            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)

    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
        
    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)

    def Stop(self, ev):
        self.bind('<B1-Motion>', lambda e: "break")
        self.sep.place(rely=0, relx=self.split, anchor=N)


class MessageList(Frame):
    def __init__(self, master, **args):
        Frame.__init__(self, master, args)
        self._sb = Scrollbar(self, orient=VERTICAL)
        self._sb.config(command=self._yview)
        
        self._colnames = [ 'msgid', 'from_name', 'subject' ]

        self._cols = []

        fo = VSplitterFrame(self, split=0.25)
        fi = VSplitterFrame(fo.two, split=0.33)
        
        l = Listbox(fo.one, yscrollcommand=self._set, bd=0)
        l.pack(side=LEFT, fill=BOTH, expand=YES)
        self._cols.append(l)

        l = Listbox(fi.one, yscrollcommand=self._set, bd=0)
        l.pack(side=LEFT, fill=BOTH, expand=YES)
        self._cols.append(l)

        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)
        self._sb.pack(side=RIGHT, fill=Y)

        
    def curselection(self):
        for col in self._cols:
            selindex = col.curselection()
            if selindex:
                break
        return selindex

    def bind(self, key, action):
        for col in self._cols:
            col.bind(key, action)
        return None

    def _set(self, *args):
        for col in self._cols:
            col.yview(MOVETO, args[0])
        apply(self._sb.set, args)
        return None
        
    def _yview(self, *args):
        for col in self._cols:
            apply(col.yview, args)
        return None

    def WhitelistSelectedMessage(self):
        from TMDA import Pending
        try:
            Pending.Message(self.msgs[int(self.curselection()[0])]).whitelist()
        except IndexError:
            return 0
        self.Refresh()
        return 1

    def BlacklistSelectedMessage(self):
        from TMDA import Pending
        try:
            Pending.Message(self.msgs[int(self.curselection()[0])]).blacklist()
        except IndexError:
            return 0
        self.Refresh()
        return 1

    def ReleaseSelectedMessage(self):
        from TMDA import Pending
        try:
            Pending.Message(self.msgs[int(self.curselection()[0])]).release()
        except IndexError:
            return 0
        self.Refresh()
        return 1

    def DeleteSelectedMessage(self):
        from TMDA import Pending
        try:
            Pending.Message(self.msgs[int(self.curselection()[0])]).delete()
            print "Deleted"
        except IndexError:
            print "No such message"
            return 0
        self.Refresh()
        return 1

    def GetSelectedMsgId(self):
        try:
            return self.msgs[int(self.curselection()[0])]
        except IndexError:
            return ''
        
    def GetSelectedMsgContent(self):
        from TMDA import Pending
        try:
            return 
Pending.Message(self.msgs[int(self.curselection()[0])]).show().split('\n\n', 1)
        except IndexError:
            return ('', '')
        
    def Refresh(self):
        from TMDA import Pending
        for col in self._cols:
            col.delete(0, END)
        self.msgs = []
        Q = Pending.Queue(descending=1).initQueue()
        for item in Q.listPendingIds() + Q.listReleasedIds() + Q.listConfirmedIds():
            self.msgs.append(item)
            msg = Pending.Message(item).terse()
            i = 0
            for col in self._cols:
                col.insert(END, msg[i])
                i = i + 1

class PendingGUI(Frame):
    AppName = "tmda-gui"
    refresh_interval = 300
    def __init__(self, master=None, **args):
        if master:
            master.title(self.AppName)
            master.protocol("WM_DELETE_WINDOW", self.FileQuit)

        self.menudef = [
            [
                { 'text': 'File', },
                { 'label': 'Open...',
                                'command': self.FileOpen, 'state': DISABLED, },
                { 'label': 'Save',
                                'command': self.FileSave, 'state': DISABLED, },
                { 'label': 'Save as...',
                                'command': self.FileSaveAs, 'state': DISABLED, },
                { 'label': 'Quit',
                                'command': self.FileQuit, },
            ],
            [
                { 'text': 'Edit', },
                { 'label': 'Undo',
                                'command': self.EditUndo, 'state': DISABLED, },
                { 'label': 'Settings...',
                                'command': self.EditSettings, },
            ],
            [
                { 'text': 'Message', },
                { 'label': 'Refresh',
                                'command': self.MessageRefresh, },
                { 'label': 'Show',
                                'command': self.MessageShow, },
                { 'label': 'Whitelist',
                                'command': self.MessageWhitelist, },
                { 'label': 'Release',
                                'command': self.MessageRelease, },
                { 'label': 'Blacklist',
                                'command': self.MessageBlacklist, },
                { 'label': 'Delete',
                                'command': self.MessageDelete, },
            ],
            [
                { 'text': 'Help', },
                { 'label': 'Help',
                                'command': self.HelpHelp, 'state': DISABLED, },
                { 'label': 'About',
                                'command': self.HelpAbout, },
            ],
        ]
        self.master=master
        Frame.__init__(self, master, args)
        self.createWidgets()
        self.counter = 0
        self.poll()

    def FileOpen(self):
        print "opening file"
        from FileDialog import LoadFileDialog
        fd = LoadFileDialog(self)
        self.filename = fd.go(key="FIXME")
    
    def FileSave(self):
        print "saving file",
        try:
            print self.filename
        except AttributeError:
            self.FileSaveAs()
    
    def FileSaveAs(self):
        from FileDialog import SaveFileDialog
        fd = SaveFileDialog(self)
        self.filename = fd.go(key="FIXME")
        print "saved file as", self.filename
    
    def FileQuit(self):
        print "Exiting..."
        self.master.destroy()
    
    def EditUndo(self):
        print "undoing stuff"
    
    def EditSettings(self):
        self.ws = Toplevel(self)
        Label(self.ws, text="Refresh interval (sec)").grid()
        self.ws.ri = Entry(self.ws)
        self.ws.ri.insert(END, self.refresh_interval)
        self.ws.ri.grid(row=0, column=1)
        Button(self.ws, text="OK", command=self.UpdateSettings, 
relief=GROOVE).grid(columnspan=2)
        self.ws.transient(self)
        
    def UpdateSettings(self):
        try:
            self.refresh_interval = int(self.ws.ri.get())
        except:
            pass
        self.ws.destroy()
        del self.ws
    
    def HelpHelp(self):
        print "Help: blah blah blah..."
    
    def HelpAbout(self):
        abouttxt = """Copyright 2002 David Guerizec <[EMAIL PROTECTED]>\n""" + \
                   """Copyright 2002 TMDA Project http://www.tmda.net/""";
        print abouttxt
        about = Toplevel()
        about.title("About %s" % self.AppName)
        f = Frame(about, bd=15, relief=FLAT)
        f.pack(side=TOP, fill=BOTH, expand=1)
        about.txt = Label(f, text=abouttxt, relief=GROOVE, padx=15, pady=15)
        about.txt.pack(side=TOP, fill=BOTH, expand=1)
        f = Frame(about, bd=10, relief=FLAT)
        f.pack(side=TOP, fill=BOTH, expand=1)
        about.ok = Button(f, text="OK", command=about.destroy, relief=GROOVE)
        about.ok.pack(side=TOP)
    
    def createMenu(self):
        self.menu = Frame(self, relief=RAISED, bd=1)
        self.menu.pack(side=TOP, fill=X)
        self.menu.buttons = [] 
        for button in self.menudef:
            m = Menubutton(self.menu, button[0])
            m.pack(side=LEFT, padx="2m")
            m.menu = Menu(m)
            for cmd in button[1:]:
                m.menu.add_command(cmd)
            m['menu'] = m.menu
            self.menu.buttons.append(m)

    def MessageRefresh(self, ev=None):
        self.listbox.Refresh()
        self.message.text.delete(1.0, END)
        self.status.label['text'] = "%d messages in pending queue" % 
len(self.listbox.msgs)

    def MessageShow(self, ev=None):
        self.message.text.delete(1.0, END)
        (hdr, bdy) = self.listbox.GetSelectedMsgContent()
        self.message.text.tag_configure('header', font=('Courier', 10, 'bold'), 
foreground='blue', background='#CCCCCC')
        self.message.text.tag_configure('body', font=('Courier', 10))
        self.message.text.insert(END, hdr+'\n', ('header',))
        self.message.text.insert(END, '\n'+bdy, ('body',))

    def MessageWhitelist(self, ev=None):
        self.MessageShow()
        self.listbox.WhitelistSelectedMessage()

    def MessageBlacklist(self, ev=None):
        self.MessageShow()
        self.listbox.BlacklistSelectedMessage()

    def MessageRelease(self, ev=None):
        self.MessageShow()
        self.listbox.ReleaseSelectedMessage()

    def MessageDelete(self, ev=None):
        self.message.text.delete(1.0, END)
        self.listbox.DeleteSelectedMessage()

    def createWidgets(self):
        self.createMenu()

        self.toolbar = Frame(self, relief=GROOVE)
        b = Button(self.toolbar, text="Rfsh", bd=1, width=1, 
command=self.MessageRefresh)
        b.pack(side=LEFT, padx=0, pady=0)
        b = Button(self.toolbar, text="Show", bd=1, width=1, command=self.MessageShow)
        b.pack(side=LEFT, padx=0, pady=0)
        b = Button(self.toolbar, text="W", bd=1, width=1, 
command=self.MessageWhitelist)
        b.pack(side=LEFT, padx=0, pady=0)
        b = Button(self.toolbar, text="Rel", bd=1, width=1, 
command=self.MessageRelease)
        b.pack(side=LEFT, padx=0, pady=0)
        b = Button(self.toolbar, text="B", bd=1, width=1, 
command=self.MessageBlacklist)
        b.pack(side=LEFT, padx=0, pady=0)
        b = Button(self.toolbar, text="Del", bd=1, width=1, command=self.MessageDelete)
        b.pack(side=LEFT, padx=0, pady=0)
        b = Button(self.toolbar, text="Quit", bd=1, width=1, command=self.FileQuit)
        b.pack(side=RIGHT, padx=0, pady=0)
        self.toolbar.pack(side=TOP, fill=X)
        
        self.split = HSplitterFrame(self, width=100, height=100, relief=GROOVE, 
bg='red')
        self.split.pack(fill=BOTH, expand=YES)

        self.listbox = MessageList(self.split.one)
        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)
        self.message.text.config(yscrollcommand=scrollbar.set)
        scrollbar.config(command=self.message.text.yview)
        scrollbar.pack(side=RIGHT, fill=Y)
        self.message.text.scrollbar=scrollbar
        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 poll(self):
        self.counter += 1
        if self.counter > self.refresh_interval:
            self.counter = 0
            self.MessageRefresh()
        self.master.after(1000, self.poll)


class AddressGUI(Frame):
    def __init__(self, master=None, **args):
        R = 0
        Frame.__init__(self, master, args)

        R += 1
        Label(self, text="Keyword:").grid(row=R, sticky=W)
        self.e_keyword = Entry(self)
        self.e_keyword.grid(row=R, column=1, sticky=W)
        self.r_keyword = Entry(self, state=DISABLED)
        self.r_keyword.grid(row=R, column=2, sticky=NW)
        
        R += 1
        Label(self, text="Sender:").grid(row=R, sticky=W)
        self.e_sender = Entry(self)
        self.e_sender.grid(row=R, column=1, sticky=W)
        self.r_sender = Entry(self, state=DISABLED)
        self.r_sender.grid(row=R, column=2, sticky=NW)
        
        R += 1
        Label(self, text="Dated:").grid(row=R, sticky=NW)
        f = Frame(self)
        f.grid(row=R, column=1, sticky=NW)
        self.e_dated = Entry(f, width=4)
        self.e_dated.insert(END, "5")
        self.e_dated.grid(row=0, column=0, sticky=NW)

        self.units = [
            ("years",  "Y"),
            ("months", "M"),
            ("weeks",  "w"),
            ("days",   "d"),
            ("hours",  "h"),
            ("mins",   "i"),
            ("secs",   "s"),
        ]
        self.uidx = 3 # default to days
        self.e_dated_unit = StringVar()
        self.e_dated_unit.set('d')

        f = Frame(f)
        f.grid(row=0, column=1)
        self.m_du = Button(f, text=self.units[self.uidx][0], relief=RAISED)
        self.m_du.bind('<Button-1>', self.LClick)
        self.m_du.bind('<Button-3>', self.RClick)
        self.m_du.pack(fill=BOTH, expand=1)

        self.r_dated = Entry(self, state=DISABLED)
        self.r_dated.grid(row=R, column=2, sticky=NW)
        
        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)

        R += 1
        Label(self, text="Check:").grid(row=R, sticky=W)
        self.e_check = Entry(self)
        self.e_check.grid(row=R, column=1, sticky=NW)
        self.e_check_sa = Entry(self)
        self.e_check_sa.grid(row=R, column=2, sticky=NW)
        R += 1
        self.r_check = Label(self, text="Enter an address to check")
        self.r_check.grid(row=R, column=1, columnspan=2, sticky=NW)
        
        self.Calc()

    def RClick(self, ev):
        self.uidx = (len(self.units) + self.uidx - 1) % len(self.units)
        self.m_du.configure(text=self.units[self.uidx][0])

    def LClick(self, ev):
        self.uidx = (len(self.units) + self.uidx + 1) % len(self.units)
        self.m_du.configure(text=self.units[self.uidx][0])

    def Calc(self, ev=None):
        self.r_dated['state'] = NORMAL
        self.r_dated.delete(0, END)
        self.r_dated.insert(END, 'Dated: ')
        self.r_dated.insert(END, self.e_dated.get() + self.units[self.uidx][1])
        self.r_dated['state'] = DISABLED

        self.r_keyword['state'] = NORMAL
        self.r_keyword.delete(0, END)
        self.r_keyword.insert(END, 'Keyword: ')
        self.r_keyword.insert(END, self.e_keyword.get())
        self.r_keyword['state'] = DISABLED

        self.r_sender['state'] = NORMAL
        self.r_sender.delete(0, END)
        self.r_sender.insert(END, 'Sender: ')
        self.r_sender.insert(END, self.e_sender.get())
        self.r_sender['state'] = DISABLED

    def LaunchPending(self):
        p = PendingGUI(Toplevel(self)).pack(fill=BOTH, expand=YES)
        

def main():
    root = Tk()
    if len(sys.argv) > 1 and sys.argv[1] == '-p':
        PendingGUI(root, bg="red").pack(fill=BOTH, expand=YES)
    else:
        AddressGUI(root).pack(fill=BOTH)
    root.mainloop()

if __name__ == '__main__':
    main()

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

Reply via email to