class Example(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.tree = Treeview(self) self.tree["columns"] = ("item1", "item2") self.tree.heading("item1", text="Column 1") self.tree.heading("item2", text="Column 2") self.tree.insert("", 0, text="Item 1", values=("Value 1", "Value 2")) row2 = self.tree.insert("", 1, "row2", text="Item 2") self.tree.insert(row2, "end", "item1", text="Item 1", values=("3", "7")) self.tree.insert(row2, "end", "item2", text="Item 2", values=("2", "5")) self.tree.pack(expand=1, fill="both") self.delete = Button(self, text="Delete Row", command=self.on_delete) self.delete.pack(side="bottom") def on_delete(self): try: selected_item = self.tree.selection()[0] self.tree.delete(selected_item) except IndexError: pass
class Multicolumn_Listbox(object): _style_index = 0 class List_Of_Rows(object): def __init__(self, multicolumn_listbox): self._multicolumn_listbox = multicolumn_listbox def data(self, index): return self._multicolumn_listbox.row_data(index) def get(self, index): return Row(self._multicolumn_listbox, index) def insert(self, data, index=None): self._multicolumn_listbox.insert_row(data, index) def delete(self, index): self._multicolumn_listbox.delete_row(index) def update(self, index, data): self._multicolumn_listbox.update_row(index, data) def select(self, index): self._multicolumn_listbox.select_row(index) def deselect(self, index): self._multicolumn_listbox.deselect_row(index) def set_selection(self, indices): self._multicolumn_listbox.set_selection(indices) def __getitem__(self, index): return self.get(index) def __setitem__(self, index, value): return self._multicolumn_listbox.update_row(index, value) def __delitem__(self, index): self._multicolumn_listbox.delete_row(index) def __len__(self): return self._multicolumn_listbox.number_of_rows class List_Of_Columns(object): def __init__(self, multicolumn_listbox): self._multicolumn_listbox = multicolumn_listbox def data(self, index): return self._multicolumn_listbox.get_column(index) def get(self, index): return Column(self._multicolumn_listbox, index) def delete(self, index): self._multicolumn_listbox.delete_column(index) def update(self, index, data): self._multicolumn_listbox.update_column(index, data) def __getitem__(self, index): return self.get(index) def __setitem__(self, index, value): return self._multicolumn_listbox.update_column(index, value) def __delitem__(self, index): self._multicolumn_listbox.delete_column(index) def __len__(self): return self._multicolumn_listbox.number_of_columns def __init__(self, master, columns, data=None, command=None, sort=True, select_mode=None, heading_anchor=CENTER, cell_anchor=W, style=None, height=None, padding=None, adjust_heading_to_content=False, stripped_rows=None, selection_background=None, selection_foreground=None, field_background=None, heading_font=None, heading_background=None, heading_foreground=None, cell_pady=2, cell_background=None, cell_foreground=None, cell_font=None, headers=True): self._stripped_rows = stripped_rows self._columns = columns self._number_of_rows = 0 self._number_of_columns = len(columns) self.row = self.List_Of_Rows(self) self.column = self.List_Of_Columns(self) s = Style() if style is None: style_name = "Multicolumn_Listbox%s.Treeview" % self._style_index self._style_index += 1 else: style_name = style style_map = {} if selection_background is not None: style_map["background"] = [('selected', selection_background)] if selection_foreground is not None: style_map["foeground"] = [('selected', selection_foreground)] if style_map: s.map(style_name, **style_map) style_config = {} if cell_background is not None: style_config["background"] = cell_background if cell_foreground is not None: style_config["foreground"] = cell_foreground if cell_font is None: font_name = s.lookup(style_name, "font") cell_font = nametofont(font_name) else: if not isinstance(cell_font, Font): if isinstance(cell_font, basestring): cell_font = nametofont(cell_font) else: if len(font) == 1: cell_font = Font(family=cell_font[0]) elif len(font) == 2: cell_font = Font(family=cell_font[0], size=cell_font[1]) elif len(font) == 3: cell_font = Font(family=cell_font[0], size=cell_font[1], weight=cell_font[2]) else: raise ValueError( "Not possible more than 3 values for font") style_config["font"] = cell_font self._cell_font = cell_font self._rowheight = cell_font.metrics("linespace") + cell_pady style_config["rowheight"] = self._rowheight if field_background is not None: style_config["fieldbackground"] = field_background s.configure(style_name, **style_config) heading_style_config = {} if heading_font is not None: heading_style_config["font"] = heading_font if heading_background is not None: heading_style_config["background"] = heading_background if heading_foreground is not None: heading_style_config["foreground"] = heading_foreground heading_style_name = style_name + ".Heading" s.configure(heading_style_name, **heading_style_config) treeview_kwargs = {"style": style_name} if height is not None: treeview_kwargs["height"] = height if padding is not None: treeview_kwargs["padding"] = padding if headers: treeview_kwargs["show"] = "headings" else: treeview_kwargs["show"] = "" if select_mode is not None: treeview_kwargs["selectmode"] = select_mode self.interior = Treeview(master, columns=columns, **treeview_kwargs) if command is not None: self._command = command self.interior.bind("<<TreeviewSelect>>", self._on_select) for i in range(0, self._number_of_columns): if sort: self.interior.heading( i, text=columns[i], anchor=heading_anchor, command=lambda col=i: self.sort_by(col, descending=False)) else: self.interior.heading(i, text=columns[i], anchor=heading_anchor) if adjust_heading_to_content: self.interior.column(i, width=Font().measure(columns[i])) self.interior.column(i, anchor=cell_anchor) if data is not None: for row in data: self.insert_row(row) @property def row_height(self): return self._rowheight @property def font(self): return self._cell_font def configure_column(self, index, width=None, minwidth=None, anchor=None, stretch=None): kwargs = {} for config_name in ("width", "anchor", "stretch", "minwidth"): config_value = locals()[config_name] if config_value is not None: kwargs[config_name] = config_value self.interior.column('#%s' % (index + 1), **kwargs) def row_data(self, index): try: item_ID = self.interior.get_children()[index] except IndexError: raise ValueError("Row index out of range: %d" % index) return self.item_ID_to_row_data(item_ID) def update_row(self, index, data): try: item_ID = self.interior.get_children()[index] except IndexError: raise ValueError("Row index out of range: %d" % index) if len(data) == len(self._columns): self.interior.item(item_ID, values=data) else: raise ValueError("The multicolumn listbox has only %d columns" % self._number_of_columns) def delete_row(self, index): list_of_items = self.interior.get_children() try: item_ID = list_of_items[index] except IndexError: raise ValueError("Row index out of range: %d" % index) self.interior.delete(item_ID) self._number_of_rows -= 1 if self._stripped_rows: for i in range(index, self._number_of_rows): self.interior.tag_configure(list_of_items[i + 1], background=self._stripped_rows[i % 2]) def insert_row(self, data, index=None): if len(data) != self._number_of_columns: raise ValueError("The multicolumn listbox has only %d columns" % self._number_of_columns) if index is None: index = self._number_of_rows - 1 item_ID = self.interior.insert('', index, values=data) self.interior.item(item_ID, tags=item_ID) self._number_of_rows += 1 if self._stripped_rows: list_of_items = self.interior.get_children() self.interior.tag_configure(item_ID, background=self._stripped_rows[index % 2]) for i in range(index + 1, self._number_of_rows): self.interior.tag_configure(list_of_items[i], background=self._stripped_rows[i % 2]) def column_data(self, index): return [ self.interior.set(child_ID, index) for child_ID in self.interior.get_children('') ] def update_column(self, index, data): for i, item_ID in enumerate(self.interior.get_children()): data_row = self.item_ID_to_row_data(item_ID) data_row[index] = data[i] self.interior.item(item_ID, values=data_row) return data def clear(self): # Another possibility: # self.interior.delete(*self.interior.get_children()) for row in self.interior.get_children(): self.interior.delete(row) self._number_of_rows = 0 def update(self, data): self.clear() for row in data: self.insert_row(row) def focus(self, index=None): if index is None: return self.interior.item(self.interior.focus()) else: item = self.interior.get_children()[index] self.interior.focus(item) def state(self, state=None): if stateSpec is None: return self.interior.state() else: self.interior.state(state) @property def number_of_rows(self): return self._number_of_rows @property def number_of_columns(self): return self._number_of_columns def toogle_selection(self, index): list_of_items = self.interior.get_children() try: item_ID = list_of_items[index] except IndexError: raise ValueError("Row index out of range: %d" % index) self.interior.selection_toggle(item_ID) def select_row(self, index): list_of_items = self.interior.get_children() try: item_ID = list_of_items[index] except IndexError: raise ValueError("Row index out of range: %d" % index) self.interior.selection_add(item_ID) def deselect_row(self, index): list_of_items = self.interior.get_children() try: item_ID = list_of_items[index] except IndexError: raise ValueError("Row index out of range: %d" % index) self.interior.selection_remove(item_ID) def deselect_all(self): self.interior.selection_remove(self.interior.selection()) def set_selection(self, indices): list_of_items = self.interior.get_children() self.interior.selection_set(" ".join(list_of_items[row_index] for row_index in indices)) @property def selected_rows(self): data = [] for item_ID in self.interior.selection(): data_row = self.item_ID_to_row_data(item_ID) data.append(data_row) return data @property def indices_of_selected_rows(self): list_of_indices = [] for index, item_ID in enumerate(self.interior.get_children()): if item_ID in self.interior.selection(): list_of_indices.append(index) return list_of_indices def delete_all_selected_rows(self): selected_items = self.interior.selection() for item_ID in selected_items: self.interior.delete(item_ID) number_of_deleted_rows = len(selected_items) self._number_of_rows -= number_of_deleted_rows return number_of_deleted_rows def _on_select(self, event): for item_ID in event.widget.selection(): data_row = self.item_ID_to_row_data(item_ID) self._command(data_row) def item_ID_to_row_data(self, item_ID): item = self.interior.item(item_ID) return item["values"] @property def table_data(self): data = [] for item_ID in self.interior.get_children(): data_row = self.item_ID_to_row_data(item_ID) data.append(data_row) return data @table_data.setter def table_data(self, data): self.update(data) def cell_data(self, row, column): """Get the value of a table cell""" try: item = self.interior.get_children()[row] except IndexError: raise ValueError("Row index out of range: %d" % row) return self.interior.set(item, column) def update_cell(self, row, column, value): """Set the value of a table cell""" item_ID = self.interior.get_children()[row] data = self.item_ID_to_row_data(item_ID) data[column] = value self.interior.item(item_ID, values=data) def __getitem__(self, index): if isinstance(index, tuple): row, column = index return self.cell_data(row, column) else: raise Exception("Row and column indices are required") def __setitem__(self, index, value): if isinstance(index, tuple): row, column = index self.update_cell(row, column, value) else: raise Exception("Row and column indices are required") def bind(self, event, handler): self.interior.bind(event, handler) def sort_by(self, col, descending): """ sort tree contents when a column header is clicked """ # grab values to sort data = [(self.interior.set(child_ID, col), child_ID) for child_ID in self.interior.get_children('')] # if the Demo_programs to be sorted is numeric change to float try: data = [(float(number), child_ID) for number, child_ID in data] except ValueError: pass # now sort the Demo_programs in place data.sort(reverse=descending) for idx, item in enumerate(data): self.interior.move(item[1], '', idx) # switch the heading so that it will sort in the opposite direction self.interior.heading( col, command=lambda col=col: self.sort_by(col, not descending)) if self._stripped_rows: list_of_items = self.interior.get_children('') for i in range(len(list_of_items)): self.interior.tag_configure(list_of_items[i], background=self._stripped_rows[i % 2]) def destroy(self): self.interior.destroy() def item_ID(self, index): return self.interior.get_children()[index]
class App: def __init__(self, window): self.window = window self.mainDaemonAlive = False self.reportServerAlive = False self.reportServerBut = None self.progressbarRunning = False self.modelTree = None self.nsListStr = StringVar(self.window) self.filterStatusStr = StringVar(self.window) self.reportClientStatusStr = StringVar(self.window) self.playModeStr = StringVar(self.window, PLAY_MODES[0]) self.pktCopyMaxSize = StringVar(self.window, "60") self.netInterfaceStr = StringVar(self.window, NET_INTERFACES[0]) self.servicePortsStr = StringVar(self.window, "DNS") self.debugLevelStr = StringVar(self.window, DEBUG_LEVELS[0]) self.filterControlButStr = StringVar(self.window, "START") self.reportClientControlButStr = StringVar(self.window, "START") self.progressFrame = Frame(self.window, width=700, height=20) self.progressFrame.pack(side=TOP) Frame(self.window, width=700, height=10).pack(side=TOP) self.parseNS("/etc/resolv.conf") self.getDaemonStatus() self.home() Frame(self.window, width=700, height=10).pack(side=TOP) self.window.resizable(width=False, height=False) Style().configure("TButton", padding=6, relief="raised", background="#999") def home(self): """ Initialize main window. """ #Configured NS info frame nsFrame = Frame(self.window, relief="groove", borderwidth=1) Label(nsFrame, text="Configured nameservers:", height=2, anchor='w').grid(row=0, sticky="nsew") Label(nsFrame, textvariable=self.nsListStr, relief="sunken").grid(row=1, sticky="nsew") nsFrame.pack(side=TOP, fill=X, padx=20, pady=10, ipadx=20, ipady=5) Separator(self.window, orient="horizontal").pack(side=TOP, padx=20, fill=X) #Runtime params frame nsFrame = Frame(self.window, relief="groove", borderwidth=1) Label(nsFrame, text="Runtime configurations:", height=2, anchor='w').grid(row=0, sticky="nsew") Label(nsFrame, text="Play mode:").grid(row=1, column=0) OptionMenu(nsFrame, self.playModeStr, *PLAY_MODES).grid(row=1, column=1) Separator(nsFrame, orient="vertical").grid(row=1, column=2, sticky="ns", padx=20) Label(nsFrame, text="Interface:").grid(row=1, column=3) OptionMenu(nsFrame, self.netInterfaceStr, *NET_INTERFACES).grid(row=1, column=4) Separator(nsFrame, orient="vertical").grid(row=1, column=5, sticky="ns", padx=20) Label(nsFrame, text="Service:").grid(row=1, column=6) OptionMenu(nsFrame, self.servicePortsStr, *NET_PORTS.keys()).grid(row=1, column=7) Separator(nsFrame, orient="vertical").grid(row=1, column=8, sticky="ns", padx=20) Label(nsFrame, text="Debug level:").grid(row=1, column=9) OptionMenu(nsFrame, self.debugLevelStr, *DEBUG_LEVELS).grid(row=1, column=10) nsFrame.pack(side=TOP, fill=X, padx=20, pady=10, ipadx=20, ipady=5) Separator(nsFrame, orient="vertical").grid(row=2, column=2, sticky="ns", padx=20) Label(nsFrame, text="Max datagram bytes to copy:").grid(row=2, column=3) Entry(nsFrame, width=5, text=self.pktCopyMaxSize.get(), textvariable=self.pktCopyMaxSize).grid(row=2, column=4) Separator(nsFrame, orient="vertical").grid(row=2, column=5, sticky="ns", padx=20) nsFrame.pack(side=TOP, fill=X, padx=20, pady=10, ipadx=20, ipady=5) Separator(self.window, orient="horizontal").pack(side=TOP, padx=20, fill=X) #filter daemon status frame statusFrame = Frame(self.window) Label(statusFrame, text="DNS filter status:", height=2, anchor='w').grid(row=0, column=0) Label(statusFrame, textvariable=self.filterStatusStr).grid(row=0, column=1) Button(statusFrame, textvariable=self.filterControlButStr, command=self.changeFilterStatus).grid(row=1, column=0, sticky=W) statusFrame.pack(side=TOP, fill=X, padx=20, pady=10, ipadx=20, ipady=5) Separator(self.window, orient="horizontal").pack(side=TOP, padx=20, fill=X) #model files frame modelFrame = Frame(self.window) Label(modelFrame, text="Model tags: [{}]".format(configs["model_tags"]), height=2, anchor='w').grid(row=0, sticky="nsew") Label(modelFrame, text="Model configuration", height=2).grid(row=1, sticky=W) self.modelConfigFrame(modelFrame).grid(row=2, columnspan=2, sticky=W) modelFrame.pack(side=TOP, fill=X, padx=20, pady=10, ipadx=20, ipady=5) Separator(self.window, orient="horizontal").pack(side=TOP, padx=20, fill=X) #web report client frame reportClientFrame = Frame(self.window) Label(reportClientFrame, text="Realtime report client status:", height=2, anchor='w').grid(row=0, column=0) Label(reportClientFrame, textvariable=self.reportClientStatusStr).grid(row=0, column=1) self.reportServerBut = Button( reportClientFrame, textvariable=self.reportClientControlButStr, command=self.changeReportClientStatus, state=self.getButtonStateForBool(self.mainDaemonAlive)) self.reportServerBut.grid(row=1, column=0, sticky=W) reportClientFrame.pack(side=TOP, fill=X, padx=20, pady=10, ipadx=20, ipady=5) Separator(self.window, orient="horizontal").pack(side=TOP, padx=20, fill=X) #Refresh status frame reloadFrame = Frame(self.window) Button(reloadFrame, text="Reload", command=self.getDaemonStatus).grid(row=0, column=1, sticky=E) reloadFrame.pack(side=TOP, fill=X, padx=20, pady=10, ipadx=20, ipady=5) Separator(self.window, orient="horizontal").pack(side=TOP, padx=20, fill=X) return def modelConfigFrame(self, parent): """ Create and place next under parent a frame containing the current model configuration. """ #Create container frame = Frame(parent) #Create treeView for model configuration self.modelTree = Treeview(parent, columns=('size', 'modified')) self.populateModelTree() self.modelTree.grid(row=1) #Bind right-click (<Button-3>) on tree items for contextual menus def treeContextualMenu(event): itemId = self.modelTree.identify_row(event.y) if itemId: self.modelTree.selection_set(itemId) item = self.modelTree.selection() ctxMenu = Menu(self.window, tearoff=0) ctxMenu.add_separator() if item[0][:4] == "tag:": tag = item[0][4:] ctxMenu.add_command( label="Add samples (from a csv file)", command=lambda: self.addSampleFileToModelDir(tag)) ctxMenu.add_separator() ctxMenu.add_command( label="Visualize feature map w.r.t loaded model", command=lambda: self.testOnLoadedModel( join(configs["model_data_dir"], tag), True)) elif item[0][:5] == "file:": filename = item[0][5:] ctxMenu.add_command( label="Test on loaded model", command=lambda: self.testOnLoadedModel( join(configs["model_data_dir"], filename), False)) ctxMenu.add_separator() ctxMenu.add_command( label="Delete", command=lambda: self.deleteModelFile(filename)) ctxMenu.add_separator() ctxMenu.tk_popup(event.x_root, event.y_root) self.modelTree.bind("<Button-3>", treeContextualMenu) return frame def testOnLoadedModel(self, sampleFile, isDir): try: modelviz.model_viz(sampleFile, isDir) except Exception as exc: tkMessageBox.showinfo("Sorry!", exc) return def populateModelTree(self): if self.modelTree is None: return #Extract model tags tags = [s.strip() for s in configs["model_tags"].split(",")] self.modelTree.column('size', width=200, anchor='center') self.modelTree.column('modified', width=200, anchor='center') self.modelTree.heading('size', text='Length') self.modelTree.heading('modified', text='Modified') treeHeight = 0 #Populate treeView with current configuration self.modelTree.delete(*self.modelTree.get_children()) for i in range(len(tags)): treeHeight += 1 dirName = join(configs["model_data_dir"], tags[i]) children = self.getDirContentDescr(dirName) rowId = self.modelTree.insert('', i, "tag:{}".format(tags[i]), text=tags[i]) for child in children: treeHeight += 1 self.modelTree.insert( rowId, "end", "file:{}/{}".format(tags[i], child['name']), text=child['name'], values=(child['size'], child['modified'])) self.modelTree['height'] = treeHeight + 1 return def addSampleFileToModelDir(self, tag): modelDir = join(configs["model_data_dir"], tag) file_opts = { 'defaultextension': '.csv', 'filetypes': [('CSV files', '.csv'), ('all files', '.*')], 'initialdir': expanduser("~"), 'title': 'Select data file' } filename = tkFileDialog.askopenfilename(**file_opts) try: modelLoader.add_file_to_model_dir(filename, modelDir) except Exception as exc: tkMessageBox.showerror("Error copying files", exc) return self.populateModelTree() tkMessageBox.showinfo( "Success", "Successfully copied data file {} to {}.".format( filename, modelDir)) return def deleteModelFile(self, filename): if tkMessageBox.askyesno("Confirm deleting {}".format(filename), "Are you sure about deleting this file?"): try: remove(join(configs["model_data_dir"], filename)) self.populateModelTree() except Exception, exc: tkMessageBox.showerror("Error deleting {}".format(filename), exc) return
class App: def __init__(self,master): self.master = master self.master.resizable(0,0) self.master.update_idletasks() self.master.overrideredirect(1) self.master.attributes("-topmost",True) self.master.title("New Graph") self.master.lift() self.menubar = Menu(self.master) self.master.config(menu=self.menubar) self.default_color = self.master.cget("bg") self.active_edit_flag = 0 self.modify_flag = 0 self.graph_types = ['Default','Maelstrom','Rankine Half-Body','Rankine Oval', 'Cylinder','Stagnation & Vortex'] #----------------------------------------------------------------------- self.file_menu = Menu(self.menubar) self.Fig = matplotlib.figure.Figure(figsize=(2.148,1.777),dpi=100,tight_layout=True) self.FigSubPlot = self.Fig.add_subplot(111) frame = Frame(master,bg='#%02x%02x%02x' % (231, 231, 231)) frame.pack(fill=BOTH, expand=1) frame2 = Frame(frame,bg='#%02x%02x%02x' % (221, 221, 221)) frame2.pack(fill=BOTH, expand=1,padx=20,pady=23) self.frame3 = Frame(frame2, bg='#%02x%02x%02x' % (221, 221, 221)) self.frame3.pack(fill=BOTH, padx=17,pady=17,expand=1) self.radio_frame = Frame(self.frame3,bg='#%02x%02x%02x' % (221, 221, 221)) #self.listbox = Listbox(self.frame3) self.radio_var = StringVar() self.radio_var.set('Default') for key in self.graph_types: b = Radiobutton(self.radio_frame,text=key,variable=self.radio_var,value = key,bg='#%02x%02x%02x' % (221, 221, 221),indicatoron=1) b.pack(anchor=W) # for key_num in range(0,len(self.graph_types)): # self.listbox.insert(END,self.graph_types[key_num]) # self.listbox.select_set(0) # self.listbox.bind('<<ListboxSelect>>',self.changegraph) self.radio_var.trace('w',self.changegraph) # self.old = self.listbox.get(self.listbox.curselection()) self.blankc = Canvas(self.frame3,width=225,height=188) self.canvas = FigureCanvasTkAgg(self.Fig, master=self.frame3) self.canvas.show() self.canvas.get_tk_widget().pack(side=RIGHT,padx=0,pady=5) self.radio_frame.pack(side=LEFT,anchor=W,padx=8,pady=5,fill=BOTH,expand=1) #self.listbox.pack(side=LEFT,anchor=W,padx=8,pady=5,fill=BOTH,expand=1) self.button_frame = Frame(frame,bg='#%02x%02x%02x' % (231, 231, 231)) self.button_frame.pack(side=RIGHT) self.buffer_frame = Frame(self.button_frame,bg='#%02x%02x%02x' % (231, 231, 231)) self.buffer_frame.pack(side=BOTTOM,pady=8) self.buffer_frame2 = Frame(self.button_frame,bg='#%02x%02x%02x' % (231, 231, 231)) self.buffer_frame2.pack(side=RIGHT,padx=11) self.button_c = Button(self.button_frame,width=9, text='Choose',bg='#%02x%02x%02x' % (231, 231, 231),command=self.Continue) self.button_x = Button(self.button_frame,text='Cancel',bg='#%02x%02x%02x' % (231, 231, 231),width=9,command=self.quit) self.button_c.focus() self.button_c.pack(side=RIGHT) self.button_x.pack(side=RIGHT,padx=14) self.line_color = StringVar() self.line_color.set('#000000') self.wt_var = StringVar() self.wt_var.set('- WT:') self.wt_var.trace('w',self.wt_update) self.linet_var = StringVar() self.linet_var.set('-') self.linet_var.trace('w',self.line_style_update) self.line_var = IntVar() self.line_var.set(25) self.line_val = 25 self.div_check_var = IntVar() self.div_check_var.set(50) self.div_val = 50 self.density_var = IntVar() self.density_var.set(35) self.density_val = 35 self.arrow_var = IntVar() self.arrow_var.set(25) self.arrow_val = 25 self.div_var = IntVar() self.div_var.set(0) self.mark_var = IntVar() self.mark_var.set(0) self.lock_var = IntVar() self.lock_var.set(1) self.active_numbers = {'s':0,'v':0,'u':0,'d':0,'n':0} self.sel_point = None self.selected = None def changegraph(self,*args): self.xlim = [-5.0,5.0] self.ylim = [-5.0,5.0] Y, X = mgrid[-5:5:100j, -5:5:100j] self.X,self.Y = X,Y self.FigSubPlot.clear() #if self.listbox.get(self.listbox.curselection()) == 'Default': if self.radio_var.get() == 'Default': self.U = 0*X self.V = 0*X self.FigSubPlot.streamplot(X,Y,self.U,self.V) #elif self.listbox.get(self.listbox.curselection()) == 'Maelstrom': elif self.radio_var.get() == 'Maelstrom': self.U = self.source(X,Y,1)[0]+self.vortex(X,Y,1)[0] self.V = self.source(X,Y,1)[1]+self.vortex(X,Y,1)[1] self.FigSubPlot.streamplot(X,Y,self.U,self.V, color='k', linewidth=(2.0/71.0)*self.line_var.get()+(13.0/71.0),density=(2.0/71.0)*self.density_var.get()+(13.0/71.0),arrowstyle='-') #elif self.listbox.get(self.listbox.curselection()) == 'Rankine Half-Body': elif self.radio_var.get() == 'Rankine Half-Body': self.U = self.source(X,Y,10)[0]+self.uniform(X,Y,1,1,0)[0] self.V = self.source(X,Y,10)[1]+self.uniform(X,Y,1,1,0)[1] self.FigSubPlot.streamplot(X, Y,self.U,self.V, color='k', linewidth=(2.0/71.0)*self.line_var.get()+(13.0/71.0),density=(2.0/71.0)*self.density_var.get()+(13.0/71.0),arrowstyle='-') #elif self.listbox.get(self.listbox.curselection()) == 'Rankine Oval': elif self.radio_var.get() == 'Rankine Oval': self.U = self.source(X+2,Y,10)[0]+self.source(X-2,Y,-10)[0]+self.uniform(X,Y,1,1,0)[0] self.V = self.source(X+2,Y,10)[1]+self.source(X-2,Y,-10)[1]+self.uniform(X,Y,1,1,0)[1] self.FigSubPlot.streamplot(X, Y,self.U,self.V, color='k', linewidth=(2.0/71.0)*self.line_var.get()+(13.0/71.0),density=(2.0/71.0)*self.density_var.get()+(13.0/71.0),arrowstyle='-') #elif self.listbox.get(self.listbox.curselection()) == 'Cylinder': elif self.radio_var.get() == 'Cylinder': self.U = self.doublet(X,Y,25)[0]+self.uniform(X,Y,1,1,0)[0] self.V = self.doublet(X,Y,25)[1]+self.uniform(X,Y,1,1,0)[1] self.FigSubPlot.streamplot(X, Y,self.U,self.V, color='k', linewidth=(2.0/71.0)*self.line_var.get()+(13.0/71.0),density=(2.0/71.0)*self.density_var.get()+(13.0/71.0),arrowstyle='-') #elif self.listbox.get(self.listbox.curselection()) == 'Stagnation & Vortex': elif self.radio_var.get() == 'Stagnation & Vortex': self.U = self.vortex(X,Y,25)[0]+self.corner(X,Y,'2,1')[0] self.V = self.vortex(X,Y,25)[1]+self.corner(X,Y,'2,1')[1] self.FigSubPlot.streamplot(X, Y,self.U,self.V, color='k', linewidth=(2.0/71.0)*self.line_var.get()+(13.0/71.0),density=(2.0/71.0)*self.density_var.get()+(13.0/71.0),arrowstyle='-') self.FigSubPlot.set_xlim(self.xlim) self.FigSubPlot.set_ylim(self.ylim) self.canvas.draw() # self.old = self.listbox.get(self.listbox.curselection()) def source(self,X,Y,l): l = float(l) U = (l/(2*pi))*X/(X*X + Y*Y) V = (l/(2*pi))*Y/(X*X + Y*Y) return (U,V) def vortex(self,X,Y,g): g = float(g) U = (g/(2*pi))*Y/(X*X + Y*Y) V = (g/(2*pi))*-X/(X*X + Y*Y) return (U,V) def uniform(self,X,Y,v_0,x_0,y_0): v_0 = float(v_0) x_0 = float(x_0) y_0 = float(y_0) U = v_0*x_0/(x_0*x_0+y_0*y_0)**0.5 V = v_0*y_0/(x_0*x_0+y_0*y_0)**0.5 return (U,V) def doublet(self,X,Y,k): k = float(k) U = (k/(2*pi))*((2*Y*Y/((X*X+Y*Y)*(X*X+Y*Y)))-(1/(X*X+Y*Y))) V = -(k/(2*pi))*(2*X*Y/((X*X+Y*Y)*(X*X+Y*Y))) return (U,V) def corner(self,X,Y,tup): comma_flag = 0 A = '' n = '' for char in tup: if char == ',': comma_flag = 1 elif comma_flag == 0: n += char elif comma_flag == 1: A += char A = float(A) n = float(n) R = (X*X+Y*Y)**0.5 t = arctan2(-Y,-X) U = -A*n*R**(n-1)*(cos(n*t)*cos(t)+sin(n*t)*sin(t)) V = -A*n*R**(n-1)*(cos(n*t)*sin(t)-sin(n*t)*cos(t)) return (U,V) def stream_source(self,X,Y,l): l = float(l) stream = (l/(2*pi))*arctan2(-Y,-X) return stream def stream_vortex(self,X,Y,g): g = float(g) stream = (g/(2*pi))*log((X*X + Y*Y)**0.5) return stream def stream_uniform(self,X,Y,v_0,x_0,y_0): v_0 = float(v_0) x_0 = float(x_0) y_0 = float(y_0) stream = (v_0*Y*x_0/(x_0*x_0+y_0*y_0)**0.5)-(v_0*X*y_0/(x_0*x_0+y_0*y_0)**0.5) return stream def stream_doublet(self,X,Y,k): k = float(k) stream = -(k/(2*pi))*Y/(X*X+Y*Y) return stream def stream_corner(self,X,Y,tup): comma_flag = 0 A = '' n = '' for char in tup: if char == ',': comma_flag = 1 elif comma_flag == 0: n += char elif comma_flag == 1: A += char A = float(A) n = float(n) stream = A*(X*X+Y*Y)**(n*0.5)*sin(n*arctan2(-Y,-X)) return stream def quit(self): self.master.destroy() def Continue(self): self.master.withdraw() self.main = Toplevel(self.master) self.main.geometry("%dx%d+%d+%d" % (1038-206, 694, int((500.0/2560.0)*screen_resolution[0]), int((60.0/1440.0)*screen_resolution[1]))) self.main.minsize(376,227) self.interior = PanedWindow(self.main,sashwidth=5) self.interior.pack(fill=BOTH, expand=1) self.elements_frame = Frame(self.interior, height=1038, width=212,relief=RIDGE,borderwidth=0) self.interior.add(self.elements_frame) self.interior.paneconfig(self.elements_frame,minsize=130) self.graph_frame = Frame(self.interior) self.interior.add(self.graph_frame) self.interior.paneconfig(self.graph_frame,minsize=130) self.main.bind("<ButtonRelease-1>",self.pan_update) self.main.bind("<ButtonRelease-3>",self.pan_update) self.main.bind("<Button-3>",self.right_menu) self.edit_frame = Frame(self.graph_frame) self.edit_frame.pack(side=TOP,fill=X,padx=10) self.canvas = FigureCanvasTkAgg(self.Fig, master=self.graph_frame) self.canvas.show() self.canvas.get_tk_widget().pack(fill=BOTH,expand=1) self.nav_frame = Frame(self.edit_frame) self.nav_frame.pack(side=LEFT,anchor=W) self.toolbar = NavigationToolbar(self.canvas, self.nav_frame) self.main.protocol('WM_DELETE_WINDOW',self.master.destroy) self.elements = Treeview(self.elements_frame,columns=("values","xlocations","ylocations"),selectmode=BROWSE) self.elements.heading("#0",text="Components") self.elements.heading("values",text="Str") self.elements.heading("xlocations",text="X") self.elements.heading("ylocations",text="Y") self.elements.column("#0",width=90,anchor=CENTER) self.elements.column("values",width=45,anchor=CENTER) self.elements.column("xlocations",width=26,anchor=CENTER) self.elements.column("ylocations",width=26,anchor=CENTER) self.elements.pack(fill=BOTH,expand=1) self.as_button_frame = Frame(self.elements_frame) self.add_button = Button(self.as_button_frame,text = '+',width=2,command=self.add) self.sub_button = Button(self.as_button_frame,text = '-',width=2,command=self.subtract) self.options_button = Button(self.as_button_frame,text='Options',command=self.options) self.as_button_frame.pack(side=BOTTOM,anchor=W) self.options_button.pack(side=RIGHT) self.sub_button.pack(side=RIGHT,anchor=W) self.add_button.pack(side=LEFT,anchor=W) self.addsub_menu = Menu(self.as_button_frame,tearoff=0) self.addsub_menu.add_command(command=self.add_source,label='Source') self.addsub_menu.add_command(command=self.add_vortex,label='Vortex') self.addsub_menu.add_command(command=self.add_uniform,label='Uniform') self.addsub_menu.add_command(command=self.add_doublet,label='Doublet') self.addsub_menu.add_command(command=self.add_corner,label='Corner') #if self.listbox.get(self.listbox.curselection()) == 'Default': if self.radio_var.get() == 'Default': self.active_components = [] self.active_calls = {} pass #elif self.listbox.get(self.listbox.curselection()) == 'Maelstrom': elif self.radio_var.get() == 'Maelstrom': self.elements.insert("",0,"M",text="Maelstrom",open=TRUE) self.active_components = ['M'] self.elements.insert("M",0,iid='s%s'%self.active_numbers['s'],text="Source",values=("%s"%1,0,0)) self.elements.insert("M",0,iid='v%s'%self.active_numbers['v'],text="Vortex",values=("%s"%1,0,0)) self.active_calls = {'s%s'%self.active_numbers['s']:("s",self.elements.item('s%s'%self.active_numbers['s'],"values")), 'v%s'%self.active_numbers['v']:("v",self.elements.item('v%s'%self.active_numbers['v'],"values"))} self.active_numbers['s'] += 1 self.active_numbers['v'] += 1 elif self.radio_var.get() == 'Rankine Half-Body': self.elements.insert("",0,"RHF",text="Rankine Half-Body",open=TRUE) self.active_components = ['RHF'] self.elements.insert("RHF",0,iid='s%s'%self.active_numbers['s'],text="Source",values=("%s"%10,0,0)) self.elements.insert("RHF",0,iid='u%s'%self.active_numbers['u'],text="Uniform",values=("%s"%1,1,0)) self.active_calls = {'s%s'%self.active_numbers['s']:("s",self.elements.item('s%s'%self.active_numbers['s'],"values")), 'u%s'%self.active_numbers['u']:("u",self.elements.item('u%s'%self.active_numbers['u'],"values"))} self.active_numbers['s'] += 1 self.active_numbers['u'] += 1 elif self.radio_var.get() == 'Rankine Oval': self.elements.insert("",0,"RO",text="Rankine Oval",open=TRUE) self.active_components = ['RO'] self.elements.insert("RO",0,iid='s%s'%self.active_numbers['s'],text="Source",values=("%s"%10,-2,0)) self.elements.insert("RO",0,iid='s%s'%(self.active_numbers['s']+1),text="Source",values=("%s"%-10,2,0)) self.elements.insert("RO",0,iid='u%s'%self.active_numbers['u'],text="Uniform",values=("%s"%1,1,0)) self.active_calls = {'s%s'%self.active_numbers['s']:("s",self.elements.item('s%s'%self.active_numbers['s'],"values")), 's%s'%(self.active_numbers['s']+1):("s",self.elements.item('s%s'%(self.active_numbers['s']+1),"values")), 'u%s'%self.active_numbers['u']:("u",self.elements.item('u%s'%self.active_numbers['u'],"values"))} self.active_numbers['s'] += 2 self.active_numbers['u'] += 1 elif self.radio_var.get() == 'Cylinder': self.elements.insert("",0,'D+U',text="Cylinder",open=TRUE) self.active_components = ['D+U'] self.elements.insert('D+U',0,iid='d%s'%self.active_numbers['d'],text="Doublet",values=("%s"%25,0,0)) self.elements.insert('D+U',0,iid='u%s'%self.active_numbers['u'],text="Uniform",values=("%s"%1,1,0)) self.active_calls = {'d%s'%self.active_numbers['d']:("d",self.elements.item('d%s'%self.active_numbers['d'],"values")), 'u%s'%self.active_numbers['u']:("u",self.elements.item('u%s'%self.active_numbers['u'],"values"))} self.active_numbers['d'] += 1 self.active_numbers['u'] += 1 elif self.radio_var.get() == 'Stagnation & Vortex': self.elements.insert("",0,'S+V',text="Stag+Vort",open=TRUE) self.active_components = ['S+V'] self.elements.insert('S+V',0,iid='n%s'%self.active_numbers['n'],text="C (n,A)",values=("%s,%s"%(2,1),0,0)) self.elements.insert('S+V',0,iid='v%s'%self.active_numbers['v'],text="Vortex",values=("%s"%25,0,0)) self.active_calls = {'n%s'%self.active_numbers['n']:("n",self.elements.item('n%s'%self.active_numbers['n'],"values")), 'v%s'%self.active_numbers['v']:("v",self.elements.item('v%s'%self.active_numbers['v'],"values"))} self.active_numbers['n'] += 1 self.active_numbers['v'] += 1 self.elements.bind("<Double-Button-1>",self.edit) self.elements.bind('<<TreeviewSelect>>',self.treeview_select) self.main.bind("<Return>",self.edit_return) self.main.bind("<Escape>",self.edit_return) self.rightc_menu = Menu(self.graph_frame,tearoff=0) self.add_menu = Menu(self.rightc_menu,tearoff=0) self.rightc_menu.add_cascade(label="Add",menu=self.add_menu) self.add_menu.add_command(command=self.addm_source,label='Source') self.add_menu.add_command(command=self.addm_vortex,label='Vortex') self.add_menu.add_command(command=self.addm_uniform,label='Uniform') self.add_menu.add_command(command=self.addm_doublet,label='Doublet') self.add_menu.add_command(command=self.addm_corner,label='Corner') def right_menu(self,event): print "event", event.x,event.y #print "graph", self.main.winfo_x()+self.interior.winfo_x()+self.graph_frame.winfo_x(), self.main.winfo_y()+self.interior.winfo_y()+self.graph_frame.winfo_y() self.plot_x,self.plot_y = self.FigSubPlot.transData.inverted().transform((event.x,event.y+20)) self.plot_y = -self.plot_y self.rightc_menu.post(self.main.winfo_x()+self.interior.winfo_x()+self.graph_frame.winfo_x()+event.x+9,self.main.winfo_y()+self.graph_frame.winfo_y()+event.y+66) def treeview_select(self,event): if self.elements.get_children(self.elements.selection()[0]) == (): if self.mark_var.get() == 0 or self.selected == self.elements.selection(): pass elif self.mark_var.get() == 1: #add red markers here if self.elements.selection() != '': child = self.elements.selection()[0] if child != '': self.sel_point = (self.elements.item(child,"values")[1],self.elements.item(child,"values")[2]) self.graph_update() self.selected = self.elements.selection() else: pass else: if self.mark_var.get() == 0 or self.selected == self.elements.selection(): pass elif self.mark_var.get() == 1: if self.elements.selection() != '': child = self.elements.selection()[0] if child != '': self.sel_point = None self.graph_update() self.selected = self.elements.selection() def mark_check_fun(self): if self.mark_var.get() == 0: self.sel_point = None self.graph_update() elif self.elements.selection() != '': child = self.elements.selection()[0] self.sel_point = [self.elements.item(child,"values")[1],self.elements.item(child,"values")[2]] self.graph_update() def add(self): self.addsub_menu.post(self.main.winfo_x()+self.as_button_frame.winfo_x()+self.add_button.winfo_x(),self.main.winfo_y()+self.as_button_frame.winfo_y()+self.add_button.winfo_y()-len(self.active_numbers.keys())*14) def subtract(self): if self.active_edit_flag == 1: self.del_edit(self) child = self.elements.selection()[0] if child == '': return if self.elements.parent(child) == '': ID = child self.active_components.remove(child) self.elements.delete(child) else: ID = self.elements.parent(child) self.active_components.remove(ID) for comp in self.elements.get_children(ID): if comp != child: self.active_components.append(comp) self.elements.move(comp,"",0) self.elements.delete(ID) self.sel_point = None self.graph_update() def options(self): self.options_window = Toplevel(self.main) self.options_window.geometry("%dx%d+%d+%d" % (280, 200+20, self.main.winfo_x()+self.as_button_frame.winfo_x()+self.options_button.winfo_x()-272+26+72+86, self.main.winfo_y()+self.as_button_frame.winfo_y()+self.options_button.winfo_y()-196-20)) self.main.bind('<FocusIn>',self.close_options) self.options_window.title("Options") self.options_window.update_idletasks() self.options_window.bind("<ButtonRelease-1>",self.pan_update) self.options_frame = Frame(self.options_window) self.options_frame.pack(fill=BOTH,expand=1) self.options_window.attributes("-topmost",True) self.line_frame = Frame(self.options_frame,bd=2,relief=RIDGE) self.line_frame.grid(row=0,column=1,sticky=N+S+E+W,ipady=7) self.color_frame = Frame(self.options_frame,bd=2,relief=RIDGE,padx=2) self.color_frame.grid(row=0,column=0,sticky=N+S+E+W) self.color_button = Label(self.color_frame,bg=self.line_color.get(),text = ' ') self.color_button.pack(side=RIGHT) Label(self.color_frame,text='C:').pack(side=RIGHT) self.color_button.bind('<Button-1>',self.getColor) self.wt_slider = Scale(self.line_frame,from_=1,to=100,orient=HORIZONTAL,variable=self.line_var) if self.wt_var.get() == '-> WT:': self.wt_slider.config(variable=self.arrow_var) elif self.wt_var.get() == '- WT:': self.wt_slider.config(variable=self.line_var) elif self.wt_var.get() == 'div WT:': self.wt_slider.config(variable=self.div_check_var) self.wt_slider.pack(side=RIGHT) self.wt_menu = OptionMenu(self.line_frame,self.wt_var,'- WT:','-> WT:','div WT:') self.wt_menu.pack(side=RIGHT,anchor='center',fill=X,expand=1) self.wt_menu.config(width=8) self.density_frame = Frame(self.options_frame,bd=2,relief=RIDGE) self.density_frame.grid(row=1,column=1,sticky=N+S+E+W) self.density_slider = Scale(self.density_frame,from_=1,to=100,orient=HORIZONTAL,variable=self.density_var) self.density_slider.pack(side=RIGHT) Label(self.density_frame,text='Density').pack(side=LEFT,anchor=CENTER,fill=X,expand=1) self.linet_frame = Frame(self.options_frame,bd=2,relief=RIDGE) self.linet_frame.grid(row=1,column=0,sticky=N+S+E+W) Label(self.linet_frame,text='Style').pack(anchor='n') self.linet_menu = OptionMenu(self.linet_frame,self.linet_var,'-','->','-|>') self.linet_menu.pack(anchor='s',side=BOTTOM) self.linet_menu.config(width=5) self.div_check = Checkbutton(self.options_frame,text = 'Dividing Streamline',variable=self.div_var,onvalue=1,offvalue=0,command = self.graph_update) self.div_check.grid(row=2,column=1,sticky=W) self.mark_check = Checkbutton(self.options_frame,text = 'Selection Marker',variable=self.mark_var,onvalue=1,offvalue=0,command = self.mark_check_fun) self.mark_check.grid(row=3,column=1,sticky=W) self.limit_frame = Frame(self.options_frame) self.limit_frame.grid(row=4,column=1,sticky=W) #self.aspect_lock = Checkbutton(self.limit_frame,text='LK',variable = self.lock_var) #self.aspect_lock.grid(row=0,column=4,rowspan=2,sticky=E) Label(self.limit_frame,text='x').grid(row=0,column=0) self.xlimlow_var = DoubleVar() self.xlimlow_var.set(self.FigSubPlot.get_xlim()[0]) self.xlimlow_entry = Entry(self.limit_frame,textvariable=self.xlimlow_var,width=5) self.xlimlow_entry.grid(row=0,column=1) Label(self.limit_frame,text='...').grid(row=0,column=2) self.xlimhigh_var = DoubleVar() self.xlimhigh_var.set(self.FigSubPlot.get_xlim()[1]) self.xlimhigh_entry = Entry(self.limit_frame,textvariable=self.xlimhigh_var,width=5) self.xlimhigh_entry.grid(row=0,column=3) Label(self.limit_frame,text='y').grid(row=1,column=0) self.ylimlow_var = DoubleVar() self.ylimlow_var.set(self.FigSubPlot.get_ylim()[0]) self.ylimlow_entry = Entry(self.limit_frame,textvariable=self.ylimlow_var,width=5) self.ylimlow_entry.grid(row=1,column=1) Label(self.limit_frame,text='...').grid(row=1,column=2) self.ylimhigh_var = DoubleVar() self.ylimhigh_var.set(self.FigSubPlot.get_ylim()[1]) self.ylimhigh_entry = Entry(self.limit_frame,textvariable=self.ylimhigh_var,width=5) self.ylimhigh_entry.grid(row=1,column=3) #self.limit_frame.bind('<FocusOut>',self.limits_update) self.xlimhigh_var.trace('w',self.limits_update) self.ylimhigh_var.trace('w',self.limits_update) self.xlimlow_var.trace('w',self.limits_update) self.ylimlow_var.trace('w',self.limits_update) def limits_update(self,*args): if self.xlimlow_entry.get() == '' or self.ylimlow_entry.get() == '' or self.xlimhigh_entry.get() == '' or self.ylimhigh_entry.get() == '': pass elif self.xlimlow_entry.get() == '-' or self.ylimlow_entry.get() == '-' or self.xlimhigh_entry.get() == '-' or self.ylimhigh_entry.get() == '-': pass elif self.xlimlow_entry.get() == '.' or self.ylimlow_entry.get() == '.' or self.xlimhigh_entry.get() == '.' or self.ylimhigh_entry.get() == '.': pass else: self.xlim = [float(self.xlimlow_var.get()),float(self.xlimhigh_var.get())] self.ylim = [float(self.ylimlow_var.get()),float(self.ylimhigh_var.get())] self.FigSubPlot.set_xlim(self.xlim) self.FigSubPlot.set_ylim(self.ylim) self.graph_update() def getColor(self,event): color=askcolor(self.line_color.get()) if color != "None": self.line_color.set(color[1]) self.graph_update() def wt_update(self,*args): if self.wt_var.get() == '-> WT:': self.wt_slider.config(variable=self.arrow_var) elif self.wt_var.get() == '- WT:': self.wt_slider.config(variable=self.line_var) elif self.wt_var.get() == 'div WT:': self.wt_slider.config(variable=self.div_check_var) def line_style_update(self,*args): self.graph_update() def close_options(self,event): self.options_window.destroy() def add_source(self): if self.modify_flag == 0: self.plot_x,self.plot_y = 0,0 self.elements.insert("",0,iid='s%s'%self.active_numbers['s'],text="Source",values=("%s"%1,self.plot_x,self.plot_y)) self.active_calls['s%s'%self.active_numbers['s']] = ("s",self.elements.item('s%s'%self.active_numbers['s'],"values")) self.active_components.append('s%s'%self.active_numbers['s']) if self.modify_flag == 1: self.elements.selection_set('s%s'%self.active_numbers['s']) self.modify_flag = 0 self.graph_update() self.active_numbers['s'] += 1 def add_vortex(self): if self.modify_flag == 0: self.plot_x,self.plot_y = 0,0 self.elements.insert("",0,iid='v%s'%self.active_numbers['v'],text="Vortex",values=("%s"%1,self.plot_x,self.plot_y)) self.active_calls['v%s'%self.active_numbers['v']] = ("v",self.elements.item('v%s'%self.active_numbers['v'],"values")) self.active_components.append('v%s'%self.active_numbers['v']) if self.modify_flag == 1: self.elements.selection_set('v%s'%self.active_numbers['v']) self.modify_flag = 0 self.graph_update() self.active_numbers['v'] += 1 def add_uniform(self): if self.modify_flag == 0: self.plot_x,self.plot_y = 1,0 self.elements.insert("",0,iid='u%s'%self.active_numbers['u'],text="Uniform",values=("%s"%1,self.plot_x,self.plot_y)) self.active_calls['u%s'%self.active_numbers['u']] = ("u",self.elements.item('u%s'%self.active_numbers['u'],"values")) self.active_components.append('u%s'%self.active_numbers['u']) if self.modify_flag == 1: self.elements.selection_set('u%s'%self.active_numbers['u']) self.modify_flag = 0 self.graph_update() self.active_numbers['u'] += 1 def add_doublet(self): if self.modify_flag == 0: self.plot_x,self.plot_y = 0,0 self.elements.insert("",0,iid='d%s'%self.active_numbers['d'],text="Doublet",values=("%s"%1,self.plot_x,self.plot_y)) self.active_calls['d%s'%self.active_numbers['d']] = ("d",self.elements.item('d%s'%self.active_numbers['d'],"values")) self.active_components.append('d%s'%self.active_numbers['d']) if self.modify_flag == 1: self.elements.selection_set('d%s'%self.active_numbers['d']) self.modify_flag = 0 self.graph_update() self.active_numbers['d'] += 1 def add_corner(self): if self.modify_flag == 0: self.plot_x,self.plot_y = 0,0 self.elements.insert("",0,iid='n%s'%self.active_numbers['n'],text="Corner (n,A)",values=("%s,%s"%(2,1),self.plot_x,self.plot_y)) self.active_calls['n%s'%self.active_numbers['n']] = ("n",self.elements.item('n%s'%self.active_numbers['n'],"values")) self.active_components.append('n%s'%self.active_numbers['n']) if self.modify_flag == 1: self.elements.selection_set('n%s'%self.active_numbers['n']) self.modify_flag = 0 self.graph_update() self.active_numbers['n'] += 1 def addm_source(self): self.modify_flag = 1 self.add_source() def addm_vortex(self): self.modify_flag = 1 self.add_vortex() def addm_uniform(self): self.modify_flag = 1 self.add_uniform() def addm_doublet(self): self.modify_flag = 1 self.add_doublet() def addm_corner(self): self.modify_flag = 1 self.add_corner() def pan_update(self,event): if [self.FigSubPlot.get_xlim()[0],self.FigSubPlot.get_xlim()[1]] != self.xlim or [self.FigSubPlot.get_ylim()[0],self.FigSubPlot.get_ylim()[1]] != self.ylim or self.density_var.get() != self.density_val or self.line_var.get() != self.line_val or self.arrow_var.get() != self.arrow_val or self.arrow_var.get() != self.arrow_val or self.div_check_var.get() != self.div_val: self.graph_update() self.density_val = self.density_var.get() self.line_val = self.line_var.get() self.arrow_val = self.arrow_var.get() self.div_val = self.div_check_var.get() else: return def graph_update(self): self.FigSubPlot.clear() Y, X = mgrid[self.FigSubPlot.get_ylim()[0]:self.FigSubPlot.get_ylim()[1]:100j, self.FigSubPlot.get_xlim()[0]:self.FigSubPlot.get_xlim()[1]:100j] self.xlim = [self.FigSubPlot.get_xlim()[0],self.FigSubPlot.get_xlim()[1]] self.ylim = [self.FigSubPlot.get_ylim()[0],self.FigSubPlot.get_ylim()[1]] self.U = 0*X self.V = 0*X self.stream = 0*X for ID in self.active_components: if self.elements.get_children(ID) == (): child = ID self.active_calls[child] = (child[0],self.elements.item(child,"values")) if self.active_calls[child][0] == "s": self.U += self.source(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[0] self.V += self.source(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[1] self.stream += self.stream_source(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0]) elif self.active_calls[child][0] == 'v': self.U += self.vortex(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[0] self.V += self.vortex(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[1] self.stream += self.stream_vortex(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0]) elif self.active_calls[child][0] == 'u': if self.active_calls[child][1][1] == '0' and self.active_calls[child][1][2] == '0': pass else: self.U += self.uniform(X,Y,self.active_calls[child][1][0],self.active_calls[child][1][1],self.active_calls[child][1][2])[0] self.V += self.uniform(X,Y,self.active_calls[child][1][0],self.active_calls[child][1][1],self.active_calls[child][1][2])[1] self.stream += self.stream_uniform(X,Y,self.active_calls[child][1][0],self.active_calls[child][1][1],self.active_calls[child][1][2]) elif self.active_calls[child][0] == 'd': self.U += self.doublet(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[0] self.V += self.doublet(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[1] self.stream += self.stream_doublet(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0]) elif self.active_calls[child][0] == 'n': self.U += self.corner(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[0] self.V += self.corner(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[1] self.stream += self.stream_corner(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0]) else: for child in self.elements.get_children(ID): self.active_calls[child] = (child[0],self.elements.item(child,"values")) if self.active_calls[child][0] == "s": self.U += self.source(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[0] self.V += self.source(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[1] self.stream += self.stream_source(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0]) elif self.active_calls[child][0] == 'v': self.U += self.vortex(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[0] self.V += self.vortex(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[1] self.stream += self.stream_vortex(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0]) elif self.active_calls[child][0] == 'u': if self.active_calls[child][1][1] == '0' and self.active_calls[child][1][2] == '0': pass else: self.U += self.uniform(X,Y,self.active_calls[child][1][0],self.active_calls[child][1][1],self.active_calls[child][1][2])[0] self.V += self.uniform(X,Y,self.active_calls[child][1][0],self.active_calls[child][1][1],self.active_calls[child][1][2])[1] self.stream += self.stream_uniform(X,Y,self.active_calls[child][1][0],self.active_calls[child][1][1],self.active_calls[child][1][2]) elif self.active_calls[child][0] == 'd': self.U += self.doublet(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[0] self.V += self.doublet(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[1] self.stream += self.stream_doublet(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0]) elif self.active_calls[child][0] == 'n': self.U += self.corner(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[0] self.V += self.corner(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0])[1] self.stream += self.stream_corner(X-float(self.active_calls[child][1][1]),Y-float(self.active_calls[child][1][2]),self.active_calls[child][1][0]) self.FigSubPlot.streamplot(X,Y,self.U,self.V,color=self.line_color.get(), linewidth=(2.0/71.0)*self.line_var.get()+(13.0/71.0),density=(2.0/71.0)*self.density_var.get()+(13.0/71.0),arrowstyle=self.linet_var.get(),arrowsize=(4.0/71.0)*self.arrow_var.get()+(13.0/71.0)) if self.div_var.get() == 1: #self.FigSubPlot.contour(X,Y,self.stream,[-0.01,0.01],linewidths=[(4.0/71.0)*self.div_check_var.get()+(13.0/71.0),(4.0/71.0)*self.div_check_var.get()+(13.0/71.0)]) self.FigSubPlot.contour(X,Y,self.stream,[0],linewidths=[(4.0/71.0)*self.div_check_var.get()+(13.0/71.0)]) if self.mark_var.get() == 1: if self.sel_point != None: self.plot_point() self.FigSubPlot.set_xlim(self.xlim) self.FigSubPlot.set_ylim(self.ylim) self.canvas.draw() def plot_point(self): if self.elements.selection()[0][0] == 'u': norm = float(float(self.sel_point[0])*float(self.sel_point[0])+float(self.sel_point[1])*float(self.sel_point[1]))**0.5 if norm == 0: norm = 1 X,Y,U,V = 0,0, float(self.sel_point[0])/norm,float(self.sel_point[1])/norm self.FigSubPlot.quiver(X,Y,U,V,angles='xy',scale_units='xy',scale=1,color='g') else: self.FigSubPlot.plot([self.sel_point[0]],[self.sel_point[1]],'r^',ms=10) def edit(self,event): if self.active_edit_flag == 1 or self.elements.identify_row(event.y) == '': pass else: self.rowid = self.elements.identify_row(event.y) self.column = self.elements.identify_column(event.x) self.edit_var = StringVar() if int(self.column[-1]) == 0: self.edit_var.set('%s'%self.elements.item("%s"%self.elements.identify("item",event.x, event.y))['text']) else: self.edit_var.set('%s'%self.elements.item("%s"%self.elements.identify("item",event.x, event.y))['values'][int(self.column[-1])-1]) x,y,width,height = self.elements.bbox(self.rowid, self.column) self.edit_entry = Entry(self.elements_frame,textvariable=self.edit_var) self.edit_entry.place(x=x,y=y,width=width) self.edit_entry.focus_force() self.edit_entry.bind("<FocusOut>", self.del_edit) self.active_edit_flag = 1 def edit_return(self,event): self.main.focus() def del_edit(self,event): if self.column[-1] == '0': self.elements.item(self.rowid,text='%s'%self.edit_var.get()) elif self.rowid[0] == 'n' and self.column[-1] == '1' and ',' not in self.edit_var.get(): pass else: value = '' initial_value = str(self.elements.item(self.rowid)['values'][int(self.column[-1])-1]) comma_flag = 0 div_flag = 0 for index in range(0,len(self.edit_var.get())): char = self.edit_var.get()[index] if char in '-0123456789.': value += char elif self.rowid[0] == 'n' and char == ',': if comma_flag == 1: self.edit_entry.destroy() self.active_edit_flag = 0 return value += char comma_flag = 1 comma_index = index if char == '/': if div_flag == 0: div_flag = 1 div_index = index elif div_flag == 1 and comma_flag == 1: div_flag = 2 div_index2 = index elif div_flag == 1 and comma_flag == 0 or div_flag == 2: self.edit_entry.destroy() self.active_edit_flag = 0 return if div_flag == 1: if comma_flag == 1: if div_index < comma_index: arg = int(float(value[:div_index])*100/float(value[div_index:comma_index-1]))/100.0 value = str(arg)+value[comma_index-1:] elif div_index > comma_index: arg = int(float(value[comma_index+1:div_index])*100/float(value[div_index:]))/100.0 value = value[:comma_index+1]+str(arg) else: arg = int(float(value[:div_index])*100/float(value[div_index:]))/100.0 value = str(arg) elif div_flag == 2: arg1 = int(float(value[:div_index])*100/float(value[div_index:comma_index-1]))/100.0 arg2 = int(float(value[comma_index:div_index2-1])*100/float(value[div_index2-1:]))/100.0 value = str(arg1)+','+str(arg2) if value == '' or value == initial_value: self.edit_entry.destroy() self.active_edit_flag = 0 return self.elements.set(self.rowid,column=(int(self.column[-1])-1),value=value) if self.mark_var.get() == 1: self.sel_point = [self.elements.item(self.rowid,"values")[1],self.elements.item(self.rowid,"values")[2]] self.graph_update() self.edit_entry.destroy() self.active_edit_flag = 0
class Display: def __init__(self, controller): self.controller = controller self.currIndex = 0 # initialize the GUI self.app = Tk() self.app.title('Jack Magee\'s Pub') self.tree = Treeview(self.app, height=30) # name the tree columns, not sure if they have to be named numbers but that's how the example did it self.tree["columns"]=("one", "two", "three", "four") # set the column widths self.tree.column("one", width=200) self.tree.column("two", width=300) self.tree.column("three", width=200) self.tree.column("four", width=200) # set the column headings self.tree.heading("#0", text= "ID") self.tree.heading("one", text="Name") self.tree.heading("two", text="Order") self.tree.heading("three", text="Price") self.tree.heading("four", text="Respond (double-click)") self.tree.pack() # register handler for double-clicks self.tree.bind("<Double-1>", self.OnDoubleClick) def mainloop(self): self.app.mainloop() # this is like making tree entries buttons def OnDoubleClick(self, event): # get the pressed item item = self.tree.selection()[0] # get the item's text response = self.tree.item(item,"text") # this is the only response we are sending for now if response == 'rdy': # get the parent directory whose text is the customer id parent = self.tree.parent(item) customer_id = self.tree.item(parent,"text") # remove it from the tree self.tree.delete(parent) # send the message to the customer self.controller.send_msg(customer_id, response) # add a new order to the tree def takeOrder(self, customer_id, name, order, price): # just a row identifier thisRow = str(self.currIndex) # insert the i.d. and name at the top level self.tree.insert("", self.currIndex, thisRow, text=customer_id, values=(name, "", "", "")) # insert the "button" for sending notification to clients self.tree.insert(thisRow, 0, text='rdy', values=("", "", "", "Ready For Pick Up")) # this is a hacky solution to get multiline orders to appear because treeviews will # crop anything more than 1 line so I just make a new entry for every line multiline_order = order.split('\n') this_line = 1 for line in multiline_order[:-1]: # exclude the last end line if this_line == 1: # the first line has the name of the order and it's price self.tree.insert(thisRow, 1, text="order",values=("", order, price, "")) else: # just keep printing the extra options, sides, and add ons self.tree.insert(thisRow, this_line, text="order",values=("", line, "", "")) this_line += 1 self.currIndex += 1
class Multicolumn_Listbox(object): _style_index = 0 class List_Of_Rows(object): def __init__(self, multicolumn_listbox): self._multicolumn_listbox = multicolumn_listbox def data(self, index): return self._multicolumn_listbox.row_data(index) def get(self, index): return Row(self._multicolumn_listbox, index) def insert(self, data, index=None): self._multicolumn_listbox.insert_row(data, index) def delete(self, index): self._multicolumn_listbox.delete_row(index) def update(self, index, data): self._multicolumn_listbox.update_row(index, data) def select(self, index): self._multicolumn_listbox.select_row(index) def deselect(self, index): self._multicolumn_listbox.deselect_row(index) def set_selection(self, indices): self._multicolumn_listbox.set_selection(indices) def __getitem__(self, index): return self.get(index) def __setitem__(self, index, value): return self._multicolumn_listbox.update_row(index, value) def __delitem__(self, index): self._multicolumn_listbox.delete_row(index) def __len__(self): return self._multicolumn_listbox.number_of_rows class List_Of_Columns(object): def __init__(self, multicolumn_listbox): self._multicolumn_listbox = multicolumn_listbox def data(self, index): return self._multicolumn_listbox.get_column(index) def get(self, index): return Column(self._multicolumn_listbox, index) def delete(self, index): self._multicolumn_listbox.delete_column(index) def update(self, index, data): self._multicolumn_listbox.update_column(index, data) def __getitem__(self, index): return self.get(index) def __setitem__(self, index, value): return self._multicolumn_listbox.update_column(index, value) def __delitem__(self, index): self._multicolumn_listbox.delete_column(index) def __len__(self): return self._multicolumn_listbox.number_of_columns def __init__(self, master, columns, data=None, command=None, sort=True, select_mode=None, heading_anchor = CENTER, cell_anchor=W, style=None, height=None, padding=None, adjust_heading_to_content=False, stripped_rows=None, selection_background=None, selection_foreground=None, field_background=None, heading_font= None, heading_background=None, heading_foreground=None, cell_pady=2, cell_background=None, cell_foreground=None, cell_font=None, headers=True): self._stripped_rows = stripped_rows self._columns = columns self._number_of_rows = 0 self._number_of_columns = len(columns) self.row = self.List_Of_Rows(self) self.column = self.List_Of_Columns(self) s = Style() if style is None: style_name = "Multicolumn_Listbox%s.Treeview"%self._style_index self._style_index += 1 else: style_name = style style_map = {} if selection_background is not None: style_map["background"] = [('selected', selection_background)] if selection_foreground is not None: style_map["foeground"] = [('selected', selection_foreground)] if style_map: s.map(style_name, **style_map) style_config = {} if cell_background is not None: style_config["background"] = cell_background if cell_foreground is not None: style_config["foreground"] = cell_foreground if cell_font is None: font_name = s.lookup(style_name, "font") cell_font = nametofont(font_name) else: if not isinstance(cell_font, Font): if isinstance(cell_font, basestring): cell_font = nametofont(cell_font) else: if len(font) == 1: cell_font = Font(family=cell_font[0]) elif len(font) == 2: cell_font = Font(family=cell_font[0], size=cell_font[1]) elif len(font) == 3: cell_font = Font(family=cell_font[0], size=cell_font[1], weight=cell_font[2]) else: raise ValueError("Not possible more than 3 values for font") style_config["font"] = cell_font self._cell_font = cell_font self._rowheight = cell_font.metrics("linespace")+cell_pady style_config["rowheight"]=self._rowheight if field_background is not None: style_config["fieldbackground"] = field_background s.configure(style_name, **style_config) heading_style_config = {} if heading_font is not None: heading_style_config["font"] = heading_font if heading_background is not None: heading_style_config["background"] = heading_background if heading_foreground is not None: heading_style_config["foreground"] = heading_foreground heading_style_name = style_name + ".Heading" s.configure(heading_style_name, **heading_style_config) treeview_kwargs = {"style": style_name} if height is not None: treeview_kwargs["height"] = height if padding is not None: treeview_kwargs["padding"] = padding if headers: treeview_kwargs["show"] = "headings" else: treeview_kwargs["show"] = "" if select_mode is not None: treeview_kwargs["selectmode"] = select_mode self.interior = Treeview(master, columns=columns, **treeview_kwargs) if command is not None: self._command = command self.interior.bind("<<TreeviewSelect>>", self._on_select) for i in range(0, self._number_of_columns): if sort: self.interior.heading(i, text=columns[i], anchor=heading_anchor, command=lambda col=i: self.sort_by(col, descending=False)) else: self.interior.heading(i, text=columns[i], anchor=heading_anchor) if adjust_heading_to_content: self.interior.column(i, width=Font().measure(columns[i])) self.interior.column(i, anchor=cell_anchor) if data is not None: for row in data: self.insert_row(row) @property def row_height(self): return self._rowheight @property def font(self): return self._cell_font def configure_column(self, index, width=None, minwidth=None, anchor=None, stretch=None): kwargs = {} for config_name in ("width", "anchor", "stretch", "minwidth"): config_value = locals()[config_name] if config_value is not None: kwargs[config_name] = config_value self.interior.column('#%s'%(index+1), **kwargs) def row_data(self, index): try: item_ID = self.interior.get_children()[index] except IndexError: raise ValueError("Row index out of range: %d"%index) return self.item_ID_to_row_data(item_ID) def update_row(self, index, data): try: item_ID = self.interior.get_children()[index] except IndexError: raise ValueError("Row index out of range: %d"%index) if len(data) == len(self._columns): self.interior.item(item_ID, values=data) else: raise ValueError("The multicolumn listbox has only %d columns"%self._number_of_columns) def delete_row(self, index): list_of_items = self.interior.get_children() try: item_ID = list_of_items[index] except IndexError: raise ValueError("Row index out of range: %d"%index) self.interior.delete(item_ID) self._number_of_rows -= 1 if self._stripped_rows: for i in range(index, self._number_of_rows): self.interior.tag_configure(list_of_items[i+1], background=self._stripped_rows[i%2]) def insert_row(self, data, index=None): if len(data) != self._number_of_columns: raise ValueError("The multicolumn listbox has only %d columns"%self._number_of_columns) if index is None: index = self._number_of_rows-1 item_ID = self.interior.insert('', index, values=data) self.interior.item(item_ID, tags=item_ID) self._number_of_rows += 1 if self._stripped_rows: list_of_items = self.interior.get_children() self.interior.tag_configure(item_ID, background=self._stripped_rows[index%2]) for i in range(index+1, self._number_of_rows): self.interior.tag_configure(list_of_items[i], background=self._stripped_rows[i%2]) def column_data(self, index): return [self.interior.set(child_ID, index) for child_ID in self.interior.get_children('')] def update_column(self, index, data): for i, item_ID in enumerate(self.interior.get_children()): data_row = self.item_ID_to_row_data(item_ID) data_row[index] = data[i] self.interior.item(item_ID, values=data_row) return data def clear(self): # Another possibility: # self.interior.delete(*self.interior.get_children()) for row in self.interior.get_children(): self.interior.delete(row) self._number_of_rows = 0 def update(self, data): self.clear() for row in data: self.insert_row(row) def focus(self, index=None): if index is None: return self.interior.item(self.interior.focus()) else: item = self.interior.get_children()[index] self.interior.focus(item) def state(self, state=None): if stateSpec is None: return self.interior.state() else: self.interior.state(state) @property def number_of_rows(self): return self._number_of_rows @property def number_of_columns(self): return self._number_of_columns def toogle_selection(self, index): list_of_items = self.interior.get_children() try: item_ID = list_of_items[index] except IndexError: raise ValueError("Row index out of range: %d"%index) self.interior.selection_toggle(item_ID) def select_row(self, index): list_of_items = self.interior.get_children() try: item_ID = list_of_items[index] except IndexError: raise ValueError("Row index out of range: %d"%index) self.interior.selection_add(item_ID) def deselect_row(self, index): list_of_items = self.interior.get_children() try: item_ID = list_of_items[index] except IndexError: raise ValueError("Row index out of range: %d"%index) self.interior.selection_remove(item_ID) def deselect_all(self): self.interior.selection_remove(self.interior.selection()) def set_selection(self, indices): list_of_items = self.interior.get_children() self.interior.selection_set(" ".join(list_of_items[row_index] for row_index in indices)) @property def selected_rows(self): data = [] for item_ID in self.interior.selection(): data_row = self.item_ID_to_row_data(item_ID) data.append(data_row) return data @property def indices_of_selected_rows(self): list_of_indices = [] for index, item_ID in enumerate(self.interior.get_children()): if item_ID in self.interior.selection(): list_of_indices.append(index) return list_of_indices def delete_all_selected_rows(self): selected_items = self.interior.selection() for item_ID in selected_items: self.interior.delete(item_ID) number_of_deleted_rows = len(selected_items) self._number_of_rows -= number_of_deleted_rows return number_of_deleted_rows def _on_select(self, event): for item_ID in event.widget.selection(): data_row = self.item_ID_to_row_data(item_ID) self._command(data_row) def item_ID_to_row_data(self, item_ID): item = self.interior.item(item_ID) return item["values"] @property def table_data(self): data = [] for item_ID in self.interior.get_children(): data_row = self.item_ID_to_row_data(item_ID) data.append(data_row) return data @table_data.setter def table_data(self, data): self.update(data) def cell_data(self, row, column): """Get the value of a table cell""" try: item = self.interior.get_children()[row] except IndexError: raise ValueError("Row index out of range: %d"%row) return self.interior.set(item, column) def update_cell(self, row, column, value): """Set the value of a table cell""" item_ID = self.interior.get_children()[row] data = self.item_ID_to_row_data(item_ID) data[column] = value self.interior.item(item_ID, values=data) def __getitem__(self, index): if isinstance(index, tuple): row, column = index return self.cell_data(row, column) else: raise Exception("Row and column indices are required") def __setitem__(self, index, value): if isinstance(index, tuple): row, column = index self.update_cell(row, column, value) else: raise Exception("Row and column indices are required") def bind(self, event, handler): self.interior.bind(event, handler) def sort_by(self, col, descending): """ sort tree contents when a column header is clicked """ # grab values to sort data = [(self.interior.set(child_ID, col), child_ID) for child_ID in self.interior.get_children('')] # if the data to be sorted is numeric change to float try: data = [(float(number), child_ID) for number, child_ID in data] except ValueError: pass # now sort the data in place data.sort(reverse=descending) for idx, item in enumerate(data): self.interior.move(item[1], '', idx) # switch the heading so that it will sort in the opposite direction self.interior.heading(col, command=lambda col=col: self.sort_by(col, not descending)) if self._stripped_rows: list_of_items = self.interior.get_children('') for i in range(len(list_of_items)): self.interior.tag_configure(list_of_items[i], background=self._stripped_rows[i%2]) def destroy(self): self.interior.destroy() def item_ID(self, index): return self.interior.get_children()[index]
class GUIBuscador(Tk): def __init__(self, master=None): Tk.__init__(self, master) self.gui(master) self.dir = 'D:\Talker\Talker\Biblia' self.direc = glob("%s\*" % self.dir) def gui(self, master): self.frm = Frame(master) self.frm.pack(side=LEFT, expand=YES, fill=BOTH) self.left_side(self.frm) self.frm = Frame(master) self.frm.pack(side=RIGHT, expand=YES, fill=BOTH) self.right_side(self.frm) def left_side(self, master): self.nombre = Entry(master, justify=CENTER, bd=3, font=('Ravie', 11), textvariable=self.NameVar) self.nombre.pack(side=TOP, fill=X) self.nombre.bind("<Key>", self.Enter) self.texto = Entry(master, justify=CENTER, bd=3, font=('Ravie', 11), textvariable=self.TextVar) self.texto.pack(side=TOP, fill=X) self.texto.bind("<Key>", self.Enter) self.tag = Entry(master, justify=CENTER, bd=3, font=('Ravie', 11), textvariable=self.TagsVar) self.tag.pack(side=TOP, fill=X) self.tag.bind("<Key>", self.Enter) self.tree = Treeview(master) self.tree.pack(side=LEFT, expand=YES, fill=BOTH) self.tree.bind("<Double-1>", self.OnDoubleClick) def right_side(self, master): self.text = Text(master, bg='skyblue', bd=5, font=('consolas', 12), fg='red') self.text.pack(expand=YES, side=LEFT, fill=BOTH) self.yscroller = Scrollbar(master, command=self.text.yview) self.yscroller.pack(side=RIGHT, fill=Y) self.text['yscrollcommand'] = self.yscroller def OnDoubleClick(self, tree): try: item = self.tree.selection()[0] self.tree.item.open(item) except IndexError: pass def Enter(self, event): if event.char == ord(13): self.buscar() def buscar(self): name = NameVar.get() text = TextVar().get() etiqueta = TagsVar.get().split(',') self.aciertos = [] for carpeta in self.direc: root = tree.insert("", 1, name[-3], text=name[-3]) self.aciertos = [] for versiculo in glob("%s\*" % carpeta): with open(versiculo, 'r') as nota: texto = nota.readlines() etiquetas = texto[-1].split(',') if name != '': versiculo = versiculo.replace(".txt", "") if re.search('%s' % name, versiculo): pass else: continue if etiqueta != []: for i in etiquetas: if i in etiqueta: break else: continue if text != '': for line in texto: if re.search(r'%s' % text, line): break else: continue tree.insert(raiz, "end", name, text=name[-1]) self.aciertos.append(versiculo) if self.aciertos == []: self.tree.delete(root)
class CommSearch(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.initUI() def initUI(self): self.entries_found = [] self.parent.title("Search your command cards") self.style = Style() self.style.theme_use("default") self.pack() self.input_title = Label(self, text="Enter your command below") self.input_title.grid(row=0, columnspan=2) self.input_box = Entry(self, width=90) self.input_box.grid(row=1, column=0) self.input_box.focus() self.input_box.bind("<Key>", self.onUpdateSearch) self.search_btn = Button(self, text="Search", command=self.onSearch) self.search_btn.grid(row=1, column=1) self.output_box = Treeview(self, columns=("Example")) ysb = Scrollbar(self, orient='vertical', command=self.output_box.yview) xsb = Scrollbar(self, orient='horizontal', command=self.output_box.xview) self.output_box.configure(yscroll=ysb.set, xscroll=xsb.set) self.output_box.heading('Example', text='Example', anchor='w') self.output_box.column("#0",minwidth=0,width=0, stretch=NO) self.output_box.column("Example",minwidth=0,width=785) self.output_box.bind("<Button-1>", self.OnEntryClick) self.output_box.grid(row=3, columnspan=2) self.selected_box = Text(self, width=110, height=19) self.selected_box.grid(row=4, columnspan=2) self.gotoadd_btn = Button(self, text="Go to Add", command=self.onGoToAdd) self.gotoadd_btn.grid(row=5) def OnEntryClick(self, event): try: item = self.output_box.selection()[0] except IndexError: pass entry_title = self.output_box.item(item,"value") for item in self.entries_found: if str(entry_title) == str("('" + item.title.strip('\n') + "',)"): self.selected_box.delete(0.1, END) self.selected_box.insert(END, item.text + '\n') def onUpdateSearch(self, key): # Somehow calling self.onSearch() does not register last key # And we need to correct "special chars" global entries, entries_map text_entries = "" for item in self.output_box.get_children(): self.output_box.delete(item) # ...like, for instance, deleting last character if key.char == '\b': search_terms = str(self.input_box.get()[:-1]) else: search_terms = str(self.input_box.get() + key.char) self.entries_found = [] self.entries_found = data.Search(search_terms,entries,entries_map) for item in range(len(self.entries_found)): aux = self.output_box.insert('', 'end', '', value=[self.entries_found[item].title.split('\n')[0]]) def onSearch(self): global entries, entries_map text_entries = "" for item in self.output_box.get_children(): self.output_box.delete(item) search_terms = str(self.input_box.get()) for item in data.Search(search_terms,entries,entries_map): self.output_box.insert('', 'end', '', value=[self.entries_found[item].title.split('\n')[0]]) def onGoToAdd(self): newroot = Tk() newcomm = CommAdd(newroot) newroot.geometry("800x600+0+0") newroot.mainloop()
class LobbyUI(Frame): """ Sudoku multiplayer lobby UI class. In case of incorrect inputs error messages are shown. """ action = None def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.row, self.col = -1, -1 self.__initUI() def __initUI(self): """ Initialize UI with a list and required entry fields and submit buttons.""" self.parent.title('Multiplayer Game') self.pack(fill=BOTH, expand=1) self.lobby_list = Treeview(self, columns=('room', 'players')) self.lobby_list['show'] = 'headings' self.lobby_list.heading('room', text='Room ID') self.lobby_list.column('room', width=250, anchor=CENTER) self.lobby_list.heading('players', text='Players') self.lobby_list.column('players', width=100, anchor=CENTER) self.lobby_list.grid(row=1, column=0, columnspan=2, rowspan=2, padx=20, pady=(10, 0)) self.connect_lobby = Button(self, text='Joining Sudoku\n Solving Session', command=self.__connect_lobby) self.connect_lobby.grid(row=3, column=1, pady=(0, 10)) Label(self, text='Creating new Sudoku\n solving session:').grid(row=4, column=0) self.max_players = Entry(self) self.max_players.grid(row=4, column=1) self.create_game = Button(self, text='Join new game', command=self.__create_game) self.create_game.grid(row=5, column=1) def __connect_lobby(self): """ Handle lobby connection button.""" LOG.debug('Lobby connect button has been pressed.') current_item = self.lobby_list.focus() selected_id = None if current_item is not None and current_item.strip() != '': # Select game column value from item values dictionary. selected_id = self.lobby_list.item(current_item)['values'][0] LOG.debug('Player wishes to join game ' + str(selected_id)) if selected_id is not None: self.action = ('select', selected_id) else: tkMessageBox.showwarning( "Connection error", "Please select a game from the lobby to join.") def __create_game(self): """ Create game with some number of max players.""" max_ok = False try: max_count = int(self.max_players.get()) except (ValueError, TypeError): max_count = -1 tkMessageBox.showwarning("Input error", "Max player count has to be an integer.") if isinstance(max_count, int): if max_count >= 2: max_ok = True LOG.debug('Ok max player count.') else: tkMessageBox.showwarning( "Input error", "Max player count has to be larger than 2.") LOG.error('Bad max count.') if max_ok: self.action = ('create', max_count) def populate_list(self, games): """ Method to re-populate the lobby list every poll. Additionally retains the focused line during polling. :param games: """ previous_selection = self.lobby_list.selection() prev_item = None if len(previous_selection) > 0: prev_item = self.lobby_list.item(previous_selection[0]) self.lobby_list.delete(*self.lobby_list.get_children()) for game in games: self.lobby_list.insert('', 'end', values=(str(game[0]), str(game[1]) + '/' + str(game[2]))) if prev_item is not None: for item in self.lobby_list.get_children(): if self.lobby_list.item(item) == prev_item: self.lobby_list.selection_set(item) self.lobby_list.focus(item)
class SleepableThreadManagerGUI: ui = None # Main UI Window top = None # Top UI frame bottom = None # Bottom UI frame allow_scroll = True manager = None # Sleepable thread manager iidList = [] ui_update_thread = None # UI Update thread thread_dropdown = None # Dropdown to select threads function_dropdown = None # Dropdown to select functions thread_selected = None # Variable for the thread selection threads_selected = [] function_selected = None # Variable for the function selection function_menu = None selection_context_menu = None empty_selection_context_menu = None info_tree_view = None # Tree view for thread info output_textbox = None # Output textbox for the UI thread to write to def __init__(self): self.manager = SleepableThreadManager() self.ui = Tk() self.ui.title('Sleepable Thread Manager') self.ui.geometry('550x600') self.function_selected = StringVar(self.ui) self.thread_selected = StringVar(self.ui) self.thread_selected.set('Select a Thread...') self.function_selected.set('Select a Function...') # create all of the main containers self.top = Frame(self.ui, width=300, height=50, pady=5) self.bottom = Frame(self.ui, bg='orange', width=300, height=20, pady=0) # main window self.ui.grid_columnconfigure( 0, weight=1) # expand main column when main ui resizes self.top.grid(row=0, sticky="ew") # Stick top frame to east/west self.bottom.grid( row=1, sticky="nsew") # Stick bottom frame to north/south/easy/west self.ui.grid_rowconfigure( 1, weight=1) # Expand bottom panel when main ui resizes # top frame component config self.top.grid_rowconfigure( 0, weight=1) # Expand first row when top frame resizes self.top.grid_rowconfigure( 1, weight=1) # Expand second row when top frame resizes self.top.grid_columnconfigure( 1, weight=1) # Expand second column when top frame resizes # bottom frame component config self.bottom.grid_rowconfigure( 0, weight=1) # Expand row 1 when bottom frame resizes self.bottom.grid_rowconfigure( 1, weight=1) # Expand row 2 when bottom frame resizes self.bottom.grid_columnconfigure( 0, weight=1) # Expand column 1 when bottom frame resizes self.bottom.grid_columnconfigure(0, weight=1) # create widgets for top frame function_label = Label(self.top, text='Function name:') self.function_dropdown = OptionMenu( self.top, self.function_selected, *self.manager.function_mappings.keys()) # layout the widgets in the top frame function_label.grid(row=1, column=0) self.function_dropdown.grid(row=1, column=1, columnspan=3, sticky="ew") # create widgets for bottom frame self.selection_context_menu = Menu(self.info_tree_view) createMultiple = Menu(self.info_tree_view) functionMenu = Menu(self.selection_context_menu) functionMenu.add_command( label='Square', command=lambda: self.set_thread_function('Square')) functionMenu.add_command( label='Cube', command=lambda: self.set_thread_function('Cube')) self.selection_context_menu.add_cascade(label='Create...', menu=createMultiple) self.selection_context_menu.add_cascade(label='Set function...', menu=functionMenu) self.selection_context_menu.add_command(label='Start', command=self.start_thread) self.selection_context_menu.add_command(label='Sleep', command=self.sleep_thread) self.selection_context_menu.add_command(label='Wake', command=self.wake_thread) self.selection_context_menu.add_command(label='Stop', command=self.stop_thread) self.selection_context_menu.add_command(label='Restart', command=self.restart_thread) self.selection_context_menu.add_command(label='Remove', command=self.remove_thread) self.empty_selection_context_menu = Menu(self.info_tree_view) createMultiple.add_command(label='1', command=self.create_thread) createMultiple.add_command( label='5', command=lambda: self.create_thread(amount=5)) createMultiple.add_command( label='10', command=lambda: self.create_thread(amount=10)) createMultiple.add_command( label='20', command=lambda: self.create_thread(amount=20)) self.empty_selection_context_menu.add_cascade(label='Create', menu=createMultiple) self.info_tree_view = Treeview(self.bottom, columns=('Function', 'Status')) self.info_tree_view.heading('#0', text='Thread Name') self.info_tree_view.heading('#1', text='Function Name') self.info_tree_view.heading('#2', text='Status') self.info_tree_view.column('#0', width=100, stretch=NO) self.info_tree_view.column('#1', width=75) self.info_tree_view.column('#2', width=100, stretch=NO) self.info_tree_view.bind('<Button-3>', self.popup) self.output_textbox = Text(self.bottom, background="white", font=("Helvetica", 8)) self.output_scrollbar = Scrollbar(self.bottom, command=self.output_textbox.yview) self.info_scrollbar = Scrollbar(self.bottom, command=self.info_tree_view.yview) # layout for the widgets in the bottom frame self.info_tree_view.grid(row=0, column=0, sticky='nsew') self.info_scrollbar.grid(row=0, column=1, sticky="nse") self.info_tree_view.config(yscrollcommand=self.info_scrollbar.set) self.output_textbox.grid(row=1, column=0, sticky='nsew') self.output_scrollbar.grid(row=1, column=1, sticky="nse") self.output_textbox.config(yscrollcommand=self.output_scrollbar.set) self.ui_update_thread = SleepableThread(work_wait=0.5) self.ui_update_thread.set_thread_work(self.refresh_output) self.ui_update_thread.start_thread() # Mainloop self.ui.mainloop() # UI refresh def refresh_tree_view(self): self.info_tree_view.delete(*self.info_tree_view.get_children()) for item in self.manager.threads.items(): self.info_tree_view.insert( '', 'end', text=item[0], values=(str(item[1].work_function), item[1].thread_state_mappings[item[1].thread_state])) def refresh_output(self): # function passed to ui thread, change to labels/gridview? need independent message queue on threads if self.manager.functions.MessageQueue.__len__() > 0: while self.manager.functions.MessageQueue.__len__() != 0: item = self.manager.functions.MessageQueue.pop() if len(item) >= 400: raise Exception('Output too large') else: self.output_textbox.delete('1.0', END) self.output_textbox.insert(END, '{}\n'.format(item)) if self.manager.thread_stats( )[1] > 0 and self.allow_scroll: self.output_textbox.see('end') def popup(self, event): self.allow_scroll = False #iid = self.info_tree_view.identify_row(event.y) self.iidList = self.info_tree_view.selection() if self.iidList: if self.iidList > 0: for i in self.iidList: self.threads_selected.append( self.info_tree_view.item(i)['text']) # self.info_tree_view.selection_set(iid) # self.thread_selected.set(self.info_tree_view.item(iid)['text']) self.selection_context_menu.post(event.x_root, event.y_root) else: self.empty_selection_context_menu.post(event.x_root, event.y_root) pass self.manager.functions.MessageQueue = [] self.allow_scroll = True # Button functions def create_thread(self, amount=1): i = 0 while i != amount: self.manager.control(command='create') i += 1 self.refresh_tree_view() def remove_thread(self): while self.threads_selected.__len__() != 0: self.manager.control(thread=self.threads_selected.pop(), command='remove') self.refresh_tree_view() def start_thread(self): while self.threads_selected.__len__() != 0: self.manager.control(thread=self.threads_selected.pop(), command='start') self.refresh_tree_view() def restart_thread(self): while self.threads_selected.__len__() != 0: self.manager.control(thread=self.threads_selected.pop(), command='restart') self.refresh_tree_view() def sleep_thread(self): while self.threads_selected.__len__() != 0: self.manager.control(thread=self.threads_selected.pop(), command='sleep') self.refresh_tree_view() def wake_thread(self): while self.threads_selected.__len__() != 0: self.manager.control(thread=self.threads_selected.pop(), command='wake') self.refresh_tree_view() def stop_thread(self): while self.threads_selected.__len__() != 0: self.manager.control(thread=self.threads_selected.pop(), command='stop') self.refresh_tree_view() def set_thread_function(self, funct): while self.threads_selected.__len__() != 0: self.manager.set_function(self.threads_selected.pop(), funct) self.refresh_tree_view()
class SDCard: def __init__(self, root, prtr, settings, log): self.app = root self.printer = prtr self.settings = settings self.log = log self.top = None def isActive(self): return self.top != None def start(self): self.app.sdchecking = True self.printer.send_now("M21") def sdCheckComplete(self, ready): if not ready: self.log.logMsg("Error initializing SD card") else: self.app.sdlisting = True self.printer.send_now("M20") def refresh(self): self.top.destroy() self.app.sdlisting = True self.printer.send_now("M20") def sdListComplete(self, sdlist): top = self.top = Toplevel(self.app) top.title("SD Card Control") top.protocol('WM_DELETE_WINDOW', self.delTop) f = Frame(top, height=150, width=150) f.grid(row=1, column=1); self.tree = Treeview(f, height=12, selectmode='browse') self.tree.column("#0", minwidth=100) self.tree.bind("<<TreeviewSelect>>", self.treeSelect) self.sb = Scrollbar(f) self.sb.config(command=self.tree.yview) self.tree.config(yscrollcommand=self.sb.set) self.sb.pack(side=RIGHT, fill=Y) self.tree.pack(side=LEFT, fill=BOTH, expand=1) SDroot = SDDir('') for item in sdlist: if item.startswith('/'): cd = SDroot l = item[1:].split('/') for d in l[:-1]: ncd = cd.getDir(d) if ncd == None: ncd = cd.addDir(d) cd = ncd cd.addFile(l[-1], fqn=item) else: SDroot.addFile(item) SDroot.sortAll() self.fileMap = {} self.startFile = None self.loadDir(SDroot, '') bf = Frame(top, width=50) bf.grid(column=3, row=1) blf = LabelFrame(bf, text="Print from SD Card", width=48, height=40) self.bPrint = Button(blf, text='Print', command=self.doPrint, width = 6) self.bPrint.pack() blf.pack(fill='x') blf = LabelFrame(bf, text="Delete from SD Card", width=48, height=40) self.bDelete = Button(blf, text="Delete", command=self.doDelete, width=6) self.bDelete.pack() blf.pack(fill='x') blf = LabelFrame(bf, text="Upload to SD Card", width=48, height=180) self.upDir = Label(blf, text="Dir:", justify=LEFT) self.upDir.pack() ef = Frame(blf) l = Label(ef, text="File:", justify=LEFT) l.pack(side=LEFT) self.entry = Entry(ef, width=12) self.entry.pack(side=LEFT) fn = 'untitled.g' if self.app.GCodeFile: fn = os.path.basename(self.app.GCodeFile) if len(fn) > 8: fn = fn[0:8] fn += ".g" self.entry.delete(0, END) self.entry.insert(0, fn) ef.pack() self.bUpload = Button(blf, text="Upload", command=self.doUpload, width=6) self.bUpload.pack() blf.pack(fill='x') if self.app.printing or self.app.sdprinting: self.bPrint.config(state=DISABLED) self.bUpload.config(state=DISABLED) if not self.app.GCodeFile: self.bUpload.config(state=DISABLED) blf = Frame(bf) self.bExit = Button(blf, text='Exit', command=self.doExit, width=6) self.bExit.pack() blf.pack() if self.startFile: self.tree.selection_set(self.startFile) self.top.geometry("360x300+100+100") def delTop(self): self.top.destroy() self.top = None def treeSelect(self, *arg): s = self.tree.selection()[0] try: d = s.split(':')[0] except: d = "" if len(d) == 0: d = '(root)' self.upDir.config(text="Dir: " + d) if self.app.printing or self.app.sdprinting or not self.app.GCodeFile: self.bUpload.config(state=DISABLED) else: self.bUpload.config(state=NORMAL) if ':' in s: # a file is chosen if self.app.printing or self.app.sdprinting: self.bPrint.config(state=DISABLED) else: self.bPrint.config(state=NORMAL) self.bDelete.config(state=NORMAL) else: # a directory is chosen self.bPrint.config(state=DISABLED) self.bDelete.config(state=DISABLED) def loadDir(self, d, did): d.resetDir() nd = d.nextDir() while (nd): myid = did + '/' + nd.dirName() self.tree.insert(did, 'end', myid, text=nd.dirName()) self.loadDir(nd, myid) nd = d.nextDir() d.resetFile() f = d.nextFile() while (f): myid = did + ':' + f[0] self.fileMap[myid] = f[1] self.tree.insert(did, 'end', myid, text=f[0]) if self.startFile == None: self.startFile = myid f = d.nextFile() def doExit(self): self.top.destroy() self.top = None def doPrint(self): s = self.tree.selection()[0] if s in self.fileMap: fn = self.fileMap[s].lower() self.log.logMsg("Starting print of SD file %s" % fn) self.printer.send_now("M23 %s" % fn) # select the file self.printer.send_now("M24") # start the print self.app.sdprinting = True self.app.setToolbarSDPrint() self.top.destroy() self.top = None def doDelete(self): s = self.tree.selection()[0] if s in self.fileMap: fn = self.fileMap[s].lower() self.log.logMsg("Deleting file %s" % fn) self.printer.send_now("M30 %s" % fn) self.refresh() def doUpload(self): bn = self.entry.get() try: d = self.tree.selection()[0].split(':')[0] except: d = "" if len(d) != 0: d += '/' fn = (d + bn).lower() self.log.logMsg("Starting upload to SD file %s" % fn) self.printer.send_now("M28 %s" % fn) # select the file self.app.startUpload() self.top.destroy() self.top = None
class GUIBuscador(Tk): def __init__(self, master = None): Tk.__init__(self, master) self.gui(master) self.dir = 'D:\Talker\Talker\Biblia' self.direc = glob("%s\*" % self.dir) def gui(self, master): self.frm = Frame(master) self.frm.pack(side = LEFT, expand = YES, fill = BOTH) self.left_side(self.frm) self.frm = Frame(master) self.frm.pack(side = RIGHT, expand = YES, fill = BOTH) self.right_side(self.frm) def left_side(self, master): self.nombre = Entry(master, justify = CENTER, bd = 3, font = ('Ravie', 11), textvariable = self.NameVar) self.nombre.pack(side = TOP, fill = X) self.nombre.bind("<Key>", self.Enter) self.texto = Entry(master, justify = CENTER, bd = 3, font = ('Ravie', 11), textvariable = self.TextVar) self.texto.pack(side = TOP, fill = X) self.texto.bind("<Key>", self.Enter) self.tag = Entry(master, justify = CENTER, bd = 3, font = ('Ravie', 11), textvariable = self.TagsVar) self.tag.pack(side = TOP, fill = X) self.tag.bind("<Key>", self.Enter) self.tree = Treeview(master) self.tree.pack(side = LEFT, expand = YES, fill = BOTH) self.tree.bind("<Double-1>", self.OnDoubleClick) def right_side(self, master): self.text = Text(master, bg = 'skyblue', bd = 5, font = ('consolas', 12), fg = 'red') self.text.pack(expand = YES, side = LEFT, fill = BOTH) self.yscroller = Scrollbar(master, command = self.text.yview) self.yscroller.pack(side = RIGHT, fill = Y) self.text['yscrollcommand'] = self.yscroller def OnDoubleClick(self, tree): try: item = self.tree.selection()[0] self.tree.item.open(item) except IndexError: pass def Enter(self, event): if event.char == ord(13): self.buscar() def buscar(self): name = NameVar.get() text = TextVar().get() etiqueta = TagsVar.get().split(',') self.aciertos = [] for carpeta in self.direc: root = tree.insert("", 1, name[-3], text = name[-3]) self.aciertos = [] for versiculo in glob("%s\*" % carpeta): with open(versiculo, 'r') as nota: texto = nota.readlines() etiquetas = texto[-1].split(',') if name != '': versiculo = versiculo.replace(".txt", "") if re.search('%s' % name, versiculo): pass else: continue if etiqueta != []: for i in etiquetas: if i in etiqueta: break else: continue if text != '': for line in texto: if re.search(r'%s' % text, line): break else: continue tree.insert(raiz, "end", name, text = name[-1]) self.aciertos.append(versiculo) if self.aciertos == []: self.tree.delete(root)
class PickerGUI(): """ This class maintains the TK Inter user interface and contains all the data from ontology. Data can be loaded from (and store to) .rdf using RDFReader class or from JSON (that is much faster). """ def __init__(self, master, annotationEffect): self.fileName = "" self.namespace = None self.aEffect = annotationEffect self.root = master self.root.bind('<Escape>', self.close) self.leftFrame = Tkinter.Frame(master) self.middleFrame = Tkinter.Frame(master) self.rightFrame = Tkinter.Frame(master) self.leftFrame.pack(side=Tkinter.LEFT, padx=10, pady=10) self.middleFrame.pack(side=Tkinter.LEFT) self.rightFrame.pack(side=Tkinter.LEFT) self.bottomLeftFrame = Tkinter.Frame(self.leftFrame) self.bottomMiddleFrame = Tkinter.Frame(self.middleFrame) self.bottomRightFrame = Tkinter.Frame(self.rightFrame) self.menuBar = Tkinter.Menu(master) self.fileMenu = Tkinter.Menu(self.menuBar, tearoff=0) self.fileMenu.add_command(label="Load Ontology", accelerator="Ctrl+L", command=self.loadOntology) self.fileMenu.add_command(label="Save to Ontology", accelerator="Ctrl+S", command=self.saveOntology) self.menuBar.add_cascade(label="File", menu=self.fileMenu) self.fileMenuUndo = Tkinter.Menu(self.menuBar, tearoff=0) self.fileMenuUndo.add_command(label="Undo", accelerator="Ctrl+Z", command=self.undoOperation) self.root.bind_all("<Control-l>", self.loadOntology) self.root.bind_all("<Control-s>", self.saveOntology) self.root.bind_all("<Control-z>", self.undoOperation) self.menuBar.add_cascade(label="Edit", menu=self.fileMenuUndo) # Treeview to choose Ontology Entities to annotate new elements self.treeEntityPicker = Treeview(self.leftFrame) self.treeEntityPicker.heading("#0", text="Entity/Subject") self.treeEntityPicker.column("#0", width=c.BASIC_WIDTH, stretch=Tkinter.NO) # Treeview to choose Object Properties self.treePropertyPicker = Treeview(self.middleFrame) self.treePropertyPicker.heading("#0", text="Properties") self.treePropertyPicker.column("#0", width=c.ENLARGERD_WIDTH, stretch=Tkinter.NO) # Treeview to choose range individuals of property self.treeRangePicker = Treeview(self.rightFrame) self.treeRangePicker.heading("#0", text="Object") self.treeRangePicker.column("#0", width=c.BASIC_WIDTH, stretch=Tkinter.NO) self.buttonAdd = Tkinter.Button(self.bottomLeftFrame) self.buttonAdd["text"] = "Add" self.buttonAddProperty = Tkinter.Button(self.bottomRightFrame) self.buttonAddProperty["text"] = "Add Prop." self.buttonEditProperty = Tkinter.Button(self.bottomRightFrame) self.buttonEditProperty["text"] = "Edit Prop." self.buttonRemoveProperty = Tkinter.Button(self.bottomRightFrame) self.buttonRemoveProperty["text"] = "Delete Prop." self.buttonSeparateAdd = Tkinter.Button(self.bottomLeftFrame) self.buttonSeparateAdd["text"] = "Add Separately" self.buttonReplace = Tkinter.Button(self.bottomLeftFrame) self.buttonReplace["text"] = "Replace" self.buttonRemove = Tkinter.Button(self.bottomLeftFrame) self.buttonRemove["text"] = "Remove" self.buttonClear = Tkinter.Button(self.bottomMiddleFrame) self.buttonClear["text"] = "Clear Views" # define options for opening or saving a file self.file_opt = options = {} options["defaultextension"] = ".rdf" options["filetypes"] = [("RDF files", ".rdf")] options["parent"] = master options["title"] = "Load a RDF Ontology" self.resetVariables() def prepare(self, master): self.treeEntityPicker.pack(pady=15) self.treePropertyPicker.pack(pady=15) self.treePropertyPicker.bind("<ButtonRelease-1>", self.propertySelect) # Handle double click on Property Tree self.treePropertyPicker.bind("<Double-1>", self.propertyClick) self.treeRangePicker.pack(pady=15) self.bottomLeftFrame.pack(fill=Tkinter.X) self.bottomMiddleFrame.pack(fill=Tkinter.X) self.bottomRightFrame.pack(fill=Tkinter.X, padx=25) self.buttonAdd.pack(side=Tkinter.LEFT) self.buttonSeparateAdd.pack(side=Tkinter.LEFT) self.buttonReplace.pack(side=Tkinter.LEFT) self.buttonAddProperty.pack(side=Tkinter.LEFT) self.buttonEditProperty.pack(side=Tkinter.LEFT) self.buttonRemoveProperty.pack(side=Tkinter.LEFT) self.buttonRemove.pack(side=Tkinter.LEFT) self.buttonClear.pack(side=Tkinter.BOTTOM) self.buttonAdd.bind("<ButtonRelease-1>", self.buttonAddClick) self.buttonAdd.bind("<Return>", self.buttonAddClick) self.buttonSeparateAdd.bind("<ButtonRelease-1>", self.buttonSeparateAddClick) self.buttonSeparateAdd.bind("<Return>", self.buttonSeparateAddClick) self.buttonAddProperty.bind("<ButtonRelease-1>", self.buttonAddPropertyClick) self.buttonAddProperty.bind("<Return>", self.buttonAddPropertyClick) self.buttonEditProperty.bind("<ButtonRelease-1>", self.buttonEditPropertyClick) self.buttonEditProperty.bind("<Return>", self.buttonEditPropertyClick) self.buttonRemoveProperty.bind("<ButtonRelease-1>", self.buttonRemovePropertyClick) self.buttonRemoveProperty.bind("<Return>", self.buttonRemovePropertyClick) self.buttonReplace.bind("<ButtonRelease-1>", self.buttonReplaceClick) self.buttonReplace.bind("<Return>", self.buttonReplaceClick) self.buttonRemove.bind("<ButtonRelease-1>", self.buttonRemoveClick) self.buttonRemove.bind("<Return>", self.buttonRemoveClick) self.buttonClear.bind("<ButtonRelease-1>", self.buttonClearClick) self.buttonClear.bind("<Return>", self.buttonClearClick) master.config(menu=self.menuBar) self.loadSerializedOntology(self.treeEntityPicker) def resetVariables(self): # Keys: classHierarchy, instances; Values: temporary data # (to be serialized and saved) self.tempData = {} # Key: Class Name; Value: List of IDs of instances of that class self.instancesbyClass = {} # Key: Property Name; Values: Entities that belong to its range self.rangesByProperty = {} # Key: Property Name; Values: Entities that belong to its domain self.domainsByProperty = {} self.ontologyTree = None self.lastId = -1 self.defaultName = "" self.defaultTypeValue = "" self.defaultTypeValue = "" self.undoStack = [] self.selectedEntities = None self.selectedRange = None self.selectedProperties = None # Keys: properties; Values: occurrences of the property # i.e. (s,p,o) triples self.objectProperties = {} # (s,p,o) triples with object properties to be added to the ontology self.objectPropertiesToAdd = [] self.objectPropertiesToRemove = [] # Key: TreeView element ID. #Value: (s,p,o) triple. self.propertiesByTreeID = {} self.dataTypeProperties = {} self.dataTypePropertiesToAdd = [] self.dataTypePropertiesToRemove = [] def buttonAddClick(self, event): """ Button handler for adding entities. """ self.prepareSelectedEntities() close = self.aEffect.addAnnotation(separateAdd=False) if close: self.closeGUI(isInstanceListChanged=True) def buttonSeparateAddClick(self, event): """ Button handler for adding entities separately. """ self.prepareSelectedEntities() close = self.aEffect.addAnnotation(separateAdd=True) if close: self.closeGUI(isInstanceListChanged=True) def buttonAddPropertyClick(self, event): """ Button handler for adding properties. """ selectedProperty, tags, rowID = self.prepareSelectedProperty( limitObjects=False) if self.validateProperty(selectedProperty, tags): serialize = self.aEffect.addProperty(selectedProperty, tags) if serialize: self.serialize() self.refreshPropertyTree(self.treePropertyPicker) def buttonEditPropertyClick(self, event): """ Button handler for editing properties. Removes the previous (s,p,o) triple and adds a new one. """ selectedProperty, tags, rowID = self.prepareSelectedProperty() if self.validateProperty(selectedProperty, tags): serialize = self.aEffect.editProperty(selectedProperty, tags, rowID) if serialize: self.serialize() self.refreshPropertyTree(self.treePropertyPicker) def buttonRemovePropertyClick(self, event): """ Button handler for removing properties. """ selectedProperties, tags, rowIDs = \ self.getSelectedProperty(multiselect=True) for p in selectedProperties: if not self.validateProperty(p, ""): return for p, tagList in tags.iteritems(): if not self.validateProperty("", tagList): return ser = self.aEffect.removeProperty(selectedProperties, tags, rowIDs) if ser: self.serialize() self.refreshPropertyTree(self.treePropertyPicker) def validateProperty(self, property, tags): """" Validate that the selected property can be chosen :param property: The property name :param tags: A list of tags of a selected tree row, containing the property name in the case of an instance :return: boolean Whether the property is valid """ valid = True invalidProperties = [ c.HAS_SVG_PROPERTY, c.HAS_X_COORD_PR, c.HAS_Y_COORD_PR ] if property in invalidProperties: valid = False tkMessageBox.showwarning(c.PROP, c.PROP_INVALID_PROP % property) elif tags: for tag in tags: if tag in invalidProperties: tkMessageBox.showwarning(c.PROP, c.PROP_INVALID_PROP % tag) valid = False break return valid def prepareSelectedProperty(self, limitObjects=True): """ Returns the selected property and ensures that instances of its domain (for its range, use validateSelectedRange) have been selected. :param limitObjects: True if only one object can be selected :return: selected property """ selectedProperty, tags, rowID = self.getSelectedProperty() if selectedProperty: validEntity = self.prepareSelectedEntities(allowOnlyInstances=True) if validEntity: if len(self.selectedEntities) > 0: if limitObjects and len(self.selectedEntities) > 1: tkMessageBox.showwarning(c.PROP, c.PROP_MORE_SUBJ) else: # TODO: validate that subject and object are instances # and are within the domain and range of the property return selectedProperty, tags, rowID else: tkMessageBox.showwarning(c.PROP, c.PROP_NO_SUBJ) return None, None, None def getSelectedProperty(self, multiselect=False): """ Fetches the selected Property from the middle TreeView and handles incorrect selections. Returns a triple with the property name (as in the Treeview), its tags and the row ID on the TreeView. :param multiselect: Is set to 'True' if selection of multiple properties is allowed, 'False' otherwise. """ selectedProperty = None tags = None rowID = None selectedProperties = self.treePropertyPicker.selection() if len(selectedProperties) == 0: tkMessageBox.showwarning(c.PROP, c.PROP_NO_PROP) elif multiselect: rowIDs = {} properties = [] tags = {} for rowID in selectedProperties: p = self.treePropertyPicker.item(rowID, "text") properties.append(p) tags[p] = self.treePropertyPicker.item(rowID, "tags") rowIDs[p] = rowID return properties, tags, rowIDs elif len(selectedProperties) > 1: tkMessageBox.showwarning(c.PROP, c.PROP_MORE_PROP) else: rowID = selectedProperties[0] selectedProperty = self.treePropertyPicker.item(rowID, "text") tags = self.treePropertyPicker.item(rowID, "tags") return selectedProperty, tags, rowID def buttonReplaceClick(self, event): """ Button handler for replace svg elements in annotation. """ self.prepareSelectedEntities() close = self.aEffect.replaceAnnotation() if close: self.closeGUI(isInstanceListChanged=True) def buttonRemoveClick(self, event): """ Button handler for moving svg elements from annotation. """ self.prepareSelectedEntities() close = self.aEffect.removeAnnotation(None, fromUndo=False) if close: self.closeGUI(isInstanceListChanged=True) def undoOperation(self, *args): """ Button handler for undo operation. """ self.prepareSelectedEntities() close = self.aEffect.undoAnnotation() if close: self.closeGUI(isInstanceListChanged=True) def buttonClearClick(self, event): """ Button handler for clearing tree view and set it into default state. """ self.treeEntityPicker.delete(*self.treeEntityPicker.get_children()) self.populatePropertyTree(self.treeEntityPicker, []) self.treeRangePicker.delete(*self.treeRangePicker.get_children()) def propertyClick(self, event): """ Load the individuals that belong to the range of the selected Property on the right-hand TreeView, and to its domain on the left-hand TreeView. """ selectedProperty, tags, rowID = self.getSelectedProperty() if selectedProperty and c.TREE_TAG_PROPERTIES_HEADER not in tags: self.treeRangePicker.delete(*self.treeRangePicker.get_children()) self.treeEntityPicker.delete(*self.treeEntityPicker.get_children()) if c.TREE_TAG_INSTANCE in tags: # Auto-expand branches of domain and range of selected property propertyTriple = self.propertiesByTreeID[rowID] self.selectedEntities = [propertyTriple[c.SUBJECT_INDEX]] if c.TREE_TAG_OBJECT_PROPERTY in tags: # Auto select range only for object properties self.selectedRange = [propertyTriple[c.OBJECT_INDEX]] else: self.selectedRange = [] # Fetch property name from tags for tag in tags: if tag not in c.TREE_TAGS: selectedProperty = tag break if selectedProperty in self.rangesByProperty: rangeEntities = self.rangesByProperty[selectedProperty] else: rangeEntities = None if selectedProperty in self.domainsByProperty: domainEntities = self.domainsByProperty[selectedProperty] else: domainEntities = None self.populatePropertyTree(self.treeEntityPicker, domainEntities, selectPrevious="subject") if c.TREE_TAG_DATATYPE_PROPERTY in tags: self.treeRangePicker.delete( *self.treeRangePicker.get_children()) else: self.populatePropertyTree(self.treeRangePicker, rangeEntities, selectPrevious="object") def propertySelect(self, event): """ Take note of selected properties. """ selectedPropertyIDs = self.treePropertyPicker.selection() self.selectedProperties = [ self.treePropertyPicker.item(rowID, "text") for rowID in selectedPropertyIDs ] def populatePropertyTree(self, treeViewInstance, entityList, selectPrevious="none"): """ Populate an Entity & Individuals TreeView according to the range or domain of a property (passed as a list of entities). For each entity of the list, its children (entities or individuals) are added to the TreeView. :param treeViewInstance: View of the tree. :param entityList: List of entities. :param selectPrevious: This should be "object", "subject" or "none". """ subtrees = [] if entityList: for entity in entityList: subtree = self.getSubTreeFromEntity(entity, self.ontologyTree) if subtree: subtrees.append(subtree) if subtrees: for tree in subtrees: self.stack = [''] self.subTreeFromFileRecursive(tree, treeViewInstance, selectPrevious) else: self.stack = [''] self.subTreeFromFileRecursive(self.ontologyTree, treeViewInstance, selectPrevious) def getSubTreeFromEntity(self, entity, entityTree): """ Returns a subTree with the given entity as the root. :param entity: Searched entity for a root of a tree. :param entityTree: Tree structure that should be searched. :return: subtree with the entity as a root. """ nodeQueue = entityTree[:] while nodeQueue: element = nodeQueue.pop(0) if isinstance(element[0], basestring): if element[0] == entity: return element iternodes = iter(element) next(iternodes) for n in iternodes: nodeQueue.append(n) return [] def prepareSelectedEntities(self, allowOnlyInstances=False): """ Initializes the selectedEntities and selectedRange properties (Entities and/or Instances) according to the user's selection on the treeView. :param allowOnlyInstances: 'True' if only instances should be added. return: 'True' if preparation process finishes correctly, 'False' otherwise. """ selectedSubjectIDs = self.treeEntityPicker.selection() selectedEntities = [] correct = True for s in selectedSubjectIDs: text = self.treeEntityPicker.item(s, "text") tags = self.treeEntityPicker.item(s, "tags") # Select all children of "Instances" group if c.TREE_TAG_INSTANCES_HEADER in tags: for child in self.treeEntityPicker.get_children(s): text = self.treeEntityPicker.item(child, "text") selectedEntities.append(text) else: if allowOnlyInstances and c.TREE_TAG_ENTITY in tags: tkMessageBox.showwarning(c.SELECT, c.SELECT_INST) correct = False elif text not in selectedEntities: selectedEntities.append(text) self.selectedEntities = selectedEntities selectedObjectIDs = self.treeRangePicker.selection() selectedRange = [] for o in selectedObjectIDs: text = self.treeRangePicker.item(o, "text") tags = self.treeRangePicker.item(o, "tags") # Select all children of "Instances" group if c.TREE_TAG_INSTANCES_HEADER in tags: for child in self.treeRangePicker.get_children(o): text = self.treeRangePicker.item(child, "text") selectedRange.append(text) else: if allowOnlyInstances and c.TREE_TAG_ENTITY in tags: tkMessageBox.showwarning(c.SELECT, c.SELECT_INST) correct = False elif text not in selectedRange: selectedRange.append(text) self.selectedRange = selectedRange return correct def saveOntology(self, *args): """ This method saves the ontology. It takes data from JSON and stores it in the rdf file. """ if not self.instancesbyClass: tkMessageBox.showwarning(c.SAVE, c.SAVE_NOT_LOADED) return if tkMessageBox.askyesno(c.SAVE, c.SAVE_TO_ORIGINAL): fileName = self.fileName else: fileName = tkFileDialog.askopenfilename(**self.file_opt) if fileName: self.readerOperation(fileName, self.namespace, serialize=False, save=True) filePath = os.path.join(os.path.expanduser("~"), c.JSON_FILENAME) if os.path.exists(filePath): os.remove(filePath) self.closeGUI(isInstanceListChanged=False) else: tkMessageBox.showwarning(c.SAVE, c.SAVE_NOT_CHOSEN) def loadOntology(self, *args): """ Ask user to choose rdf file. Then load the ontology onto GUI and serialize it to a temp file. """ if self.ontologyTree and tkMessageBox.askyesno(c.LOAD, c.LOAD_SAVING): self.saveOntology() tkMessageBox.showwarning(c.LOAD, c.LOAD_CHOOSING) self.resetVariables() filePath = os.path.join(os.path.expanduser("~"), c.JSON_FILENAME) if os.path.exists(filePath): os.remove(filePath) namespace = None fileName = tkFileDialog.askopenfilename(**self.file_opt) if fileName: self.fileName = fileName candidateSet = self.getCandidateSetOfPrefixes(fileName) namespace = self.resolveNamespace(candidateSet) if not namespace: # User cancels the process or enter empty namespace return self.namespace = namespace self.readerOperation(fileName, namespace, serialize=True, save=False) # Detect if the ontology is not loaded properly if self.ontologyTree == [c.RDF_ROOT_NAME]: tkMessageBox.showwarning(c.LOAD, c.LOAD_NO_TREE) def readerOperation(self, fileName, namespace, serialize=True, save=False): """ Function created instance of a reader class and loads the data into appropriate variables or saves them into rdf file. :param fileName: Original fileName of .rdf file. :param namespace: Namespace of the original .rdf file. :param serialize: If it is 'True' than loaded data are saved into JSON :param save: If it is 'True' than data from JSON are stored into .rdf file """ try: reader = RDFReader(fileName, namespace) if save: self.addDefaultProperties(reader) self.treeEntityPicker.delete(*self.treeEntityPicker.get_children()) self.treePropertyPicker.delete( *self.treePropertyPicker.get_children()) self.treeRangePicker.delete(*self.treeRangePicker.get_children()) self.ontologyTree = reader.generateSubTree(c.RDF_ROOT_NAME, self.treeEntityPicker) self.instancesbyClass = reader.instancesbyClass self.initializeTriples(reader, "object") self.initializeTriples(reader, "datatype") self.domainsByProperty = reader.domainsByProperty self.rangesByProperty = reader.rangesByProperty self.treeConfiguration(self.treeEntityPicker) self.treeConfiguration(self.treeRangePicker) self.initializePropertyTree(self.treePropertyPicker) self.lastId = reader.getLastId() if serialize: self.serialize() if save: self.savingOperations(reader) except IOError as e: tkMessageBox.showwarning(c.FILE, c.FILE_ERROR % e.strerror) self.closeGUI() def initializeTriples(self, reader, type): """ Initialize instances of properties. Allowed types: object, datatype. :param reader: Reader instance with data. :param type: Type of the data. """ if type == "object": properties = reader.objectProperties else: # type == "datatype": properties = reader.dataTypeProperties for property in properties: triples = reader.getPropertyInstances(property) if type == "object": self.objectProperties[property] = [] else: self.dataTypeProperties[property] = [] for s, p, o in triples: subject = s.split('#')[1] obj = o.split('#') # Some objects (e.g. SVG paths) have no NS obj = obj[1 if len(obj) > 1 else 0] if type == "object": # Cast to lists so they can be serialized self.objectProperties[property].append( [subject, property, obj]) else: self.dataTypeProperties[property].append( [subject, property, obj]) def savingOperations(self, reader): """ Save current data into an .rdf file. :param reader: Instance of the reader class. """ self.loadSerializedInstances() # Check all 'remove' operations performed; maybe elements need # to be removed from the ontology self.loadSerializedInstances() for operation in self.undoStack: for atomicAction in operation: if atomicAction["type"] == "remove": instance = atomicAction["instanceId"] entity = atomicAction["entityName"] if entity not in self.instancesbyClass or instance not in \ self.instancesbyClass[entity]: # Whole annotation removed; check if exists in ontology # and if so, delete it if reader.hasInstance(entity, instance): reader.removeInstance(instance) else: svgElements = atomicAction["SVGElements"] for svgElement in svgElements: if reader.hasSVGElement(instance, svgElement): reader.removeSVGElementProperty( instance, svgElement) for entity, annotations in self.instancesbyClass.iteritems(): if reader.hasEntity(entity): # Ensure entity belongs to ontology for annotation, svgElements in annotations.iteritems(): if not reader.hasInstance(entity, annotation): reader.addInstance(entity, annotation) svg = SVGParser(self.aEffect.document.getroot()) cPnt = svg.countCentralPointForListOfElements(svgElements) if cPnt is not None: reader.addCoordinatesXY(annotation, cPnt[0], cPnt[1]) h, w = svg.computeDimForListOfElements(svgElements) if h is not None: reader.addLengthAndWidth(annotation, h, w) for svgElement in svgElements: reader.addSVGElementProperty(annotation, svgElement) for triple in self.objectPropertiesToRemove: reader.removeObjectProperty(triple[c.SUBJECT_INDEX], triple[c.PROPERTY_INDEX], triple[c.OBJECT_INDEX]) for triple in self.objectPropertiesToAdd: reader.addObjectProperty(triple[c.SUBJECT_INDEX], triple[c.PROPERTY_INDEX], triple[c.OBJECT_INDEX]) for triple in self.dataTypePropertiesToRemove: reader.removeDatatypeProperty(triple[c.SUBJECT_INDEX], triple[c.PROPERTY_INDEX], triple[c.OBJECT_INDEX]) for triple in self.dataTypePropertiesToAdd: reader.addDatatypeProperty(triple[c.SUBJECT_INDEX], triple[c.PROPERTY_INDEX], triple[c.OBJECT_INDEX]) reader.saveOntology() def getCandidateSetOfPrefixes(self, fileName): """ This method tries to find the correct prefix of ontology directly from .rdf file. :param fileName: Name of the file to be searched. :return: Candidate set of prefixes that are used in ontology without common ones. """ tree = etree.parse(fileName) root = tree.getroot() setOfPrefixes = set() for name in root.nsmap: setOfPrefixes.add(self.removeLastHTag(root.nsmap[name])) # namespace generated by the Protege inkex.NSS['owl'] = c.OWL_PREFIX ontNS = root.xpath(".//owl:Ontology", namespaces=inkex.NSS) if ontNS is not None and len(ontNS) > 0 and ontNS[0] is not None: if c.RDF_NS_ATTRIBUTE in ontNS[0].attrib: cand = self.removeLastHTag(ontNS[0].attrib[c.RDF_NS_ATTRIBUTE]) setOfPrefixes.add(cand) return setOfPrefixes - c.COMMON_PREFIXES def resolveNamespace(self, candidateNSSet): """ Method allows to resolve the selection of namespaces. It solves the cases when nothing is is found, one is found or multiple namespaces exists. :param candidateNSSet: Candidate set of namespaces. :return: Final name of the namespace. """ if len(candidateNSSet) == 0: fName = tkSimpleDialog.askstring(c.NSNAME, c.NSNAME_NO_NS) if fName is not None and not fName: tkMessageBox.showwarning(c.NSNAME, c.NSNAME_NOT_ADDED) fName = c.DEFAULT_NS elif len(candidateNSSet) == 1: el = next(iter(candidateNSSet)) if tkMessageBox.askokcancel(c.NSNAME, c.NSNAME_DETECTED % el): fName = el else: fName = tkSimpleDialog.askstring(c.NSNAME, c.NSNAME_ENTER) if fName is not None and not fName: tkMessageBox.showwarning(c.NSNAME, c.NSNAME_NOT_ADDED) fName = c.DEFAULT_NS else: description = "\n".join(candidateNSSet) el = next(iter(candidateNSSet)) fName = tkSimpleDialog.askstring(c.NSNAME, c.NSNAME_MULTIPLE % description, initialvalue=el) return fName def removeLastHTag(self, str): """ Removes the last hashtag form the string. :param str: String to be changed. :return: String without the last hashtag. """ if str.endswith("#"): return str[:-1] return str def treeConfiguration(self, treeInstance): """ Method configures the tree and set colors for different type of entities and instances in the tree. :param treeInstance: instance of the tree. """ treeInstance.tag_configure(c.TREE_TAG_ENTITY, background="white") treeInstance.tag_configure(c.TREE_TAG_INSTANCE, background="grey") treeInstance.tag_configure(c.TREE_TAG_HIGHLIGHT, background="yellow") def subTreeFromFileRecursive(self, treeList, treeViewInstance, selectPrevious="none"): """ Method creates tree from the treeList. :param treeList: List with data from whom the tree is generated. :param treeViewInstance: :param selectPrevious: This should be "object", "subject" or "none". """ if selectPrevious != "none": selected = self.previousSelectedEntities(selectPrevious) for i in iter(treeList): if isinstance(i, basestring): parentID = self.stack[-1] # Insert element into GUI ViewTree childID = treeViewInstance.insert(parentID, 'end', text=i, tags=(c.TREE_TAG_ENTITY, )) if selectPrevious != "none" and i in selected: self.expandBranches(treeViewInstance, childID) # Insert instances of current Entity if i in self.instancesbyClass: self.insertInstancesInTree(self.instancesbyClass[i], treeViewInstance, childID, selectPrevious) self.stack.append(childID) else: self.subTreeFromFileRecursive(i, treeViewInstance, selectPrevious) if self.stack: self.stack.pop() def expandBranches(self, treeViewInstance, rowID): """ Expand all branches from the root to the given one. :param treeViewInstance: View of the tree. :param rowID: Id of the searched row. """ treeViewInstance.item(rowID, open=True) tempStack = self.stack[:] # Slice clone while tempStack: treeViewInstance.item(tempStack.pop(), open=True) self.setFocus(treeViewInstance, rowID) def insertInstancesInTree(self, instanceList, treeViewInstance, parentID, selectPrevious="none"): """ Insert instances from instanceList into treeView. :param instanceList: List of instances. :param treeViewInstance: View of the tree. :param parentID: Id of the parent in the tree view. :param selectPrevious: This should be "object", "subject" or "none". """ localParentID = parentID # Only in case that there is a lot of instances if len(instanceList) > c.MAX_INSTANCES_IN_DIR: localParentID = \ treeViewInstance.insert(parentID, 'end', text=c.INSTANCES_NAME, tags=(c.TREE_TAG_INSTANCE, c.TREE_TAG_INSTANCES_HEADER, )) for instance in sorted(instanceList.keys()): if set(self.aEffect.selected).intersection(instanceList[instance]): tag = c.TREE_TAG_HIGHLIGHT else: tag = c.TREE_TAG_INSTANCE rowID = treeViewInstance.insert(localParentID, 'end', text=instance, tags=(tag, )) # Expand all branches to instance if it was previously selected if selectPrevious != 'none' and instance in \ self.previousSelectedEntities(selectPrevious): self.expandBranches(treeViewInstance, localParentID) # If instances are grouped, expand "Instances" header if parentID != localParentID: treeViewInstance.item(parentID, open=True) self.setFocus(treeViewInstance, rowID) def initializePropertyTree(self, treeViewInstance): """ Method initializes tree of properties. :param treeViewInstance: View of the tree. """ if self.objectProperties: oID = treeViewInstance.insert( '', 'end', text='Object Properties', tags=(c.TREE_TAG_PROPERTIES_HEADER, )) if self.dataTypeProperties: dID = treeViewInstance.insert( '', 'end', text='Datatype Properties', tags=(c.TREE_TAG_PROPERTIES_HEADER, )) self.addPropertiesToTreeView(treeViewInstance, self.objectProperties, oID, type=c.TREE_TAG_OBJECT_PROPERTY) self.addPropertiesToTreeView(treeViewInstance, self.dataTypeProperties, dID, type=c.TREE_TAG_DATATYPE_PROPERTY) def addPropertiesToTreeView(self, treeViewInstance, props, headerID, type): """ Insert properties from the instanceList into treeView. :param treeViewInstance: View of the tree. :param props: Properties to be added. :param headerID: Id of the header for adding properties. :param type: Type of the property. """ selected = self.previousSelectedProperties() for property in props: textAdd = property parID = treeViewInstance.insert(headerID, 'end', text=textAdd, tags=(c.TREE_TAG_PROPERTY, type)) triples = props[property] if selected and textAdd in selected: self.expandPropertyBranches(treeViewInstance, [headerID], parID) for triple in triples: textAdd = "%s -> %s" % (triple[c.SUBJECT_INDEX], triple[c.OBJECT_INDEX]) childID = treeViewInstance.insert(parID, 'end', text=textAdd, tags=(c.TREE_TAG_INSTANCE, type, property)) self.propertiesByTreeID[childID] = [ triple[c.SUBJECT_INDEX], property, triple[c.OBJECT_INDEX] ] if selected and textAdd in selected: self.expandPropertyBranches(treeViewInstance, [headerID, parID], childID) def expandPropertyBranches(self, treeViewInstance, ancestorIDs, childID): """ Method for expanding branches in the property tree view. :param treeViewInstance: View of the tree. :param ancestorIDs: ID of the ancestor. :param childID: ID of the child. """ for id in ancestorIDs: treeViewInstance.item(id, open=True) treeViewInstance.item(childID, open=True) self.setFocus(treeViewInstance, childID) def setFocus(self, treeViewInstance, rowID): """ Method for expanding setting focus on specific in the property row in the tree view. :param treeViewInstance: View of the tree. :param rowID: ID of the row that should be focused. """ treeViewInstance.focus(rowID) treeViewInstance.selection_set(rowID) treeViewInstance.focus_set() def refreshPropertyTree(self, treeViewInstance): """ Reload all properties and feed the given TreeView with them. :param treeViewInstance: View of the tree. """ treeViewInstance.delete(*treeViewInstance.get_children()) if self.objectProperties or self.dataTypeProperties: self.initializePropertyTree(treeViewInstance) else: tkMessageBox.showwarning(c.PROP, c.PROP_NOTHING_FOUND) def loadSerializedOntology(self, treeViewInstance): """ Tries to load a serialized ontology and other relevant data from a json file. :param treeViewInstance: View of the tree. """ filePath = os.path.join(os.path.expanduser("~"), "viso.json") if os.path.exists(filePath): with open(filePath, 'r') as f: try: self.tempData = json.load(f) self.ontologyTree = self.tempData["classHierarchy"] self.stack = [''] self.instancesbyClass = self.tempData["instances"] self.defaultName = self.tempData["defaultName"] self.defaultTypeValue = self.tempData["defaultValue"] self.defaultTypeValue = self.tempData["defaultValue"] self.fileName = self.tempData["fileName"] self.namespace = self.tempData["namespace"] self.lastId = self.tempData["lastId"] self.undoStack = self.tempData["undoStack"] self.subTreeFromFileRecursive(self.ontologyTree, treeViewInstance, selectPrevious="subject") self.treeConfiguration(self.treeEntityPicker) self.treeConfiguration(self.treeRangePicker) self.objectProperties = self.tempData["objectProperties"] self.dataTypeProperties = \ self.tempData["dataTypeProperties"] self.domainsByProperty = self.tempData["domains"] self.rangesByProperty = self.tempData["ranges"] self.objectPropertiesToAdd = \ self.tempData["propertyTriples"] self.objectPropertiesToRemove = \ self.tempData["propertyTriplesToRemove"] self.dataTypePropertiesToAdd = \ self.tempData["dataTypePropertyTriples"] self.dataTypePropertiesToRemove = \ self.tempData["dataTypePropertyTriplesToRemove"] self.initializePropertyTree(self.treePropertyPicker) except ValueError: self.ontologyTree = None finally: self.stack = None f.close() def loadSerializedInstances(self): """ Load the current instance information (intancesByClass, domains, ranges) from the JSON file. """ filePath = os.path.join(os.path.expanduser("~"), "viso.json") if os.path.exists(filePath): with open(filePath, 'r') as f: try: self.tempData = json.load(f) self.instancesbyClass = self.tempData["instances"] self.domainsByProperty = self.tempData["domains"] self.rangesByProperty = self.tempData["ranges"] self.objectProperties = self.tempData["objectProperties"] self.dataTypeProperties = \ self.tempData["dataTypeProperties"] self.objectPropertiesToAdd = \ self.tempData["propertyTriples"] self.dataTypePropertiesToAdd = \ self.tempData["dataTypePropertyTriples"] self.dataTypePropertiesToRemove = \ self.tempData["dataTypePropertyTriplesToRemove"] self.objectPropertiesToRemove = \ self.tempData["propertyTriplesToRemove"] self.namespace = self.tempData["namespace"] except ValueError as e: tkMessageBox.showwarning(c.FILE, c.FILE_SER_ERROR % e.strerror) finally: f.close() def previousSelectedEntities(self, type="subject"): """ Returns the selected Entities/Instances previously selected by the user on the last time the GUI was closed. :param type: This should be "object", "subject" or "none". """ if type == "subject": if self.selectedEntities: selected = self.selectedEntities elif "selectedEntities" in self.tempData: selected = self.tempData["selectedEntities"] else: selected = [] elif type == "object": if self.selectedRange: selected = self.selectedRange elif "selectedRanges" in self.tempData: selected = self.tempData["selectedRanges"] else: selected = [] else: selected = [] return selected def previousSelectedProperties(self): """ Returns the last properties selected by the user. """ if self.selectedProperties: selected = self.selectedProperties elif "selectedProperties" in self.tempData: selected = self.tempData["selectedProperties"] else: selected = [] return selected def instanceExists(self, instance): """ Checks if instance exist. :param instance: Instance to be checked. :return: 'True' if instance already exist, 'False' otherwise. """ for entity in self.instancesbyClass: if instance in self.instancesbyClass[entity]: return True return False def addDefaultProperties(self, reader): """ Check if the ontology has the required properties. If not, add them and inform the user. :param reader: Instance of the RDFReader class that allows to store properties into .rdf file. """ default_properties = [ c.HAS_SVG_PROPERTY, c.COOR_PROPERTY, c.X_COOR_PROPERTY, c.Y_COOR_PROPERTY ] added = [] for property in default_properties: if not reader.hasProperty(property, "datatype"): added.append(property) reader.addProperty(property, "datatype") if added: tkMessageBox.showwarning(c.PROP, c.PROP_DATA_NOT_FOUND % ', '.join(added)) reader.saveOntology() def close(self, event): self.closeGUI(isInstanceListChanged=True) def closeGUI(self, isInstanceListChanged): """ Closes the gui. :param isInstanceListChanged: True if something was changed and serialization should be done. """ if isInstanceListChanged: self.serialize() self.root.destroy() def serialize(self): """ Serialize Ontology into JSON file in the user's home folder. """ serializedInfo = {} if self.ontologyTree: serializedInfo["classHierarchy"] = self.ontologyTree else: tkMessageBox.showwarning(c.FILE, c.FILE_JSON_ERROR) serializedInfo["fileName"] = self.fileName serializedInfo["namespace"] = self.namespace serializedInfo["instances"] = self.instancesbyClass serializedInfo["objectProperties"] = self.objectProperties serializedInfo["dataTypeProperties"] = self.dataTypeProperties serializedInfo["ranges"] = self.rangesByProperty serializedInfo["domains"] = self.domainsByProperty serializedInfo["lastId"] = self.lastId serializedInfo["undoStack"] = self.undoStack serializedInfo["selectedEntities"] = [] if not self.selectedEntities \ else self.selectedEntities serializedInfo["selectedRanges"] = [] if not self.selectedRange \ else self.selectedRange serializedInfo["selectedProperties"] = [] if not self.selectedProperties \ else self.selectedProperties serializedInfo["propertyTriples"] = self.objectPropertiesToAdd serializedInfo["propertyTriplesToRemove"] = \ self.objectPropertiesToRemove serializedInfo["dataTypePropertyTriples"] = \ self.dataTypePropertiesToAdd serializedInfo["dataTypePropertyTriplesToRemove"] = \ self.dataTypePropertiesToRemove serializedInfo["defaultName"] = self.defaultName serializedInfo["defaultValue"] = self.defaultTypeValue serializedInfo["defaultValue"] = self.defaultTypeValue serialized = json.dumps(serializedInfo) filePath = os.path.join(os.path.expanduser("~"), c.JSON_FILENAME) try: f = open(filePath, 'w+') f.write(serialized) except IOError as e: tkMessageBox.showwarning(c.FILE, c.FILE_JSON_FOLDER) raise e finally: f.close()
class CommSearch(Frame): def __init__(self, parent): Frame.__init__(self, parent) self.parent = parent self.initUI() def initUI(self): self.entries_found = [] self.parent.title("Search your command cards") self.style = Style() self.style.theme_use("default") self.pack() self.input_title = Label(self, text="Enter your command below") self.input_title.grid(row=0, columnspan=2) self.input_box = Entry(self, width=90) self.input_box.grid(row=1, column=0) self.input_box.focus() self.input_box.bind("<Key>", self.onUpdateSearch) self.search_btn = Button(self, text="Search", command=self.onSearch) self.search_btn.grid(row=1, column=1) self.output_box = Treeview(self, columns=("Example")) ysb = Scrollbar(self, orient='vertical', command=self.output_box.yview) xsb = Scrollbar(self, orient='horizontal', command=self.output_box.xview) self.output_box.configure(yscroll=ysb.set, xscroll=xsb.set) self.output_box.heading('Example', text='Example', anchor='w') self.output_box.column("#0", minwidth=0, width=0, stretch=NO) self.output_box.column("Example", minwidth=0, width=785) self.output_box.bind("<Button-1>", self.OnEntryClick) self.output_box.grid(row=3, columnspan=2) self.selected_box = Text(self, width=110, height=19) self.selected_box.grid(row=4, columnspan=2) self.gotoadd_btn = Button(self, text="Go to Add", command=self.onGoToAdd) self.gotoadd_btn.grid(row=5) def OnEntryClick(self, event): try: item = self.output_box.selection()[0] except IndexError: pass entry_title = self.output_box.item(item, "value") for item in self.entries_found: if str(entry_title) == str("('" + item.title.strip('\n') + "',)"): self.selected_box.delete(0.1, END) self.selected_box.insert(END, item.text + '\n') def onUpdateSearch(self, key): # Somehow calling self.onSearch() does not register last key # And we need to correct "special chars" global entries, entries_map text_entries = "" for item in self.output_box.get_children(): self.output_box.delete(item) # ...like, for instance, deleting last character if key.char == '\b': search_terms = str(self.input_box.get()[:-1]) else: search_terms = str(self.input_box.get() + key.char) self.entries_found = [] self.entries_found = data.Search(search_terms, entries, entries_map) for item in range(len(self.entries_found)): aux = self.output_box.insert( '', 'end', '', value=[self.entries_found[item].title.split('\n')[0]]) def onSearch(self): global entries, entries_map text_entries = "" for item in self.output_box.get_children(): self.output_box.delete(item) search_terms = str(self.input_box.get()) for item in data.Search(search_terms, entries, entries_map): self.output_box.insert( '', 'end', '', value=[self.entries_found[item].title.split('\n')[0]]) def onGoToAdd(self): newroot = Tk() newcomm = CommAdd(newroot) newroot.geometry("800x600+0+0") newroot.mainloop()