class TraceFrame(Frame): def __init__(self, *args, **kwargs): Frame.__init__(self, *args, **kwargs) self.t = ScrolledText(self, wrap="word") self.t.configure(background="light cyan") self.t.configure(height = 10) self.t.tag_config("in", foreground="forest green") self.t.tag_config("err", foreground="orange red") self.t.tag_config("time", foreground="sea green") self.t.tag_config("curr", foreground="black") self.t.tag_config("out", foreground="firebrick") self.t.pack(side="top", fill="both", expand=True) def add_To_Trace(self, st, tag): ''' :param st: txte a afficher :param tag: type de texte a afficher :return: ''' self.t.insert(INSERT, st, tag) self.t.see(END) def clear_Trace(self): ''' Efface la zone de texte :return: ''' self.t.delete('1.0', 'end')
class App(object): def __init__(self): self.window = tk.Tk() self.window.attributes("-fullscreen",True) self.window.minsize(width=320, height=240) self.window.maxsize(width=320, height=240) self.buttonFrame = tk.Frame(self.window) self.printButton=tk.Button(self.buttonFrame, text='PRINT!', height=2, command=self.printTxt) self.printButton.pack(side=tk.LEFT, fill=tk.X, padx=5, pady=5) self.loadButton=tk.Button(self.buttonFrame, text='LOAD', height=2, command=self.load) self.loadButton.pack(side=tk.LEFT, fill=tk.X, padx=5, pady=5, expand=1) self.exitButton=tk.Button(self.buttonFrame, text='EXIT', height=2, command=self.exitWin) self.exitButton.pack(side=tk.LEFT, fill=tk.X, padx=5, pady=5, expand=1) self.buttonFrame.pack(side=tk.TOP) self.filename = '/home/pi/Desktop/fly.txt' self.txt = ScrolledText(self.window) self.txt.vbar.config(width=18) self.txt.pack(expand=True, fill=tk.BOTH) self.loadFile() self.poll() def poll(self): if(float(self.txt.vbar.get()[1])==1): self.txt.see(1.0) #goto top else: self.txt.yview(tk.SCROLL,1,tk.UNITS) self.window.after(1000, self.poll) def load(self): self.filename = askopenfilename(initialdir="/home/pi/Desktop", title="SELECT TXT", filetypes=(("txt files","*.txt"),("all files","*.*")) ) self.loadFile() def loadFile(self): self.txt.delete(1.0,tk.END) fly = open(self.filename,'r') self.txt.insert(1.0, fly.read()) fly.close() def printTxt(self): call(["lp", self.filename]) tkMessageBox.showinfo("PRINT", "it's printing!") def exitWin(self): result = tkMessageBox.askquestion("EXIT?!", "zomg, u sure?", icon='warning') if result == 'yes': self.window.quit()
class MainApplication(): def __init__(self, master): self.filename = "" self.confg = "" self.master = master #setting color. bkc = "floral white" fgc = "RosyBrown4" bgc = "misty rose" self.FontForButton = tkFont.Font(family="Verdana", size=12) self.FontForLabel = tkFont.Font(family="Verdana", weight="bold") self.frame = tk.Frame(self.master, bg=bkc) self.frame.pack() self.chose_button = tk.Button(self.frame, text = u"選擇檔案", command = self.open_file, font=self.FontForButton, width = 20, bg=bgc, fg=fgc) self.chose_button.pack(padx = 5, pady = 10, side = tk.TOP) self.chose_confg_button = tk.Button(self.frame, text = u"選擇設定檔", command = self.get_confg, font=self.FontForButton, width = 20, bg=bgc, fg=fgc) self.chose_confg_button.pack(padx = 5, pady = 10, side = tk.TOP) self.run_button = tk.Button(self.frame, text = u"執行", command = self.run, font=self.FontForButton, width = 20, bg=bgc, fg=fgc) self.run_button.pack(padx = 5, pady = 10, side = tk.TOP) self.text = ScrolledText(self.frame) self.text.pack() self.mdby = tk.Label(self.frame, text="\nPowered By MITLab", font=self.FontForLabel, fg="SkyBlue1", bg=bkc) self.mdby.pack(side='bottom') def open_file(self): self.filename = tkFileDialog.askopenfilename() if self.filename : setup_env.display_message(u"選擇檔案: " + self.filename) def get_confg(self): self.confg = tkFileDialog.askopenfilename() if self.confg : setup_env.display_message(u"選擇設定檔案: " + self.confg) def write(self, massage): self.text.insert(tk.END, massage) self.text.see(tk.END) self.text.update_idletasks()#display message real time def run(self): try: if not self.filename or not self.confg: raise Exception('請選擇檔案!') setup_env.display_message(u"開始執行...") setup_env.set_environment(self.confg) table = rw_data.read_excel(self.filename, 0) rw_data.get_title_col(table) cmp_data.filter_data(table) cmp_data.cmp_data() except Exception as e: setup_env.display_message(e.message) finally: setup_env.clean_envirnoment()
class GuiOutput: def __init__(self, parent=None): self.text = None if parent: self.popupnow(parent) # popup now or on first write def popupnow(self, parent=None): # in parent now, Toplevel later if self.text: return self.text = ScrolledText(parent or Toplevel()) self.text.config(font=('courier', 9, 'normal')) self.text.pack() def write(self, text): self.popupnow() self.text.insert(END, str(text)) self.text.see(END) self.text.update() def writelines(self, lines): # lines already have '\n' for line in lines: self.write(line) # or map(self.write, lines)
def onHist(self): # show recent calcs log popup from ScrolledText import ScrolledText new = Toplevel() # make new window ok = Button(new, text="OK", command=new.destroy) ok.pack(pady=1, side=BOTTOM) # pack first=clip last text = ScrolledText(new, bg='beige') # add Text + scrollbar text.insert('0.0', self.eval.getHist()) # get Evaluator text text.see(END) # 3.0: scroll to end text.pack(expand=YES, fill=BOTH) # new window goes away on ok press or enter key new.title("PyCalc History") new.bind("<Return>", (lambda event: new.destroy())) ok.focus_set() # make new window modal: new.grab_set() # get keyboard focus, grab app new.wait_window() # don't return till new.destroy
class StringViewer(Frame): def __init__(self, parent, get_func, title=None): Frame.__init__(self,parent) self.text = ScrolledText(parent) self.text.pack(fill=BOTH,expand="yes") self.prev = get_func() self.text.insert(END,self.prev) self.after(1000, self.poll) self.get_func=get_func parent.wm_title(title) def poll(self): str = self.get_func() if not str == self.prev: self.text.delete("1.0", END) self.text.insert(END, self.get_func()) self.text.see(END) self.after(1000,self.poll)
class StringViewer(Frame): def __init__(self, parent, get_func, title=None): Frame.__init__(self, parent) self.text = ScrolledText(parent) self.text.pack(fill=BOTH, expand="yes") self.prev = get_func() self.text.insert(END, self.prev) self.after(1000, self.poll) self.get_func = get_func parent.wm_title(title) def poll(self): str = self.get_func() if not str == self.prev: self.text.delete("1.0", END) self.text.insert(END, self.get_func()) self.text.see(END) self.after(1000, self.poll)
def __init__(self): Toplevel.__init__(self) self.geometry('500x400') Label(self, text = 'Read Me').pack() text= ScrolledText(self, bg="lightgray") text['font'] = ('console','10') text.insert(END," welcome to monitor tool\n\n \ Here is some notes which will help you use monitor tool\n\n\ 1. About SMTP setting, please input your smtp user/passwd information, till now only QQ email smtp is varified\ for other smtp emails can not garantee. also you should open POP3/SMTP setting, the passwd is grant access passwd\ you can click verity email button to check the input smtp server is okay or not\n\n\ 2. About server information, please input the target server ip/user/passwd and command keyword which will be used\ to search its pid, ps -ef | grep <command keyword>. also input the command log path, which will be used to fetch command\ result, the frequency(mins), default value is 5 mins, means monitor will ssh to server every 5 mins to fetch pid status\n\n\ 3. About the email to address, you can add more then one email address into this enty, like ***@qq.com;***@ericsson.com\n\n\ 4. About Enable report progress, if want to know the script progress every certain period(30 mins, 1 hour...), you can select this checkbutton\ the monitor will fetch script log and send out by email") text.see("end") text.pack() text.config(state=DISABLED)
class GuiOutput: def __init__(self, parent=None): self.text = None if parent: self.popupnow(parent) # popup now or on first write def popupnow(self, parent=None): # in parent now, Toplevel later if self.text: return self.text = ScrolledText(parent or Toplevel()) self.text.config(font=('courier', 9, 'normal')) self.text.pack() def write(self, text): self.popupnow() self.text.insert(END, str(text)) self.text.see(END) self.text.update() def writelines(self, lines): # lines already have '\n' for line in lines: self.write(line) # or map(self.write, lines)
class GuiOutput: def __init__(self, name,parent=None): self.text = None self.titleName = name if parent: self.popupnow(name,parent) # popup now or on first write def popupnow(self,name,parent=None): # in parent now, Toplevel later if self.text: return newTopLevel = Toplevel() self.text = ScrolledText(parent or newTopLevel) newTopLevel.title(name) self.text.config(font=('courier', 9, 'normal')) #if it is a toplevel textbox, set its title. self.text.pack() def write(self, text): self.popupnow(self.titleName) #if len(self.text.get("1.0")) > 1024: # self.text.delete("1.0",END) self.text.insert(END, str(text)) self.text.see(END) self.text.update() def writelines(self, lines): # lines already have '\n' for line in lines: self.write(line) # or map(self.write, lines) def flush(self): pass
class ChatWindow(Toplevel): chats = {} @staticmethod def get(peer): try: return ChatWindow.chats[peer] except KeyError: ChatWindow.chats[peer] = ChatWindow(peer) return ChatWindow.chats[peer] def __init__(self, peer): Toplevel.__init__(self, mainwindow) self.peer = peer self.title(peer[0] + ':' + str(peer[1])) #self.root = Tk() #self.main = Frame(self.root) self.main = Frame(self) self.main.pack(expand=True, fill=BOTH) self.chat_Text = ScrolledText(self.main) self.chat_Text.pack(expand=True, fill=BOTH) self.chat_Text['height'] = 10 #print self.keys() #print self.chat_Text.keys() self.send_Frame = Frame(self.main) self.send_Frame.pack(fill=X) self.send_Text = Entry(self.send_Frame) self.send_Text.pack(side=LEFT, expand=True, fill=X) self.send_Text.bind('<Return>', self.send_Action) self.send_Button = Button(self.send_Frame, text='Send', command=self.send_Action) self.send_Button.pack(side=LEFT) self.status_Label = Label(self.main, text='Peer: ' + self.peer[0] + ':' + str(self.peer[1])) self.status_Label.pack() self.send_Text.focus() #self.protocol("WM_DELETE_WINDOW", self._destroy) def destroy(self): #print 'destroy' del ChatWindow.chats[self.peer] Toplevel.destroy(self) def send_Action(self, *args): text = self.send_Text.get() message = myname + ': ' + text if (text.strip()): self.chat_Text.insert(END, timestamp() + ' ' + message) self.chat_Text.see(END) self.send_Text.delete(0, len(text)) sock.sendto('TEXT' + message, self.peer) sock.lastActive = time.time() else: self.send_Text.delete(0,END)
class Globby_Text_Editor(tk.Frame): def __init__(self, parent_widget, settings): # some initial values # TODO this Values are obsolete since Project_Settings covers them # --> self.settings.projects_path self.hash_opened_filename = None self.opened_filename = None self.settings = settings self.edit_button_list=[ {'text':'new page', 'cmd':self.on_new_page, 'keytxt':'CTRL+n','hotkey':'<Control-n>'}, {'text':'del page', 'cmd':self.on_del_page, 'keytxt':'CTRL+n','hotkey':'<DELETE>'} , {'text':'save', 'cmd':self.on_save, 'keytxt':'CTRL+s','hotkey':'<Control-s>'}, {'text':'undo', 'cmd':self.on_undo, 'keytxt':'CTRL+z','hotkey':'<Control-z>'}, {'text':'redo', 'cmd':self.on_redo, 'keytxt':'CTRL+y','hotkey':'<Control-y>'}] self.syntax_button_list=[ {'text':'**bold**', 'cmd':self.on_tag_insert, 'open_tag':'**', 'close_tag':'**','keytxt':'CTRL+b','hotkey':'<Control-b>'}, {'text':'//italic//', 'cmd':self.on_tag_insert, 'open_tag':'//', 'close_tag':'//', 'keytxt':'CTRL+i','hotkey':'<Control-i>'}, {'text':'__underline__', 'cmd':self.on_tag_insert, 'open_tag':'__', 'close_tag':'__', 'keytxt':'CTRL+u','hotkey':'<Control-u>'}, {'text':'[Link]', 'cmd':self.on_tag_insert, 'open_tag':'[', 'close_tag':']', 'keytxt':'CTRL+l','hotkey':'<Control-l>'}, {'text':'¸¸sub¸¸', 'cmd':self.on_tag_insert, 'open_tag':'¸¸', 'close_tag':'¸¸', 'keytxt':'CTRL+d','hotkey':'<Control-d>'}, {'text':'^^upper^^', 'cmd':self.on_tag_insert, 'open_tag':'^^', 'close_tag':'^^', 'keytxt':'CTRL+q','hotkey':'<Control-q>'}, {'text':'-~smaller~-', 'cmd':self.on_tag_insert, 'open_tag':'-~', 'close_tag':'~-', 'keytxt':'CTRL+w','hotkey':'<Control-w>'}, {'text':'+~bigger~+', 'cmd':self.on_tag_insert, 'open_tag':'+~', 'close_tag':'~+', 'keytxt':'CTRL+e','hotkey':'<Control-e>'}, {'text':'~~strike_thru~~', 'cmd':self.on_tag_insert, 'open_tag':'~~', 'close_tag':'~~', 'keytxt':'CTRL+t','hotkey':'<Control-t>'} ] # build Widgets tk.Frame.__init__(self, parent_widget) self.pack(fill=tk.BOTH, expand=tk.YES) #self.baseframe = tk.Frame(parent_widget) #self.baseframe.pack(fill=tk.BOTH, expand=tk.YES) self.editor() self.button_frame() # start tracking text changes inside the editfield thread.start_new_thread(self.on_txt_changes, ('',)) def editor(self): """ combine some Widgets to an enhanced editor (incl. Scrollbar) --> self.text the text widget itself --> self.opened_file_label Label on top of the editfield to show the name of the current opened File It can be used to show textchanges """ # build widgets self.txtfrm = tk.Frame(self) self.txtfrm.pack(fill=tk.BOTH, side=tk.LEFT, expand=tk.YES) self.opened_file_label = tk.Label(self.txtfrm, text="No File chosen") self.opened_file_label.pack(fill=tk.X) self.text = ScrolledText(self.txtfrm, bg="white", undo=1, maxundo=30, wrap=tk.WORD) self.text.pack(fill=tk.BOTH, expand=tk.YES, side=tk.LEFT) self.text.insert(1.0, u"Please open a File to edit") # build first(reference -- new name??) hash for comparison on changes self.hash_opened_filename = hash(self.text.get(1.0,tk.END)) # Set focus on textwidget and move cursor to the upper left self.text.focus_set() self.text.mark_set(tk.INSERT, '0.0') # goto line self.text.see(tk.INSERT) # scroll to line def label_button_row(self, parent_widget=None, btnlst=None, start_count=0): """Build a 2 column table with a label beside each button in a row. Bind a keyboard sequence to the button command. Display this keyboard sequence on the label. todo: - think about a parameter for the widget to bind the Hotkeys - rename to: labled_button_row, draw_labled_button_row Parameter: --> parent_widget: Parent widget to place the table --> btnlst: Type: List of dicts representing a button Example: {'text':'**bold**', # displayed on the Button (string) 'cmd':self.on_tag_insert, # command 'open_tag':'**', # chars representing the beginning # of a tag for inserting (string) 'close_tag':'**', # chars representing the end # of a tag for inserting (string) 'keytxt':'CTRL+b', # displayed on the Label (string) 'hotkey':'<Control-b>'} # keyboard sequence (string) Note: The existence of 'open_tag' and 'close_tag' in btnlst decides which command is bound to the Button. If they aren't there 'cmd' must be a function without parameters!!! otherwise 'cmd' needs following parameters: otag = btn['open_tag'] ctag = btn['close_tag'] event = None # Placeholder for a keysequence --> start_count: Type: int Description: The table is relized with tkinter grid layout manager. start_count is used if there is already a grid (with a Label beside a button). start_count can add the automatic genrated buttons under the existing. In Globby_Editor it is used to put a label_button_row under a Tkinter menubutton(file choose, headlines). """ i = start_count for btn in btnlst: try: otag = btn['open_tag'] ctag = btn['close_tag'] event = None doit = lambda e=event, o=otag, c=ctag:self.on_tag_insert(e,o,c) tk.Button(parent_widget, text=btn['text'], command=doit, relief=tk.RIDGE ).grid(column=0, row=i, sticky=tk.W+tk.E) self.text.bind(btn['hotkey'],doit) except KeyError: tk.Button(parent_widget, text=btn['text'], command=btn['cmd'], relief=tk.RIDGE ).grid(column=0, row=i, sticky=tk.W+tk.E) tk.Label(parent_widget, text=btn['keytxt'], relief=tk.FLAT ).grid(column=1, row=i, sticky=tk.W) i +=1 def button_frame(self): """draws a frame to hold a edit- and syntax-buttons under each other """ self.btnfrm = tk.Frame(self) self.btnfrm.pack(fill=tk.BOTH, side=tk.LEFT) self.edit_buttons() self.syntax_buttons() def edit_buttons(self): """draws a frame with buttons for editing (save, undo, redo, open) """ # genrate a labelframe self.efrm = tk.LabelFrame(self.btnfrm, text="Edit Buttons") self.efrm.pack(fill=tk.BOTH, padx=5, pady=5) # generate a button with a pulldown menue to open a file to edit self.file_open_mbtn = tk.Menubutton(self.efrm, text='Open File') # generate the pulldown menue self.file_open_menu = tk.Menu(self.file_open_mbtn, postcommand=self.gen_file2edit_menu) # bind the pulldown menue to the menubutton self.file_open_mbtn.config(menu=self.file_open_menu, relief=tk.RIDGE) self.file_open_mbtn.grid(column=0,row=0, sticky=tk.W+tk.E) # label beside the Button to display the associated keyboard shortcut self.file_open_lbl = tk.Label(self.efrm, text='CTRL+o', relief=tk.FLAT) self.file_open_lbl.grid(column=1, row=0, sticky=tk.W+tk.E) # generate buttons as described in self.edit_button_list self.label_button_row(self.efrm, self.edit_button_list, 2) # bind keyboard shortcut to the menue self.text.bind('<Control-o>', lambda e: self.file_open_menu.tk_popup(e.x_root, e.y_root)) def gen_file2edit_menu(self): """generates a (new) menu bound to the file chooser button so every time when a project is created or deleted gen_choose_project_menu should be called """ # delete all existing menue entrys self.file_open_menu.delete(0,tk.END) proj_path = os.path.join(self.settings.projects_path, self.settings.current_project ) print "proj_path", proj_path for this_file in os.listdir(proj_path): splitted = os.path.splitext(this_file) if splitted[1] == ".txt" and splitted[0] != "menue": #print "this_file",this_file open_file = os.path.join(proj_path, this_file) do_it = lambda bla = open_file:self.on_open(bla) self.file_open_menu.add_command(label=splitted, command=do_it) def syntax_buttons(self): """draws a frame with buttons for insert (wiki)markup idea: new parameter for on_tag_insert() jump_in_between=True/False so a pulldown list for different levels of headlines arn't necessary """ # genrate a labelframe self.sfrm = tk.LabelFrame(self.btnfrm, text="Syntax Buttons") self.sfrm.pack(fill=tk.BOTH, padx=5, pady=5) # generate a button with a pulldown menue für headline Syntax self.headln_menubtn = tk.Menubutton(self.sfrm, text='= Headlines =') # generate the pulldown menue self.headln_menu = tk.Menu(self.headln_menubtn) # bind the pulldown menue to the menubutton self.headln_menubtn.config(menu=self.headln_menu, relief=tk.RIDGE) # generate menue entrys i=1 for entry in ('h1','h2','h3','h4','h5','h6'): otag = '\n\n'+'='*i+' ' ctag = ' '+'='*i+'\n\n' doit = lambda event=None, o=otag, c=ctag:self.on_tag_insert(event,o,c) self.headln_menu.add_command(label=entry, command=doit) i+=1 self.headln_menubtn.grid(column=0,row=0, sticky=tk.W+tk.E) # label beside the Button to display the associated keyboard shortcut self.headln_lbl = tk.Label(self.sfrm, text='CTRL+h', relief=tk.FLAT) self.headln_lbl.grid(column=1, row=0, sticky=tk.W+tk.E) # generate buttons as described in self.edit_button_list self.label_button_row(self.sfrm, self.syntax_button_list, 1) # bind keyboard shortcut to the menue self.text.bind('<Control-h>', lambda e: self.headln_menu.tk_popup(e.x_root, e.y_root)) def on_txt_changes(self, dummy_value=tk.NONE): """ tracks text changes inside the editfield by comparing hash values new name: visualize_txt_changes??? """ while True: new_hash = hash(self.text.get(1.0, tk.END)) if new_hash != self.hash_opened_filename: #print "changes" self.opened_file_label.configure(fg="red") else: #print "no changes" self.opened_file_label.configure(fg="black") sleep(0.2) def on_open(self, file_to_open=None): """- opens a *.txt file from project folder - generates a reference hash. - Brings the cursor to the upper left and show this position in the textfield Parameter: --> file_to_open: complete path for file to open idea: - rename file_to_open to openfile or file_to_open """ self.opened_file_to_open = file_to_open self.opened_file_label.configure(text=file_to_open) self.text.delete(1.0, tk.END) self.opened_filename = os.path.basename(file_to_open) # write file content into the editfield editfile = codecs.open(file_to_open,'r', 'utf-8') self.text.insert(1.0, editfile.read()) editfile.close() # generate reference hash for a comparison to track text changes self.hash_opened_filename = hash(self.text.get(1.0,tk.END)) self.text.edit_reset() # clear tk's undo/redo stacks self.text.focus_set() # focus to textfield self.text.mark_set(tk.INSERT, '0.0') # place cursor to upper left self.text.see(tk.INSERT) # and display this line def on_save(self): """ Safes the current edited file""" if self.opened_filename: print "on_safe_" print " self.opened_filename",self.opened_filename self.hash_opened_filename = hash(self.text.get(1.0,tk.END)) path_to_safe_file = os.path.join(self.settings.projects_path, self.settings.current_project, self.opened_filename) safefile = codecs.open(path_to_safe_file,'w', 'utf-8') safefile.write(self.text.get(1.0,tk.END)) safefile.close() self.text.edit_reset() #clear tk's undo/redo stacks else: showinfo('Globby Text Editor','No File to save \n\n' 'You need to choose a File before editing') def on_undo(self): try: # tk8.4 keeps undo/redo stacks self.text.edit_undo( ) # exception if stacks empty except tk.TclError: showinfo('Globby Text Editor', 'Nothing to undo') def on_redo(self): print "redo" try: # tk8.4 keeps undo/redo stacks self.text.edit_redo() # exception if stacks empty except tk.TclError: showinfo('Globby Text Editor', 'Nothing to redo') def on_new_page(self): """ Ask the user to name the new File, create a blank File and load it into the Editorwidget TODO: check if file with the new filename allready exists check if Filename contains Specialchars """ print "on_new_page" nfile_name = tkSimpleDialog.askstring("New File Name", "Fill in a new File Name") proj_path = os.path.join(self.settings.projects_path, self.settings.current_project) nfile_name = os.path.join(proj_path, nfile_name.strip()+'.txt') nfile = codecs.open(nfile_name, 'w', 'utf-8') current_project = self.settings.current_project infostring1 = u'# Diese Datei wurde automatisch mit ' infostring2 = u'dem Projekt "%s" erstellt' % current_project nfile.write(infostring1+infostring2 ) nfile.close() self.on_open(nfile_name) def on_del_page(self): """""" print "del page" # self.settings.current_project del_file = os.path.join(self.settings.projects_path, self.settings.current_project, self.opened_filename) del_page = askyesno("Do you really want to delete ", del_file) if del_page: #self.set_project(self.new_project_name) print "%s geloescht" % del_file os.remove(del_file) def on_tag_insert(self, event=None, open_tag=None, close_tag=None): """ inserts a (wiki)tag to the current cursor position. If there is no text marked in the editfield, open_tag and close_tag are inserted to the current cursor position behind each other and the cursor jumps in between. Otherwise the marked string is enclosed by open_tag and close_tag and inserted to the current cursor position. Here the new cursor position is right behind the complete inserted string with tags. At this moment this behavior is quite buggy :-( idea: - new parameter for on_tag_insert() jump_in_between=True/False so a pulldown list for different levels of headlines arn't necessary - rename to: on_insert_tag?? on_tag_insert Parameter: --> event # keyboard shortcut --> open_tag # string --> close_tag # string """ #print 'event',event #print 'open_tag',open_tag #print 'close_tag',close_tag ## when no String is selected: if not self.text.tag_ranges(tk.SEL): print "no String is selected" insert_point = self.text.index('insert') insertline = insert_point.split('.')[0] addit = 1 if event != None: print "event not None" addit = 2 insertrow = str(int(insert_point.split('.')[1])+len(open_tag)+addit) new_insert_point = insertline+'.'+ insertrow self.text.insert(insert_point, open_tag+''+close_tag) # place cursor to insert_point self.text.mark_set(tk.INSERT, new_insert_point) # display this position on the editfield self.text.see(tk.INSERT) ## when a String is selected: else: #print "im else" marked_text = self.text.get(self.text.index(tk.SEL_FIRST), self.text.index(tk.SEL_LAST)) replace_index = self.text.index(tk.SEL_FIRST) print "replace_index in selected", replace_index self.text.delete(self.text.index(tk.SEL_FIRST), self.text.index(tk.SEL_LAST)) self.text.insert(replace_index, open_tag+marked_text+close_tag)
class MyThing(Frame): def __init__(self, master=None): Frame.__init__(self, master) self.pack() self.createWidgets() def createWidgets(self): self.textBox = ScrolledText(self, height=30, width=85) self.textBox.pack() self.addText() def leftMouseClick(self, event): print "got a click" mouseIndex = "@%d,%d" % (event.x, event.y) current = self.textBox.index(mouseIndex) row = current.split(".")[0] + ".0" rowFl = float(row) + 1.0 row = str(rowFl) target = self.rowIndex[row] target = float(target) + 12.0 target = str(target) print "moving to target", target self.textBox.see(target) def rightMouseClick(self, event): self.textBox.see("0.0") def addText(self): f = open("help.txt", 'r') lines = f.readlines() f.close() flag = 1 i = 0 sectionOrder = {} sectionHeads = {} outlines = {} targetId = 0 defaultTarget = "" tocEntries = [] lineId = 0 for line in lines: if line[0:1] == "#": tocEntries.append(line) if flag: top = lineId flag = 0 lineId += 1 self.tocEntries = tocEntries # header text header = lines[0:top] for line in header: hid = self.textBox.insert(END, line, "header") self.textBox.tag_config("header", foreground=FGCOLOR) self.textBox.tag_config("header", background=BGCOLOR) self.textBox.insert(END, "Table of Contents\n", "toc") self.textBox.tag_config("toc", foreground="red") self.textBox.tag_config("toc", background=BGCOLOR) self.textBox.insert( END, "(Left-click entry to navigate, right-click to return)\n\n", "directions") self.textBox.tag_config("directions", background=BGCOLOR) self.textBox.tag_config("directions", foreground="purple") sectionDict = {} rowIndex = {} for tocEntry in tocEntries: if tocEntry[0:2] == "##": line = "\t" + tocEntry[2:] else: line = tocEntry[1:] rowPosition = self.textBox.index(END).split(".")[0] + ".0" rowIndex[rowPosition] = "0.0" sectionDict[tocEntry] = rowPosition self.textBox.insert(END, line, "tocEntry") self.textBox.tag_bind("tocEntry", '<ButtonRelease-1>', self.leftMouseClick) self.textBox.tag_config("tocEntry", background=BGCOLOR) self.textBox.tag_config("tocEntry", foreground=hfg) for i in range(50): self.textBox.insert(END, "\n", "regular") lines = lines[top:] for line in lines: if sectionDict.has_key(line): print "section id", line position = self.textBox.index(END) tocPosition = sectionDict[line] rowIndex[tocPosition] = position line = line.replace("#", "") self.textBox.insert(END, line, "regular") self.rowIndex = rowIndex self.sectionDict = sectionDict self.textBox.see("0.0") self.textBox.bind_all('<ButtonRelease-3>', self.rightMouseClick) self.textBox.tag_config("regular", background=BGCOLOR) self.textBox.tag_config("regular", foreground="black")
class MainApplication(): def __init__(self, master): self.filename = "" self.confg = "" self.master = master #setting color. bkc = "floral white" fgc = "RosyBrown4" bgc = "misty rose" self.FontForButton = tkFont.Font(family="Verdana", size=12) self.FontForLabel = tkFont.Font(family="Verdana", weight="bold") self.frame = tk.Frame(self.master, bg=bkc) self.frame.pack() self.chose_button = tk.Button(self.frame, text=u"選擇檔案", command=self.open_file, font=self.FontForButton, width=20, bg=bgc, fg=fgc) self.chose_button.pack(padx=5, pady=10, side=tk.TOP) self.chose_confg_button = tk.Button(self.frame, text=u"選擇設定檔", command=self.get_confg, font=self.FontForButton, width=20, bg=bgc, fg=fgc) self.chose_confg_button.pack(padx=5, pady=10, side=tk.TOP) self.run_button = tk.Button(self.frame, text=u"執行", command=self.run, font=self.FontForButton, width=20, bg=bgc, fg=fgc) self.run_button.pack(padx=5, pady=10, side=tk.TOP) self.text = ScrolledText(self.frame) self.text.pack() self.mdby = tk.Label(self.frame, text="\nPowered By MITLab", font=self.FontForLabel, fg="SkyBlue1", bg=bkc) self.mdby.pack(side='bottom') def open_file(self): self.filename = tkFileDialog.askopenfilename() if self.filename: setup_env.display_message(u"選擇檔案: " + self.filename) def get_confg(self): self.confg = tkFileDialog.askopenfilename() if self.confg: setup_env.display_message(u"選擇設定檔案: " + self.confg) def write(self, massage): self.text.insert(tk.END, massage) self.text.see(tk.END) self.text.update_idletasks() #display message real time def run(self): try: if not self.filename or not self.confg: raise Exception('請選擇檔案!') setup_env.display_message(u"開始執行...") setup_env.set_environment(self.confg) table = rw_data.read_excel(self.filename, 0) rw_data.get_title_col(table) cmp_data.filter_data(table) cmp_data.cmp_data() except Exception as e: setup_env.display_message(e.message) finally: setup_env.clean_envirnoment()
class BackupUI(Frame): def __init__(self, parent=None, **options): Frame.__init__(self, parent, padx=10, pady=10) self.dataQueue = queue.Queue() self.thread = None self.outputPath = StringVar() self.userVar = IntVar() self.photoVar = IntVar() self.photoVar.set(1) self.top = Frame(self) self.top.pack(side=TOP, expand=YES, fill=X) self.top.config(bd=2) self.createForm() self.createButtons() self.createText() def createButtons(self): frm = Frame(self.top) frm.pack(side=RIGHT, expand=YES, anchor=NE) self.btnStart = Button(frm, text='开始备份', command=self.start) self.btnStart.pack(side=TOP) self.btnStop = Button(frm, text='停止备份', command=self.stop) self.btnStop.pack(side=TOP) self.btnStop.config(state=DISABLED) frm = Frame(self.top) frm.pack(side=RIGHT, expand=YES, anchor=NE) self.userCheck = Checkbutton(frm, text='备份好友资料', variable=self.userVar) self.userCheck.config(command=self.callback) self.userCheck.pack(side=TOP) self.photoCheck = Checkbutton( frm, text='备份相册照片', variable=self.photoVar) self.photoCheck.config(command=self.callback) self.photoCheck.pack(side=TOP) frm = Frame(self, pady=5, padx=5) frm.pack(side=TOP, anchor=W) self.btnSelect = Button(frm, text='选择保存路径', command=self.selectPath) self.btnSelect.pack(side=LEFT) self.savePath = Entry(frm, width=45, textvariable=self.outputPath) self.savePath.pack(side=LEFT) self.savePath.insert(END, os.path.abspath(os.path.join('.', 'output'))) def createForm(self): self.login = Frame(self.top) # self.login.config(padx=4, pady=4) self.login.pack(side=LEFT, anchor=W) fields = const.LOGIN_FIELDS self.inputs = [] for i in range(len(fields)): lbl = Label(self.login, text=fields[i]) lbl.grid(row=i, column=0) var = StringVar() self.inputs.append(var) ent = Entry(self.login, textvariable=var) ent.grid(row=i, column=1) self.login.rowconfigure(i, weight=1) self.login.columnconfigure(0, weight=1) self.login.columnconfigure(1, weight=1) def createText(self): winfont = ('simhei', 10, 'normal') font = ('Helvetica', 12, 'normal') self.content = Frame(self, pady=5) self.content.pack(side=LEFT, expand=YES, fill=BOTH) self.text = ScrolledText(self.content) self.text.pack(side=TOP, expand=YES, fill=BOTH) self.text.config(bg='light gray', fg='black') self.text.config(padx=10, pady=10, font=winfont if isWin32 else font) self.text.insert(END, const.USER_GUIDE) self.text.config(state=DISABLED) def selectPath(self): path = askdirectory(initialdir='.') if path: self.savePath.delete(0, END) self.savePath.insert(END, path) def callback(self): #print('callback', self.userVar.get(), self.photoVar.get()) pass def write(self, message): if message and message.strip(): # timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f') timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') self.dataQueue.put(timestamp+" - "+message+'\n') def updateText(self, message): self.text.config(state=NORMAL) self.text.insert(END, str(message)) self.text.config(state=DISABLED) self.text.see(END) self.text.update() def updateUI(self): try: message = self.dataQueue.get(block=False) if message: self.updateText(message) except queue.Empty: pass running = self.thread and self.thread.is_alive() self.btnStart.config(state=DISABLED if running else NORMAL) self.btnStop.config(state=NORMAL if running else DISABLED) self.after(100, self.updateUI) def stop(self): if getattr(self, 'thread'): self.thread.stop() def start(self): keys = ['username', 'password', 'target'] values = map(lambda x: x.get(), self.inputs) if not any(values): showerror(const.NO_INPUT_TITLE, const.NO_INPUT_MESSAGE) return options = dict(zip(keys, values)) options['output'] = self.savePath.get() options['include_user'] = self.userVar.get() options['include_photo'] = self.photoVar.get() print('启动参数:', options) self.text.config(state=NORMAL) self.text.delete('0.0', END) self.text.config(state=DISABLED) self.updateUI() self.thread = BackupThread(self, self.dataQueue, **options) self.thread.start()
class MainWindow(Tkinter.Tk, TkSelectMixIn): def __init__(self): Tkinter.Tk.__init__(self) self.textbox = ScrolledText(self, bg='white') self.textbox.pack(fill=BOTH, expand=1) self.server() self.start() def server(self): # inicializa o servidor self.sock = socket.socket(socket.AF_INET, \ socket.SOCK_STREAM) self.sock.bind(('localhost', 8000)) self.sock.listen(1) # a chamada para input_read para o socket do servidor e # um pouco diferente, tendo como callback o metodo # self.accept self.server_tag = self.input_add(self.sock, \ INPUT_READ, self.accept) # mantemos uma lista dos clientes conectados self.clients = {} def accept(self, source, condition): # metodo chamado quando o servidor tem um cliente # esperando para ser aceito conn, addr = source.accept() self.insert("%s:%s conectado\n" % addr) # insere o cliente na lista e registra o metodo self.write # como callback para quando existirem dados esperando para # serem lidos. self.clients[addr] = (conn, self.input_add(conn, INPUT_READ, self.write)) def write(self, source, condition): # metodo chamado quando um cliente envia dados data = source.recv(1024) if not data.strip() or data.strip() == 'bye': # se o cliente enviar um "bye" ou uma linha em branco, # desconecte-o source.close() for addr, (conn, tag) in self.clients.iteritems(): if source is conn: self.input_remove(tag) self.insert('%s:%s desconectado\n' % addr) del self.clients[addr] break else: for (addr, port), (conn, tag) in \ self.clients.iteritems(): if source is conn: self.insert('%s:%s>>>%s\n'%(addr, port, \ data.strip())) break def insert(self, data): self.textbox.insert(END, data) self.textbox.see(END) def quit(self): self.input_remove(self.server_tag) for add, (conn, tag) in self.clients.iteritems(): self.input_remove(tag) conn.close() self.sock.close() Tkinter.Tk.destroy(self)
class ServerGUI(object): server_on = False def __init__(self, window_title="Server GUI"): self.base_gui = pygui.Tk() self.window_title = window_title self.server_port = 0 self.server = None # [GUI Initialization] ::start self.server_config_frame = pygui.Frame(self.base_gui) self.port_to_use_field = pygui.Entry(self.server_config_frame) self.server_controls_frame = pygui.Frame(self.base_gui) self.create_server_btn = pygui.Button(self.server_controls_frame, text="Start Server", command=self.invoke_server) self.stop_server_btn = pygui.Button(self.server_controls_frame, text="Stop Server", command=self.stop_server) self.quit_btn = pygui.Button(self.server_controls_frame, text="Quit", command=self.destroy_gui) # [GUI Initialization] ::end self.server_logs_frame = pygui.Frame(self.base_gui) self.activity_log_area = ScrolledText(self.server_logs_frame, height=10, width=50) def bootstrap(self): if self.server is None: print "Server Object must be specified. Call the set_server() method and set the ServerGUI Object." sys.exit(1) # set window title self.base_gui.wm_title(self.window_title) # [Config Section] :start self.server_config_frame.pack(side=pygui.TOP, pady=10) # Add field for port to use pygui.Label(self.server_config_frame, text="Server port to use").grid(row=0, column=0) self.port_to_use_field.grid(row=0, column=1) self.port_to_use_field.bind("<Return>", self.invoke_server) # [Config Section] :end # [Controls Section] ::start self.server_controls_frame.pack(side=pygui.RIGHT, fill=pygui.Y) # Add Start server button self.create_server_btn.grid(row=0, column=1) # Stop Server self.stop_server_btn.grid(row=1, column=1) # Quit Button self.quit_btn.grid(row=2, column=1) # [Controls Section] ::end # [Logs Section] ::start self.server_logs_frame.pack(side=pygui.LEFT, padx=10, pady=10) # Create a text area for showing logs. pygui.Label(self.server_logs_frame, text="Logs").grid(row=0) self.activity_log_area.edit_modified(0) self.activity_log_area.grid(row=1) self.activity_log_area.config(highlightbackground="black") self.activity_log_area.bind('<<Modified>>', self.scroll_to_end) # [Logs Section] ::end # handle close button self.base_gui.protocol("WM_DELETE_WINDOW", self.destroy_gui) # Start the GUI self.base_gui.mainloop() def set_server(self, server): self.server = server def scroll_to_end(self, *_): # scroll to the end of text area self.activity_log_area.see(pygui.END) self.activity_log_area.edit_modified(0) def destroy_gui(self): self.stop_server() self.base_gui.destroy() def stop_server(self, *_): if self.server_on is True: self.server.stop(self.log) # set the SERVER_ON flag to false to enable create a new server instance self.server_on = False else: self.log("Server already stopped.") def invoke_server(self, *_): portval = self.port_to_use_field.get() if portval != '': # check if the input for port number is a valid integer try: self.server_port = int(portval) except ValueError: msgBox.showinfo("Client GUI", "Invalid Port Number") return # start the server if not yet started if self.server_on is False: # log the message self.server.set_port(self.server_port) if not self.server.invoke(self.log): msgBox.showinfo( "Client GUI", "Cannot bind to port: %s. Please select another port to bind on." % str(self.server_port)) return # Prevent starting another instance of server self.server_on = True else: self.log("Server already started on port: " + str(self.server_port)) else: self.log( "Please provide port number for the server to bind on. Thanks!" ) def log(self, message): self.activity_log_area.insert(pygui.END, message + "\n")
class my_form(Frame): """Form""" def __init__(self, master=None): """create elements of form""" Frame.__init__(self, master) self.pack() self.textBox = ScrolledText(self, height=5, width=115) #self.textBox.pack() self.textBox.tag_config("b", foreground="blue") self.textBox.tag_config("r", foreground="red") self.label_dummy = Label(self, width=100, text=" ") self.label_dummy.pack() self.label_dummy1 = Label(self, width=100, text=" ") self.pressButton = Button(self, text="Write ID3 Tags", command=self.write_id3_tags_prepare) #self.pressButton.pack() # registering callback self.listenID = self.after(400, self.lets_rock) def display_logging(self, log_message, text_format): """display messages in form, loading periodically """ if text_format is None: self.textBox.insert(END, log_message + "\n") else: self.textBox.insert(END, log_message + "\n", text_format) def write_id3_tags_prepare(self): """prepare for writing tags""" result = tkMessageBox.askquestion( self.msg[5], self.msg[6], icon='warning') if result == 'yes': self.display_logging(self.msg[7], None) z = 0 for item in self.mp3_files: self.display_logging(self.entry_a[z].get(), "b") self.display_logging(self.entry_b[z].get(), "b") write_id3_tags(self, item, self.entry_a[z].get(), self.entry_b[z].get()) self.textBox.see(END) z += 1 else: self.display_logging(self.msg[8], None) self.textBox.see(END) def lets_rock(self): """man funktion""" print "lets rock" switch_lang(self) self.display_logging(self.msg[1], None) # check packages check_package = True check_package = check_packages(self, ["sox", "mp3gain", "mp3splt", "easytag"]) if check_package is None: return try: path_files = ( os.environ['NAUTILUS_SCRIPT_SELECTED_FILE_PATHS'].splitlines()) except Exception, e: self.display_logging("Error: %s" % str(e), "r") self.display_logging(self.err[2], None) return self.display_logging(self.msg[2], None) self.display_logging(os.path.dirname(path_files[0]), None) self.display_logging(self.msg[3], None) self.mp3_files = [] for item in path_files: if string.rfind(item, ".mp3") == -1: # no mp3: continue self.mp3_files.append(item) self.display_logging(extract_filename(item), "b") # check for mp3 files if len(self.mp3_files) == 0: self.display_logging(self.err[3], "r") self.display_logging(self.msg[4], None) return #return z = 0 self.label_dummy = [] self.label = [] self.entry_a = [] self.entry_b = [] for item in self.mp3_files: if z == 10: self.display_logging(self.msg[9], "b") continue #self.display_logging(extract_filename(item), "r") author, title = read_id3_tags(self, item) try: self.my_label = Label(self, width=100, text=extract_filename(item)) self.label.append(self.my_label) self.label[z].pack() self.my_entry_a = Entry(self, width=100) self.entry_a.append(self.my_entry_a) self.entry_a[z].pack() self.entry_a[z].insert(0, author) self.my_entry_b = Entry(self, width=100) self.entry_b.append(self.my_entry_b) self.entry_b[z].pack() self.entry_b[z].insert(0, title) self.my_label_dummy = Label(self, width=100, text=" ") self.label_dummy.append(self.my_label_dummy) self.label_dummy[z].pack() z += 1 except Exception, e: self.display_logging("Error: %s" % str(e), "r")
class ClientGUI(object): def __init__(self, windowTitle="Client GUI"): # create new instance of TK self.base_gui = pygui.Tk() # store the windowTitle in an object attribute self.base_window_title = windowTitle # Connection Details self.connection_host = '' self.connection_name = '' self.connection_port = 0 # Client Object self.client = None # [Connection GUI Initialization] ::start self.connection_gui_bootstrapped = False self.connection_config_frame = pygui.Frame(self.base_gui) self.host_to_use_field = pygui.Entry(self.connection_config_frame) self.port_to_use_field = pygui.Entry(self.connection_config_frame) self.name_field = pygui.Entry(self.connection_config_frame) self.connect_server_btn = pygui.Button(self.connection_config_frame, text="Connect", command=self.connect_to_server) # [Connection GUI Initialization] ::end # [Main GUI Initialization] ::start self.main_gui_bootstrapped = False self.chat_room_frame = pygui.Frame(self.base_gui) self.activity_log_area = ScrolledText(self.chat_room_frame, height=10, width=50) self.message_field = pygui.Entry(self.chat_room_frame) self.submit_msg_btn = pygui.Button(self.chat_room_frame, text="Send", command=self.send_msg) self.exit_chat_btn = pygui.Button(self.chat_room_frame, text="Leave Chat Room", command=lambda: self.switch_context('connection')) # [Connection GUI Initialization] ::end def bootstrap(self): if self.client is None: print "Client Object must be specified. Call the set_client() method and set the ClientGUI Object." sys.exit(1) self.connection_gui() # set window title self.base_gui.wm_title(self.base_window_title) # handle close button self.base_gui.protocol("WM_DELETE_WINDOW", self.destroy_gui) # Start the GUI self.base_gui.mainloop() def connection_gui(self): # [Config Section] :start # assemble the UI and the frame if the attribute does not exist if self.connection_gui_bootstrapped is False: # Add field for host/hostname to use pygui.Label(self.connection_config_frame, text="Host").grid(row=0, column=0) self.host_to_use_field.grid(row=0, column=1) # Add field for port to use pygui.Label(self.connection_config_frame, text="Port").grid(row=1, column=0) self.port_to_use_field.grid(row=1, column=1) # Add field for chat username/alias pygui.Label(self.connection_config_frame, text="Name").grid(row=2, column=0) self.name_field.grid(row=2, column=1) self.connect_server_btn.grid(row=3, column=1) self.connection_gui_bootstrapped = True self.connection_config_frame.pack(side=pygui.TOP, padx=10, pady=10) # [Config Section] :end def main_gui(self): # [Chat Room] ::start # assemble the UI and the frame if the attribute does not exist if self.main_gui_bootstrapped is False: self.activity_log_area.grid(row=0) self.activity_log_area.edit_modified(0) self.activity_log_area.config(highlightbackground="black") self.activity_log_area.bind('<<Modified>>', self.scroll_to_end) self.message_field.grid(row=1, column=0) self.message_field.config(width=30) self.message_field.bind("<Return>", self.send_msg) self.submit_msg_btn.grid(row=1, column=1) self.exit_chat_btn.grid(row=2) self.main_gui_bootstrapped = True # empty the chat logs self.activity_log_area.delete("1.0", pygui.END) # show the frame for chat room self.chat_room_frame.pack(side=pygui.TOP, padx=10, pady=10) # [Chat Room] ::end def destroy_gui(self): # disconnect from the server self.client.disconnect() # destroy the window self.base_gui.destroy() def switch_context(self, context): if context == 'main': # hide the connection frame/GUI from the window if hasattr(self, 'connection_config_frame'): self.connection_config_frame.pack_forget() self.main_gui() title = "%s connected on %s:%s - %s" % (strip_uid(self.connection_name), self.connection_host, str(self.connection_port), self.base_window_title) # change the window title to show the connection details self.base_gui.wm_title(title) else: # disconnect from the server self.client.disconnect() # hide the chat room frame/GUI from the window if hasattr(self, 'chat_room_frame'): self.chat_room_frame.pack_forget() self.connection_gui() # set window title self.base_gui.wm_title(self.base_window_title) def scroll_to_end(self, *_): # scroll to the end of text area self.activity_log_area.see(pygui.END) self.activity_log_area.edit_modified(0) def connect_to_server(self): hostval = self.host_to_use_field.get() portval = self.port_to_use_field.get() nameval = self.name_field.get() if hostval != '' and portval != '' and nameval != '': self.connection_host = str(hostval) self.connection_name = str(nameval) # check if the host supplied is a valid ip address if not is_ipv4(self.connection_host): msgBox.showinfo("Client GUI", "Invalid IP Address") return # check if the input for port number is a valid integer try: self.connection_port = int(portval) except ValueError: msgBox.showinfo("Client GUI", "Invalid Port Number") return # initiate client-server connection if self.client.connect(self.connection_host, self.connection_port, self.connection_name) is True: # swap UI components/widgets self.switch_context('main') # log any broadcast message and disconnect on lost connection self.client.start_communications(self.log, lambda: self.switch_context('connection')) else: msgBox.showinfo("Client GUI", "Cant connect to server. Please try again later.") else: msgBox.showinfo("Client GUI", "Please enter the host, and port to connect to as well as your chat name") def set_client(self, client): self.client = client def send_msg(self, *_): message = self.message_field.get() # only send messages which are not empty if message: # show the message on your side self.log('[' + strip_uid(self.connection_name) + '] ' + message) # send the message to the other side self.client.send_msg(str(message)) # delete the message self.message_field.delete(0, pygui.END) def log(self, message): self.activity_log_area.insert(pygui.END, message + "\n")
displayT.configure(state="disabled") displayT.pack() # User input textbox (at the lower part of the window, only 2 rows x 80 column) inputT = Text(root, height=2, width=80, bg='#ffa64d') inputT.insert(END, "") inputT.bind('<KeyRelease>', inputKeyup) inputT.pack(side=LEFT) sendbutton = Button(root, text="Send") sendbutton.bind('<Button-1>', sendmsg) sendbutton.pack() quitbutton = Button(root, text="Quit") quitbutton.bind('<Button-1>', quit) quitbutton.pack() inputT.focus_set() # ensure focus on the input textbox #Startup message displayT.configure(state="normal") displayT.insert(END, 'Enter "!help" for the list of available commands.\n') displayT.see(END) # simulate autoscroll displayT.configure(state="disabled") # starting a separate thread to monitor and display incoming message from # chat server t = threading.Thread(target=monitor, args=(socket, )) t.start() # mainloop() is required to start the window activities. mainloop()
class LoggingUI(TimedFrame): u'''ロギング用UI''' def __init__(self, *args, **kwargs): TimedFrame.__init__(self, *args, **kwargs) self.pack() self.init() self.startTimer() def init(self): if not config.normalize.points: self._label = tk.Label(self, text = u'まだ正規化が済んでいません。\n正規化を行ってください。') self._label.pack() return if not config.template.images or len(config.template.images) < 10 or not all(config.template.images): self._label = tk.Label(self, text = u'まだ学習が済んでいません。\n学習を行ってください。') self._label.pack() return # テンプレートの読み込み self.loadTemplates() # カメラの準備 self._camera = cv.CaptureFromCAM(config.camera.id) # 左側UI frame1 = tk.Frame(self) frame1.pack(side = tk.LEFT, expand = True, fill = tk.BOTH) # カメラ画像表示用Canvasなどの準備 self._cvmat = None self._image = tk.PhotoImage(width = config.canvas.width, height = config.canvas.height) self._canvas = tk.Canvas(frame1, width = config.canvas.width, height = config.canvas.height) self._canvas.create_image(config.canvas.width / 2, config.canvas.height / 2, image = self._image, tags = 'image') self._canvas.pack(expand = True, fill = tk.BOTH) # ボタン self._main_button = tk.Button(frame1) self._main_button.pack(side = tk.LEFT) self.logStop() self._reset_button = tk.Button(frame1, text = u'リセット', command = self.reset) self._reset_button.pack(side = tk.RIGHT) # 生データ表示領域 self._textarea = ScrolledText(self, width = 6, height = 18) self._textarea.pack(side = tk.LEFT, expand = True) # 右側UI frame2 = tk.Frame(self) frame2.pack(side = tk.LEFT, expand = True, fill = tk.BOTH) # ログデータ表示領域 self._graph = tk.Canvas(frame2, width = config.canvas.width, height = config.canvas.height, bg = 'white') self._graph.pack(expand = True, fill = tk.BOTH) self._bar_graph = BarGraph(A(width = config.canvas.width, height = config.canvas.height), config.logging.graph_max_count) # ボタン self._out_button = tk.Button(frame2, text = u'生データをコピー', command = self.datacopy) self._out_button.pack(side = tk.LEFT) self._gchart_button = tk.Button(frame2, text = u'Google Chart URLをコピー', command = self.gchart) self._gchart_button.pack(side = tk.RIGHT) # 画像をフィルタするための変数 self._clip_rect, self._perspective_points = Points2Rect(config.normalize.points) # ロギング開始、停止のフラグ self._take_log = False # ログ self._log = [] # カメラ画像の更新を1秒間隔にする self.addTiming(self.showImage, 1) def setValue(self, value): if value is None: value = 0 self._bar_graph.setValue(value) self._graph.delete('bar') for bar in self._bar_graph.getAllBars(): self._graph.create_rectangle( bar.p1.x, bar.p1.y, bar.p2.x, bar.p2.y, fill = 'green', stipple = 'gray25', tags = 'bar' ) def loadTemplates(self): u'''テンプレート画像の読み込み''' self._templates = [] for i, cvimageinfo in enumerate(config.template.images): cvmat = cv.CreateMatHeader(cvimageinfo.rows, cvimageinfo.cols, cvimageinfo.type) cv.SetData(cvmat, cvimageinfo.data) self._templates.append(A( image = cv.GetImage(cvmat), number = i, result = None, )) def showImage(self): u'''カメラ画像の表示''' captured = cv.QueryFrame(self._camera) self._cvmat = self.filter(captured) self._image = CvMat2TkImage(self._cvmat) self._canvas.itemconfigure('image', image = self._image) if self._take_log: self.logging() def logging(self): u'''ログを取る''' target = self._cvmat digits_sieve = DigitsSieve() for template in self._templates: if not template.result: # マッチング結果保存用領域の準備 template.result = cv.CreateImage( (target.width - template.image.width + 1, target.height - template.image.height + 1), cv.IPL_DEPTH_32F, 1, ) cv.MatchTemplate(target, template.image, template.result, config.logging.match_method) # 数値の読み取り minVal, maxVal, minLoc, maxLoc = cv.MinMaxLoc(template.result) while maxVal > config.logging.match_threshold: # 検出された数値情報の保持 digits_sieve.push(A( number = template.number, x = maxLoc[0], y = maxLoc[1], width = template.image.width, height = template.image.height, score = maxVal, )) # 現在の位置周辺のスコアをクリアし、次にスコアの高い位置を取得する SetReal2DAround(template.result, maxLoc, config.logging.match_exclusion_size, 0.0) minVal, maxVal, minLoc, maxLoc = cv.MinMaxLoc(template.result) value = digits_sieve.getValue() if value is not None: self._log.append(value) self.setValue(value) self._textarea.insert(tk.END, '%d\n' % value) self._textarea.see(tk.END) def logStart(self): u'''ロギングを開始する''' self._main_button.configure(text = u'ストップ', command = self.logStop) self._take_log = True def logStop(self): u'''ロギングを停止する''' self._main_button.configure(text = u'スタート', command = self.logStart) self._take_log = False def reset(self): u'''リセット''' self._bar_graph.init() self.setValue(0) self._log = [] self._textarea.delete('1.0', tk.END) def datacopy(self): u'''生データをクリップボードにコピーする''' text = self._textarea.get('1.0', tk.END) self.clipboard_clear() self.clipboard_append(text) def gchart(self): u'''Google Chart API用のURLをクリップボードにコピーする''' if self._log \ and len(self._log) > 0 \ and max(self._log) > 0: unit = float(4095) / max(self._log) url = gExtendedUrl( map(lambda x: unit * x, self._log), cht = 'bvs', # 棒グラフ chxt = 'y', # y軸の目盛り表示 chxr = '0,0,%d' % max(self._log), # y軸の最小最大値 chg = '0,10,3,2', # 補助線 chbh = '%d,1' % (480 / len(self._log) - 1), # 棒グラフの棒の幅 ) self.clipboard_clear() self.clipboard_append(url) def filter(self, cvmat): u'''画像をフィルタする''' # サイズ調整 thumbnail = cv.CreateMat(config.canvas.height, config.canvas.width, cv.CV_8UC3) cv.Resize(cvmat, thumbnail) return NormalizeImage(thumbnail, self._clip_rect, self._perspective_points)
class Interactive(object): def __init__(self): self.printQueue = Queue() # Tkinter components: self.root = Tk() self.root.title = "PGF API App" self.text_box = ScrolledText(self.root) self.runPrintQueue = True self.is_running = False self.prompt_var = StringVar() self.user_input = StringVar() self.of = RediOrderFactory() self.google_sheet = None def gui_start(self): printer_thread = Thread(target=self.queue_printer) printer_thread.daemon = True printer_thread.start() # start printer_thread self.text_box.pack() self.text_box.config(state=DISABLED) user_prompt_entry = Entry(self.root, textvariable=self.prompt_var) user_prompt_entry.pack(fill=BOTH) entry_var = StringVar() entry_box = Entry(self.root, textvariable=entry_var) def enter_pressed(event): print event self.user_input = entry_box.get() self.print_user_input(self.user_input) request_thread = Thread(target=self.process_user_input, args=[entry_box.get()]) # self.process_user_input(entry_box.get()) request_thread.start() entry_box.delete(0, 'end') entry_box.bind("<Return>", enter_pressed) entry_box.pack(fill=BOTH) entry_box.focus_set() self.user_input.set('') mainloop() self.runPrintQueue = False def queue_printer(self): while True: item = self.printQueue.get() self.text_box.config(state=NORMAL) self.text_box.insert(END, item) if isinstance(item, basestring): self.text_box.insert(END, '\n') if isinstance(item, ListType): self.text_box.insert(END, '\n') self.text_box.config(state=DISABLED) self.text_box.see('end') if not self.runPrintQueue: break time.sleep(.1) self.printQueue.task_done() def print_user_input(self, item): self.text_box.config(state=NORMAL) self.text_box.tag_config("b", foreground="blue") self.text_box.insert(END, item, "b") self.text_box.insert(END, '\n') self.text_box.config(state=DISABLED) self.text_box.see('end') def print2(self, txt): print txt self.printQueue.put(txt) def process_user_input(self, ui): # build this one function at a time if ui[:4].upper() == 'ECHO': self.print2(ui[4:]) self.prompt_var.set(ui[4:]) elif ui.upper() == 'QUIT' or ui.upper() == 'Q': self.print2('Breaking out of interactive.') sys.stdout.flush() self.root.quit() return -1 elif ui.upper() == 'LOAD SHEET': self.print2('Called Load Sheet') try: self.google_sheet = gs.GoogleSheetDailyTradingProcedure() self.print2('wait a moment . . . ') sys.stdout.flush() self.google_sheet.load_sheet() self.print2('sheet loaded') except E: self.print2('problem loading sheet' + E) elif ui.upper() == 'PRINT SHEET': if self.google_sheet: for row in self.google_sheet.sheet: self.print2(row) else: self.print2('Load sheet first. (cmd = load sheet)') elif ui.upper()[:10] == 'SUBMIT ROW': row = int(ui.split(' ')[2]) - 1 self.submit_row(row) # submit_row_thread = Thread(target=self.submit_row,args=[row]) # submit_row_thread.start() elif ui.upper() == 'SUBMIT ALL': if self.google_sheet.sheet: i = -1 for _ in self.google_sheet.sheet: i += 1 if i < 2: continue a = self.submit_row(i) if a == 'b': break else: pass elif ui.upper() == 'LOAD ADRS': self.google_sheet = gs.GoogleSheetDailyTradingProcedure() sheet_id = '1Z3POIK8N5Vi_CsF_MDLszrJeNviBwrU9BuVFC8h-xgQ' worksheet_range = 'ADRs Test!A1:F' self.print2('wait a moment') sys.stdout.flush() self.google_sheet.load_sheet(sheet_id, worksheet_range) self.print2('adrs loaded') elif ui.upper()[:14] == 'SUBMIT ADR ROW': r = int(ui.split(' ')[3]) self.submit_our_adr_row(r) self.print2('submit adr row') elif ui.upper() == 'SUBMIT ALL ADRS': if self.google_sheet.sheet: i = -1 for _ in self.google_sheet.sheet: i += 1 if i < 2: continue a = self.submit_our_adr_row(i) if a == 'b': break else: pass self.print2('submit adrs') elif ui.upper() == 'SUBMIT ALL MOCS': if self.google_sheet.sheet: i = -1 for _ in self.google_sheet.sheet: i += 1 if i < 2: continue a = self.submit_our_moc_row(i) if a == 'b': break else: pass elif ui.upper()[:14] == 'SUBMIT MOC ROW': r = int(ui.split(' ')[3]) self.submit_our_moc_row(r) self.print2('submit adr row') elif ui.upper()[:8] == 'STOP ROW': stop_tokens = ui.split(' ') row_num = int(stop_tokens[2]) - 1 row = self.google_sheet.sheet[row_num] if len(stop_tokens) == 4: quantity = int(stop_tokens[3]) else: quantity = int(row[4]) side = 'sell' if (row[3].upper() == 'LONG' or row[3].upper() == 'BUY' or row[3].upper() == 'B') else 'buy' if side == 'sell': quantity *= -1 symbol = row[2].split()[0].upper() stop_price = 0 if len(row) >= 13: stop_price = round(float(row[12]), 2) account = row[1].upper() if side == 'sell': stop_limit = round(stop_price * .99, 2) else: stop_limit = round(stop_price * 1.01, 2) self.of.generate_stop_limit_order(quantity, symbol, stop_price, stop_limit, account) elif ui.upper()[:9] == 'PRINT ROW': if self.google_sheet: tokens = ui.split(' ') self.print2(self.google_sheet.sheet[int(tokens[2]) - 1]) else: self.print2('Load sheet first. (cmd = load sheet)') else: if ui != 'y' and ui != 'n' and ui != 'b': self.print2('Command not understood.') def submit_row(self, r, confirm=True): try: if self.google_sheet: row = self.google_sheet.sheet[r] self.print2(row) sys.stdout.flush() account = row[1].upper() symbol = row[2].split()[0].upper() if symbol == '': return if row[4] == '': self.print2( "Row doesn't have quantity. Enter quantity and reload sheet." ) sys.stdout.flush() return quantity = int(row[4]) side = 'buy' if (row[3].upper() == 'LONG' or row[3].upper() == 'BUY' or row[3].upper() == 'B') else 'sell' if side == 'sell': quantity *= -1 o_type = None if len(row) >= 7: o_type = row[6].upper() price = 0 if len(row) >= 8: if row[7] == '': price = 0 else: price = float( row[7][1:]) if row[7][0] == '$' else float(row[7]) trade_date = None if len(row) >= 9: trade_date = row[8] if str(datetime.datetime.now())[:10] != trade_date: self.print2('Date is not today') sys.stdout.flush() return order_string = '{} {} {} {} {} in {}'.format( side, abs(quantity), symbol, price, o_type, account) if confirm: confirm_msg = '{}? (y/n/b)'.format(order_string) self.user_input = '' self.prompt_var.set(confirm_msg) while self.user_input == '': time.sleep(.1) inp = self.user_input self.prompt_var.set('') else: inp = 'y' if inp == 'y': o = False if o_type == 'MOO': o = self.of.generate_opg_market_order( quantity, symbol, account) elif o_type == 'LOO': o = self.of.generate_opg_limit_order( quantity, symbol, price, account) elif o_type == 'LOC': o = self.of.generate_loc_order(quantity, symbol, price, account) elif o_type == 'MOC': o = self.of.generate_moc_order(quantity, symbol, account) elif o_type == 'LIMIT' or o_type == 'LMT': o = self.of.generate_limit_order( quantity, symbol, price, account) time.sleep(.05) if o: return '1' else: return '0' elif inp == 'b': return 'b' # user requested break else: return inp else: self.print2('Load sheet first. (cmd = load sheet)') sys.stdout.flush() return 'b' except Exception as e: self.print2('row {} failed to submit: {}'.format(r + 1, e)) sys.stdout.flush() def submit_our_adr_row(self, r, confirm=False): try: if self.google_sheet: row = self.google_sheet.sheet[r - 1] self.print2(row) sys.stdout.flush() symbol = row[1].split()[0].upper() if symbol == '': return if row[3] == '': self.print2( "Row doesn't have quantity. Enter quantity and reload sheet." ) sys.stdout.flush() return quantity = int(row[3]) if row[2] == '': return side = 'buy' if (row[2].upper() == 'LONG' or row[2].upper() == 'BUY' or row[2].upper() == 'B') else 'sell' if side == 'sell': quantity *= -1 order_type = None if len(row) >= 6: order_type = row[5].upper() price = 0 if len(row) >= 5: if row[4] == '': price = 0 else: price = float( row[4][1:]) if row[4][0] == '$' else float(row[4]) trade_date = None if len(row) >= 1: trade_date = row[0] if str(datetime.datetime.now())[:10] != trade_date: self.print2('Date is not today') sys.stdout.flush() return order_string = '{} {} {} {} {}'.format(side, abs(quantity), symbol, price, order_type) if confirm: sys.stdout.write('{} {} {} {} {}? (y/n/b)'.format( side, abs(quantity), symbol, price, order_type)) sys.stdout.flush() inp = raw_input() else: inp = 'y' if inp == 'y': o = 0 if order_type == 'MOO': o = self.of.generate_opg_market_order(quantity, symbol) elif order_type == 'LOO': o = self.of.generate_opg_limit_order( quantity, symbol, price) elif order_type == 'LOC': o = self.of.generate_loc_order(quantity, symbol, price) elif order_type == 'MOC': o = self.of.generate_moc_order(quantity, symbol) elif order_type == 'LIMIT' or order_type == 'LMT': o = self.of.generate_limit_order( quantity, symbol, price) if o: return '1' else: return '0' if inp == 'b': return 'b' else: self.print2('order not submitted: {}'.format(order_string)) sys.stdout.flush() return '' else: self.print2('Load sheet first. (cmd = load sheet)') sys.stdout.flush() return 'b' except Exception as e: self.print2('row {} failed to submit: {}'.format(r + 1, e)) sys.stdout.flush() def submit_our_moc_row(self, r, confirm=False): try: if self.google_sheet: row = self.google_sheet.sheet[r - 1] self.print2(row) sys.stdout.flush() symbol = row[1].split()[0].upper() if symbol == '': return if row[3] == '': self.print2( "Row doesn't have quantity. Enter quantity and reload sheet." ) sys.stdout.flush() return quantity = int(row[3]) if row[2] == '': return side = 'sell' if (row[2].upper() == 'LONG' or row[2].upper() == 'BUY' or row[2].upper() == 'B') else 'buy' if side == 'sell': quantity *= -1 order_type = 'MOC' price = 0 order_string = '{} {} {} {} {}'.format(side, abs(quantity), symbol, price, order_type) if confirm: sys.stdout.write('{} {} {} {} {}? (y/n/b)'.format( side, abs(quantity), symbol, price, order_type)) sys.stdout.flush() inp = raw_input() else: inp = 'y' if inp == 'y': o = 0 if order_type == 'MOC': o = self.of.generate_moc_order(quantity, symbol) time.sleep(.05) if o: return '1' else: return '0' if inp == 'b': return 'b' else: self.print2('order not submitted: {}'.format(order_string)) sys.stdout.flush() return '' else: self.print2('Load sheet first. (cmd = load sheet)') sys.stdout.flush() return 'b' except Exception as e: self.print2('row {} failed to submit: {}'.format(r + 1, e)) sys.stdout.flush()
class LoggingUI(TimedFrame): u'''ロギング用UI''' def __init__(self, *args, **kwargs): TimedFrame.__init__(self, *args, **kwargs) self.pack() self.init() self.startTimer() def init(self): if not config.normalize.points: self._label = tk.Label(self, text = u'まだ正規化が済んでいません。\n正規化を行ってください。') self._label.pack() return if not config.template.images or len(config.template.images) < 10 or not all(config.template.images): self._label = tk.Label(self, text = u'まだ学習が済んでいません。\n学習を行ってください。') self._label.pack() return # テンプレートの読み込み self.loadTemplates() # カメラの準備 self._camera = cv.CaptureFromCAM(config.camera.id) # 左側UI frame1 = tk.Frame(self) frame1.pack(side = tk.LEFT, expand = True, fill = tk.BOTH) # カメラ画像表示用Canvasなどの準備 self._cvmat = None self._image = tk.PhotoImage(width = config.canvas.width, height = config.canvas.height) self._canvas = tk.Canvas(frame1, width = config.canvas.width, height = config.canvas.height) self._canvas.create_image(config.canvas.width / 2, config.canvas.height / 2, image = self._image, tags = 'image') self._canvas.pack(expand = True, fill = tk.BOTH) # ボタン self._main_button = tk.Button(frame1) self._main_button.pack(side = tk.LEFT) self.logStop() self._reset_button = tk.Button(frame1, text = u'リセット', command = self.reset) self._reset_button.pack(side = tk.RIGHT) # 生データ表示領域 self._textarea = ScrolledText(self, width = 6, height = 18) self._textarea.pack(side = tk.LEFT, expand = True) # 右側UI frame2 = tk.Frame(self) frame2.pack(side = tk.LEFT, expand = True, fill = tk.BOTH) # ログデータ表示領域 self._graph = tk.Canvas(frame2, width = config.canvas.width, height = config.canvas.height, bg = 'white') self._graph.pack(expand = True, fill = tk.BOTH) self._bar_graph = BarGraph(A(width = config.canvas.width, height = config.canvas.height), config.logging.graph_max_count) # ボタン self._out_button = tk.Button(frame2, text = u'生データをコピー', command = self.datacopy) self._out_button.pack(side = tk.LEFT) self._gchart_button = tk.Button(frame2, text = u'Google Chart URLをコピー', command = self.gchart) self._gchart_button.pack(side = tk.RIGHT) # 画像をフィルタするための変数 self._clip_rect, self._perspective_points = Points2Rect(config.normalize.points) # ロギング開始、停止のフラグ self._take_log = False # ログ self._log = [] # カメラ画像の更新を1秒間隔にする self.addTiming(self.showImage, 1) def setValue(self, value): if value is None: value = 0 self._bar_graph.setValue(value) self._graph.delete('bar') for bar in self._bar_graph.getAllBars(): self._graph.create_rectangle( bar.p1.x, bar.p1.y, bar.p2.x, bar.p2.y, fill = 'green', stipple = 'gray25', tags = 'bar' ) def loadTemplates(self): u'''テンプレート画像の読み込み''' self._templates = [] for i, cvimageinfo in enumerate(config.template.images): cvmat = cv.CreateMatHeader(cvimageinfo.rows, cvimageinfo.cols, cvimageinfo.type) cv.SetData(cvmat, cvimageinfo.data) self._templates.append(A( image = cv.GetImage(cvmat), number = i, result = None, )) def showImage(self): u'''カメラ画像の表示''' captured = cv.QueryFrame(self._camera) self._cvmat = self.filter(captured) self._image = CvMat2TkImage(self._cvmat) self._canvas.itemconfigure('image', image = self._image) if self._take_log: self.logging() def logging(self): u'''ログを取る''' target = self._cvmat digits_sieve = DigitsSieve() for template in self._templates: if not template.result: # マッチング結果保存用領域の準備 template.result = cv.CreateImage( (target.width - template.image.width + 1, target.height - template.image.height + 1), cv.IPL_DEPTH_32F, 1, ) cv.MatchTemplate(target, template.image, template.result, config.logging.match_method) # 数値の読み取り minVal, maxVal, minLoc, maxLoc = cv.MinMaxLoc(template.result) while maxVal > config.logging.match_threshold: # 検出された数値情報の保持 digits_sieve.push(A( number = template.number, x = maxLoc[0], y = maxLoc[1], width = template.image.width, height = template.image.height, score = maxVal, )) # 現在の位置周辺のスコアをクリアし、次にスコアの高い位置を取得する SetReal2DAround(template.result, maxLoc, config.logging.match_exclusion_size, 0.0) minVal, maxVal, minLoc, maxLoc = cv.MinMaxLoc(template.result) value = digits_sieve.getValue() if value is not None: self._log.append(value) self.setValue(value) self._textarea.insert(tk.END, '%d\n' % value) self._textarea.see(tk.END) def logStart(self): u'''ロギングを開始する''' self._main_button.configure(text = u'ストップ', command = self.logStop) self._take_log = True def logStop(self): u'''ロギングを停止する''' self._main_button.configure(text = u'スタート', command = self.logStart) self._take_log = False def reset(self): u'''リセット''' self._bar_graph.init() self.setValue(0) self._log = [] self._textarea.delete('1.0', tk.END) def datacopy(self): u'''生データをクリップボードにコピーする''' text = self._textarea.get('1.0', tk.END) self.clipboard_clear() self.clipboard_append(text) def gchart(self): u'''Google Chart API用のURLをクリップボードにコピーする''' if self._log \ and len(self._log) > 0 \ and max(self._log) > 0: unit = float(4095) / max(self._log) url = gExtendedUrl( map(lambda x: unit * x, self._log), cht = 'bvs', # 棒グラフ chxt = 'y', # y軸の目盛り表示 chxr = '0,0,%d' % max(self._log), # y軸の最小最大値 chg = '0,10,3,2', # 補助線 chbh = '%d,1' % (480 / len(self._log) - 1), # 棒グラフの棒の幅 ) self.clipboard_clear() self.clipboard_append(url) def filter(self, cvmat): u'''画像をフィルタする''' # サイズ調整 thumbnail = cv.CreateMat(config.canvas.height, config.canvas.width, cv.CV_8UC3) cv.Resize(cvmat, thumbnail) return NormalizeImage(thumbnail, self._clip_rect, self._perspective_points)
class TermWindow(Frame): ## # constructor method def __init__(self, master = None, **cnf): apply(Frame.__init__, (self, master), cnf) self.__create_widgets__() self.rxThread = None self.rxWaitEvent = threading.Event() self.rxWaitPattern = "" self.localEcho = False self.logFile = None self.textQueue = Queue.Queue() self.update_thread_safe() def update_thread_safe(self): try: while 1: element = self.textQueue.get_nowait() if element is not None: msg,tag = element self.__display__(msg,tag) self.st_trm.update_idletasks() except Queue.Empty: pass self.st_trm.after(100, self.update_thread_safe) ## # worker function for threaded reading from the input of # the assigned device # def __thrd_reader__(self): self.waitbuf = "" while 1: try: x = self.device.read() if len(x): cmd = self.cmdVar.get() if len(cmd): self.cmdVar.set("") self.write(x) if self.rxWaitEvent.isSet(): self.waitbuf += x if self.waitbuf.find(self.rxWaitPattern) > -1: self.rxWaitEvent.clear() while not self.rxWaitEvent.isSet(): pass self.rxWaitEvent.clear() except: traceback.print_exc() time.sleep(1) else: # this infinitesimal sleep keeps the GUI update alive time.sleep(.01) def waitfor(self, pattern, maxwait=10): self.waitbuf = "" self.rxWaitPattern = pattern self.rxWaitEvent.set() self.maxwait = 10 while self.rxWaitEvent.isSet() and self.maxwait > 0: time.sleep(1) self.maxwait -= 1 if self.maxwait == 0: self.message("PatternNotFound") self.rxWaitEvent.set() ## # def __create_widgets__(self): dfl_font = 'Courier 10' # the title frame of the terminal self.f_title = Frame(self) self.f_title.pack(fill=BOTH) self.f_title.configure(FRAMEBORDER) self.shVar = StringVar() # show/hide button self.b_sh = Button(self.f_title, textvariable=self.shVar, font=dfl_font) self.b_sh.pack(side=RIGHT) self.b_sh['command'] = self.show_hide_cont # clear screen button self.b_cls = Button(self.f_title, text="CLS", font=dfl_font, underline=0) self.b_cls.pack(side=RIGHT) self.b_cls['command'] = self.clear_screen # echo on/off button self.al_echo = Label(self.f_title, text = "ECHO", relief = RAISED, font = dfl_font, padx='3m', pady='1m', underline=0) self.al_echo.pack(side=RIGHT, padx=1, pady=1, fill=BOTH) self.al_echo.bind("<Button-1>", self.__echo_handler__) # log on/off button self.al_log = Label(self.f_title, text = "LOG", relief = RAISED, font = dfl_font, padx='3m', pady='1m', underline=0) self.al_log.pack(side=RIGHT, padx=1, pady=1, fill=BOTH) self.al_log.bind("<Button-1>", self.__log_handler__) # device connect button self.al_connect = Label(self.f_title, text = "CONNECT", relief = RAISED, font = dfl_font, padx='3m', pady='1m', underline=1) self.al_connect.pack(side=RIGHT, padx=1, pady=1, fill=BOTH) self.al_connect.bind("<Button-1>", self.__connect_handler__) self.mb_macros = Menubutton(self.f_title, text = "Macros", relief=RAISED) self.mb_macros.pack(side=RIGHT, padx=1, pady=1, fill=BOTH) self.mb_macros.menu = Menu(self.mb_macros, tearoff = 0) self.mb_macros["menu"] = self.mb_macros.menu # title of terminal window self.tVar = StringVar() self.l_title = Label(self.f_title, text="foo", font=dfl_font) self.l_title['textvariable'] = self.tVar self.l_title.pack(side=LEFT, expand=1, fill=X) self.l_title['width'] = 42 self.update_title("------ XXX ------") # frame for scrolled text window # (this frame handle needs to be kept fo show_hide_cont()) self.f_cont = Frame(self) # IO data scrolled text window self.st_trm = ScrolledText(self.f_cont, height=10, state=DISABLED, wrap=NONE) self.st_trm.pack(expand=1,fill=BOTH) self.st_trm['font'] = dfl_font self.st_trm.tag_config('E', foreground="blue") self.st_trm.tag_config('M', foreground="magenta") tframe = Frame(self.f_cont) tframe.pack(expand = 0, fill = X) self.cmdVar = StringVar() self.ent_trm = Entry(tframe, textvariable=self.cmdVar, font=dfl_font) self.ent_trm.pack(side=LEFT, expand =1, fill = X) self.ent_trm.bind("<Control-l>", self.__log_handler__) self.ent_trm.bind("<Control-e>", self.__echo_handler__) self.ent_trm.bind("<Control-o>", self.__connect_handler__) self.ent_trm.bind("<Control-c>", self.clear_screen) self.ent_trm.bind("<Control-x>", self.show_hide_cont) self.ent_trm.bind("<Control-m>", lambda *args: self.do_macro("M")) self.ent_trm.bind("<KeyPress>", self.__input_handler__) self.gui_elements = [ self.b_sh, self.b_cls, self.al_echo, self.al_log, self.al_connect, self.mb_macros, self.l_title, self.st_trm, self.ent_trm] self.show_cont() def add_macro(self, id, title, text = None, function = None, params = None): if text: cmd = lambda *args: self.do_macro(text) if function: user_func = eval(function) params = eval(str(params)) cmd = lambda *args: user_func(DEVICES, **params) mb = self.mb_macros.menu.add_command(label = title, command = cmd) def _configure_(self,**args): for e in self.gui_elements: e.configure(args) def __input_handler__(self, *args): for i in args: if self.localEcho: self.display(i.char, "E") if len(i.char): if i.char == "\r": self.device.write("\r\n") self.cmdVar.set("") else: self.device.write(i.char) def __echo_handler__(self, *args): if self.localEcho: self.localEcho = False self.al_echo['relief'] = RAISED self.message("Local Echo OFF") else: self.localEcho = True self.al_echo['relief'] = SUNKEN self.message("Local Echo ON") def __log_handler__(self, *args): try: do_open = self.logFile.closed logname = self.logFile.name except: do_open = True logname = "" if do_open: if self.device.logname: logname = self.device.logname self.message("logfile from config file %s " % logname) else: fd = FileDialog(self) logname = fd.go(logname) try: if self.device.logmode not in "wa": self.device.logmode = "a" print "force _a_ppend" self.logFile = open(logname, self.device.logmode) self.al_log['relief'] = SUNKEN self.message("Logging ON: %s" % self.logFile.name) except: self.message("Error open logfile: %s" % logname) else: self.message("Logging OFF: %s" % self.logFile.name) self.logFile.flush() self.logFile.close() self.al_log['relief'] = RAISED def __connect_handler__(self, *args): if self.device.isConnected: self.device.disconnect() self.al_connect['relief'] = RAISED self.message("Disconnected") else: try: self.device.connect() self.al_connect['relief'] = SUNKEN self.message("Connected") self.al_connect['fg'] = "black" except: self.device.isConnected = False self.message( str(sys.exc_info()[1]) ) self.al_connect['fg'] = "red" def clear_screen(self, *args): self.st_trm['state'] = NORMAL self.st_trm.delete("0.0",END) self.st_trm['state'] = DISABLED def set_device(self,device): self.device = device self.rxThread = threading.Thread(target = self.__thrd_reader__) # if a thread is not a daemon, the program needs to join all self.rxThread.setDaemon(1) print "**",self.device, self.device.name self.rxThread.setName("GUI_RX_%s" % self.device.name) self.rxThread.start() self.update_title(self.device) # if self.device.echo: self.localEcho = 0 self.__echo_handler__() if self.device.log: self.__log_handler__() if self.device.auto_connect: self.__connect_handler__() def update_title(self, title): self.tVar.set(title) def show_cont(self): self.shVar.set("X") self.f_cont.pack(expand=1,fill=BOTH) def hide_cont(self): self.shVar.set("+") self.f_cont.pack_forget() def show_hide_cont(self, *args): if self.shVar.get() == "X": self.hide_cont() else: self.show_cont() def do_macro(self, *args): if self.localEcho: self.display(args[0] + "\n", "E") self.device.write(args[0]+ "\n") def write(self, data): self.textQueue.put((data, None)) def message(self, text, tag='M'): msg = "[%s:%s:%s]\n" % (time.asctime(),self.device.name, text) if self.st_trm.index(AtInsert()).find(".0") < 1: msg = "\n" + msg self.textQueue.put((msg, tag)) def display(self, text, tag = None): self.textQueue.put((text, tag)) def __display__(self, msg, tag = None): self.st_trm['state'] = NORMAL here = self.st_trm.index(AtInsert()) for d in re.split("([\r\v\t\n])", msg): if len(d): if d != '\r': self.st_trm.insert(END, d) if tag: self.st_trm.tag_add(tag, here, AtInsert()) self.st_trm.see(END) self.st_trm['state'] = DISABLED try: self.logFile.write(msg) self.logFile.flush() except: pass
class ExportApp(Frame): """GUI version of the Phoshare tool.""" def __init__(self, master=None): """Initialize the app, setting up the UI.""" Frame.__init__(self, master, padding=10) top = self.winfo_toplevel() menu_bar = Menu(top) top["menu"] = menu_bar apple = Menu(menu_bar, name='apple') menu_bar.add_cascade(label='Phoshare', menu=apple) apple.add_command(label="About Phoshare", command=self.__aboutHandler) sub_menu = Menu(menu_bar, name='help') menu_bar.add_cascade(label="Help", menu=sub_menu) sub_menu.add_command(label="Phoshare Help", command=self.help_buttons) self.thread_queue = Queue.Queue(maxsize=100) self.active_library = None top.columnconfigure(0, weight=1) top.rowconfigure(0, weight=1) self.grid(sticky=N+S+E+W) self.valid_library = False self.exiftool = False self.iphoto_library = StringVar() self.iphoto_library_status = StringVar() self.browse_library_button = None self.export_folder = StringVar() self.library_status = None self.dryrun_button = None self.export_button = None self.text = None self.events = StringVar() self.albums = StringVar() self.smarts = StringVar() self.foldertemplate = StringVar() self.nametemplate = StringVar() self.captiontemplate = StringVar() self.update_var = IntVar() self.delete_var = IntVar() self.originals_var = IntVar() self.link_var = IntVar() self.folder_hints_var = IntVar() self.faces_box = None self.faces_var = IntVar() self.face_keywords_box = None self.face_keywords_var = IntVar() self.face_albums_var = IntVar() self.face_albums_text = StringVar() self.iptc_box = None self.iptc_all_box = None self.iptc_var = IntVar() self.iptc_all_var = IntVar() self.gps_box = None self.gps_var = IntVar() self.verbose_var = IntVar() self.info_icon = PhotoImage(file="info-b16.gif") self.create_widgets() # Set up logging so it gets redirected to the text area in the app. self.logging_handler = logging.StreamHandler(self) self.logging_handler.setLevel(logging.WARN) _logger.addHandler(self.logging_handler) def __aboutHandler(self): HelpDialog(self, """%s %s Copyright 2010 Google Inc. http://code.google.com/p/phoshare""" % (phoshare_version.PHOSHARE_VERSION, phoshare_version.PHOSHARE_BUILD), title="About Phoshare") def init(self): """Initializes processing by launching background thread checker and initial iPhoto library check.""" self.thread_checker() if exiftool.check_exif_tool(sys.stdout): self.exiftool = True self.faces_box.configure(state=NORMAL) self.face_keywords_box.configure(state=NORMAL) self.iptc_box.configure(state=NORMAL) self.iptc_all_box.configure(state=NORMAL) self.gps_box.configure(state=NORMAL) options = self.Options() options.load() self.init_from_options(options) self.check_iphoto_library() def init_from_options(self, options): """Populates the UI from options.""" self.iphoto_library.set(options.iphoto) self.export_folder.set(options.export) self.albums.set(su.fsdec(options.albums)) self.events.set(su.fsdec(options.events)) self.smarts.set(su.fsdec(options.smarts)) self.foldertemplate.set(su.unicode_string(options.foldertemplate)) self.nametemplate.set(su.unicode_string(options.nametemplate)) self.captiontemplate.set(su.unicode_string(options.captiontemplate)) self.update_var.set(_int_from_bool(options.update)) self.delete_var.set(_int_from_bool(options.delete)) self.originals_var.set(_int_from_bool(options.originals)) self.link_var.set(_int_from_bool(options.link)) self.folder_hints_var.set(_int_from_bool(options.folderhints)) self.faces_var.set(_int_from_bool(options.faces) and self.exiftool) self.face_keywords_var.set(_int_from_bool(options.face_keywords) and self.exiftool) self.face_albums_var.set(_int_from_bool(options.facealbums)) self.face_albums_text.set(options.facealbum_prefix) if options.iptc and self.exiftool: self.iptc_var.set(1) if options.iptc == 2: self.iptc_all_var.set(1) self.gps_var.set(_int_from_bool(options.gps) and self.exiftool) def _add_section(self, container, text, help_command): """Adds a new UI section with a bold label and an info button. Args: container: UI element that will contain this new item row: row number in grid. Uses two rows. text: label frame text. help_command: command to run when the info button is pressed. Returns: tuple of new section and content frames. """ section_frame = Frame(container) section_frame.columnconfigure(0, weight=1) label = Label(section_frame, text=text) label.config(font=_BOLD_FONT) label.grid(row=0, column=0, sticky=W, pady=5) Button(section_frame, image=self.info_icon, command=help_command).grid(row=0, column=1, sticky=E) content_frame = Frame(section_frame) content_frame.grid(row= 1, column=0, columnspan=2, sticky=N+S+E+W, pady=5) return (section_frame, content_frame) def _create_button_bar(self, container, row): """Creates the button bar with the Dry Run and Export buttons. Args: row: row number in grid. Returns: next row number in grid. """ button_bar = Frame(container) button_bar.grid(row=row, column=0, sticky=E+W, padx=10) button_bar.columnconfigure(0, weight=1) verbose_box = Checkbutton(button_bar, text="Show debug output", var=self.verbose_var) verbose_box.grid(row=0, column=0, sticky=E) self.dryrun_button = Button(button_bar, text="Dry Run", command=self.do_dryrun, state=DISABLED) self.dryrun_button.grid(row=0, column=1, sticky=E, pady=5) self.export_button = Button(button_bar, text="Export", command=self.do_export, state=DISABLED) self.export_button.grid(row=0, column=2, pady=5) return row + 1 def _create_library_tab(self, library_tab): library_tab.columnconfigure(0, weight=1) row = 0 f = Frame(library_tab) f.grid(row=row, columnspan=2, stick=E+W, padx=5, pady=5) row += 1 f.columnconfigure(1, weight=1) Label(f, text="iPhoto Library:").grid(sticky=E) iphoto_library_entry = Entry(f, textvariable=self.iphoto_library) iphoto_library_entry.grid(row=0, column=1, sticky=E+W) self.browse_library_button = Button(f, text="Browse...", command=self.browse_library) self.browse_library_button.grid(row=0, column=2) self.library_status = Label(f, textvariable=self.iphoto_library_status) self.library_status.grid(row=1, column=1, sticky=W) (cf, lf) = self._add_section(library_tab, "Events, Albums and Smart Albums", self.help_events) cf.grid(row=row, columnspan=2, stick=E+W) row += 1 lf.columnconfigure(1, weight=1) Label(lf, text="Events:").grid(sticky=E) events_entry = Entry(lf, textvariable=self.events) events_entry.grid(row=0, column=1, sticky=EW) Label(lf, text="Albums:").grid(sticky=E) albums_entry = Entry(lf, textvariable=self.albums) albums_entry.grid(row=1, column=1, sticky=EW) Label(lf, text="Smart Albums:").grid(sticky=E) smarts_entry = Entry(lf, textvariable=self.smarts) smarts_entry.grid(row=2, column=1, columnspan=3, sticky=EW) def _create_files_tab(self, files_tab): files_tab.columnconfigure(0, weight=1) # Export folder and options row = 0 (cf, lf) = self._add_section(files_tab, "Export Folder and Options", self.help_export) cf.grid(row=row, columnspan=2, stick=E+W) row += 1 lf.columnconfigure(1, weight=1) label = Label(lf, text="Export Folder:") label.grid(sticky=E) export_folder_entry = Entry(lf, textvariable=self.export_folder) export_folder_entry.grid(row=0, column=1, columnspan=2, sticky=E+W) Button(lf, text="Browse...", command=self.browse_export).grid(row=0, column=3) update_box = Checkbutton(lf, text="Overwrite changed pictures", var=self.update_var) update_box.grid(row=1, column=1, sticky=W) originals_box = Checkbutton(lf, text="Export originals", var=self.originals_var) originals_box.grid(row=2, column=1, sticky=W) hint_box = Checkbutton(lf, text="Use folder hints", var=self.folder_hints_var) hint_box.grid(row=3, column=1, sticky=W) delete_box = Checkbutton(lf, text="Delete obsolete pictures", var=self.delete_var) delete_box.grid(row=4, column=1, sticky=W) link_box = Checkbutton(lf, text="Use file links", var=self.link_var) link_box.grid(row=5, column=1, sticky=W) # Templates ---------------------------------------- (cf, lf) = self._add_section(files_tab, "Name Templates", self.help_templates) cf.grid(row=row, columnspan=2, stick=E+W) row += 1 lf.columnconfigure(1, weight=1) Label(lf, text="Folder names:").grid(sticky=E) foldertemplate_entry = Entry(lf, textvariable=self.foldertemplate) foldertemplate_entry.grid(row=0, column=1, sticky=EW) Label(lf, text="File names:").grid(sticky=E) nametemplate_entry = Entry(lf, textvariable=self.nametemplate) nametemplate_entry.grid(row=1, column=1, sticky=EW) Label(lf, text="Captions:").grid(sticky=E) captiontemplate_entry = Entry(lf, textvariable=self.captiontemplate) captiontemplate_entry.grid(row=2, column=1, sticky=EW) def _create_metadata_tab(self, metadata_tab): metadata_tab.columnconfigure(0, weight=1) row = 0 # Metadata -------------------------------------------- (cf, lf) = self._add_section(metadata_tab, "Metadata", self.help_metadata) cf.grid(row=row, columnspan=2, stick=E+W) row += 1 self.iptc_box = Checkbutton(lf, text=("Export metadata (descriptions, " "keywords, ratings, dates)"), var=self.iptc_var, state=DISABLED, command=self.change_iptc_box) self.iptc_box.grid(row=0, column=0, columnspan=2, sticky=W) self.iptc_all_box = Checkbutton(lf, text="Check previously exported images", var=self.iptc_all_var, command=self.change_metadata_box, state=DISABLED) self.iptc_all_box.grid(row=1, column=0, sticky=W) self.gps_box = Checkbutton(lf, text="Export GPS data", var=self.gps_var, command=self.change_metadata_box, state=DISABLED) self.gps_box.grid(row=2, column=0, sticky=W) # Faces --------------------------------------------------- (cf, lf) = self._add_section(metadata_tab, "Faces", self.help_faces) cf.grid(row=row, columnspan=2, stick=E+W) row += 1 lf.columnconfigure(2, weight=1) self.faces_box = Checkbutton(lf, text="Copy faces into metadata", var=self.faces_var, state=DISABLED, command=self.change_metadata_box) self.faces_box.grid(row=0, column=0, sticky=W) self.face_keywords_box = Checkbutton( lf, text="Copy face names into keywords", var=self.face_keywords_var, command=self.change_metadata_box, state=DISABLED) self.face_keywords_box.grid(row=1, column=0, sticky=W) checkbutton = Checkbutton(lf, text="Export faces into folders", var=self.face_albums_var) checkbutton.grid(row=2, column=0, sticky=W) label = Label(lf, text="Faces folder prefix:") label.grid(row=2, column=1, sticky=E) entry = Entry(lf, textvariable=self.face_albums_text) entry.grid(row=2, column=2, sticky=E+W) def create_widgets(self): """Builds the UI.""" self.columnconfigure(0, weight=1) n = Notebook(self) n.grid(row=0, sticky=E+W+N+S) library_tab = Frame(n) n.add(library_tab, text='Library') self._create_library_tab(library_tab) files_tab = Frame(n) n.add(files_tab, text='Files') self._create_files_tab(files_tab) metadata_tab = Frame(n) n.add(metadata_tab, text='Metadata') self._create_metadata_tab(metadata_tab) self._create_button_bar(self, 1) self.text = ScrolledText(self, borderwidth=4, relief=RIDGE, padx=4, pady=4) self.text.grid(row=2, column=0, sticky=E+W+N+S) self.rowconfigure(2, weight=1) def change_iptc_box(self): """Clears some options that depend on the metadata export option.""" mode = self.iptc_var.get() if not mode: self.faces_var.set(0) self.face_keywords_var.set(0) self.iptc_all_var.set(0) self.gps_var.set(0) def change_metadata_box(self): """Sets connected options if an option that needs meta data is changed. """ mode = (self.faces_var.get() or self.face_keywords_var.get() or self.iptc_all_var.get() or self.gps_var.get()) if mode: self.iptc_var.set(1) def help_events(self): HelpDialog(self, """Events, Albums and Smart Albums Selects which events, albums, or smart albums to export. Each field is a regular expression, and at least one must be filled in. Matches are done against the beginning of the event or album name. An entry in Events of Family will export all events that start with "Family", including "Family 2008" and "Family 2009". "|" separates alternate patterns, so Family|Travel will export all events that start with either "Family" or "Travel". "." matches any character, and therefore, . will export all events. To export all events with "2008" in the name, use .*2008 For more details on regular expressions, see http://en.wikipedia.org/wiki/Regular_expression""") def help_templates(self): HelpDialog(self, """Folder, file, and image caption templates. Templates are strings with place holders for values. The place holders have the format "{name}". Everything else in the template will be copied. Examples: {title} {yyyy}/{mm}/{dd} {title} - generates "2010/12/31 My Birthday" if the date of the pictures is Dec 31, 2010, and the title is "My Birthday". {yyyy} Event: {event} - generates "2010 Event: Birthday" for an event with any date in 2010 and the name "Birthday". Available place holders for folder names: {name} - name of the album or event. {hint} - folder hint (taken from line event or album description starting with @). {yyyy} - year of album or event date. {mm} - month of album or event date. {dd} - date of album or event date. Available place holders for file names: {album} - name of album (or in the case of an event, the name of the event). {index} - number of image in album, starting at 1. {index0} - number of image in album, padded with 0s, so that all numbers have the same length. {event} - name of the event. In the case of an album, the name of the event to which the image belongs. {event_index} - number of image in the event, starting at 1. If the case of an album, this number will be based on the event to which the image belongs. {event_index0} - same as {event_index}, but padded with leading 0s so that all values have the same length. {title} - image title. {yyyy} - year of image. {mm} - month of image (01 - 12). {dd} - day of image (01 - 31). If you are using {album}/{index}/{index0} place holders, the image will be named based on whatever album or event it is contained. That means an image in two albums will be exported with different names, even so the files are identical. If you want to use the same name for each image, regardless of which album it is in, use {event}, {event_index}, and {event_index0} instead. Available place holders for captions: {title} - image title. {description} - image description. {title_description} - concatenated image title and description, separated by a : if both are set. {yyyy} - year of image. {mm} - month of image (01 - 12). {dd} - day of image (01 - 31). """) def help_buttons(self): HelpDialog(self, """Export modes. Click on "Dry Run" to see what Phoshare would do without actually modifying any files. Click on "Export" to export your files using the current settings. All your settings will be saved when you click either Dry Run and Export, and re-loaded if you restart Phoshare. Check "Show debug output" to generate additional output message that can assist in debugging Phoshare problems. """) def help_export(self): HelpDialog(self, """Export Settings Export Folder: path to the folder for exporting images. Overwrite changed pictures: If set, pictures that already exist in the export folder will be overriden if an different version exist in iPhoto. Any edits made to previously exported images in the export folder will be lost! Use Dry Run to see which files would be overwritten. Export originals: If set, and an image has been modified in iPhoto, both the original and the edited version will be exported. The original will be stored in a sub-folder called "Originals". Use folder hints: By default, each exported event or album will become a folder in the export folder. With folder hints, a sub-folder name can be given in the event or album description by adding a line starting with a @ character. Example: Family Vacation @Vacation would export all images in that event into a sub-folder called "Vacation". Delete obsolete pictures: If set, any image, movie file or folder in the export folder that does not exist in the iPhoto library will be deleted. Use Dry Run to see which files would be deleted. Use file links: Don't copy images during export, but make a link to the files in the iPhoto library instead. This option is only available if the export folder is on the same drive as the iPhoto library. This option will save a lot of disk space because it avoids making copies of all your images and videos. Using this option causes the metadata of the images IN YOUR IPHOTO LIBRARY to be modified. While phoshare should not cause any problems to your images, it is best to use this option only if you have a backup of your iPhoto library, and you know how to restore your library from the backup. For more details on link mode, see https://sites.google.com/site/phosharedoc/Home#TOC-link-mode""") def help_faces(self): HelpDialog(self, """Faces options. Copy faces into metadata: faces tags and face regions will be copied into the image metadata using the Microsoft Photo Region Schema: http://msdn.microsoft.com/en-us/library/ee719905(VS.85).aspx Copy faces names into keywords: If set, face names will be merged into image keywords. Requires "Export metadata" checked. Export faces into folders: If checked, folders will be created for each face tag, each containing all the images tagged with that person. Faces folder prefix: If set, the string will be used as a prefix for the face export folders if "Exported faces into folders" is checked. This can be just a value like "Face: ", or a sub-folder name like "Faces/" if it ends with a "/" Metadata options will be disabled if exiftool is not available. """) def help_metadata(self): HelpDialog(self, """Metadata options. Export metadata: sets the description, keywords, rating and date metadata in the exported images to match the iPhoto settings. Check previously exported images: If not checked, metadata will only be set for new or updated images. If checked, metadata will be checked in all images, including ones that were previously exported. This is much slower. Export GPS data: export the GPS coordinates into the image metadata. Metadata options will be disabled if exiftool is not available.""") def check_iphoto_library(self): self.valid_library = False self.enable_buttons() self.iphoto_library_status.set("Checking library location...") self.launch_export("library") def set_library_status(self, good, message): if good: self.valid_library = True self.enable_buttons() self.iphoto_library_status.set(message) def write_progress(self, text): self.text.insert(END, text) self.text.see(END) def enable_buttons(self): if self.valid_library: self.dryrun_button.config(state=NORMAL) self.export_button.config(state=NORMAL) else: self.dryrun_button.config(state=DISABLED) self.export_button.config(state=DISABLED) self.browse_library_button.config(state=NORMAL) def browse_library(self): path = tkFileDialog.askopenfilename(title="Locate iPhoto Library") self.iphoto_library.set(path) self.check_iphoto_library() def browse_export(self): path = tkFileDialog.askdirectory(title="Locate Export Folder") self.export_folder.set(path) def do_export(self): if self.active_library: self.stop_thread() return if not self.can_export(): return self.export_button.config(text="Stop Export") self.dryrun_button.config(state=DISABLED) self.run_export(False) def do_dryrun(self): if self.active_library: self.stop_thread() return if not self.can_export(): return self.dryrun_button.config(text="Stop Dry Run") self.export_button.config(state=DISABLED) self.run_export(True) def stop_thread(self): if self.active_library: self.active_library.abort() def export_done(self): self.active_library = None self.dryrun_button.config(text="Dry Run") self.export_button.config(text="Export") self.enable_buttons() class Options(object): """Simple helper to create an object compatible with the OptionParser output in Phoshare.py.""" def __init__(self): self.iphoto = '~/Pictures/iPhoto Library' self.export = '~/Pictures/Album' self.albums = '' self.events = '.' self.smarts = '' self.ignore = [] self.delete = False self.update = False self.link = False self.dryrun = False self.folderhints = False self.captiontemplate = u'{description}' self.foldertemplate = u'{name}' self.nametemplate = u'{title}' self.aperture = False # TODO self.size = '' # TODO self.picasa = False # TODO self.movies = True # TODO self.originals = False self.iptc = 0 self.gps = False self.faces = False self.facealbums = False self.facealbum_prefix = '' self.face_keywords = False self.verbose = False def load(self): """Attempts to load saved options. Returns True if saved options were available.""" if not os.path.exists(_CONFIG_PATH): return False config = ConfigParser.SafeConfigParser() config.read(_CONFIG_PATH) s = 'Export1' if config.has_option(s, 'iphoto'): self.iphoto = config.get(s, 'iphoto') if config.has_option(s, 'export'): self.export = config.get(s, 'export') if config.has_option(s, 'albums'): self.albums = config.get(s, 'albums') if config.has_option(s, 'events'): self.events = config.get(s, 'events') if config.has_option(s, 'smarts'): self.smarts = config.get(s, 'smarts') if config.has_option(s, 'foldertemplate'): self.foldertemplate = config.get(s, 'foldertemplate') if config.has_option(s, 'nametemplate'): self.nametemplate = config.get(s, 'nametemplate') if config.has_option(s, 'captiontemplate'): self.captiontemplate = config.get(s, 'captiontemplate') if config.has_option(s, 'delete'): self.delete = config.getboolean(s, 'delete') if config.has_option(s, 'update'): self.update = config.getboolean(s, 'update') if config.has_option(s, 'link'): self.link = config.getboolean(s, 'link') if config.has_option(s, 'folderhints'): self.folderhints = config.getboolean(s, 'folderhints') if config.has_option(s, 'captiontemplate'): self.nametemplate = unicode(config.get(s, 'captiontemplate')) if config.has_option(s, 'nametemplate'): self.nametemplate = unicode(config.get(s, 'nametemplate')) if config.has_option(s, 'size'): self.size = config.get(s, 'size') if config.has_option(s, 'picasa'): self.picasa = config.getboolean(s, 'picasa') if config.has_option(s, 'movies'): self.movies = config.getboolean(s, 'movies') if config.has_option(s, 'originals'): self.originals = config.getboolean(s, 'originals') if config.has_option(s, 'iptc'): self.iptc = config.getint(s, 'iptc') if config.has_option(s, 'gps'): self.gps = config.getboolean(s, 'gps') if config.has_option(s, 'faces'): self.faces = config.getboolean(s, 'faces') if config.has_option(s, 'facealbums'): self.facealbums = config.getboolean(s, 'facealbums') if config.has_option(s, 'facealbum_prefix'): self.facealbum_prefix = config.get(s, 'facealbum_prefix') if config.has_option(s, 'face_keywords'): self.face_keywords = config.getboolean(s, 'face_keywords') return True def save(self): """Saves the current options into a file.""" config = ConfigParser.RawConfigParser() s = 'Export1' config.add_section(s) config.set(s, 'iphoto', self.iphoto) config.set(s, 'export', self.export) config.set(s, 'albums', su.fsenc(self.albums)) config.set(s, 'events', su.fsenc(self.events)) config.set(s, 'smarts', su.fsenc(self.smarts)) config.set(s, 'foldertemplate', su.fsenc(self.foldertemplate)) config.set(s, 'nametemplate', su.fsenc(self.nametemplate)) config.set(s, 'captiontemplate', su.fsenc(self.captiontemplate)) config.set(s, 'delete', self.delete) config.set(s, 'update', self.update) config.set(s, 'link', self.link) config.set(s, 'dryrun', self.dryrun) config.set(s, 'folderhints', self.folderhints) config.set(s, 'captiontemplate', self.captiontemplate) config.set(s, 'nametemplate', self.nametemplate) config.set(s, 'size', self.size) config.set(s, 'picasa', self.picasa) config.set(s, 'movies', self.movies) config.set(s, 'originals', self.originals) config.set(s, 'iptc', self.iptc) config.set(s, 'gps', self.gps) config.set(s, 'faces', self.faces) config.set(s, 'facealbums', self.facealbums) config.set(s, 'facealbum_prefix', self.facealbum_prefix) config.set(s, 'face_keywords', self.face_keywords) config_folder = os.path.split(_CONFIG_PATH)[0] if not os.path.exists(config_folder): os.makedirs(config_folder) configfile = open(_CONFIG_PATH, 'wb') config.write(configfile) configfile.close() def can_export(self): if (not self.albums.get() and not self.events.get() and not self.smarts.get()): tkMessageBox.showerror( "Export Error", ("Need to specify at least one event, album, or smart album " "for exporting.")) return False return True def run_export(self, dry_run): mode = "export" if dry_run: mode = "dry_run" self.launch_export(mode) def launch_export(self, mode): """Launch an export operation in a new thread, to not block the UI. Args: mode - name of operation to run, "library", "dry_run", or "export". """ self.text.delete('1.0', END) self.browse_library_button.config(state=DISABLED) export_thread = threading.Thread(target=self.export_thread, args=(mode,)) export_thread.start() def export_thread(self, mode): """Run an export operation in a thread, to not block the UI. Args: mode - name of operation to run, "library", "dry_run", or "export". """ try: # First, load the iPhoto library. library_path = su.expand_home_folder(self.iphoto_library.get()) album_xml_file = iphotodata.get_album_xmlfile(library_path) data = iphotodata.get_iphoto_data(album_xml_file) msg = "Version %s library with %d images" % ( data.applicationVersion, len(data.images)) self.write(msg + '\n') if mode == "library": # If we just need to check the library, we are done here. self.thread_queue.put(("done", (True, mode, msg))) return # Do the actual export. export_folder = su.expand_home_folder(self.export_folder.get()) args = ['Phoshare.py', '--export', '"' + export_folder + '"'] options = self.Options() options.iphoto = self.iphoto_library.get() args.extend(['--iphoto', '"' + options.iphoto + '"']) options.export = self.export_folder.get() options.dryrun = mode == "dry_run" options.albums = self.albums.get() if options.albums: args.extend(['--albums', '"' + options.albums + '"']) options.events = self.events.get() if options.events: args.extend(['--events', '"' + options.events + '"']) options.smarts = self.smarts.get() if options.smarts: args.extend(['--smarts', '"' + options.smarts + '"']) options.foldertemplate = unicode(self.foldertemplate.get()) if options.foldertemplate: args.extend(['--foldertemplate', '"' + options.foldertemplate + '"']) options.nametemplate = unicode(self.nametemplate.get()) if options.nametemplate: args.extend(['--nametemplate', '"' + options.nametemplate + '"']) options.captiontemplate = unicode(self.captiontemplate.get()) if options.captiontemplate: args.extend(['--captiontemplate', '"' + options.captiontemplate + '"']) options.ignore = [] # TODO options.update = self.update_var.get() == 1 if options.update: args.append('--update') options.delete = self.delete_var.get() == 1 if options.delete: args.append('--delete') options.originals = self.originals_var.get() == 1 if options.originals: args.append('--originals') options.link = self.link_var.get() == 1 if options.link: args.append('--link') options.folderhints = self.folder_hints_var.get() == 1 if options.folderhints: args.append('--folderhints') options.faces = self.faces_var.get() == 1 if options.faces: args.append('--faces') options.face_keywords = self.face_keywords_var.get() == 1 if options.face_keywords: args.append('--face_keywords') if self.iptc_all_var.get() == 1: options.iptc = 2 args.append('--iptcall') elif self.iptc_var.get() == 1: options.iptc = 1 args.append('--iptc') else: options.iptc = 0 options.gps = self.gps_var.get() if options.gps: args.append('--gps') options.facealbums = self.face_albums_var.get() == 1 if options.facealbums: args.append('--facealbums') options.facealbum_prefix = self.face_albums_text.get() if options.facealbum_prefix: args.append('--facealbum_prefix') exclude = None # TODO options.save() print " ".join(args) self.logging_handler.setLevel(logging.DEBUG if self.verbose_var.get() else logging.INFO) self.active_library = phoshare_main.ExportLibrary(export_folder) phoshare_main.export_iphoto(self.active_library, data, exclude, options) self.thread_queue.put(("done", (True, mode, ''))) except Exception, e: # IGNORE:W0703 self.thread_queue.put(("done", (False, mode, str(e) + '\n\n' + traceback.format_exc())))
class LoggerDialog(Toplevel): def __init__(self, master, customers, payments, refresh): Toplevel.__init__(self,master) self.root = master self.refresh = refresh self.title("Check In") self.iconname = "Check In" self.name = StringVar() # variable for customer self.customers = customers # customers object self.payments = payments self.names = [] self.workout = StringVar() self.workouts = [] self.workouts_form = [] self.date = StringVar() self.date.set(strftime("%m/%d/%Y")) self.refresh_time = 15 # in minutes self.output = '' # for the output label at the bottom self.schedule = Schedule() self.logger = Logger() #throws IOError if file is open inf = Frame(self) inf.pack(padx=10,pady=10,side='top') Label(inf, text="Name:").grid(row=0,column=0,sticky=E,ipady=2,pady=2,padx=10) Label(inf, text='Date:').grid(row=1,column=0,sticky=E,ipady=2,pady=2,padx=10) Label(inf, text="Workout:").grid(row=2,column=0,sticky=E,ipady=2,pady=2,padx=10) self.name_cb = Combobox(inf, textvariable=self.name, width=30, values=self.names) self.name_cb.grid(row=0,column=1,sticky=W,columnspan=2) self.date_ent = Entry(inf, textvariable=self.date) self.date_ent.grid(row=1,column=1,sticky=W) self.date_ent.bind('<FocusOut>', self.update_workouts) Button(inf,text='Edit', command=self.enable_date_ent).grid(row=1,column=2,sticky=E) self.workout_cb = Combobox(inf, textvariable=self.workout, width=30, values=self.workouts_form,state='readonly') self.workout_cb.grid(row=2,column=1,sticky=W,columnspan=2) self.log_btn=Button(inf,text="Log Workout",command=self.log,width=12) self.log_btn.grid(row=3,column=1,columnspan=2,pady=4,sticky='ew') stf = Frame(self) stf.pack(padx=10,pady=10,fill='x',side='top') self.scrolled_text = ScrolledText(stf,height=15,width=50,wrap='word',state='disabled') self.scrolled_text.pack(expand=True,fill='both') self.update_workouts() self.update_names() self.bind('<Return>',self.log) self.name_cb.focus_set() # set the focus here when created #disable the date field self.disable_date_ent() #start time caller self.time_caller() def output_text(self,outstr): self.scrolled_text['state'] = 'normal' self.scrolled_text.insert('end',outstr) self.scrolled_text.see('end') self.scrolled_text['state'] = 'disabled' def log(self, e=None): #check to see if name is blank logged = False if self.name.get() == '': self.output_text("! - Please select your name.\n") elif self.workout.get() not in self.workouts_form: self.output_text("! - Select valid workout.\n") elif self.name.get() not in self.names: # new customer self.new_customer_error() else: # log the workout name = self.name.get().split(' ',2) (line, r) = self.customers.find(name[2],name[0],name[1]) name_str = str(self.name.get()) date = datetime.strptime(str(self.date.get()),'%m/%d/%Y') if not line: self.output_text("!! - No record: " + self.name.get() + ".\n") while (not logged): try: self.logger.log(self.workouts[self.workout_cb.current()][0], self.workouts[self.workout_cb.current()][1], name_str, day=date) logged = True except IOError: showerror("Error writting to file", "Please close " + self.logger.filename + " and press OK.") if logged: self.output_text(self.name.get() + " - " + line[3] + "\n") logged_payment = False while(not logged_payment): try: if line[3] == 'Monthly': payment_due = self.payments.next_payment_due(name_str) if payment_due < datetime.today(): self.output_text("$ - Please pay your monthly dues.\n") else: self.output_text("$ - Next payment due: " + payment_due.strftime("%B %d, %Y\n")) elif line[3] == 'Punch Card': punch = self.payments.punch(name_str) if punch == 0: self.output_text("$ - Last punch on card, please purchase another.\n") elif not punch: self.output_text("$ - Please purchase another punch card.\n") else: self.output_text("$ - You have " + str(punch) + " remaining workouts on your card.\n") elif line[3] == 'Drop In': self.payments.drop_in(name_str, date) self.output_text("$ - Drop In payment logged.\n") logged_payment = True except IOError: # this is bad, you logged a workout and you failed to log payment showerror("Error writting to file", "Please close " + self.payments.filename + " and press OK.") else: #exception not raised try: #accessing log file here workout_count = str(workouts_this_month(name_str,self.logger.filename,date.strftime("%B"))) self.output_text("Workouts you've completed this month: " + workout_count + "\n") except IOError: showerror("Error reading from file", "Please close " + self.logger.filename + " and press OK.") self.refresh() def new_customer_error(self): self.ncd = NewCustomerDialog(self,self.customers,self.refresh) if askquestion(title="New Customer?", message="Add new customer: " + self.name.get(), parent = self) == 'yes': temp = self.name.get().split(' ') self.ncd.fname.set(temp[0]) if len(temp) == 2: self.ncd.lname.set(temp[1]) elif len(temp) == 3: self.ncd.mname.set(temp[1]) self.ncd.lname.set(temp[2]) elif len(temp) > 3: self.ncd.mname.set(temp[1]) self.ncd.lname.set(' '.join(temp[2:4])) self.ncd.show() if self.ncd.new_customer_name: self.add_name(self.ncd.new_customer_name) self.output_text("+ - " + self.ncd.new_customer_name + " added.\n") def disable_date_ent(self, e=None): self.date_ent['state'] = 'disabled' def enable_date_ent(self, e=None): self.date_ent['state'] = 'normal' def time_caller(self): #updates every 15 min automatically msec = self.refresh_time * 6000 self.update_time_now() #update time to current time self.set_workout_now() self.update_workouts() #update the workouts self.after(msec, self.time_caller) #call again def update_time_now(self): self.enable_date_ent() self.date.set(strftime("%m/%d/%Y")) def set_workout_now(self): #set workout field if len(self.workouts) == 0: self.disable_date_ent() return #no workouts index = 0 now = datetime.today() for i, workout in enumerate(self.workouts): test = datetime.combine(date.today(),workout[0]) if now < (test - timedelta(minutes=15)): index = i break self.workout_cb.current(index) self.disable_date_ent() def update_workouts(self, e=None): try: self.populate_workouts() self.workout_cb['values'] = self.workouts_form except ValueError: self.workout.set(' Enter Valid Date ') if len(self.workouts) > 0 and e: self.workout_cb.current(0) def populate_workouts(self): today = datetime.strptime(str(self.date.get()), "%m/%d/%Y") #get date dow = self.schedule.weekday_to_str(today.weekday()) #get dow string self.workouts = self.schedule.get_wkday(dow) self.workouts_form = [] for w in self.workouts: self.workouts_form.append(w[0].strftime("%H:%M") + ' - ' + w[1]) if len(self.workouts) == 0: self.workout.set(' No workouts today ') def update_names(self): self.populate_names() if len(self.names) == 0: self.names = [''] self.name_cb['values'] = self.names self.name_cb.set(' ') def add_name(self, name): self.names.append(name) split_names = [x.split(' ') for x in self.names] split_names.sort(key = lambda x: ' '.join([x[2],x[0],x[1]])) self.names = [' '.join(x) for x in split_names] self.name_cb['values'] = self.names self.name.set(name) def populate_names(self): try: clist = self.customers.get_list() except IOError: self.output_text("! - " + self.customers.filename + " open in another application.\n") return clist.sort(key = lambda x: ', '.join(x[0:3]).lower()) self.names = [] for line in clist: self.names.append(' '.join([line[1],line[2],line[0]])) def find_line(self, name): [fname, mname, lname] = name.split(' ') try: return self.customers.find(lname, fname, mname) except IOError: self.output_text("! - " + self.customers.filename + " open in another application.\n") return None
class Dialog(ui.Dialog): def __init__(self, frame=None): self.parent_frame = frame # set the parent frame self.confirm_frame = None self.make_change = False self.new_line = u"" self.status_text = u"" self.make_silent = False self.cancel = False # set screen position... x = 0 y = 0 ##x = config.get('status_x',0) ##y = config.get('status_y',0) ##if x and y: ## self.parent_frame.geometry("+%d+%d" % (int(x),int(y))) # create a status message widget and bind it to the parent... # self.status_text = ScrolledText(self.parent_frame, height=20, width=80, state=DISABLED) # self.status_text.pack() self.status_text = ScrolledText(self.parent_frame, wrap=WORD, pady=2, padx=3, state=DISABLED) self.status_text.pack(fill=BOTH, expand=Y) self.parent_frame.protocol("WM_DELETE_WINDOW", self.destroy) self.parent_frame.bind("<Escape>", self.destroy) self.parent_frame.bind("<Configure>", self.save_pos) self.status_text.update() def confirm_change(self, old_line, new_line, old_tuple=(), new_tuple=(), filepath=""): self.confirm_frame = Tkinter.Toplevel(self.parent_frame, padx=10, pady=10) # self.confirm_frame.grid(padx=10,pady=10) self.confirm_frame.protocol("WM_DELETE_WINDOW", self.confirm_decline) # set screen position... ##x = config.get('dialog_x', (self.parent_frame.winfo_rootx() + 50)) ##y = config.get('dialog_y', (self.parent_frame.winfo_rooty() + 50)) x = self.parent_frame.winfo_rootx() + 50 y = self.parent_frame.winfo_rooty() + 50 if x and y: self.confirm_frame.geometry("+%s+%s" % (x, y)) # bind enter to ok and escape to cancel buttons... self.confirm_frame.bind("<Return>", self.confirm_accept) self.confirm_frame.bind("<Escape>", self.confirm_decline) self.confirm_frame.bind("<Configure>", self.save_pos) # make the new dialog a part of the parent... self.confirm_frame.transient(self.parent_frame) # focus onto the dialog... self.confirm_frame.focus_set() label = Tkinter.Label(self.confirm_frame, text=filepath) label.pack() label = Tkinter.Label(self.confirm_frame, text="Change:") # label.grid(row=row_i, column=0, sticky=W) label.pack() # entry = Tkinter.Text(self.confirm_frame, width=75, height=5) # entry = ScrolledText(self.confirm_frame, width=75, height=5) entry = ScrolledText(self.confirm_frame, height=5, wrap=WORD, pady=2, padx=3) entry.insert(Tkinter.INSERT, old_line.encode("utf-8")) # highlight the text to be changed... if len(old_tuple) == 2: entry.tag_add("found", "1.%s" % (old_tuple[0]), "1.%s+%sc" % (old_tuple[0], old_tuple[1] - old_tuple[0])) entry.tag_config("found", foreground="red") entry.config(state=DISABLED) entry.pack(fill=BOTH, expand=Y) label = Tkinter.Label(self.confirm_frame, text="To:") label.pack() self.new_entry = ScrolledText(self.confirm_frame, height=5, wrap=WORD, pady=2, padx=3) self.new_entry.insert(Tkinter.INSERT, new_line.encode("utf-8")) # highlight the text to be changed... if len(new_tuple) == 2: self.new_entry.tag_add( "found", "1.%s" % (new_tuple[0]), "1.%s+%sc" % (new_tuple[0], new_tuple[1] - new_tuple[0]) ) self.new_entry.tag_config("found", foreground="red") self.new_entry.config(state=DISABLED) self.new_entry.pack(fill=BOTH, expand=Y) btnDisplay = Tkinter.Button(self.confirm_frame, text="Yes", command=self.confirm_accept, default=ACTIVE) # btnDisplay.grid(row=row_i, column=0) btnDisplay.pack(side=LEFT, padx=5, pady=5) btnDisplay = Tkinter.Button(self.confirm_frame, text="No", command=self.confirm_decline) # btnDisplay.grid(row=row_i, column=1) btnDisplay.pack(side=LEFT, padx=5, pady=5) btnDisplay = Tkinter.Button(self.confirm_frame, text="Cancel", command=self.confirm_cancel) # btnDisplay.grid(row=row_i, column=1) btnDisplay.pack(side=LEFT, padx=5, pady=5) btnDisplay = Tkinter.Button(self.confirm_frame, text="Yes to All", command=self.confirm_silence) # btnDisplay.grid(row=row_i, column=1) btnDisplay.pack(side=LEFT, padx=5, pady=5) self.confirm_frame.update() try: self.parent_frame.wait_window(self.confirm_frame) except Tkinter.TclError: # sometimes the wait_window fails, I'm not sure why, but it seems to be # safe to just ignore it *shrug* pass self.confirm_frame = None def confirm_silence(self): self.make_change = True self.make_silent = True self.clean_up() def confirm_cancel(self): self.make_change = False self.cancel = True self.clean_up() def confirm_accept(self): # self.new_line = self.new_entry.get(1.0, END) self.make_change = True self.clean_up() def confirm_decline(self): self.make_change = False self.clean_up() def clean_up(self, event=None): self.save_pos() # print self.screen_pos_x,self.screen_pos_y self.parent_frame.focus_set() self.confirm_frame.destroy() def destroy(self, event=None): self.parent_frame.destroy() def save_pos(self, event=None): return ## save the screen position of the dialog box # if self.confirm_frame: # try: # config.add('dialog_x',(self.confirm_frame.winfo_rootx() - 4)) # config.add('dialog_y',(self.confirm_frame.winfo_rooty() - 30)) # except: # pass ## save the status box's position # if self.parent_frame: # try: # config.add('status_x',self.parent_frame.winfo_rootx() - 4) # config.add('status_y',self.parent_frame.winfo_rooty() - 30) # except: # pass def update(self, msg): # if the window no longer exists, its text can't be updated try: self.status_text.config(state=NORMAL) # Add the new message self.status_text.insert(END, msg.encode("utf-8") + os.linesep) # Scroll down to the bottom again self.status_text.see(END) # Make the display uneditable self.status_text.config(state=DISABLED) self.status_text.update() except: pass
class LogHandler(object): ''' Logging and warnings ''' def __init__(self, app): self.app = app self.enabled = True # enabling or disabling logging # get package loggers self.loggers = [] self.pkgName = __name__.split('.')[0] for name in logging.Logger.manager.loggerDict.keys(): if self.pkgName in name: self.loggers.append(logging.getLogger(name)) self.font = tkFont.Font(family='Courier New', size=12) # make text for normal logs self.logFrame = tk.Frame(self.app.root) self.logScroll = ScrolledText(self.app.root, bd=0, highlightthickness=0, font=self.font, bg=COL_PRIM, fg=COL_HL, width=80) self.logScroll.pack(side=tk.RIGHT, fill=tk.Y) # make warning panel self.alert = tk.Label(self.app.graphEditor.bg, cursor='X_cursor', font=self.font, bg=COL_HL, fg=COL_BG) self.alert.bind('<Button-1>', lambda _: self.resetWarning()) self.alert.pack(side=tk.TOP) self.alert.pack_forget() # initially not visible self.enableLog(False) # initially, disable normal logs def enableLog(self, enable): ''' Enables/Disables logging and shows/hides the log scroll ''' self.enabled = enable if enable: # slow, but comprehensive logging self.logScroll.pack(side=tk.RIGHT, fill=tk.Y) self.setLogLevel(logging.DEBUG) else: # only alerts can occur now self.clear() self.logScroll.pack_forget() self.setLogLevel(logging.WARNING) def setLogLevel(self, level): ''' Sets all package related loggers to a new level. This results in better performance, but other log handlers won't see messages below level too of course. ''' for logger in self.loggers: logger.setLevel(level) def warn(self, warning): ''' Shows a warning ''' # append linefeed to current text curText = self.alert.cget('text') if curText and not curText.endswith('\n'): curText += '\n' # add warning to current text and show self.alert.config(text=curText + warning) self.alert.pack() def resetWarning(self): ''' Resets the warnings in the alert panel ''' self.alert.config(text='') self.alert.pack_forget() def write(self, msg): ''' This method is called from the logging module for each message ''' if any(lvl in msg for lvl in ('WARNING', 'ERROR', 'CRITICAL')): # user needs attention self.warn(msg) if self.enabled: # normal logging self.logScroll.insert(tk.END, msg) def flush(self): ''' This method might be called from the logging module ''' pass def tail(self): ''' Scrolls down to the last messages ''' if self.enabled: self.logScroll.see(tk.END) # super useful but super slow def clear(self): self.logScroll.delete(1.0, tk.END)
class MyThing (Frame): def __init__(self, master=None): Frame.__init__(self, master) self.pack() self.createWidgets() def createWidgets(self): self.textBox = ScrolledText(self, height=30, width=85) self.textBox.pack() self.addText() def leftMouseClick(self,event): print "got a click" mouseIndex = "@%d,%d" % (event.x, event.y) current = self.textBox.index(mouseIndex) row = current.split(".")[0] + ".0" rowFl = float(row)+1.0 row = str(rowFl) target = self.rowIndex[row] target = float(target)+12.0 target = str(target) print "moving to target",target self.textBox.see(target) def rightMouseClick(self,event): self.textBox.see("0.0") def addText(self): f=open("help.txt",'r') lines = f.readlines() f.close() flag = 1 i=0 sectionOrder = {} sectionHeads = {} outlines = {} targetId = 0 defaultTarget = "" tocEntries = [] lineId=0 for line in lines: if line[0:1] =="#": tocEntries.append(line) if flag: top = lineId flag = 0 lineId+=1 self.tocEntries = tocEntries # header text header = lines[0:top] for line in header: hid=self.textBox.insert(END,line,"header") self.textBox.tag_config("header",foreground=FGCOLOR) self.textBox.tag_config("header",background=BGCOLOR) self.textBox.insert(END,"Table of Contents\n","toc") self.textBox.tag_config("toc",foreground="red") self.textBox.tag_config("toc",background=BGCOLOR) self.textBox.insert(END, "(Left-click entry to navigate, right-click to return)\n\n","directions") self.textBox.tag_config("directions",background=BGCOLOR) self.textBox.tag_config("directions",foreground="purple") sectionDict = {} rowIndex = {} for tocEntry in tocEntries: if tocEntry[0:2] == "##": line = "\t"+tocEntry[2:] else: line = tocEntry[1:] rowPosition = self.textBox.index(END).split(".")[0] + ".0" rowIndex[rowPosition] = "0.0" sectionDict[tocEntry] = rowPosition self.textBox.insert(END,line,"tocEntry") self.textBox.tag_bind("tocEntry",'<ButtonRelease-1>', self.leftMouseClick) self.textBox.tag_config("tocEntry",background=BGCOLOR) self.textBox.tag_config("tocEntry",foreground=hfg) for i in range(50): self.textBox.insert(END,"\n","regular") lines = lines[top:] for line in lines: if sectionDict.has_key(line): print "section id",line position = self.textBox.index(END) tocPosition = sectionDict[line] rowIndex[tocPosition] = position line = line.replace("#","") self.textBox.insert(END,line,"regular") self.rowIndex = rowIndex self.sectionDict = sectionDict self.textBox.see("0.0") self.textBox.bind_all('<ButtonRelease-3>', self.rightMouseClick) self.textBox.tag_config("regular",background=BGCOLOR) self.textBox.tag_config("regular",foreground="black")
class GUI_hcheck: # do everything! def __init__(self): self.top = Tk() self.top.title('Health Check Tool') self.top.geometry('1400x800') #------- Label,Entry defination ----------# self.l1 = Label(self.top, text="IP:").grid(row=1, column=1, sticky="w") self.e1 = Entry(self.top) self.e1.grid(row=1, column=2,sticky="ew") self.l2 = Label(self.top, text="User:"******"w") self.e2 = Entry(self.top) self.e2.grid(row=2, column=2,sticky="ew") self.l3 = Label(self.top, text="Passwd:").grid(row=3, column=1, sticky="w") self.e3 = Entry(self.top) self.e3['show'] = '*' self.e3.grid(row=3, column=2,sticky="ew") self.l4 = Label(self.top, text="Command pool:").grid(row=4, column=1, sticky="e") self.l5 = Label(self.top, text="To be run command:").grid(row=4, column=5, sticky="e") self.e4 = Entry(self.top, width=30) self.e4.grid(row=16, column=0, columnspan=3, sticky="ew") #------- Checkbutton defination ----------# self.cb1State = IntVar() self.cb1 = Checkbutton(self.top, variable=self.cb1State, text = "Always Yes", command=self.callCheckbutton) self.cb1.grid(row=21, column=16) #------- Listbox defination ----------# self.cmdfm = Frame(self.top) self.cmdsb = Scrollbar(self.cmdfm) self.cmdsb_x = Scrollbar(self.cmdfm,orient = HORIZONTAL) self.cmdsb.pack(side=RIGHT, fill=Y) self.cmdsb_x.pack(side=BOTTOM, fill=X) self.cmdls = Listbox(self.cmdfm, selectmode=EXTENDED, height=25, width=40, xscrollcommand=self.cmdsb_x.set, yscrollcommand=self.cmdsb.set) self.cmdsb.config(command=self.cmdls.yview) self.cmdsb_x.config(command=self.cmdls.xview) self.cmdls.pack(side=LEFT, fill=BOTH) self.cmdfm.grid(row=5, rowspan=10, column=0,columnspan=4,sticky="ew") self.db_file = os.path.join(os.getcwd(),'%s' % constants.DB_NAME) flist = utility.load_file(self.db_file) if flist != None: log.debug ("db file found, start load command") for element in flist: element = element.strip('\n') if element == '' or element.startswith('#'): continue self.cmdls.insert(END, element) else: log.debug ("db file doesn't existed, initail cmd") for element in constants.CMD_LIST_COMM: self.cmdls.insert(END, element) self.dirfm = Frame(self.top) self.dirsb = Scrollbar(self.dirfm) self.dirsb_x = Scrollbar(self.dirfm,orient = HORIZONTAL) self.dirsb.pack(side=RIGHT, fill=Y) self.dirsb_x.pack(side=BOTTOM, fill=X) self.dirs = Listbox(self.dirfm, selectmode=EXTENDED, height=25, width=40, xscrollcommand=self.dirsb_x.set,yscrollcommand=self.dirsb.set) self.dirsb.config(command=self.dirs.yview) self.dirsb_x.config(command=self.dirs.xview) self.dirs.pack(side=LEFT, fill=BOTH) self.dirfm.grid(row=5, rowspan=10, column=5,columnspan=4,sticky="ew") #------- Buttion defination ----------# # add command button self.b1 = Button(self.top,text=">>",width=6,borderwidth=3,relief=RAISED, command=self.move_cmd) self.b1.grid(row=7, column=4) # del command button self.b2 = Button(self.top,text="<<",width=6,borderwidth=3,relief=RAISED, command=self.del_cmd) self.b2.grid(row=8, column=4) # move up command button self.b3 = Button(self.top,text="up",width=6,borderwidth=3,relief=RAISED, command=self.up_cmd) self.b3.grid(row=7, column=10) # move down command button self.b4 = Button(self.top,text="down",width=6,borderwidth=3,relief=RAISED, command=self.down_cmd) self.b4.grid(row=8, column=10) # start command button self.b5 = Button(self.top,text="Start",bg='red',width=10,borderwidth=3,relief=RAISED, command=self.start_process) self.b5.grid(row=2, column=11) # yes button self.b6 = Button(self.top,text="Yes",width=6,borderwidth=3,relief=RAISED, command=self.set_confirm_yes) self.b6.grid(row=21, column=13) # No button self.b7 = Button(self.top,text="No",width=6,borderwidth=3,relief=RAISED, command=self.set_confirm_no) self.b7.grid(row=21, column=14) # Skip button self.b8 = Button(self.top,text="Skip",width=6,borderwidth=3,relief=RAISED, command=self.set_confirm_skip) self.b8.grid(row=21, column=15) # Add button self.b9 = Button(self.top,text="add cmd",width=10,borderwidth=3,relief=RAISED, command=self.add_command) self.b9.grid(row=15, column=1) # Del button self.b10 = Button(self.top,text="del cmd",width=10,borderwidth=3,relief=RAISED, command=self.del_command) self.b10.grid(row=15, column=2) # Manual button self.manual = False self.b11 = Button(self.top,text="Manual model",width=10,borderwidth=3,relief=RAISED, command=self.manual_mode) self.b11.grid(row=2, column=12) #------- ScrolledText defination ----------# self.sfm = Frame(self.top) self.console = ScrolledText(self.sfm,height=45, width=86,bg='black',fg='green',insertbackground='green') self.console['font'] = ('lucida console','10') self.console.bind("<Return>", self.process_input) self.console.pack() self.sfm.grid(row=4, rowspan=15, column=11,columnspan=10,sticky="ew") self.redir = redirect(self.console) sys.stdout = self.redir sys.stderr = self.redir self.fconsole = logging.StreamHandler(sys.stdout) self.fconsole.setLevel(logging.INFO) logging.getLogger('').addHandler(self.fconsole) #------- Menu defination ----------# self.menubar = Menu() # file menu self.fmenu = Menu() #self.fmenu.add_command(label = 'New',command=self.new_win) self.fmenu.add_command(label = 'Import cmd',command=self.load_cmd) self.fmenu.add_command(label = 'Export cmd',command=self.export_cmd) self.menubar.add_cascade(label = 'File', menu = self.fmenu) # edit menu self.emenu = Menu() self.cmenu = Menu() self.cvar = StringVar() for item in ['white/black', 'black/white', 'green/black']: self.cmenu.add_radiobutton(label = item, variable=self.cvar, value=item, command=self.sel_color_style) self.emenu.add_cascade(label = 'console style', menu = self.cmenu) self.emenu.add_command(label = 'reset cmd pool',command=self.reset_cmd_pool) self.menubar.add_cascade(label = 'Edit', menu = self.emenu) self.top['menu'] = self.menubar def new_win(self): #GUI_hcheck() pass def sel_color_style(self): log.debug ("select console color style: %s " % self.cvar.get()) color = self.cvar.get() if color == 'white/black': self.console.config(bg='black',fg='white',insertbackground='white') elif color == 'black/white': self.console.config(bg='white',fg='black',insertbackground='black') elif color == 'green/black': self.console.config(bg='black',fg='green',insertbackground='green') def move_cmd(self): if self.cmdls.curselection() != (): for i in self.cmdls.curselection(): if utility.elemet_exists(self.dirs.get(0,END), self.cmdls.get(i)) == None: self.dirs.insert(END,self.cmdls.get(i)) log.debug ("move command %s" % self.cmdls.get(i)) else: tkMessageBox.showwarning('Message', 'Please select at lease one item') def load_cmd(self): file = tkFileDialog.askopenfilename() flist = utility.load_file(file) if flist != None: self.dirs.delete(0,END) for element in flist: element = element.strip('\n') if element == '' or element.startswith('#'): continue if utility.elemet_exists(self.dirs.get(0,END), element) == None: self.dirs.insert(END, element) else: tkMessageBox.showerror('Message', 'import failed') def export_cmd(self): file = tkFileDialog.askopenfilename() if utility.export_file(self.dirs.get(0,END), file) == True: tkMessageBox.showinfo('Message', 'export finish') else: tkMessageBox.showerror('Message', 'export failed') def del_cmd(self): if self.dirs.curselection() != (): for i in self.dirs.curselection(): self.dirs.delete(i) else: tkMessageBox.showwarning('Message', 'Please select at lease one item') def up_cmd(self): select = self.dirs.curselection() if (len(select)) >= 2: tkMessageBox.showwarning('Message', 'Only one select is supported') return log.debug ("move up select pos: %s" % str(select)) if select != () and select != (0,): element = self.dirs.get(select) self.dirs.delete(select) self.dirs.insert((select[0] - 1), element) self.dirs.select_set(select[0] - 1) def down_cmd(self): select = self.dirs.curselection() if (len(select)) >= 2: tkMessageBox.showwarning('Message', 'Only one select is supported') return log.debug ("move down select pos: %s" % str(select)) if select != () and select != (END,): element = self.dirs.get(select) self.dirs.delete(select) self.dirs.insert((select[0] + 1), element) self.dirs.select_set(select[0] + 1) def start_process(self): log.debug ("current thread total numbers: %d" % threading.activeCount()) response = tkMessageBox.askokcancel('Message', 'Will start healthcheck, please click OK to continue, or cancel') if response == False: return th = threading.Thread(target=self.start_cmd) th.setDaemon(True) th.start() def start_cmd(self): self.manual = False cmd = list(self.dirs.get(0,END)) if len(cmd) == 0: log.info ("To be run cmd numbers none, quit...") return log.debug ("fetch cmd list from GUI: %s" % cmd) (ip, port) = utility.getipinfo(self.e1.get()) log.debug ("get ip infor-> ip: %s, port:%s" % (ip,port)) if ip == False: log.error ("Given ip infor is wrong! The right ip address: xxx.xxx.xxx.xxx or IP:port ") return self.b5.config(state=DISABLED) self.b11.config(state=DISABLED) self.console.delete('1.0',END) try: self.wf = Workflow(cmd, ip, self.e2.get(), self.e3.get(), port) self.wf.start() except: pass self.b5.config(state=NORMAL) self.b11.config(state=NORMAL) def manual_mode(self): cmd = [] (ip, port) = utility.getipinfo(self.e1.get()) log.debug ("get ip infor-> ip: %s, port:%s" % (ip,port)) if ip == False: log.error ("Given ip infor is wrong! The right ip address: xxx.xxx.xxx.xxx or IP:port ") return self.wf_manual = Workflow(cmd, ip, self.e2.get(), self.e3.get(), port) if self.wf_manual.setup_ssh(self.wf_manual.hostip) == False: log.error ("\nssh setup error! please check ip/user/passwd and network is okay") del self.wf_manual return self.console.delete('1.0',END) self.console.insert(END, "Switch to manual mode...\n\ Please input command directly after \">>> \"\n\n") self.prompt = ">>> " self.insert_prompt() self.manual = True self.b5.config(state=DISABLED) self.b11.config(state=DISABLED) def set_confirm_yes(self): try: self.wf.set_confirm('Yes') except AttributeError: log.debug("wf doesn't existed") def set_confirm_no(self): try: self.wf.set_confirm('No') except AttributeError: log.debug("wf doesn't existed") def set_confirm_skip(self): try: self.wf.set_confirm('Skip') except AttributeError: log.debug("wf doesn't existed") def callCheckbutton(self): try: if self.cb1State.get() == 1: self.wf.set_automatic(5) else: self.wf.set_automatic(None) except AttributeError: log.debug("wf doesn't existed") self.cb1.deselect() tkMessageBox.showwarning('Message', 'please press start button first') def saveinfo(self): pass def add_command(self): item = self.e4.get() if item != '': if utility.elemet_exists(self.cmdls.get(0,END), item) == None: self.cmdls.insert(END,item) self.cmdls.see(END) log.debug ("add new command %s" % item) self.save_command() else: tkMessageBox.showwarning('Message', 'entry can not empty') def del_command(self): if self.cmdls.curselection() != (): for i in self.cmdls.curselection(): self.cmdls.delete(i) self.save_command() else: tkMessageBox.showwarning('Message', 'Please select at lease one item') def save_command(self): if utility.export_file(self.cmdls.get(0,END), self.db_file) != True: log.error ("save command pool failed") def reset_cmd_pool(self): log.debug ("start to reset command pool list") self.cmdls.delete(0,END) for element in constants.CMD_LIST_COMM: self.cmdls.insert(END, element) self.save_command() def insert_prompt(self): c = self.console.get("end-2c") if c != "\n": self.console.insert("end", "\n") self.console.insert("end", self.prompt, ("prompt",)) #self.text.insert("end", self.prompt) # this mark lets us find the end of the prompt, and thus # the beggining of the user input self.console.mark_set("end-of-prompt", "end-1c") self.console.mark_gravity("end-of-prompt", "left") def process_input(self,event): index = self.console.index("end-1c linestart") line = self.console.get(index,'end-1c') log.debug ("last line: %s" % line) if self.manual == True: self.console.insert("end", "\n") command = self.console.get("end-of-prompt", "end-1c") command = command.strip() if command != '': if command == 'bye' or command == 'exit': log.info ("quit from manual mode...") self.wf_manual.ssh.close() self.manual = False self.b5.config(state=NORMAL) self.b11.config(state=NORMAL) return elif command == 'help': log.info ("This is used for run command on target server by ssh, for example: >>> df -h, >>> svcs -xv") elif self.wf_manual.remote_cmd(command) == 1: log.error ("command %s execute failed" % command) self.insert_prompt() self.console.see("end") # this prevents the class binding from firing, since we # inserted the newline in this method return "break" else: if line == 'Yes' or line == 'y' or line == 'yes': self.set_confirm_yes() elif line == 'No' or line == 'n' or line == 'no': self.set_confirm_no() elif line == 'Skip' or line == 's' or line == 'skip': self.set_confirm_skip() else: pass
class SigBridgeUI(Tk): server = None server_thread = None def __init__(self): Tk.__init__(self) self.columnconfigure(0, weight=1) self.rowconfigure(0, weight=1) # 2 rows: firts with settings, second with registrar data self.main_frame = Frame(self) # Commands row doesn't expands self.main_frame.rowconfigure(0, weight=0) # Logs row will grow self.main_frame.rowconfigure(1, weight=1) # Main frame can enlarge self.main_frame.columnconfigure(0, weight=1) self.main_frame.columnconfigure(1, weight=1) self.main_frame.grid(row=0, column=0) # Run/Stop button self.server_button = Button(self.main_frame, text="Connect", command=self.start_server) self.server_button.grid(row=0, column=0) # Clear button self.clear_button = Button(self.main_frame, text="Clear Log", command=self.clear_log) self.clear_button.grid(row=0, column=1) # Logs Widget self.log_widget = ScrolledText(self.main_frame) self.log_widget.grid(row=1, column=0, columnspan=2) # made not editable self.log_widget.config(state='disabled') # Queue where the logging handler will write self.log_queue = Queue.Queue() # Setup the logger self.uilogger = logging.getLogger('SigBridgeUI') self.uilogger.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') # Use the QueueLogger as Handler hl = QueueLogger(queue=self.log_queue) hl.setFormatter(formatter) self.uilogger.addHandler(hl) # self.log_widget.update_idletasks() self.set_geometry() # Setup the update_widget callback reading logs from the queue self.start_log() def clear_log(self): self.log_widget.config(state='normal') self.log_widget.delete(0.0, END) self.log_widget.config(state='disabled') def start_log(self): self.uilogger.info("SigBridge Started.") self.update_widget() # self.control_log_button.configure(text="Pause Log", command=self.stop_log) def update_widget(self): self.log_widget.config(state='normal') # Read from the Queue and add to the log widger while not self.log_queue.empty(): line = self.log_queue.get() tag = "error" if " ERROR " in line else 'info' self.log_widget.insert(END, line, tag) self.log_widget.see(END) # Scroll to the bottom self.log_widget.update_idletasks() self.log_widget.tag_config('error', foreground="red") self.log_widget.config(state='disabled') self.log_widget.after(10, self.update_widget) def set_geometry(self): # set position in window w = 600 # width for the Tk h = 300 # height for the Tk # get screen width and height ws = self.winfo_screenwidth() # width of the screen hs = self.winfo_screenheight() # height of the screen # calculate x and y coordinates for the Tk window x = (ws/2) - (w/2) y = (hs/2) - (h/2) # set the dimensions of the screen # and where it is placed self.geometry('%dx%d+%d+%d' % (w, h, x, y)) def start_server(self): try: self.server = SigServer(('0.0.0.0', 25), None, self.uilogger) self.server_thread = threading.Thread(name='server', target=self.server.run) self.server_thread.daemon = True self.server_thread.start() self.server_button.configure(text="Disconnect", command=self.stop_server) except Exception as err: self.uilogger("Cannot start the server: %s" % err.message) # self.label_variable.set(self.entry_variable.get()+"(Started Signal Server)") # self.entry.focus_set() # self.entry.selection_range(0, END) def stop_server(self): self.server.shutdown() self.server_button.configure(text="Connect", command=self.start_server) self.server = None
class TermWindow(Frame): EOL = None ## # constructor method def __init__(self, master=None, **cnf): apply(Frame.__init__, (self, master), cnf) self.__create_widgets__() self.rxWaitPattern = "" self.localEcho = False self.logFile = None self.inQueue = Queue.Queue() self.outQueue = Queue.Queue() self.update_thread_safe() def update_thread_safe(self): while not self.inQueue.empty(): element = self.inQueue.get_nowait() if element is not None: msg, tag = element self.__display__(msg, tag) self.st_trm.update_idletasks() self.st_trm.after(100, self.update_thread_safe) ## # def __create_widgets__(self): dfl_font = 'Courier 10' # the title frame of the terminal self.f_title = Frame(self) self.f_title.pack(fill=BOTH) self.f_title.configure(FRAMEBORDER) self.shVar = StringVar() # show/hide button self.b_sh = Button(self.f_title, textvariable=self.shVar, font=dfl_font) self.b_sh.pack(side=RIGHT) self.b_sh['command'] = self.show_hide_cont # clear screen button self.b_cls = Button(self.f_title, text="CLS", font=dfl_font, underline=0) self.b_cls.pack(side=RIGHT) self.b_cls['command'] = self.clear_screen # echo on/off button self.al_echo = Label(self.f_title, text="ECHO", relief=RAISED, font=dfl_font, padx='3m', pady='1m', underline=0) self.al_echo.pack(side=RIGHT, padx=1, pady=1, fill=BOTH) self.al_echo.bind("<Button-1>", self.__echo_handler__) # log on/off button self.al_log = Label(self.f_title, text="LOG", relief=RAISED, font=dfl_font, padx='3m', pady='1m', underline=0) self.al_log.pack(side=RIGHT, padx=1, pady=1, fill=BOTH) self.al_log.bind("<Button-1>", self.__log_handler__) # device connect button self.al_connect = Label(self.f_title, text="CONNECT", relief=RAISED, font=dfl_font, padx='3m', pady='1m', underline=1) self.al_connect.pack(side=RIGHT, padx=1, pady=1, fill=BOTH) self.al_connect.bind("<Button-1>", self.__connect_handler__) self.mb_macros = Menubutton(self.f_title, text="Macros", relief=RAISED) self.mb_macros.pack(side=RIGHT, padx=1, pady=1, fill=BOTH) self.mb_macros.menu = Menu(self.mb_macros, tearoff=0) self.mb_macros["menu"] = self.mb_macros.menu # title of terminal window self.tVar = StringVar() self.l_title = Label(self.f_title, text="foo", font=dfl_font) self.l_title['textvariable'] = self.tVar self.l_title.pack(side=LEFT, expand=1, fill=X) self.l_title['width'] = 42 self.update_title("------ XXX ------") # frame for scrolled text window # (this frame handle needs to be kept fo show_hide_cont()) self.f_cont = Frame(self) # IO data scrolled text window self.st_trm = ScrolledText(self.f_cont, height=10, state=DISABLED, wrap=NONE) self.st_trm.pack(expand=1, fill=BOTH) self.st_trm['font'] = dfl_font self.st_trm.tag_config('E', foreground="blue") self.st_trm.tag_config('M', foreground="magenta") tframe = Frame(self.f_cont) tframe.pack(expand=0, fill=X) self.cmdVar = StringVar() self.ent_trm = Entry(tframe, textvariable=self.cmdVar, font=dfl_font) self.ent_trm.pack(side=LEFT, expand=1, fill=X) self.ent_trm.bind("<Control-l>", self.__log_handler__) self.ent_trm.bind("<Control-e>", self.__echo_handler__) self.ent_trm.bind("<Control-o>", self.__connect_handler__) self.ent_trm.bind("<Control-c>", self.clear_screen) self.ent_trm.bind("<Control-x>", self.show_hide_cont) self.ent_trm.bind("<Control-m>", lambda *args: self.do_macro("M")) self.ent_trm.bind("<KeyPress>", self.__input_handler__) self.gui_elements = [ self.b_sh, self.b_cls, self.al_echo, self.al_log, self.al_connect, self.mb_macros, self.l_title, self.st_trm, self.ent_trm ] self.show_cont() def add_macro(self, id, title, text=None, function=None, params=None): if text: cmd = lambda *args: self.do_macro(text) if function: user_func = eval(function) if params: params = eval(str(params)) else: params = {} cmd = lambda *args: user_func(self, DEVICES, **params) mb = self.mb_macros.menu.add_command(label=title, command=cmd) def _configure_(self, **args): for e in self.gui_elements: e.configure(args) def __input_handler__(self, *args): for i in args: self.terminal_device_write(i.char) def terminal_device_write(self, *args): for i in args: if self.localEcho: self.display(i, "E") if len(i): if i == "\r" or i == "\n": self.device.write(self.EOL) self.display(self.EOL, "E") self.cmdVar.set("") else: self.device.write(i) self.st_trm.update_idletasks() def __echo_handler__(self, *args): if self.localEcho: self.localEcho = False self.al_echo['relief'] = RAISED self.message("Local Echo OFF") else: self.localEcho = True self.al_echo['relief'] = SUNKEN self.message("Local Echo ON") def __log_handler__(self, *args): try: do_open = self.logFile.closed logname = self.logFile.name except: do_open = True logname = "" if do_open: if self.device.logname: logname = self.device.logname self.message("logfile from config file %s " % logname) else: fd = FileDialog(self) logname = fd.go(logname) try: if self.device.logmode not in "wa": self.device.logmode = "a" _print(3, "force _a_ppend") self.logFile = open(logname, self.device.logmode) self.al_log['relief'] = SUNKEN self.message("Logging ON: %s" % self.logFile.name) except: self.message("Error open logfile: %s" % logname) else: self.message("Logging OFF: %s" % self.logFile.name) self.logFile.flush() self.logFile.close() self.al_log['relief'] = RAISED def __connect_handler__(self, *args): if self.device.isConnected: self.device.disconnect() self.al_connect['relief'] = RAISED self.message("Disconnected") else: try: self.device.connect() self.al_connect['relief'] = SUNKEN self.message("Connected") self.al_connect['fg'] = "black" except: self.device.isConnected = False self.message(str(sys.exc_info()[1])) self.al_connect['fg'] = "red" def clear_screen(self, *args): self.st_trm['state'] = NORMAL self.st_trm.delete("0.0", END) self.st_trm['state'] = DISABLED def set_device(self, device): self.device = device self.device.configure(TxQueue=self.outQueue, RxQueue=self.inQueue) self.update_title(self.device) if self.device.log: self.__log_handler__() if self.device.auto_connect: self.__connect_handler__() def update_title(self, title): self.tVar.set(title) def show_cont(self): self.shVar.set("X") self.f_cont.pack(expand=1, fill=BOTH) def hide_cont(self): self.shVar.set("+") self.f_cont.pack_forget() def show_hide_cont(self, *args): if self.shVar.get() == "X": self.hide_cont() else: self.show_cont() def do_macro(self, *args): if self.localEcho: self.display(args[0] + "\n", "E") self.device.write(args[0] + "\n") def write(self, data): self.outQueue.put((data, None)) def message(self, text, tag='M'): msg = "[%s:%s:%s]\n" % (time.asctime(), self.device.name, text) if self.st_trm.index(AtInsert()).find(".0") < 1: msg = "\n" + msg self.inQueue.put((msg, tag)) def display(self, text, tag=None): self.inQueue.put((text, tag)) def __display__(self, msg, tag=None): self.st_trm['state'] = NORMAL here = self.st_trm.index(AtInsert()) for d in re.split("([\r\v\t\n])", msg): if len(d): if d != '\r': self.st_trm.insert(END, d) if tag: self.st_trm.tag_add(tag, here, AtInsert()) self.st_trm.see(END) self.st_trm['state'] = DISABLED try: self.logFile.write(msg) self.logFile.flush() except: pass
class UploadWizard(Wizard): def __init__(self, root, data): self.root = root self.data = data self.secure = False super(UploadWizard, self).__init__( width=450, height=300, cancelcommand=self._handle_cancel, finishcommand=self._handle_finish, ) self.servers = ServerList() self.server_lbox = None self.upthread = None self.old_upload_state = None self.setup_gui() def setup_gui(self): self.title("Upload Wizard") self.protocol("WM_DELETE_WINDOW", self._handle_cancel) self.setup_gui_server_pane() self.setup_gui_user_pane() self.setup_gui_program_pane() self.setup_gui_upload_pane() def setup_gui_server_pane(self): fr = self.add_pane( 'server', 'Select Server', entrycommand=self._enter_server_pane ) fr.config(padx=20, pady=20) self.ssl_enable = IntVar() lbox_lbl = Label(fr, text="Select a Server to upload to:") self.server_lbox = ScrolledListbox( fr, horiz_scroll=False, width=20, highlightthickness=1) muck_lbl = Label(fr, text="Name") host_lbl = Label(fr, text="Host") port_lbl = Label(fr, text="Port") svalid = (self.register(self._serv_validate)) pvalid = (self.register(self._port_validate), '%P') self.muck_entry = Entry( fr, width=30, validate=ALL, validatecommand=svalid) self.host_entry = Entry( fr, width=30, validate=ALL, validatecommand=svalid) self.port_entry = Entry( fr, width=10, validate=ALL, validatecommand=pvalid) self.port_entry.insert(END, '8888') self.ssl_cb = Checkbutton( fr, text="SSL", variable=self.ssl_enable, highlightthickness=3, command=self._update_server_buttons, ) self.serv_del = Button(fr, text="-", width=1, command=self._del_server) self.serv_add = Button(fr, text="+", width=1, command=self._add_server) self.serv_save = Button(fr, text="Save", command=self._save_server) ToolTip(self.serv_del, "Delete selected Favorite Server") ToolTip(self.serv_add, "Enter a new Server") ToolTip(self.serv_save, "Save as a Favorite Server") self.server_lbox.bind('<<ListboxSelect>>', self._server_listbox_select) lbox_lbl.grid(row=0, column=0, sticky=N+W) self.server_lbox.grid( row=1, column=0, rowspan=8, padx=5, sticky=N+S+E+W) muck_lbl.grid(row=1, column=1, sticky=W, padx=5) self.muck_entry.grid(row=2, column=1, columnspan=3, sticky=E+W, padx=5) host_lbl.grid(row=3, column=1, sticky=W, padx=5) self.host_entry.grid(row=4, column=1, columnspan=3, sticky=E+W, padx=5) port_lbl.grid(row=5, column=1, sticky=W, padx=5) self.port_entry.grid(row=6, column=1, columnspan=2, sticky=E+W, padx=5) self.ssl_cb.grid(row=6, column=3, sticky=E, padx=5) self.serv_del.grid(row=8, column=1, sticky=N+W, padx=5) self.serv_add.grid(row=8, column=2, sticky=N+W, padx=5) self.serv_save.grid(row=8, column=3, sticky=N+E, padx=5) fr.grid_columnconfigure(2, weight=1, minsize=50) fr.grid_rowconfigure(7, weight=1) self.server_lbox.focus() return fr def setup_gui_user_pane(self): fr = self.add_pane( 'user', 'Select a user', entrycommand=self._enter_user_pane ) fr.config(padx=20, pady=20) lbox_lbl = Label(fr, text="Select a User to upload to:") self.user_lbox = ScrolledListbox(fr, horiz_scroll=False, width=20) user_lbl = Label(fr, text="UserName") pass_lbl = Label(fr, text="Password") uvalid = (self.register(self._user_validate)) self.user_entry = Entry( fr, width=30, validate=ALL, validatecommand=uvalid) self.pass_entry = Entry( fr, width=30, show="*", validate=ALL, validatecommand=uvalid) self.user_del = Button(fr, text="-", width=1, command=self._del_user) self.user_add = Button(fr, text="+", width=1, command=self._add_user) self.user_save = Button(fr, text="Save", command=self._save_user) ToolTip(self.user_del, "Delete selected User") ToolTip(self.user_add, "Enter a new User") ToolTip(self.user_save, "Save User Info") self.user_lbox.bind('<<ListboxSelect>>', self._user_listbox_select) lbox_lbl.grid(row=0, column=0, sticky=N+W) self.user_lbox.grid(row=1, column=0, rowspan=8, padx=5, sticky=N+S+E+W) user_lbl.grid(row=1, column=1, sticky=W, padx=5) self.user_entry.grid(row=2, column=1, columnspan=3, sticky=E+W, padx=5) pass_lbl.grid(row=3, column=1, sticky=W, padx=5) self.pass_entry.grid(row=4, column=1, columnspan=3, sticky=E+W, padx=5) self.user_del.grid(row=6, column=1, sticky=N+W, padx=5) self.user_add.grid(row=6, column=2, sticky=N+W, padx=5) self.user_save.grid(row=6, column=3, sticky=N+E, padx=5) fr.grid_columnconfigure(2, weight=1, minsize=50) fr.grid_rowconfigure(5, weight=1) return fr def setup_gui_program_pane(self): fr = self.add_pane( 'program', 'Program Info', entrycommand=self._enter_program_pane ) pvalid = (self.register(self._program_validate)) fr.config(padx=20, pady=20) prog_lbl = Label(fr, text="Program Name or DBRef") self.prog_entry = Entry( fr, width=30, validate=ALL, validatecommand=pvalid) global previous_progname self.prog_entry.insert(END, previous_progname) prog_lbl.grid(row=0, column=0, sticky=W+S) self.prog_entry.grid(row=1, column=0, sticky=N+E+W) fr.grid_columnconfigure(0, weight=1) fr.grid_rowconfigure(2, weight=1) return fr def setup_gui_upload_pane(self): fr = self.add_pane( 'upload', 'Uploading', entrycommand=self._enter_upload_pane ) fr.config(padx=20, pady=20) self.upload_lbl = Label( fr, text="", justify=LEFT, anchor=W, wraplength=400) self.progressbar = ProgressBar( fr, length=300, value=10.0, maximum=100.0, mode=INDETERMINATE, ) self.console_log = ScrolledText( fr, font='TkFixedFont', relief=SUNKEN, borderwidth=2, background="black", foreground="white", width=1, height=1, insertontime=0, takefocus=0, cursor='arrow', ) ro_binds = [ "<Key>", "<<Cut>>", "<<Clear>>", "<<Paste>>", "<<PasteSelection>>", "<Double-Button-1>", ] for bind in ro_binds: self.console_log.bind(bind, lambda e: "break") self.upload_lbl.grid(row=0, column=0, sticky=W+S) self.progressbar.grid(row=1, column=0, sticky=N+E+W, padx=15, pady=5) self.console_log.grid(row=2, column=0, sticky=N+S+E+W) fr.grid_columnconfigure(0, weight=1) fr.grid_rowconfigure(2, weight=1) return fr def _enter_server_pane(self): self.set_finish_enabled(False) self.set_next_enabled(False) self.set_next_text() self.set_default_button("next") self.set_finish_text("Done") self._populate_server_listbox() if self.server_lbox.size() > 0: self.server_lbox.focus() else: self.muck_entry.focus() self._update_server_buttons() def _enter_user_pane(self): self.set_finish_enabled(False) self.set_next_enabled(False) self.set_next_text() self.set_default_button("next") self._populate_user_listbox() if self.user_lbox.size() > 0: self.user_lbox.focus() else: self.user_entry.focus() self._update_user_buttons() def _enter_program_pane(self): self.set_finish_enabled(False) self.set_next_enabled(False) self.set_next_text("Upload") self.set_default_button("next") self.prog_entry.focus() def _enter_upload_pane(self): self.set_default_button("finish") self.set_next_text() self.set_prev_enabled(False) self.set_finish_enabled(False) self._upload_start() global previous_progname previous_progname = self.prog_entry.get() def _populate_server_listbox(self): self.server_lbox.delete(0, END) for serv in self.servers.get_servers(): self.server_lbox.insert(END, str(serv)) def _update_server_listbox(self): sel = self.server_lbox.curselection() self._populate_server_listbox() if sel: self.server_lbox.selection_set(sel[0]) self._update_server_buttons() def _server_listbox_select(self, event=None): try: sel = int(self.server_lbox.curselection()[0]) servers = self.servers.get_servers() serv = servers[sel] self.muck_entry.delete(0, END) self.host_entry.delete(0, END) self.port_entry.delete(0, END) self.muck_entry.insert(END, serv.name) self.host_entry.insert(END, serv.host) self.port_entry.insert(END, serv.port) self.ssl_enable.set(serv.ssl) self._update_server_buttons() except (ValueError, IndexError): return def _update_server_buttons(self, event=None): add_state = 'normal' del_state = 'normal' save_state = 'normal' items = self.server_lbox.curselection() if not items: del_state = 'disabled' if not self.muck_entry.get(): if not self.host_entry.get(): if self.port_entry.get() == '8888': if not self.ssl_enable.get(): add_state = 'disabled' if not self.host_entry.get() or not self.port_entry.get(): save_state = 'disabled' self.serv_del.config(state=del_state) self.serv_add.config(state=add_state) self.serv_save.config(state=save_state) self.set_next_enabled( bool(items or (self.host_entry.get() and self.port_entry.get())) ) def _serv_validate(self): self.after_idle(self._update_server_buttons) return True def _port_validate(self, val): self.after_idle(self._update_server_buttons) if val == '': return True try: val = int(val) return True except ValueError: self.bell() return False def _add_server(self): self.server_lbox.selection_clear(0, END) self.muck_entry.delete(0, END) self.host_entry.delete(0, END) self.port_entry.delete(0, END) self.port_entry.insert(END, '8888') self.ssl_enable.set('0') self.muck_entry.focus() self._update_server_buttons() def _del_server(self): del_confirmed = askyesno( "Delete Server", "Are you sure you want to delete this server?", parent=self ) if del_confirmed: try: sel = int(self.server_lbox.curselection()[0]) self.servers.del_server(sel) self.servers.save() self._update_server_listbox() except (ValueError, IndexError): self.bell() def _save_server(self): sel = -1 try: sel = int(self.server_lbox.curselection()[0]) self.servers.del_server(sel) self._update_server_listbox() except (ValueError, IndexError): pass server = ServerInfo( name=self.muck_entry.get(), host=self.host_entry.get(), port=self.port_entry.get(), use_ssl=self.ssl_enable.get() ) self.servers.add_server(server) self.servers.save() self._update_server_listbox() if sel >= 0: self.server_lbox.selection_set(sel) self._server_listbox_select() self._update_server_buttons() def _populate_user_listbox(self): host = self.host_entry.get() port = int(self.port_entry.get()) serv = self.servers.find_by_host_and_port(host, port) self.user_lbox.delete(0, END) if not serv: return for user in serv.get_users(): self.user_lbox.insert(END, user.user) def _update_user_listbox(self): sel = self.user_lbox.curselection() self._populate_user_listbox() if sel: self.user_lbox.selection_set(sel[0]) self._update_user_buttons() def _user_listbox_select(self, event=None): host = self.host_entry.get() port = int(self.port_entry.get()) serv = self.servers.find_by_host_and_port(host, port) if not serv: return try: sel = int(self.user_lbox.curselection()[0]) users = serv.get_users() user = users[sel] self.user_entry.delete(0, END) self.pass_entry.delete(0, END) self.user_entry.insert(END, user.user) self.pass_entry.insert(END, user.password) self._update_server_buttons() except (ValueError, IndexError): return def _update_user_buttons(self, event=None): add_state = 'normal' del_state = 'normal' save_state = 'normal' host = self.host_entry.get() port = int(self.port_entry.get()) serv = self.servers.find_by_host_and_port(host, port) if not serv: del_state = 'disabled' add_state = 'disabled' save_state = 'disabled' items = self.user_lbox.curselection() if not items: del_state = 'disabled' if not self.user_entry.get(): if not self.pass_entry.get(): add_state = 'disabled' if not self.user_entry.get(): save_state = 'disabled' self.user_del.config(state=del_state) self.user_add.config(state=add_state) self.user_save.config(state=save_state) self.set_next_enabled( bool(items or (self.user_entry.get() and self.pass_entry.get())) ) def _user_validate(self): self.after_idle(self._update_user_buttons) return True def _add_user(self): self.user_lbox.selection_clear(0, END) self.user_entry.delete(0, END) self.pass_entry.delete(0, END) self._update_user_buttons() self.user_entry.focus() def _del_user(self): del_confirmed = askyesno( "Delete User", "Are you sure you want to delete this user?", parent=self ) if del_confirmed: host = self.host_entry.get() port = int(self.port_entry.get()) serv = self.servers.find_by_host_and_port(host, port) if not serv: return try: sel = int(self.server_lbox.curselection()[0]) serv.del_user(sel) self.servers.save() self._update_user_listbox() except (ValueError, IndexError): self.bell() def _save_user(self): host = self.host_entry.get() port = int(self.port_entry.get()) serv = self.servers.find_by_host_and_port(host, port) if not serv: return serv.add_user( user=self.user_entry.get(), password=self.pass_entry.get(), ) self.servers.save() self._update_user_listbox() def _update_program_buttons(self, event=None): self.set_next_enabled(bool(self.prog_entry.get())) def _program_validate(self): self.after_idle(self._update_program_buttons) return True def _upload_start(self): force_ssl = bool(self.ssl_enable.get()) host = self.host_entry.get() port = int(self.port_entry.get()) user = self.user_entry.get() password = self.pass_entry.get() progname = self.prog_entry.get() self.upload_lbl.config(text="Connecting to %s:%s..." % (host, port)) self.progressbar.start() self.upthread = UploadThread( host, port, force_ssl, user, password, progname, self.data, ) self.upthread.start() self.old_upload_state = '' self._update_upload_state() def _update_upload_state(self): logtxt = self.upthread.get_log_text() if logtxt: self.console_log.insert(END, logtxt) self.console_log.see(END) state = self.upthread.state self.upload_lbl.config(text=self.upthread.status) if state in [UPLOAD_FAIL, UPLOAD_SUCCESS]: self.set_finish_enabled(True) self.set_cancel_enabled(False) else: self.after(100, self._update_upload_state) if state == UPLOADING: uploaded = self.upthread.bytes_uploaded total = self.upthread.total_bytes pcnt = float(uploaded) / total self.progressbar.config(value=pcnt) if state == self.old_upload_state: return self.old_upload_state = state if state == UPLOADING: self.progressbar.stop() self.progressbar.config(mode=DETERMINATE) elif state == UPLOAD_FAIL: self.progressbar.stop() self.progressbar.grid_forget() elif state == UPLOAD_SUCCESS: self.progressbar.stop() self.progressbar.config(mode=DETERMINATE) self.progressbar.config(value=100.0) def _handle_cancel(self): self.destroy() def _handle_finish(self): self.destroy()
class facades_main(Tkinter.Tk): def __init__(self, parent): Tkinter.Tk.__init__(self, parent) self.parent = parent self.initialize() self.clock_tick() def update_val_from_entry(self): global G_RUN_STATUS global G_SHUTDOWN_DELAY global G_WAKEUP_AFTER global G_LOOP_NUMBER global G_LONGRUN_ACTION G_SHUTDOWN_DELAY = int(self.entry_second.get(), base=10) G_WAKEUP_AFTER = int(self.entry_wakeafter.get(), base=10) G_LOOP_NUMBER = int(self.entry_loop.get(), base=10) G_LONGRUN_ACTION = self.var_action.get() def reset_rtcdata(self): efiapi = WinApiEfiVariables() rtcdata = efiapi.read(UEFI_VAR_NAME, UEFI_VAR_GUID) data = RtcWakeData(*struct.unpack_from(RTC_WAKE_DATA_FORMAT, rtcdata)) #just reset to not wake up data2 = data._replace(Alarm_Wake=3,Alarm_Week=0, \ RtcWakeTime_Hour= 0, \ RtcWakeTime_Minute= 0, \ RtcWakeTime_Second= 0 ) rtcdata = data2.packstring() efiapi.write(UEFI_VAR_NAME, UEFI_VAR_GUID, rtcdata) def func_shutdown(self): global G_CURRENT_LOOPNUM G_CURRENT_LOOPNUM += 1 self.confighandle.set_config('run_status', 'True') self.confighandle.set_config('current_loop', str(G_CURRENT_LOOPNUM)) self.confighandle.update_file() if (G_LONGRUN_ACTION == 4): print "reboot" Hour = int(time.strftime("%H"), 10) Minute = int(time.strftime("%M"), 10) Second = int(time.strftime("%S"), 10) self.logger.info("reboot time: %d:%d:%d" %(Hour, Minute, Second)) os.system('shutdown /r /f /t 0') while(1): pass efiapi = WinApiEfiVariables() rtcdata = efiapi.read(UEFI_VAR_NAME, UEFI_VAR_GUID) data = RtcWakeData(*struct.unpack_from(RTC_WAKE_DATA_FORMAT, rtcdata)) (Hour, Minute, Second) = self.CalAlarmTimer() data2 = data._replace(Alarm_Wake=1,Alarm_Week=0, \ RtcWakeTime_Hour= Hour, \ RtcWakeTime_Minute= Minute, \ RtcWakeTime_Second= Second ) rtcdata = data2.packstring() efiapi.write(UEFI_VAR_NAME, UEFI_VAR_GUID, rtcdata) if (G_LONGRUN_ACTION == 3): print "shutdown" os.system('shutdown /s /f /t 0') if (G_LONGRUN_ACTION == 2): print "suspend" os.system('rundll32.exe PowrProf.dll,SetSuspendState') if (G_LONGRUN_ACTION == 1): print "sleep" os.system('rundll32.exe powrprof.dll,SetSuspendState 0,1,0') def CalAlarmTimer(self): Hour = int(time.strftime("%H"), 10) Minute = int(time.strftime("%M"), 10) Second = int(time.strftime("%S"), 10) print "current time:", Hour, Minute, Second print "wake after:", G_WAKEUP_AFTER self.logger.info("current time: %d:%d:%d" %(Hour, Minute, Second)) # total_secs = Hour*3600 + Minute*60 + Second total_secs += G_WAKEUP_AFTER total_secs += G_SHUTDOWN_DELAY # Hour = total_secs / 3600 Minute = (total_secs % 3600) / 60 Second = (total_secs % 3600) % 60 if Hour >= 24: Hour = 0 print "wake time: %d:%d:%d" %(Hour, Minute, Second) self.logger.info("wake time: %d:%d:%d" %(Hour, Minute, Second)) return (Hour,Minute,Second) def clock_tick(self): now = time.strftime("%H:%M:%S") self.label_ticker.configure(text=now) self.label_ticker.after(200, self.clock_tick) def clock_timeout(self): count = self.entry_second.get() #print count count = int(count, 10) print count if (G_RUN_STATUS): if (count > 0): self.count_second.set(count - 1) self._job = self.entry_second.after(1000, self.clock_timeout) if (count == 0): print "function to action!" self.func_shutdown() def initialize(self): global G_RUN_STATUS global G_SHUTDOWN_DELAY global G_WAKEUP_AFTER global G_LOOP_NUMBER global G_CURRENT_LOOPNUM global G_LONGRUN_ACTION self.geometry("400x450+300+100") self.minsize(350,250) self.grid() self._job = None self.confighandle = lrConfigParser(configfn) self.count_second = Tkinter.IntVar() self.str_action = Tkinter.StringVar() self.var_action = Tkinter.IntVar() self.loop_number = Tkinter.IntVar() self.current_loop = Tkinter.IntVar() self.wake_after = Tkinter.IntVar() self.str_start = Tkinter.StringVar() self.var_action.set(G_LONGRUN_ACTION ) self.count_second.set(G_SHUTDOWN_DELAY) self.loop_number.set(G_LOOP_NUMBER) self.current_loop.set(G_CURRENT_LOOPNUM) self.wake_after.set(G_WAKEUP_AFTER) if (G_LONGRUN_ACTION == 4): self.str_action.set("reboot ") if (G_LONGRUN_ACTION == 3): self.str_action.set("Shutdown") self.log_queue = Queue.Queue() self.label_blank = Tkinter.Label(self, text='') self.label_ticker = Tkinter.Label(self, text="test",anchor='e',font=('times', 20, 'bold'), bg='green') self.entry_second = Tkinter.Entry(self, text=self.count_second, font=('times', 20, 'bold'),width=5) self.label_str1 = Tkinter.Label(self, text='seconds to',font=('times', 20, 'bold')) self.label_str2 = Tkinter.Label(self, text='Loop',font=('times', 20, 'bold')) self.label_str3 = Tkinter.Label(self, text='seconds to',font=('times', 20, 'bold')) self.label_str4 = Tkinter.Label(self, text='wakeup', font=('times', 20, 'bold')) self.entry_wakeafter = Tkinter.Entry(self, text=self.wake_after, font=('times', 20, 'bold'),width=5) self.label_str_action = Tkinter.Label(self, textvariable=self.str_action, font=('times', 20, 'bold')) self.radiobtn_s3 = Tkinter.Radiobutton(self, text='S3',variable=self.var_action, value=1, command=self.radiobtn_callback, state='disabled') self.radiobtn_s4 = Tkinter.Radiobutton(self, text='S4',variable=self.var_action, value=2, command=self.radiobtn_callback, state='disabled') self.radiobtn_s5 = Tkinter.Radiobutton(self, text='S5',variable=self.var_action, value=3, command=self.radiobtn_callback) self.radiobtn_reboot = Tkinter.Radiobutton(self, text='reboot',variable=self.var_action, value=4, command=self.radiobtn_callback) self.entry_loop = Tkinter.Entry(self, text=self.loop_number, font=('times', 20, 'bold'),width=5) self.btn_start = Tkinter.Button(self, text="Start",bg="green",font=('times', 20, 'bold'), command=self.btn_start_callback) self.btn_edit = Tkinter.Button(self, text="Edit", font=('times', 20, 'bold'), state="disabled", command=self.btn_edit_callback) self.label_current_loop = Tkinter.Label(self, textvariable=self.current_loop, font=('times', 20, 'bold')) self.btn_clrlog = Tkinter.Button(self, text="Clear Log",font=('times', 15, 'bold'), command=self.btn_clearlog_callback) self.log_widget = ScrolledText(self, width = 50, heigh = 15) self.label_blank.grid(row=0,column=0,ipadx=20) self.label_ticker.grid(row=0,column=2,sticky='w') self.entry_second.grid(row=1,column=0) self.label_str1.grid(row=1,column=1,sticky='w') self.label_str_action.grid(row=1,column=2,sticky='w') self.entry_loop.grid(row=2,column=0) self.label_str2.grid(row=2, column=1,sticky='w') self.radiobtn_s3.grid(row=2,column=2,sticky='w') self.radiobtn_s4.grid(row=2,column=2,sticky='w', padx=40) self.radiobtn_s5.grid(row=2,column=2,sticky='w', padx=80) self.radiobtn_reboot.grid(row=2,column=2,sticky='w',padx=120) self.entry_wakeafter.grid(row=3, column=0) self.label_str3.grid(row=3, column=1) self.label_str4.grid(row=3, column=2,sticky='w') self.label_blank.grid(row=4,column=0) self.btn_start.grid(row=5, column=0) self.btn_edit.grid(row=5, column=1) self.btn_clrlog.grid(row=5,column=2,sticky='w') self.label_current_loop.grid(row=5, column=2,sticky='w',padx=120) self.log_widget.grid(row=6, column=0, columnspan=3, sticky='w') #init log queue self.logger = logging.getLogger(logfn) self.logger.setLevel(logging.INFO) logformat = logging.Formatter(LOG_FORMAT) hl = QueueLogger(queue=self.log_queue) hl.setFormatter(logformat) self.logger.addHandler(hl) self.start_logwidget() if G_CURRENT_LOOPNUM <= G_LOOP_NUMBER: if G_RUN_STATUS: print "auto run loop %d" %(G_CURRENT_LOOPNUM) self.logger.info("\ncurrent loop: %d" %(G_CURRENT_LOOPNUM)) self.btn_start_callback() else: print "loop pass!" self.current_loop.set(G_CURRENT_LOOPNUM-1) if G_RUN_STATUS: print "reset run status here" G_RUN_STATUS = False G_CURRENT_LOOPNUM -= 1 self.current_loop.set(str(G_CURRENT_LOOPNUM)) self.confighandle.set_config('current_loop', str(G_CURRENT_LOOPNUM)) self.confighandle.update_file() self.reset_rtcdata() def radiobtn_callback(self): global G_LONGRUN_ACTION seltmp = self.var_action.get() G_LONGRUN_ACTION = seltmp if (seltmp == 4): self.str_action.set("reboot") if (seltmp == 3): self.str_action.set("Shutdown") if (seltmp == 2): self.str_action.set("Suspend ") if (seltmp == 1): self.str_action.set("Sleep ") def btn_clearlog_callback(self): global G_CURRENT_LOOPNUM self.log_widget.config(state='normal') self.log_widget.delete(0.0, Tkinter.END) self.log_widget.config(state='disabled') if os.path.isfile(logfn): with open(logfn, 'w'): pass #reset current loop to zero if G_CURRENT_LOOPNUM != 0: G_CURRENT_LOOPNUM = 0 self.confighandle.set_config('current_loop', str(G_CURRENT_LOOPNUM)) self.confighandle.update_file() self.current_loop.set(G_CURRENT_LOOPNUM) def btn_start_callback(self): global G_RUN_STATUS global G_EDITABLE if G_EDITABLE: G_EDITABLE = False print "set get from entry" self.update_val_from_entry() self.confighandle.set_config('shutdown_delay', str(G_SHUTDOWN_DELAY)) self.confighandle.set_config('loop_number', str(G_LOOP_NUMBER)) self.confighandle.set_config('wake_after', str(G_WAKEUP_AFTER)) self.confighandle.set_config('longrun_action', str(G_LONGRUN_ACTION)) self.confighandle.update_file() self.btn_start.config(text='Stop ', bg = "red", command=self.btn_stop_callback) self.entry_second.config(state='disabled') self.entry_loop.config(state='disabled') self.btn_edit.config(state='disabled') self.entry_wakeafter.config(state='disabled') G_EDITABLE = False if not G_RUN_STATUS: G_RUN_STATUS = True self.clock_timeout() def btn_stop_callback(self): global G_RUN_STATUS G_RUN_STATUS = False self.btn_start.config(text="Start", bg = "green", command=self.btn_start_callback) self.btn_edit.config(state='normal') self.confighandle.set_config('run_status', str(G_RUN_STATUS)) self.confighandle.update_file() self.reset_rtcdata() def btn_edit_callback(self): global G_EDITABLE print "edit callback, to enable change variables" self.btn_edit.config(text="Apply", command=self.btn_apply_callback) self.entry_second.config(state='normal') self.entry_loop.config(state='normal') self.entry_wakeafter.config(state='normal') G_EDITABLE = True def btn_apply_callback(self): global G_EDITABLE print "apply callback, save changes to cfg file after edit" self.btn_edit.config(text="Edit", command=self.btn_edit_callback) self.entry_second.config(state='disabled') self.entry_loop.config(state='disabled') self.entry_wakeafter.config(state='disabled') G_EDITABLE = False self.update_val_from_entry() ##update into cfg file self.confighandle.set_config('shutdown_delay', str(G_SHUTDOWN_DELAY)) self.confighandle.set_config('loop_number', str(G_LOOP_NUMBER)) self.confighandle.set_config('wake_after', str(G_WAKEUP_AFTER)) self.confighandle.set_config('longrun_action', str(G_LONGRUN_ACTION)) self.confighandle.update_file() def start_logwidget(self): if os.path.isfile(logfn): self.log_widget.config(state='normal') print "read log file into log widget" with open(logfn) as fin: for line in fin: self.log_widget.insert(Tkinter.END, line) self.log_widget.see(Tkinter.END) self.log_widget.update_idletasks() self.log_widget.config(state='disabled') self.update_logwidget(self.log_widget, self.log_queue) def update_logwidget(self, widget, queue): widget.config(state='normal') while not queue.empty(): line = queue.get() widget.insert(Tkinter.END, line) widget.see(Tkinter.END) widget.update_idletasks() widget.config(state='disabled') self.logger_alarm = widget.after(10, self.update_logwidget, widget, queue)
class myPanel(tkinter.Tk): def __init__(self): tkinter.Tk.__init__(self, 'lsx') try: self.ss = self.clipboard_get() except: self.ss = '' self.cnt = 0 self.slices = paragraph(self.ss, qrlen) self.string = None if not os.path.exists('config.ini'): x = - 100 + 0.2 * self.winfo_screenwidth() # 100: 补偿初始Tk界面为200x200 y = - 100 + 0.7 * self.winfo_screenheight() xy = '+%d+%d'%(x,y) with open('config.ini','w') as f: f.write(xy) with open('config.ini','r') as f: xy = f.read() self.geometry(xy) self.minsize(450,206) self.qrc = tkinter.Label(self) self.ent = ScrolledText(self, width=1, height=15) self.ent.insert(1.0, self.ss) self.ent.mark_set('insert','0.0') # 程序首次运行时不使用see函数,否则会有未知原因半行内容沉没在Text窗体上面一点点 self.ent.focus() text = self.slices[self.cnt] basic = (len(self.slices),len(self.ss)) info = 'Page: %s, Length: %s'%basic if zh_cn: info = '共%s页, %s字'%basic self.withdraw() # withdraw/deiconify 阻止页面闪烁 self.update_idletasks() self.ent.pack(padx=2, pady=2, fill='both', expand=True, side='right') # RIGHT为了在Label隐藏再显示后所在位置一致 self.qrc.pack() self.setQrcode(text, info) self.deiconify() self.qrc.bind('<Button-2>',self.onExit) self.qrc.bind('<Button-1>',self.fliping) self.qrc.bind('<Button-3>',self.fliping) self.qrc.bind('<Double-Button-1>',self.setting) self.qrc.bind('<Double-ButtonRelease-3>',self.openFile) # 没有Release会在窗口打开之后的鼠标抬起时唤起右键菜单 self.ent.bind('<Escape>',self.onExit) self.ent.bind('<F1>',self.openFile) self.ent.bind('<F2>',self.fliping) self.ent.bind('<F3>',self.fliping) self.ent.bind('<F4>',self.setting) self.ent.bind('<KeyRelease>',self.refresh) self.ent.bind('<ButtonRelease-1>',self.selected) self.bind('<Destroy>',lambda evt:self.onExit(evt,close=True)) def setQrcode(self, string, info): if self.string != string: self.string = string if string == '': self.qrc.forget() else: global img img = qrmake(string) self.qrc.config(image=img) self.qrc.pack() log(string, info) self.title('Text Helper v1.06 (%s)'%info) if zh_cn: self.title('文本助手v1.06 (%s)'%info) def refresh(self, evt): if evt.keysym in ['Control_L', 'Return', 'BackSpace']: ss2 = self.ent.get('0.0', 'end')[:-1] if self.ss != ss2: self.ss = ss2 self.cnt = 0 self.slices = paragraph(self.ss, qrlen) text = self.slices[self.cnt] basic = (len(self.slices),len(self.ss)) info = 'Page: %s, Length: %s'%basic if zh_cn: info = '共%s页, %s字'%basic self.setQrcode(text, info) def fliping(self, evt): if evt.num == 1 or evt.keysym == 'F3': self.cnt = min(self.cnt+1,len(self.slices)-1) else: self.cnt = max(self.cnt-1,0) cur1 = getIndex(''.join(self.slices[:self.cnt])) cur2 = getIndex(''.join(self.slices[:self.cnt+1])) self.setCursor(cur1, cur2) text = self.slices[self.cnt] basic = (self.cnt+1,len(self.slices),len(text),len(self.ss)) info = 'Page: %s/%s, Sel: %s/%s'%basic if zh_cn: info = '第%s/%s页, 共%s/%s字'%basic self.setQrcode(text, info) def selected(self, evt): if self.ent.tag_ranges('sel'): text = self.ent.selection_get() info = 'Sel: %s/%s'%(len(text),len(self.ss)) if zh_cn: info = '选中%s/%s字'%(len(text),len(self.ss)) self.setQrcode(text, info) def setCursor(self, cur1, cur2): self.ent.mark_set('insert', cur1) self.ent.tag_remove('sel','0.0','end') self.ent.tag_add('sel',cur1,cur2) self.ent.see(cur1) def setting(self, evt): max_page = len(self.slices) num = tkinter.simpledialog.askinteger('Goto','Go to page (1-%s):'%max_page, initialvalue=self.cnt+1) self.ent.focus() if num: self.cnt = max(1,min(max_page,num)) - 1 text = self.slices[self.cnt] basic = (self.cnt+1,len(self.slices),len(text),len(self.ss)) info = 'Page: %s/%s, Sel: %s/%s'%basic if zh_cn: info = '第%s/%s页, 共%s/%s字'%basic self.setQrcode(text, info) def openFile(self, evt): path = tkinter.filedialog.askopenfilename() if path != '': filename = os.path.basename(path) with open(path,'rb') as f: s = f.read() try: try: res = s.decode() except: try: res = s.decode('gbk') except: raise except: s = base64.urlsafe_b64encode(filename.encode()+b'\n'+s).decode() total = int((len(s)-1)/(qrlen-10)+1) res = '' for i in range(total): res += '%04d%04d.%s,'%(total, i+1, s[(qrlen-10)*i:(qrlen-10)*(i+1)]) self.ss = res self.cnt = 0 self.slices = paragraph(self.ss, qrlen) self.ent.delete(1.0, 'end') self.ent.insert(1.0, res) text = self.slices[self.cnt] basic = (len(self.slices),len(self.ss)) info = 'Page: %s, Length: %s'%basic if zh_cn: info = '共%s页, %s字'%basic self.setQrcode(text, info) def onExit(self, evt, close=False): xy = '+%d+%d'%(self.winfo_x(),self.winfo_y()) with open('config.ini','w') as f: f.write(xy) if not close: self.destroy()
class client_GUI(Thread): alias = None room = None flag = False in_room = False client = socket() IP = raw_input("IP Address: ") if not IP: IP = 'localhost' try: client.connect((IP, 9000)) except Exception as e: print "Could not connect to IP" logging.exception(e) exit() def __init__(self, master): Thread.__init__(self) frame = Frame(master) frame.pack() self.setAlias() #creates the thread for listening to the Server def run(self): Recieve(self.client) def clearWindow(self): for widget in root.winfo_children(): widget.destroy() def assemble_packet(self, msg, code): parser = Parser() if code == utils.codes["send_msg"]: date = datetime.datetime.now().strftime(utils.DATE_FORMAT) packet = parser.assemble(utils.codes["send_msg"], self.alias, self.room, date, msg) elif code == utils.codes["set_alias"]: packet = parser.assemble(utils.codes["set_alias"], msg, "", "", "") elif code == utils.codes["set_room"]: packet = parser.assemble(utils.codes["set_room"], self.alias, msg, "", "") elif code == utils.codes["get_roomlist"]: packet = parser.assemble(utils.codes["get_roomlist"], self.alias, self.room, "", "") logging.info("Sending packet %s" % (packet)) return packet def breakdown_packet(self, packet): parser = Parser() parser.breakdown(packet) if parser.code == utils.codes["recv_msg"]: return parser.body elif parser.code == utils.codes["recv_roomlist"]: return parser.body elif parser.code == utils.codes["alias_success"]: self.alias = parser.alias return parser.body elif parser.code == utils.codes["alias_invalid"]: return parser.alias elif parser.code == utils.codes["room_success"]: self.room = parser.room return parser.room elif parser.code == utils.codes["room_invalid"]: return parser.room else: logging.info("Invalid packet recieved") return def setAlias(self): def setRoom(): aliasCheck = None self.alias = self.aliasInfo.get().translate(None, '\\') self.alias = self.alias.translate(None, ' ') if len(self.alias) > 20: self.alias = self.alias[:19] packet = self.assemble_packet(self.alias, utils.codes["set_alias"]) try: self.client.send(packet) except Exception as e: logging.exception(e) time.sleep(1) if not inputQueue.empty(): aliasCheck = str(inputQueue.get()) if aliasCheck.startswith(utils.codes["alias_success"]): roomList = self.breakdown_packet(aliasCheck) self.clearWindow() self.changeRoom(roomList) else: self.flag = True self.clearWindow() self.setAlias() else: self.flag = True self.clearWindow() self.setAlias() self.intro = Label(root, text="Welcome to TrashTalk", width=600, font=8000, fg="red", pady=100) self.intro.pack(anchor=CENTER) self.aliasLabel = Label(root, text="Set Your Alias:", pady=10) self.aliasLabel.pack(anchor=CENTER) self.aliasInfo = Entry(root, width=40) self.aliasInfo.pack(anchor=CENTER) self.spacing = Label(root, text="", pady=70) if self.flag: self.spacing.config(text="Invalid, please try again", fg="red") self.spacing.pack(anchor=CENTER) self.login = Button(root, height=2, width=10, text="Pick A Room", command=setRoom) self.login.pack(anchor=CENTER) def changeRoom(self, roomList): def enterRoom(): self.clearWindow() chosenRoom = self.v.get() if not chosenRoom: chosenRoom = firstRoom packet = self.assemble_packet(chosenRoom, utils.codes["set_room"]) try: self.client.send(packet) except Exception as e: logging.exception(e) time.sleep(1) if not inputQueue.empty(): roomCheck = str(inputQueue.get()) if roomCheck.startswith(utils.codes["room_success"]): self.room = chosenRoom self.in_room = True self.inRoom(chosenRoom) else: self.changeRoom(roomList) root.title("TrashTalk") rooms = roomList.split() firstRoom = rooms[0] self.v = StringVar(value=firstRoom) self.roomLabel = Label( root, text="Select which Chat Room You Would Like to Join", pady=70, font=800) self.roomLabel.pack(anchor=CENTER) for room in rooms: self.b = Radiobutton(root, text=room, variable=self.v, value=room) self.b.pack(anchor=CENTER) self.b.deselect() self.login = Button(root, height=2, width=20, text="Enter Chosen Room", command=enterRoom) self.login.place(relx=0.5, y=400, anchor=CENTER) def inRoom(self, room): def newMessage(): message = self.entryBox.get() if message: self.entryBox.delete(0, 'end') message = message.translate(None, '\\') if len(message) > 900: message = message[:899] packet = self.assemble_packet(message, utils.codes["send_msg"]) try: self.client.send(packet) except Exception as e: logging.exception(e) def changingRoom(): packet = self.assemble_packet("", utils.codes["get_roomlist"]) try: self.client.send(packet) except Exception as e: logging.exception(e) time.sleep(1) if not inputQueue.empty(): roomCheck = str(inputQueue.get()) if roomCheck.startswith(utils.codes["recv_roomlist"]): in_room = False roomList = self.breakdown_packet(roomCheck) self.clearWindow() self.changeRoom(roomList) def exitProgram(): self.client.close() os._exit(1) root.title("TrashTalk - " + room) self.messageHistory = ScrolledText(root, undo=True) self.messageHistory.bind("<Key>", lambda e: "break") self.messageHistory.pack(anchor=W) self.messageHistory.insert( END, "Welcome " + self.alias + " to the " + room + " chat room!") self.entryBox = Entry(root, width=85) self.entryBox.place(x=0, y=400, anchor=W) self.sendButton = Button(root, height=2, width=19, text="Send Message", command=newMessage) self.sendButton.place(x=518, y=388, anchor=NW) self.sendButton = Button(root, height=4, width=25, text="Change Room", command=changingRoom) self.sendButton.place(x=725, y=300, anchor=NW) self.sendButton = Button(root, height=4, width=25, text="Quit", command=exitProgram) self.sendButton.place(x=725, y=400, anchor=NW) def update_chat(): if not buildQueue.empty(): MYINFO = buildQueue.get() if MYINFO.startswith(utils.codes["leave_room"]): changingRoom() elif self.in_room: msg = self.breakdown_packet(MYINFO) endOfBox = self.messageHistory.vbar.get() self.messageHistory.insert(END, "\n" + msg) if endOfBox[1] == 1.0: endOfBox = self.messageHistory.see("end") root.after(100, update_chat) root.after(100, update_chat)