#!/usr/bin/env python from dblookup import * from dbnode import * from dbgui import * import Tix from Tkconstants import * import sys import os import threading import Queue import re import Module import time from dbprocess import * from dbextFile import dbExtFile displaytargets=[] class testThread(threading.Thread): """Simple class to debug thread locking problems""" def __init__(self): threading.Thread.__init__(self) self.start() def run(self): "This is the actual thread. It is never called directly by the user." while (1): time.sleep(.25) print "alive" class mainWindow: """This class implements the main interface window""" def __init__(self,tree,getqueue,putqueue,procqueue,extfilequeue, window=None): if (window==None): self.window=Tix.Toplevel() else : self.window=window self.tree=tree # The root node of the database tree self.loc=tree # currently displayed 'directory' self.iloc=tree # currently displayed item self.history=[] # a stack used for 'back' self.trace = [] # a list to keep all the objects has been browsed self.idledisp=None # used to delay screen updates so double-clicks work in the browser self.getqueue=getqueue # queue of nodes that need to be retrieved self.putqueue=putqueue self.procqueue=procqueue self.extfilequeue = extfilequeue self.menubar=Tix.Frame(self.window,borderwidth=2,relief=Tix.RAISED,height=20) self.menubar.grid(row=0,column=0,columnspan=2,sticky=NW) self.filemenu = Tix.Menubutton(self.menubar, underline = 0) self.filemenu.grid() self.filemenu.configure(text="File") self.filemenu_m1 = Tix.Menu(self.filemenu) self.filemenu_m1.add_command(label="Exit",command=self.myquit,underline=0) self.filemenu['menu'] = self.filemenu_m1 self.butrefresh=Tix.Button(self.menubar,text="Refresh",command=self.refresh) self.butrefresh.grid(row=0,column=1,sticky=E+W) self.pframe=Tix.Frame(self.window) self.pframe.grid(row=1,column=0,columnspan=2,sticky=NSEW) self.path=Tix.Label(self.pframe,text="/Groups",justify=LEFT) self.path.grid(row=0,column=0,sticky=EW) self.downmeter=Tix.Meter(self.pframe,width=100,value=0,text="0") self.downmeter.grid(row=0,column=1,sticky=E) self.upmeter=Tix.Meter(self.pframe,width=100,value=0,text="0") self.upmeter.grid(row=0,column=2,sticky=E) self.pframe.grid_columnconfigure(1,weight=1) self.browserframe=Tix.Frame(self.window,borderwidth=1) self.browserframe.grid(row=2,column=0,sticky=N+S+W) # self.moduleframe=Tix.Frame(self.window,borderwidth=1) # self.moduleframe.grid(row=2,column=1) # the browser grid self.buttop=Tix.Button(self.browserframe,text="Top",command=self.doTop) self.buttop.grid(row=0,column=0,sticky=E+W) self.buttop=Tix.Button(self.browserframe,text="Back",command=self.doBack) self.buttop.grid(row=0,column=1,sticky=E+W) self.butup=Tix.Button(self.browserframe,text="Up",command=self.doUp) self.butup.grid(row=0,column=2,sticky=E+W) self.browser=Tix.ScrolledListBox(self.browserframe,command=self.select,browsecmd=self.browse) self.browser.configure(height=500) self.browser.configure(width=250) self.browser.listbox.configure(selectmode=SINGLE,exportselection=0) self.browser.grid(row=1,column=0,columnspan=3,sticky=N+S) self.browserframe.grid_rowconfigure(1,weight=1) # the module grid # self.modulenb=Tix.NoteBook(self.window,raisecmd=self.refresh) self.modulenb=Tix.NoteBook(self.window) self.modulenb.grid(row=2,column=1,sticky=N+S+E+W) self.window.grid_columnconfigure(1,weight=1) self.window.grid_rowconfigure(2,weight=1) self.modules={} self.cwd = os.getcwd() # Here we load all of the individual modules if os.environ.has_key('PYDBDIR'): pydbDir = os.environ['PYDBDIR'] os.chdir(pydbDir) lst=os.listdir( "modules") lst=filter(lambda x: (x[-3:]==".py"),lst) lst=["Acquire.py"] for i in lst: j=i[:-3] k=j.lower() try: exec("import %s"%j) except: print "Unable to load %s module"%j continue thelabel = j try: thelabel = eval("%s.tabname"%j) except: pass sub=self.modulenb.add(k,label=thelabel,raisecmd=self.refresh,anchor="nw") sub=self.modulenb.page(k) v=eval("%s.%s(sub, self.getqueue,self.putqueue,self.procqueue)"%(j,j)) v.grid(row=0,column=0,sticky=N+S+E+W) sub.grid_columnconfigure(0,weight=1) sub.grid_rowconfigure(0,weight=1) self.modules[k]=v displaytargets.append(v) # a global, yuck! #print self.modulenb.subwidget('refine').configure() #print self.modulenb.pageconfigure('refine') #print self.modulenb.subwidget('refine').pageconfigure() #self.modulenb.subwidget('refine').configure(label='EMAN Refinement') self.browseto(self.loc) os.chdir(self.cwd) def doTop(self): "When the 'top' button is pressed" return self.browseto(self.tree) def doUp(self): "When the 'up' button is pressed" return if (self.loc.parent==None or self.loc.parent.parent==None) : return self.browseto(self.loc.parent, back=1) def doBack(self): "When the 'back' button is pressed (pop from browsing history path)" return # print map(lambda x: x.name,self.history) if (len(self.history)==0) : return self.browseto(self.history.pop(0),hist=0, back=1) #self.browseto(self.history[0], hist=0, back=1) def select(self): "This occurs when an item is selected (double-clicked) in the browser" return # always use the last selection if no new item is selected tempSelect = self.browser.listbox.curselection() #print tempSelect if tempSelect != '': self.sel=self.browser.listbox.curselection() # self.sel=map((lambda x: self.browser.listbox.get(int(x))),self.sel) if (len(self.sel)==0) : return # if (self.sel[0][:3]=="---") : return self.sel=map(lambda x:int(x),self.sel) nl=self.loc.branches[self.sel[0]] # print "select %s,%s"%(self.sel,nl.name) #print "Select ",self.sel #print nl.dbid,nl.name,nl.branches """ if nl.dbid != 'Labnotebook' and nl.dbclass!='Labnotebook': self.modulenb.page(0).grid_forget() self.window.refresh() """ self.browseto(nl) def browse(self): "This occurs when an item is browsed (single-clicked) in the browser" return self.sel=self.browser.listbox.curselection() self.sel=map(lambda x:int(x),self.sel) # self.sel=map((lambda x: self.browser.listbox.get(int(x))),self.sel) if (len(self.sel)==0) : return # if (self.sel[0][:3]=="---") : return nl=self.loc.branches[self.sel[0]] # print "browse %s,%s"%(str(self.sel),nl.name) # print "Select ",self.sel #print nl.dbid,nl.name,nl.branches self.idledisp=nl self.window.after(200,self.doIdle) def doIdle(self): "This is just a trick to help reduce multiple refreshes. 'browse' will set this to be called." return if (self.idledisp!=None) : self.display(self.idledisp) self.idledisp=None def poll(self,changed): "Called whenever a node changes. We check to see if the browser needs to be updated" return if (self.loc in changed) : self.browseto(self.loc,self.iloc) def refresh(self) : try: self.browseto(self.loc,self.iloc,hist=0, refresh=1) except: pass def myquit(self): qs = extFileQueue.qsize() if qs != 0: confirm = confirmDialog(top, message="Your uploading is not complete, do you want to exit anyway?").run() if confirm == 1: self.window.destroy() else: self.window.destroy() def display(self,newloc) : """ This will cause an object to become the currently displayed object in one of the modules """ if (self.iloc!=newloc) : if newloc not in self.trace: self.getqueue.put(newloc) # request a web update for the displayed object if it's older than 1 min if (newloc==None) : self.iloc=self.loc else : self.iloc=newloc tab=self.modulenb.raised() try: self.modules[tab].display(self.iloc) except: print "Module update error %s"%tab def browseto(self,newloc,items=None,hist=1,refresh=0, back=0): """This will display the subobjects of a particular node in the browser It also sets the current item as if display(newloc) newloc is a 'dbnode' object to display""" return if (newloc==None) : newloc=self.tree # print "browseto None" # else : print "browseto ",newloc.namepath() if (self.loc!=newloc) or refresh: if (hist) : self.history.insert(0, self.loc) self.trace.insert(0, self.loc) t=time.time() # for i in newloc.branches.values(): # getqueue.put(i) if back==0: if newloc not in self.trace: newloc.recurse=2 self.getqueue.put(newloc) # if (len(newloc.branches)==0) : getqueue.put(newloc) # request a web update for the displayed object self.loc=newloc if (items==None): self.iloc=self.loc else: self.iloc=items self.path.configure(text=newloc.namepath()) self.browser.listbox.delete(0,END) if (len(newloc.branches)==0) : self.browser.listbox.insert(0,"--- Please Wait ---") else : newloc.branches.sort(itemcmp) lst=newloc.branches for i in lst: if (newloc.dbclass == 'Microscopy' and i.dbclass == 'Scan'): continue try: j=int(i.subcount) except: j=0 # if (newloc.dbclass=="Group") : # if (j<=7) : j=i+" " # else : j=i+("(%0d)"%(j-7)).rjust(5) # else : if (j==0) : j=i.name+" " else : j=i.name+("(%0d)"%j).rjust(5) self.browser.listbox.insert(END,j) self.window.update() tab=self.modulenb.raised() try: self.modules[tab].display(self.loc) except KeyError: pass # print "Module update error %s"%tab # for tab in self.modules.values(): # try: # tab.display(self.iloc) # except: # print "Module update error %s"%tab.__dict__ ## To exit the program without crashing def quit(): try: top.destroy() except: pass # This is for idle-processing, generally used for displaying asynchronous # updates from the webserver, through the getthreads def poll(self,displaytargets): # print "poll" self.after(200,poll,self,displaytargets) qs=getqueue.qsize() upqs = extFileQueue.qsize() if (qs<500) : clr="green" elif (qs<900) : clr="yellow" else : clr="red" if (upqs<500) : clr_up="green" elif (upqs<900) : clr_up="yellow" else : clr_up="red" if qs == 0: main.downmeter.configure(value=min(1.0, float(qs)/50.0), text=" ", fillcolor=clr) else: main.downmeter.configure(value=min(1.0, float(qs)/50.0),text='downloading '+str(qs),fillcolor=clr) if upqs == 0: main.upmeter.configure(value=min(1.0, float(upqs)/50.0), text=" ", fillcolor=clr_up) else: main.upmeter.configure(value=min(1.0, float(upqs)/50.0),text='uploading '+str(upqs),fillcolor=clr_up) if (len(dbnode.changedlist)==0) : return # print "Change!" changed=dbnode.changedlist[:] # copy list dbnode.changedlist=[] for i in displaytargets: i.poll(changed) lastlabelclick=None def labelClick(event): trg=event.widget trg.clipboard_clear() trg.clipboard_append(trg.cget("text")) global lastlabelclick if (lastlabelclick!=None) : lastlabelclick.configure(bg="white") if (lastlabelclick!=trg) : trg.configure(bg="#DDF") lastlabelclick=trg else: lastlabelclick=None ################################ # The 'main' block starts here # ################################ # important globals: # top - main Tix.Tk instance # dblogin - tuple containing url, username, password # tree - the root of the dbnode tree structure # group - the currently selected group # getqueue - the queue containing dbnode's requiring updates # getthrX - threads used to query the database # main - the mainWindow object that sets up and maintains the overall GUI # displaytargets - a list of objects that display or use dbnode info, must respond to poll(changedlist) sys.path.append("modules") top=Tix.Tk() #top.grid() top.grid_propagate(1) top.geometry("1280x800+%d+%d"%((top.winfo_screenwidth()-800)/2,(top.winfo_screenheight()-600)/2)) top.resizable(width=1,height=1) #top.withdraw() #top.configure(width=800) #top.configure(height=600) top.update() top.bind_class("Label","",labelClick) # Login to the database ##setlogin(loginDialog(top).run()) ##if (getlogin()==None) : sys.exit(0) ##top.update() # Get the list of available groups and get the user to pick one ##try: ## groups=db_getlist("Groups") ##except: ## print "Database login failed!" ## sys.exit(1) ##gnames=map((lambda x: x[1].strip()),groups) ##group=groupDialog(top,gnames,"Select a group").run() ##if (group==None or len(group)==0) : ## print("Error: No group selected") ## sys.exit(1) ##group=group[0] ##top.update() # set up the root of the tree ##tree=dbnode("Groups","Groups",None,[],[]) ##for i in groups: ## tree.branches.append(dbnode(i[0],striphtml(i[1]),tree,[],[])) ##init_lookups(getlogin()) ##### Ok, all set, now start running getqueue=emdbQueue(1000) # LIFO putqueue=Queue.Queue(500) # FIFO procqueue=Queue.Queue(1000) # FIFO extFileQueue = Queue.Queue(500) #Queue for uploading extFiles # We'll just run one get thread for now global mymutex mymutex = threading.Lock() ##getthr1=getThread(getqueue,getlogin()) ##getthr1.start() ##getthr2=getThread(getqueue,getlogin()) ##getthr2.start() ##putthr=putThread(putqueue,getlogin(), mymutex) ##putthr.start() ##procthr1=dbProcessThread(procqueue) ##procthr1.start() ##extFileThread = dbExtFile(extFileQueue, getlogin(), mymutex) ##extFileThread.start() ##getqueue.put(tree.branch(name=group)) ##main=mainWindow(tree.branch(name=group),getqueue,putqueue,procqueue,extFileQueue, top) main=mainWindow(dbnode("0.0","No database",None,[],[]),None,None,None,None, top) displaytargets.append(main) # do an idle callback for screen updates top.after(200,poll,top,displaytargets) top.update() #t=testThread() # main event loop #top.deiconify() top.mainloop() # Kill the other threads before we exit getqueue.put("EXIT") getqueue.put("EXIT") getqueue.put("EXIT") putqueue.put("EXIT") procqueue.put("EXIT") extFileQueue.put(["EXIT"]) ##getthr1.join() #getthr2.join() #putthr.join()