class ViewportCard(object): ''' Manages the graphical representation of a card in a Tkinter canvas. Creates and destroys items as necessary, facilitates editing, and so on and so forth. Members: * card: model.Card * viewport: GPViewport * gpfile: gpfile.GraphPaperFile, contains model.graph() * canvas: TKinter canvas we get drawn on * editing: bool, text is being edited * moving: bool, being dragged * moving_edgescroll_id: callback id to scroll periodically when hovering near edge of screen * resize_state: {} * resize_edgescroll_id: as moving_edgescroll_id * slot: calls callbacks whenever geometry changes * new_edge: if an edge is being dragged out from a handle, this is it. * card_after_new_edge: bool, if we should make a new card when edge is dropped. ''' def __init__(self, viewport, gpfile, card): self.card = card self.viewport = viewport self.gpfile = gpfile self.canvas = viewport.canvas self.draw() self.editing = False self.moving = False self.moving_edgescroll_id = None self.resize_state = None self.resize_edgescroll_id = None # slot triggered when geometry (pos/size) changes # fn args: (self, x, y, w, h) self.geom_slot = Slot() self.deletion_slot = Slot() self.new_edge = None def draw(self): self.frame_thickness = 5 self.window = ResizableCanvasFrame(self.canvas, self.card.x, self.card.y, self.card.w, self.card.h, min_width=MIN_CARD_SIZE, min_height=MIN_CARD_SIZE) self.text = ScrolledText(self.window, wrap=WORD) self.text.pack(expand=1, fill='both') # set up text for editing, dragging, deleting self.text.bind("<Button-1>", self.mousedown) self.text.bind("<Shift-Button-1>", self.shiftmousedown) self.text.bind("<Double-Button-1>", self.doubleclick) self.text.bind("<B1-Motion>", self.mousemove) self.text.bind("<ButtonRelease-1>", self.mouseup) self.text.bind("<FocusIn>", self.focusin) self.text.bind("<FocusOut>", self.focusout) self.text.bind("<Control-Delete>", self.ctrldelete) self.text.insert(END, self.card.text) # set up frame for resizing self.window.bind('<Configure>', self.configure) self.window.save_callback = self.save_card # draw edge handles self.edge_handles = None #self.redraw_edge_handles() def redraw_edge_handles(self): ''' Either creates or modifies the edge handles, little circles poking out the side of the card, based on the current position and width. self.edge_handles is a list of itemids of the circles in (top, right, bottom, left) order. ''' def create_circle(bbox): # create circle suitable for edge-handle use new = self.canvas.create_oval(bbox[0], bbox[1], bbox[2], bbox[3], fill='green', outline='') self.canvas.addtag_withtag('card_handle_tag', new) # for z-ordering self.canvas.tag_bind(new, '<Button-1>', self.handle_click) self.canvas.tag_bind(new, '<Shift-Button-1>', self.handle_shift_click) self.canvas.tag_bind(new, '<B1-Motion>', self.handle_mousemove) self.canvas.tag_bind(new, '<ButtonRelease-1>', self.handle_mouseup) return new x, y = self.window.canvas_coords() w, h = self.window.winfo_width(), self.window.winfo_height() # 2*radius should be < MIN_CARD_SIZE, and offset < radius radius = 30 offset = 19 # offset of center of circle from card edge left_coords = (x + offset, y + h / 2) right_coords = (x + w - offset, y + h / 2) top_coords = (x + w / 2, y + offset) bottom_coords = (x + w / 2, y + h - offset) all_coords = (top_coords, right_coords, bottom_coords, left_coords) bboxes = [(x - radius, y - radius, x + radius, y + radius) for x, y in all_coords] if self.edge_handles: # move the edge handles for i, box in enumerate(bboxes): #self.canvas.coords(handle, box[0], box[1], box[2], box[3]) self.canvas.delete(self.edge_handles[i]) self.edge_handles[i] = create_circle(box) #self.canvas.itemconfig(handle, bbox = box) else: # create new ones self.edge_handles = [create_circle(b) for b in bboxes] # have to do this every time, every time we recreate the edge handles self.viewport.fix_z_order() def get_text(self): "gets the text from the actual editor, which may not be saved yet" return self.text.get('0.0', END) def save_text(self): # get text from window text = self.get_text() if text != self.card.text: self.card.text = text self.gpfile.commit() def canvas_coords(self): return self.window.canvas_coords() def start_moving(self, event): # set up state for a drag self.moving = True self.foocoords = (event.x, event.y) self.set_moving_edgescroll_callback() def edge_scroll(self): # if any edges are too close to the edge, move and scroll the canvas canvas_coords = self.canvas_coords() relative_mouse_pos = self.foocoords canvas_mouse_coords = (canvas_coords[0] + relative_mouse_pos[0] + self.frame_thickness, canvas_coords[1] + relative_mouse_pos[1] + self.frame_thickness) scroll_x, scroll_y = self.viewport.edge_scroll(canvas_mouse_coords) # move the opposite direction the viewport scrolled scroll_x, scroll_y = -scroll_x, -scroll_y #print 'card.edgescroll x y', scroll_x, scroll_y, 'relative_mouse_pos', relative_mouse_pos self.window.move(scroll_x, scroll_y) self.viewport.reset_scroll_region() self.set_moving_edgescroll_callback() def set_moving_edgescroll_callback(self): self.moving_edgescroll_id = self.text.after(10, self.edge_scroll) def cancel_moving_edgescroll_callback(self): self.text.after_cancel(self.moving_edgescroll_id) self.moving_edgescroll_id = None def mousedown(self, event): self.window.lift() def doubleclick(self, event): self.start_moving(event) return 'break' def shiftmousedown(self, event): self.mousedown(event) self.start_moving(event) return "break" def mousemove(self, event): if self.moving: # coords are relative to card, not canvas if self.foocoords: delta = (event.x - self.foocoords[0], event.y - self.foocoords[1]) else: delta = (event.x, event.y) self.window.move(delta[0], delta[1]) self.geometry_callback() self.viewport.reset_scroll_region() return "break" def mouseup(self, event): if self.moving: self.moving = False new_coords = self.canvas_coords() self.card.x, self.card.y = new_coords[0], new_coords[1] self.gpfile.commit() self.cancel_moving_edgescroll_callback() self.geometry_callback() # next several functions are bound to the circular edge handles def handle_click(self, event): # create new edge self.new_edge = ViewportEdge(self.viewport, self.gpfile, None, self, None) self.new_edge.mousemove(event) # give it a real start pos def handle_shift_click(self, event): self.handle_click(event) self.new_edge.make_new_card = True def handle_mousemove(self, event): if self.new_edge: self.new_edge.mousemove(event) def handle_mouseup(self, event): if self.new_edge: self.new_edge.mouseup(event) self.new_edge = None def configure(self, event): self.redraw_edge_handles() def focusin(self, event): self.editing = True def focusout(self, event): self.editing = False self.save_text() def ctrldelete(self, event): title_sample = self.get_text().split('\n', 1)[0] if len(title_sample) > 20: title_sample = title_sample[:20] + '...' # delete the card if tkMessageBox.askokcancel( "Delete?", "Delete card \"%s\" and all its edges?" % title_sample): for handle in self.edge_handles: self.canvas.delete(handle) self.deletion_slot.signal() self.viewport.remove_card(self) self.card.delete() self.window.destroy() self.gpfile.commit() return "break" def save_card(self): # grab values from self.window, # and put them in the model.card self.card.x, self.card.y = self.window.canvas_coords() self.card.w, self.card.h = self.window.winfo_width( ), self.window.winfo_height() self.geometry_callback() # here so it gets called after resizing self.gpfile.commit() def add_geom_signal(self, fn): return self.geom_slot.add(fn) def remove_geom_signal(self, handle): self.geom_slot.remove(handle) def add_deletion_signal(self, fn): return self.deletion_slot.add(fn) def remove_deletion_signal(self, handle): self.deletion_slot.remove(handle) def geometry_callback(self): x, y = self.canvas_coords() w, h = self.window.winfo_width(), self.window.winfo_height() self.geom_slot.signal(self, x, y, w, h) def highlight(self): self.text.config(background='#ffffa2') def unhighlight(self): self.text.config(background='white')
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 LogFrame: def __init__(self, root, options, main_logger): self.root = root self.options = options self.main_logger = main_logger self.frame = tk.Frame(self.root) self.frame.columnconfigure(0, weight=1) # first row doesn't expoands self.frame.rowconfigure(0, weight=0) # let the second row grow self.frame.rowconfigure(1, weight=1) self.log_commands_frame = tk.LabelFrame(self.frame, text="Controls", padx=5, pady=5) self.log_commands_frame.grid(row=0, column=0, sticky=tk.NSEW, padx=4, pady=5) self.log_messages_frame = tk.Frame(self.frame) self.log_messages_frame.grid(row=1, column=0, sticky=tk.NSEW) # let the SIP trace growing self.log_messages_frame.columnconfigure(0, weight=1) self.log_messages_frame.rowconfigure(0, weight=1) self.log_messages = ScrolledText(self.log_messages_frame) self.log_messages.grid(row=0, column=0, sticky=tk.NSEW) # Log Messages frame row = 0 self.log_messages_clear_button = tk.Button( self.log_commands_frame, text="Clear", command=self.clear_log_messages) self.log_messages_clear_button.grid(row=row, column=0, sticky=tk.N) self.log_messages_pause_button = tk.Button( self.log_commands_frame, text="Pause", command=self.pause_log_messages) self.log_messages_pause_button.grid(row=row, column=1, sticky=tk.N) row = row + 1 def get_frame(self): return self.frame def clear_log_messages(self): self.log_messages.config(state='normal') self.log_messages.delete(0.0, tk.END) self.log_messages.config(state='disabled') def pause_log_messages(self): if self.log_messages_alarm is not None: self.log_messages.after_cancel(self.log_messages_alarm) self.log_messages_pause_button.configure( text="Resume", command=self.start_log_messages) self.log_messages_alarm = None def start_log_messages(self): self.update_log_messages_widget() self.log_messages_pause_button.configure( text="Pause", command=self.pause_log_messages) def update_log_messages_widget(self): self.update_widget(self.log_messages, self.log_queue) self.log_messages_alarm = self.log_messages.after( 20, self.update_log_messages_widget) def update_widget(self, widget, queue): widget.config(state='normal') while not queue.empty(): line = queue.get() widget.insert(tk.END, line) widget.see(tk.END) # Scroll to the bottom widget.update_idletasks() widget.config(state='disabled')
class ViewportCard(object): """ Manages the graphical representation of a card in a Tkinter canvas. Creates and destroys items as necessary, facilitates editing, and so on and so forth. Members: * card: model.Card * viewport: GPViewport * gpfile: gpfile.GraphPaperFile, contains model.graph() * canvas: TKinter canvas we get drawn on * editing: bool, text is being edited * moving: bool, being dragged * moving_edgescroll_id: callback id to scroll periodically when hovering near edge of screen * resize_state: {} * resize_edgescroll_id: as moving_edgescroll_id * slot: calls callbacks whenever geometry changes * new_edge: if an edge is being dragged out from a handle, this is it. * card_after_new_edge: bool, if we should make a new card when edge is dropped. """ def __init__(self, viewport, gpfile, card): self.card = card self.viewport = viewport self.gpfile = gpfile self.canvas = viewport.canvas self.draw() self.editing = False self.moving = False self.moving_edgescroll_id = None self.resize_state = None self.resize_edgescroll_id = None # slot triggered when geometry (pos/size) changes # fn args: (self, x, y, w, h) self.geom_slot = Slot() self.deletion_slot = Slot() self.new_edge = None def draw(self): self.frame_thickness = 5 self.window = ResizableCanvasFrame( self.canvas, self.card.x, self.card.y, self.card.w, self.card.h, min_width=MIN_CARD_SIZE, min_height=MIN_CARD_SIZE, ) self.text = ScrolledText(self.window, wrap=WORD) self.text.pack(expand=1, fill="both") # set up text for editing, dragging, deleting self.text.bind("<Button-1>", self.mousedown) self.text.bind("<Shift-Button-1>", self.shiftmousedown) self.text.bind("<Double-Button-1>", self.doubleclick) self.text.bind("<B1-Motion>", self.mousemove) self.text.bind("<ButtonRelease-1>", self.mouseup) self.text.bind("<FocusIn>", self.focusin) self.text.bind("<FocusOut>", self.focusout) self.text.bind("<Control-Delete>", self.ctrldelete) self.text.insert(END, self.card.text) # set up frame for resizing self.window.bind("<Configure>", self.configure) self.window.save_callback = self.save_card # draw edge handles self.edge_handles = None # self.redraw_edge_handles() def redraw_edge_handles(self): """ Either creates or modifies the edge handles, little circles poking out the side of the card, based on the current position and width. self.edge_handles is a list of itemids of the circles in (top, right, bottom, left) order. """ def create_circle(bbox): # create circle suitable for edge-handle use new = self.canvas.create_oval(bbox[0], bbox[1], bbox[2], bbox[3], fill="green", outline="") self.canvas.addtag_withtag("card_handle_tag", new) # for z-ordering self.canvas.tag_bind(new, "<Button-1>", self.handle_click) self.canvas.tag_bind(new, "<Shift-Button-1>", self.handle_shift_click) self.canvas.tag_bind(new, "<B1-Motion>", self.handle_mousemove) self.canvas.tag_bind(new, "<ButtonRelease-1>", self.handle_mouseup) return new x, y = self.window.canvas_coords() w, h = self.window.winfo_width(), self.window.winfo_height() # 2*radius should be < MIN_CARD_SIZE, and offset < radius radius = 30 offset = 19 # offset of center of circle from card edge left_coords = (x + offset, y + h / 2) right_coords = (x + w - offset, y + h / 2) top_coords = (x + w / 2, y + offset) bottom_coords = (x + w / 2, y + h - offset) all_coords = (top_coords, right_coords, bottom_coords, left_coords) bboxes = [(x - radius, y - radius, x + radius, y + radius) for x, y in all_coords] if self.edge_handles: # move the edge handles for i, box in enumerate(bboxes): # self.canvas.coords(handle, box[0], box[1], box[2], box[3]) self.canvas.delete(self.edge_handles[i]) self.edge_handles[i] = create_circle(box) # self.canvas.itemconfig(handle, bbox = box) else: # create new ones self.edge_handles = [create_circle(b) for b in bboxes] # have to do this every time, every time we recreate the edge handles self.viewport.fix_z_order() def get_text(self): "gets the text from the actual editor, which may not be saved yet" return self.text.get("0.0", END) def save_text(self): # get text from window text = self.get_text() if text != self.card.text: self.card.text = text self.gpfile.commit() def canvas_coords(self): return self.window.canvas_coords() def start_moving(self, event): # set up state for a drag self.moving = True self.foocoords = (event.x, event.y) self.set_moving_edgescroll_callback() def edge_scroll(self): # if any edges are too close to the edge, move and scroll the canvas canvas_coords = self.canvas_coords() relative_mouse_pos = self.foocoords canvas_mouse_coords = ( canvas_coords[0] + relative_mouse_pos[0] + self.frame_thickness, canvas_coords[1] + relative_mouse_pos[1] + self.frame_thickness, ) scroll_x, scroll_y = self.viewport.edge_scroll(canvas_mouse_coords) # move the opposite direction the viewport scrolled scroll_x, scroll_y = -scroll_x, -scroll_y # print 'card.edgescroll x y', scroll_x, scroll_y, 'relative_mouse_pos', relative_mouse_pos self.window.move(scroll_x, scroll_y) self.viewport.reset_scroll_region() self.set_moving_edgescroll_callback() def set_moving_edgescroll_callback(self): self.moving_edgescroll_id = self.text.after(10, self.edge_scroll) def cancel_moving_edgescroll_callback(self): self.text.after_cancel(self.moving_edgescroll_id) self.moving_edgescroll_id = None def mousedown(self, event): self.window.lift() def doubleclick(self, event): self.start_moving(event) return "break" def shiftmousedown(self, event): self.mousedown(event) self.start_moving(event) return "break" def mousemove(self, event): if self.moving: # coords are relative to card, not canvas if self.foocoords: delta = (event.x - self.foocoords[0], event.y - self.foocoords[1]) else: delta = (event.x, event.y) self.window.move(delta[0], delta[1]) self.geometry_callback() self.viewport.reset_scroll_region() return "break" def mouseup(self, event): if self.moving: self.moving = False new_coords = self.canvas_coords() self.card.x, self.card.y = new_coords[0], new_coords[1] self.gpfile.commit() self.cancel_moving_edgescroll_callback() self.geometry_callback() # next several functions are bound to the circular edge handles def handle_click(self, event): # create new edge self.new_edge = ViewportEdge(self.viewport, self.gpfile, None, self, None) self.new_edge.mousemove(event) # give it a real start pos def handle_shift_click(self, event): self.handle_click(event) self.new_edge.make_new_card = True def handle_mousemove(self, event): if self.new_edge: self.new_edge.mousemove(event) def handle_mouseup(self, event): if self.new_edge: self.new_edge.mouseup(event) self.new_edge = None def configure(self, event): self.redraw_edge_handles() def focusin(self, event): self.editing = True def focusout(self, event): self.editing = False self.save_text() def ctrldelete(self, event): title_sample = self.get_text().split("\n", 1)[0] if len(title_sample) > 20: title_sample = title_sample[:20] + "..." # delete the card if tkMessageBox.askokcancel("Delete?", 'Delete card "%s" and all its edges?' % title_sample): for handle in self.edge_handles: self.canvas.delete(handle) self.deletion_slot.signal() self.viewport.remove_card(self) self.card.delete() self.window.destroy() self.gpfile.commit() return "break" def save_card(self): # grab values from self.window, # and put them in the model.card self.card.x, self.card.y = self.window.canvas_coords() self.card.w, self.card.h = self.window.winfo_width(), self.window.winfo_height() self.geometry_callback() # here so it gets called after resizing self.gpfile.commit() def add_geom_signal(self, fn): return self.geom_slot.add(fn) def remove_geom_signal(self, handle): self.geom_slot.remove(handle) def add_deletion_signal(self, fn): return self.deletion_slot.add(fn) def remove_deletion_signal(self, handle): self.deletion_slot.remove(handle) def geometry_callback(self): x, y = self.canvas_coords() w, h = self.window.winfo_width(), self.window.winfo_height() self.geom_slot.signal(self, x, y, w, h) def highlight(self): self.text.config(background="#ffffa2") def unhighlight(self): self.text.config(background="white")
class LogFrame: def __init__(self, root, options, main_logger): self.root = root self.options = options self.main_logger = main_logger self.frame = tk.Frame(self.root) self.frame.columnconfigure(0, weight=1) # first row doesn't expoands self.frame.rowconfigure(0, weight=0) # let the second row grow self.frame.rowconfigure(1, weight=1) self.log_commands_frame = tk.LabelFrame(self.frame, text="Controls", padx=5, pady=5) self.log_commands_frame.grid(row=0, column=0, sticky=tk.NSEW, padx=4, pady=5) self.log_messages_frame = tk.Frame(self.frame) self.log_messages_frame.grid(row=1, column=0, sticky=tk.NSEW) # let the SIP trace growing self.log_messages_frame.columnconfigure(0, weight=1) self.log_messages_frame.rowconfigure(0, weight=1) self.log_messages = ScrolledText(self.log_messages_frame) self.log_messages.grid(row=0, column=0, sticky=tk.NSEW) # Log Messages frame row = 0 self.log_messages_clear_button = tk.Button(self.log_commands_frame, text="Clear", command=self.clear_log_messages) self.log_messages_clear_button.grid(row=row, column=0, sticky=tk.N) self.log_messages_pause_button = tk.Button(self.log_commands_frame, text="Pause", command=self.pause_log_messages) self.log_messages_pause_button.grid(row=row, column=1, sticky=tk.N) row = row + 1 def get_frame(self): return self.frame def clear_log_messages(self): self.log_messages.config(state='normal') self.log_messages.delete(0.0, tk.END) self.log_messages.config(state='disabled') def pause_log_messages(self): if self.log_messages_alarm is not None: self.log_messages.after_cancel(self.log_messages_alarm) self.log_messages_pause_button.configure(text="Resume", command=self.start_log_messages) self.log_messages_alarm = None def start_log_messages(self): self.update_log_messages_widget() self.log_messages_pause_button.configure(text="Pause", command=self.pause_log_messages) def update_log_messages_widget(self): self.update_widget(self.log_messages, self.log_queue) self.log_messages_alarm = self.log_messages.after(20, self.update_log_messages_widget) def update_widget(self, widget, queue): widget.config(state='normal') while not queue.empty(): line = queue.get() widget.insert(tk.END, line) widget.see(tk.END) # Scroll to the bottom widget.update_idletasks() widget.config(state='disabled')
class LogReader(object): def __init__(self, root, **kwargs): self.root = root self.filenameLog = kwargs.get('filenameLog', None) self.ClearDisplay = kwargs.get('ClearDisplay', False) ''' By default don't display Filenames and directory ''' mainstyle = ttk.Style() # mainstyle.theme_use(mainstyle.theme_names()[0]) mainstyle.configure('My.TFrame', background='gray50', foreground='gray97', font="Monospace 12") Btnstyle = ttk.Style() Btnstyle.configure('My.TButton', background='gray50', foreground='gray97', font="Monospace 12") root.title("Log reader v0.1") Chkstyle = ttk.Style() Chkstyle.configure('My.TCheckbutton', background='gray50', foreground='gray97', font="Monospace 12") Chkstyle = ttk.Style() Chkstyle.configure('My.TLabel', background='gray50', foreground='gray97', font="Monospace 12") root.title("Libretto v0.1") self.initParam() #====================================================================== # Main Frame #====================================================================== self.f0 = ttk.Frame(self.root, style='My.TFrame') self.f0.pack(expand=True, fill='both') LabelUP = ttk.Label( self.f0, text="Please select the log file then click on read", style='My.TLabel') LabelUP.pack(side="top") self.fDisp = ttk.Frame(self.f0, style='My.TFrame') self.fDisp.pack(expand=True, fill='both', side="right") self.fParam = ttk.Frame(self.f0, style='My.TFrame') self.fParam.pack(side="left") #====================================================================== # Frame fDisp #====================================================================== # Display stdout self.customFont = tkFont.Font( family="Helvetica", size=12) self.text_area = ScrolledText( self.fDisp, font=self.customFont, undo=True, background='gray20', foreground="gray92") self.text_area.pack(expand=True, fill='both') self.text_area.configure(state='normal') self.text_area.yview(END) self.text_area.after(0) self.text_area.tag_configure("comment", font="Helvetica 12", foreground="gray60") self.text_area.tag_configure("subsubTitle", font="Helvetica 12 bold") self.text_area.tag_configure("subTitle", font="Helvetica 14 bold") self.text_area.tag_configure("Title", font="Helvetica 16 bold") self.text_area.tag_configure("warn", font="Helvetica 12 bold", foreground="red") self.text_area.tag_configure("File", font="Helvetica 10", foreground="DarkSlateGray1") self.text_area.tag_configure("FileOther", font="Helvetica 10", foreground="plum") self.text_area.tag_configure("Directory", font="Helvetica 10", foreground="goldenrod1") self.text_area.tag_configure("validate", font="Helvetica 12 bold", foreground="OliveDrab1") self.text_area.tag_configure("param", font="Helvetica 12", foreground="wheat") # stdout redirection sys.stdout = StdoutRedirector(self.text_area) #====================================================================== # Parameters #====================================================================== # File Selection button SelectLogFileBtn = ttk.Button( self.fParam, text="Select the log file", style='My.TButton') SelectLogFileBtn.grid(row=0, column=0) SelectLogFileBtn.configure(command=lambda: self.set_LogFile()) Label = ttk.Label(self.fParam, text="", style='My.TLabel') Label.grid(row=1, column=0) # Refresh button SelectLogFileBtn = ttk.Button( self.fParam, text="Refresh", style='My.TButton') SelectLogFileBtn.grid(row=2, column=0) SelectLogFileBtn.configure(command=lambda: self.RefreshLog()) Label = ttk.Label(self.fParam, text="", style='My.TLabel') Label.grid(row=9, column=0) # Display Files button ChkBtnDispFilenames = ttk.Checkbutton( self.fParam, text="Display the filenames", style='My.TCheckbutton') ChkBtnDispFilenames.grid(row=10, column=0) ChkBtnDispFilenames.configure(variable=self.Entry_DispFilenames, command=lambda: self.set_DispFilenames()) # Display Comments button ChkBtnDispCom = ttk.Checkbutton( self.fParam, text="Display the comments", style='My.TCheckbutton') ChkBtnDispCom.grid(row=11, column=0) ChkBtnDispCom.configure(variable=self.Entry_DispComment, command=lambda: self.set_DispComment()) # Display Directories button ChkBtnDispDir = ttk.Checkbutton( self.fParam, text="Display the directories", style='My.TCheckbutton') ChkBtnDispDir.grid(row=12, column=0) ChkBtnDispDir.configure(variable=self.Entry_DispDir, command=lambda: self.set_DispDir()) # Display Warnings button ChkBtnDispWarn = ttk.Checkbutton( self.fParam, text="Display the warnings", style='My.TCheckbutton') ChkBtnDispWarn.grid(row=13, column=0) ChkBtnDispWarn.configure(variable=self.Entry_DispWarn, command=lambda: self.set_DispWarn()) # Display Warnings button ChkBtnDispParam = ttk.Checkbutton( self.fParam, text="Display the parameters", style='My.TCheckbutton') ChkBtnDispParam.grid(row=14, column=0) ChkBtnDispParam.configure(variable=self.Entry_DispParam, command=lambda: self.set_DispParam()) self.RefreshLog() if self.ClearDisplay: self.UpdateAllDisp() def printExample(self): return ["=========================================", "= Welcome in the Log Reader ", "=========================================", "", "=== This is a big title ! ===", " ~ A little bit different of this sub-Title", " * And guess what, now a sub-sub-Title ! ", " # right now I am commenting my example", " p_Dodo is a parameter", " BlablablaAudyIsTheBestBlablabla...", " X_something is a most of the time the filename of " + " an MRI image or created", " Z_something is the filename of a file which is not an " + "mri image (it can be some stats or a matrix)", " D_anotherthing is a directory", " > Well this task seems to be a success", " !! But this is a message you should read"] def initParam(self): self.logExtension = ("*.txt", "*.log") self.LogMessage = None self.listHideBal = [] global DefaultFileNameMRIImage global DefaultFileNameMRIMasks global DefaultFileNameOther global DefaultFileNameMatrix global DefaultDirectory global DefaultName global DefaultWarning global DefaultTitle global DefaultSubTitle global DefaultSubSubTitle global DefaultComment global DefaultValidate global DefaultParameter self.DefaultFileNameMRIImage = DefaultFileNameMRIImage self.DefaultFileNameMRIMasks = DefaultFileNameMRIMasks self.DefaultFileNameOther = DefaultFileNameOther self.DefaultFileNameMatrix = DefaultFileNameMatrix self.DefaultDirectory = DefaultDirectory self.DefaultName = DefaultName self.DefaultWarning = DefaultWarning self.DefaultTitle = DefaultTitle self.DefaultSubTitle = DefaultSubTitle self.DefaultSubSubTitle = DefaultSubSubTitle self.DefaultComment = DefaultComment self.DefaultValidate = DefaultValidate self.DefaultParameter = DefaultParameter self.DispWarn = True self.Entry_DispWarn = IntVar(value=1) self.DispParam = True self.Entry_DispParam = IntVar(value=1) if self.ClearDisplay: self.DispFilenames = False self.Entry_DispFilenames = IntVar(value=0) self.DispComment = False self.Entry_DispComment = IntVar(value=0) self.DispDir = False self.Entry_DispDir = IntVar(value=0) else: self.DispFilenames = True self.Entry_DispFilenames = IntVar(value=1) self.DispComment = True self.Entry_DispComment = IntVar(value=1) self.DispDir = True self.Entry_DispDir = IntVar(value=1) def DispOrHide(self, DispSomething, listHideBal): if DispSomething: # update the balise to hide list listHideBal = [e for e in self.listHideBal if e not in listHideBal] else: listHideBal = listHideBal + self.listHideBal self.listHideBal = listHideBal self.resetDisp() self.watchLog(bal=self.listHideBal) def set_DispFilenames(self): self.DispFilenames = self.Entry_DispFilenames.get() listbal0 = [self.DefaultFileNameMRIImage, self.DefaultFileNameMatrix, self.DefaultFileNameMRIMasks, self.DefaultFileNameOther] self.DispOrHide(self.DispFilenames, listbal0) def set_DispDir(self): self.DispDir = self.Entry_DispDir.get() listbal0 = [self.DefaultDirectory] self.DispOrHide(self.DispDir, listbal0) def set_DispComment(self): self.DispComment = self.Entry_DispComment.get() listbal0 = [self.DefaultComment] self.DispOrHide(self.DispComment, listbal0) def set_DispWarn(self): self.DispWarn = self.Entry_DispWarn.get() listbal0 = [self.DefaultWarning] self.DispOrHide(self.DispWarn, listbal0) def set_DispParam(self): self.DispParam = self.Entry_DispParam.get() listbal0 = [self.DefaultParameter] self.DispOrHide(self.DispParam, listbal0) def UpdateAllDisp(self): self.set_DispComment() self.set_DispDir() self.set_DispFilenames() def set_LogFile(self): self.filenameLog = self.OpenFile( self.OriginalDirectory, self.logExtension) self.RefreshLog() def filterLog(self, str0, bal): ''' delete the lines which contain a specific balise ''' if type(bal) != list: if type(bal) != str: if not bal: return str0 else: bal = [bal] try: str1 = DeleteTabulation(str0) except: str1 = str0 for e in bal: if str1[0:len(e)] == e: return None return str0 def loadLog(self): ''' load a log ''' if self.filenameLog: with open(self.filenameLog) as f: self.LogMessage = f.read().splitlines() else: self.LogMessage = self.printExample() def watchLog(self, bal=None): ''' display the log ''' for line in self.LogMessage: l = self.filterLog(line, bal) if l: print l def resetDisp(self): ''' ''' self.text_area.delete('1.0', END) def RefreshLog(self): self.loadLog() self.resetDisp() self.watchLog(bal=self.listHideBal) def OpenFile(self, initialdir0="", filetype='*.*'): if filetype != '*.*': filetypes0 = (("Files", filetype), ("All Files", "*.*")) name = askopenfilename(initialdir=initialdir0, filetypes=filetypes0, title="Choose a file.") else: name = askopenfilename(initialdir=initialdir0, title="Choose a file.") return name def close(self): print "close" exit()