#
# $Id: gui.py,v 1.23 2005/06/05 20:29:52 pj Exp $
#
from Tkinter import *
from tkFileDialog import *
from FileDialog import *
import os, os.path, sys, galleries, functions, Queue, copy

props = None

class Gui(Frame):
    def __init__(self, requestqueue, resultqueue, xProps=None):
        Frame.__init__(self)
        global props
        props = xProps
        self.requestqueue = requestqueue
        self.resultqueue = resultqueue
        self.worker = galleries.Galleries(requestqueue, resultqueue, props)
        self.pack(expand=YES, fill=BOTH)
        self.master.title("gallery2.py")
        self.master.iconname("gallery2.py")
        self.storedMessages = []

        self.listeners = {}

        # mappings to program options
        self.title = StringVar()
        self.columns = StringVar()
        self.fullsize = StringVar()
        self.recursion = StringVar()
        self.sourcedir = StringVar()
        self.destdir = StringVar()
        self.status = StringVar()

        #widget references
        self.wTitle = None #implemented
        self.wColumns = None
        self.wFullsize = None
        self.wRecursion = None
        self.wSourcedir = None
        self.wSestdir = None
        self.wStatus = None

        self.createWidgets()


    def createWidgets(self): 
        # title
        self.label(self, "Title:", LEFT).grid(row=0, column=0, sticky=W, padx=3, pady=4)
        self.wTitle = Entry(self, width=40, textvariable=self.title)
        if props["title"] is not None:
            self.title.set(props["title"])
        self.wTitle.grid(row=0, column=1, sticky=W, padx=3, pady=2)
        self.addlistener("recursion", "changed", self.lisTitle)

        # columns
        self.label(self, "# columns:", LEFT).grid(row=1, column=0, sticky=W, padx=3, pady=2)
        self.entry(self, 2, self.columns, props["columns"], LEFT, NONE).grid(row=1, column=1, sticky=W, padx=3, pady=2)

        fsize = 0
        if props["fullsize"] == "Yes":
            fsize = 1
        # fullsize
        self.checkbutton(self, LEFT, self.fullsize, fsize, "Include fullsize pictures").grid(row=2, column=1, sticky=W, padx=0, pady=2)

        # recursion
        self.checkbutton(self, LEFT, self.recursion, int(props["recurse"]), "Recurse through directory structure", self.recurseCallback).grid(row=3, column=1, sticky=W, padx=0, pady=2)
        self.recurseCallback()

        # source directory
        self.label(self, "Source dir:", LEFT).grid(row=4, column=0, sticky=W, padx=3, pady=2)
        self.entry(self, 40, self.sourcedir, props["sourcedir"], LEFT).grid(row=4, column=1, sticky=W, padx=3, pady=1)
        self.button(self, LEFT, "Find dir", self.findSourceDir).grid(row=4, column=2, sticky=W, padx=3, pady=2)

        # destination directory
        self.label(self, "Destination dir:", LEFT).grid(row=5, column=0, sticky=W, padx=3, pady=2)
        self.entry(self, 40, self.destdir, props["baseDestinationDir"], LEFT).grid(row=5, column=1, sticky=W, padx=3, pady=2)
        self.button(self, LEFT, "Find dir", self.findDestDir).grid(row=5, column=2, sticky=W, padx=3, pady=2)


        self.frame = self.getFrame(self)
        # Buttons
        self.button(self.frame, LEFT, "Create gallery", self.createGallery).grid(row=0, column=0, padx=3, pady=2)
        self.button(self.frame, LEFT, "Messages", self.displaybox).grid(row=0, column=1, padx=3, pady=2)
        self.button(self.frame, LEFT, "Quit", self.quit).grid(row=0, column=2, padx=3, pady=2)
        self.frame.grid(row=6, column=0, columnspan=2, sticky=W)


        # status line
        self.wStatus = Entry(self, width=67, textvariable=self.status)
        self.wStatus.grid(row=7, column=0, columnspan=3, sticky=W, padx=3, pady=2)
        self.wStatus.configure(state=NORMAL, fg="black", bg="lightgray")

    #--------------------------------------------------------
    #  Widget callbacks
    #--------------------------------------------------------

    def findSourceDir(self):
        dir = None
        dir = askdirectory(initialdir=self.sourcedir.get(),mustexist=1)
        if dir != None and len(dir) != 0:
            self.sourcedir.set(dir.encode("ISO-8859-1"))

    def findDestDir(self):
        dir = None
        dir = askdirectory(initialdir=self.destdir.get(), mustexist=1)
        if dir != None and len(dir) != 0:
            self.destdir.set(dir.encode("ISO-8859-1"))

    def recurseCallback(self):
        "is called when recursion checkbutton is pressed"
        message = { "state" : int(self.recursion.get()) }
        self.broadcast("recursion", "changed", message)
    

    def createGallery(self):
        """User activated Create button, do the gallery"""
        global props
        if len(self.title.get()) > 0:
            props["title"] = self.title.get()
        props["columns"] = int(self.columns.get())
        if self.fullsize.get() == "1":
            props["fullsize"] = "Yes"
        else:
            props["fullsize"] = 0
        props["recurse"] = int(self.recursion.get()) 
        props["sourcedir"] = self.sourcedir.get()
        props["baseDestinationDir"] = self.destdir.get()
        props["forcecreate"] = 1

        requestID = self.worker.perform()
        self.requestqueue.put((requestID, props))        

        self.status.set("Job no '%s' put in queue for processing" % requestID)
        self.after(300, self.displayResultqueue)

        

    def displayResultqueue(self):
        """ Grap items from resultqueue and display appropriate
        messages in status bar
        Store messages for later display in separatre window, don't
        store messages of type status_working
        """
        try:
            (requestID, msg, status) = self.resultqueue.get_nowait()
            m = None

            if status == functions.status_working:
                m = "JOB[%s]: INFO: working: %s"% (requestID, msg)
            elif status == functions.status_finished_ok:
                m = "JOB[%s]: INFO: completed successfully."% requestID
            elif status == functions.status_finished:
                m = "JOB[%s]: INFO: %s" % (requestID,msg)
            elif status == functions.status_info:
                m = "JOB[%s]: INFO: %s" % (requestID,msg)
            elif status == functions.status_error:
                m = "JOB[%s]: ERROR: %s" % (requestID,msg)
                
            if status != functions.status_working:
                self.storedMessages.append(m)
            if m:
                self.status.set(m)
        except Queue.Empty:
            requestID=None
            msg=None
            status=None
        
        self.after(300, self.displayResultqueue) # look for queue messeage in 300 milli secs
        


    """
    # Defined listeners
    Listener      item           action      message
    ------------------------------------------------------------------
    lisTitle()    'recursion'    'changed'   'state': 0 or 1
    
    """

    #--------------------------------------------------
    #   Listeners
    #--------------------------------------------------

    def lisTitle(self, message):
        """change title state according to recursion button. As it
        does not make sense to have a single title when recursing,
        the interface reflects that.
        Message is a dict, key is 'state', values: 0 or 1"""
        if message["state"] == 0:
            self.wTitle.configure(state=NORMAL, fg="black")
            self.status.set("Title field enabled")
        else:
            self.wTitle.configure(state=DISABLED, fg="white")
            self.status.set("Title field disabled")


    #----------------------------------
    #  Publish / subscribe
    #----------------------------------

    def addlistener(self, item, action, listener):
        """Register a listener for a given event. Callback method will be
        executed given a dictionary with event information
        Example: item='recursion', action='changed', listerner=self.configureTitleEntry"""
        if not self.listeners.has_key((item, action)):
            self.listeners[(item,action)] = []
        self.listeners[(item,action)].append(listener)
        
    def broadcast(self, item, action, message):
        """Broadcast a message to listeners who have registered an interest
        in (item, action)
        message is a dictionary"""
        for listener in self.listeners[(item,action)]:
            listener(message)



    # ----------------------------------------
    #  Widget generators
    # ----------------------------------------

    def getFrame(self, root, anchor=W):
        w = Frame(root)
        w.place(anchor=anchor)
        return w

    def button(self, root, side, text, command=None):
        w = Button(root, text=text,  command=command)
        w.pack(side=side, expand=NO, fill=NONE)
        return w

    def label(self, root, text, side):
        w = Label(root, text=text,justify=LEFT)
        w.pack(side=side)
        return w

    def checkbutton(self, root, side, variable, value, text, command=None):
        w = Checkbutton(root, text=text, variable=variable, command=command)
        variable.set(value)
        w.pack(side=side)
        return w

    def entry(self, root,width, variable, text, side, fill=BOTH, command=None):
        w = Entry(root, width=width, textvariable=variable, command=command)
        variable.set(text)
        w.pack(side=side, expand=YES, fill=fill, anchor=W)
        return w

    def displaybox(self):
        """window showing messages"""
        root = Tk()
        frame = Frame(root)
        text = Text(frame, width=70, height=8, highlightthickness=2)
        scroll = Scrollbar(frame, command=text.yview)
        text.configure(yscrollcommand=scroll.set)
        for i in xrange(len(self.storedMessages)-1, 0, -1):
            text.insert(END, "%s\n" % self.storedMessages[i])
        if len(self.storedMessages)>0:
            text.insert(END, "%s\n" % self.storedMessages[0])
        text.pack(side=LEFT, fill=BOTH, expand=YES)
        scroll.pack(side=RIGHT, fill=Y)
        frame.pack(fill=BOTH, expand=YES)
        frame.master.title("gallery2.py messages")

        root.mainloop()


if __name__ == '__main__':
    Gui().mainloop()
