# 2/00: wrap note file save in try so doesn't fail if run off cd;
#       add note about threads and PyMailGui
#
# MENTION: idle path browser -> Tkinter.py; Tcl/Tk parms books
# note: can't map back from image to self.files list from initial
# glob--may open file anywhere, in open dialog (not on glob list)
# mention ipwp for internet topics
# after works as good as threads here (uses threads)
# + show top menu varient
# disable file menu for component (TextEditor)
# note: superclass's makeWidgets hasn't set self.msecs 
# yet in overloaded makeWidgets here (later in constructor)
# note: from canvaspicsthreads import SlideShow -> fails, 
# because doesn't call overloadable method each time, so
# changed canvaspics to have common drawNext method
#
# thread bug and locks: when close note box by pressing 'Note',
# it's possible that the timer thread may be in the midst of a
# drawNext call: drawNext->switchNote->saveNote->editor.getAllText
# ->text.get('1.0',...); when it starts saveNote the editor is
# open, but by the time it gets to the text widget operation,
# the text widget may have been destroyed as the result of the 
# onNote callback handler execution (the thread runs in parallel
# with the callback handler);  to prevent this, a lock is used 
# to prevent saveNote from running is a destroy is in progress;
# the thread module's allocate_lock returns a lock object, which
# is sometimes called a mutex or binary semaphore; lock objects
# may be acquired by at most one thread at a given time; they 
# start unlocked,and is used to synchronize (serialize) the thread
# and callback handler;  this isn't an issue if we use the Tk
# after to do the timer, but threads can be faster in general...
#     see PyMailGui: only main thread can do GUI updates/ops
##################################################################


import os, string, thread
from Tkinter import *
from PP2E.Gui.TextEditor.textEditor import *
from slideShow_threads import SlideShow

class SlideShowPlus(SlideShow):
    def __init__(self, parent, picdir, editclass, msecs=2000):
        self.msecs = msecs
        self.editclass = editclass
        self.destroyer = thread.allocate_lock()
        SlideShow.__init__(self, parent=parent, picdir=picdir, msecs=msecs)
    def makeWidgets(self):
        self.name = Label(self, text='None', bg='red', relief=RIDGE)
        self.name.pack(fill=X)
        SlideShow.makeWidgets(self)
        Button(self, text='Note', command=self.onNote).pack(fill=BOTH)
        s = Scale(label='Speed: msec delay', command=self.onScale, 
                  from_=0, to=3000, resolution=50, showvalue=YES,
                  length=400, tickinterval=250, orient='horizontal')
        s.pack(side=BOTTOM, fill=X, expand=YES)
        s.set(self.msecs)
        self.editor = self.image = None
    def onStart(self):
        SlideShow.onStart(self)
        self.config(cursor='watch')
    def onStop(self):
        SlideShow.onStop(self)
        self.config(cursor='hand2')
    def onOpen(self):
        SlideShow.onOpen(self)
        if self.image: 
            self.name.config(text=os.path.split(self.image[0])[1])
        self.config(cursor='crosshair')
        self.switchNote()
    def onQuit(self):
        self.saveNote()
        SlideShow.onQuit(self)
    def drawNext(self):
        SlideShow.drawNext(self)
        if self.image: 
            self.name.config(text=os.path.split(self.image[0])[1])
        self.destroyer.acquire()
        self.switchNote()                         # don't let editor go away
        self.destroyer.release()
    def onScale(self, value):
        self.msecs = string.atoi(value)
    def onNote(self):
        if self.editor:                           # if editor already open 
            self.destroyer.acquire()              # save text, delete editor
            self.saveNote() 
            self.editor.destroy()                 # serialize the destroy 
            self.editor = None
            self.destroyer.release()
        else:                                           # else create editor
            if self.editclass == TextEditorMain:        # and load note text
                win = Toplevel() 
                self.editor = TextEditorMain(win)       # new popup window
                self.editor.pack(side=TOP) 
            else:
                self.editor = self.editclass(self)      # embedded in self
                self.editor.pack(side=TOP)
            self.loadNote()
    def switchNote(self):
        if self.editor:
            self.saveNote()       # save current image's note
            self.loadNote()       # load note for new image
    def saveNote(self):
        if self.editor:
            currfile = self.editor.getFileName()
            currtext = self.editor.getAllText()
            if currfile and currtext:
                try:
                    open(currfile, 'w').write(currtext)
                except:
                    pass # may be normal if run off cd
    def loadNote(self):
        if self.image:
            root, ext = os.path.splitext(self.image[0])
            notefile  = root + '.note'
            self.editor.setFileName(notefile)
            try:
                self.editor.setAllText(open(notefile).read())
            except:
                self.editor.clearAllText()

if __name__ == '__main__':
    import sys
    editstyle = TextEditorComponentMinimal
    if len(sys.argv) >= 2:
        try:
            editstyle = [TextEditorMain,
                         TextEditorComponent,
                         TextEditorComponentMinimal][string.atoi(sys.argv[1])]
        except: pass
    picdir = '../gifs'
    if len(sys.argv) == 3:
        picdir = sys.argv[2]

    root = Tk()
    root.title('PyView 1.1, plus text notes - threads test')
    Label(root, text="Slide show subclass").pack()
    SlideShowPlus(parent=root, picdir=picdir, editclass=editstyle).pack()
    root.mainloop()
