class DialogOpenArchive(Toplevel): def __init__(self, parent, openType, filesource, filenames, title, colHeader, showAltViewButton=False): if isinstance(parent, Cntlr): cntlr = parent parent = parent.parent # parent is cntlrWinMain else: # parent is a Toplevel dialog cntlr = parent.cntlr super(DialogOpenArchive, self).__init__(parent) self.parent = parent self.showAltViewButton = showAltViewButton parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)", parent.geometry()) dialogX = int(parentGeometry.group(3)) dialogY = int(parentGeometry.group(4)) self.accepted = False self.transient(self.parent) frame = Frame(self) treeFrame = Frame(frame, width=500) vScrollbar = Scrollbar(treeFrame, orient=VERTICAL) hScrollbar = Scrollbar(treeFrame, orient=HORIZONTAL) self.treeView = Treeview(treeFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set) self.treeView.grid(row=0, column=0, sticky=(N, S, E, W)) hScrollbar["command"] = self.treeView.xview hScrollbar.grid(row=1, column=0, sticky=(E, W)) vScrollbar["command"] = self.treeView.yview vScrollbar.grid(row=0, column=1, sticky=(N, S)) treeFrame.columnconfigure(0, weight=1) treeFrame.rowconfigure(0, weight=1) treeFrame.grid(row=0, column=0, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.treeView.focus_set() if openType not in (PLUGIN, PACKAGE): cntlr.showStatus(_("loading archive {0}").format(filesource.url)) self.filesource = filesource self.filenames = filenames self.selection = filesource.selection self.hasToolTip = False selectedNode = None if openType == ENTRY_POINTS: try: metadataFiles = filesource.taxonomyPackageMetadataFiles ''' take first for now if len(metadataFiles) != 1: raise IOError(_("Taxonomy package contained more than one metadata file: {0}.") .format(', '.join(metadataFiles))) ''' metadataFile = metadataFiles[0] metadata = filesource.url + os.sep + metadataFile self.metadataFilePrefix = os.sep.join( os.path.split(metadataFile)[:-1]) if self.metadataFilePrefix: self.metadataFilePrefix += "/" # zip contents have /, never \ file seps self.taxonomyPkgMetaInf = '{}/META-INF/'.format( os.path.splitext(os.path.basename(filesource.url))[0]) self.taxonomyPackage = parsePackage( cntlr, filesource, metadata, os.sep.join(os.path.split(metadata)[:-1]) + os.sep) if self.taxonomyPackage["entryPoints"]: # may have instance documents too self.packageContainedInstances = [] packageContentTypeCounts = {} for suffix in (".xhtml", ".htm", ".html"): for potentialInstance in filesource.dir: if potentialInstance.endswith(".xhtml"): _type = "Inline Instance" self.packageContainedInstances.append( [potentialInstance, _type]) packageContentTypeCounts[ potentialInstance] = packageContentTypeCounts.get( potentialInstance, 0) + 1 if self.packageContainedInstances: break if self.packageContainedInstances: # add sequences to any duplicated entry types for _type, count in packageContentTypeCounts.items(): if count > 1: _dupNo = 0 for i in range( len(self.packageContainedInstances)): if self.packageContainedInstances[i][ 0] == _type: _dupNo += 1 self.packageContainedInstances[i][ 0] = "{} {}".format(_type, _dupNo) else: # may be a catalog file with no entry oint names openType = ARCHIVE # no entry points to show, just archive self.showAltViewButton = False except Exception as e: self.close() err = _( "Failed to parse metadata; the underlying error was: {0}" ).format(e) messagebox.showerror(_("Malformed taxonomy package"), err) cntlr.addToLog(err) return if openType not in (PLUGIN, PACKAGE): cntlr.showStatus(None) if openType in (DISCLOSURE_SYSTEM, PLUGIN, PACKAGE): y = 3 else: y = 1 okButton = Button(frame, text=_("OK"), command=self.ok) cancelButton = Button(frame, text=_("Cancel"), command=self.close) okButton.grid(row=y, column=2, sticky=(S, E, W), pady=3) cancelButton.grid(row=y, column=3, sticky=(S, E, W), pady=3, padx=3) if self.showAltViewButton: self.altViewButton = Button(frame, command=self.showAltView) self.altViewButton.grid(row=y, column=0, sticky=(S, W), pady=3, padx=3) self.loadTreeView(openType, colHeader, title) self.geometry("+{0}+{1}".format(dialogX + 50, dialogY + 100)) frame.grid(row=0, column=0, sticky=(N, S, E, W)) frame.columnconfigure(0, weight=1) frame.rowconfigure(0, weight=1) window = self.winfo_toplevel() window.columnconfigure(0, weight=1) window.rowconfigure(0, weight=1) self.bind("<Return>", self.ok) self.bind("<Escape>", self.close) self.toolTipText = StringVar() if self.hasToolTip: self.treeView.bind("<Motion>", self.motion, '+') self.treeView.bind("<Leave>", self.leave, '+') self.toolTipText = StringVar() self.toolTip = ToolTip(self.treeView, textvariable=self.toolTipText, wraplength=640, follow_mouse=True, state="disabled") self.toolTipRowId = None self.protocol("WM_DELETE_WINDOW", self.close) self.grab_set() self.wait_window(self) def loadTreeView(self, openType, title, colHeader): self.title(title) self.openType = openType selectedNode = None # clear previous treeview entries for previousNode in self.treeView.get_children(""): self.treeView.delete(previousNode) # set up treeView widget and tabbed pane if openType in (ARCHIVE, DISCLOSURE_SYSTEM, PLUGIN, PACKAGE): if openType in (PLUGIN, PACKAGE): width = 770 else: width = 500 self.treeView.column("#0", width=width, anchor="w") self.treeView.heading("#0", text=colHeader) self.isRss = getattr(self.filesource, "isRss", False) if self.isRss: self.treeView.column("#0", width=350, anchor="w") self.treeView["columns"] = ("descr", "date", "instDoc") self.treeView.column("descr", width=50, anchor="center", stretch=False) self.treeView.heading("descr", text="Form") self.treeView.column("date", width=170, anchor="w", stretch=False) self.treeView.heading("date", text="Pub Date") self.treeView.column("instDoc", width=200, anchor="w", stretch=False) self.treeView.heading("instDoc", text="Instance Document") elif openType == PLUGIN: self.treeView.column("#0", width=150, anchor="w") self.treeView["columns"] = ("name", "vers", "descr", "license") self.treeView.column("name", width=150, anchor="w", stretch=False) self.treeView.heading("name", text="Name") self.treeView.column("vers", width=60, anchor="w", stretch=False) self.treeView.heading("vers", text="Version") self.treeView.column("descr", width=300, anchor="w", stretch=False) self.treeView.heading("descr", text="Description") self.treeView.column("license", width=60, anchor="w", stretch=False) self.treeView.heading("license", text="License") elif openType == PACKAGE: self.treeView.column("#0", width=200, anchor="w") self.treeView["columns"] = ("vers", "descr", "license") self.treeView.column("vers", width=100, anchor="w", stretch=False) self.treeView.heading("vers", text="Version") self.treeView.column("descr", width=400, anchor="w", stretch=False) self.treeView.heading("descr", text="Description") self.treeView.column("license", width=70, anchor="w", stretch=False) self.treeView.heading("license", text="License") else: self.treeView["columns"] = tuple() loadedPaths = [] for i, filename in enumerate(self.filenames): if isinstance(filename, tuple): if self.isRss: form, date, instDoc = filename[2:5] elif openType == PLUGIN: name, vers, descr, license = filename[3:7] elif openType == PACKAGE: vers, descr, license = filename[3:6] filename = filename[0] # ignore tooltip self.hasToolTip = True if filename.endswith("/"): filename = filename[:-1] path = filename.split("/") if not self.isRss and len( path) > 1 and path[:-1] in loadedPaths: parent = "file{0}".format(loadedPaths.index(path[:-1])) else: parent = "" node = self.treeView.insert(parent, "end", "file{0}".format(i), text=path[-1]) if self.isRss: self.treeView.set(node, "descr", form) self.treeView.set(node, "date", date) self.treeView.set(node, "instDoc", os.path.basename(instDoc)) elif openType == PLUGIN: self.treeView.set(node, "name", name) self.treeView.set(node, "vers", vers) self.treeView.set(node, "descr", descr) self.treeView.set(node, "license", license) elif openType == PACKAGE: self.treeView.set(node, "vers", vers) self.treeView.set(node, "descr", descr) self.treeView.set(node, "license", license) if self.selection == filename: selectedNode = node loadedPaths.append(path) elif openType == ENTRY_POINTS: self.treeView.column("#0", width=200, anchor="w") self.treeView.heading("#0", text="Name") self.treeView["columns"] = ("url", ) self.treeView.column("url", width=300, anchor="w") self.treeView.heading("url", text="URL") for fileType, fileUrl in getattr(self, "packageContainedInstances", ()): self.treeView.insert("", "end", fileUrl, values=fileType, text=fileUrl or urls[0][2]) for name, urls in sorted( self.taxonomyPackage["entryPoints"].items(), key=lambda i: i[0][2]): self.treeView.insert("", "end", name, values="\n".join(url[1] for url in urls), text=name or urls[0][2]) self.hasToolTip = True else: # unknown openType return None if selectedNode: self.treeView.see(selectedNode) self.treeView.selection_set(selectedNode) if self.showAltViewButton: self.altViewButton.config(text=_("Show Files") if openType == ENTRY_POINTS else _("Show Entries")) def ok(self, event=None): selection = self.treeView.selection() if len(selection) > 0: if hasattr(self, "taxonomyPackage"): # load file source remappings self.filesource.mappedPaths = self.taxonomyPackage[ "remappings"] filename = None if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM): filename = self.filenames[int(selection[0][4:])] if isinstance(filename, tuple): if self.isRss: filename = filename[4] else: filename = filename[0] elif self.openType == ENTRY_POINTS: epName = selection[0] #index 0 is the remapped Url, as opposed to the canonical one used for display # Greg Acsone reports [0] does not work for Corep 1.6 pkgs, need [1], old style packages filenames = [] for _url, _type in self.packageContainedInstances: # check if selection was an inline instance if _type == epName: filenames.append(_url) if not filenames: # else if it's a named taxonomy entry point for url in self.taxonomyPackage["entryPoints"][epName]: filename = url[0] if not filename.endswith("/"): # check if it's an absolute URL rather than a path into the archive if not isHttpUrl( filename ) and self.metadataFilePrefix != self.taxonomyPkgMetaInf: # assume it's a path inside the archive: filename = self.metadataFilePrefix + filename filenames.append(filename) if filenames: self.filesource.select(filenames) self.accepted = True self.close() return elif self.openType in (PLUGIN, PACKAGE): filename = self.filenames[int(selection[0][4:])][2] if filename is not None and not filename.endswith("/"): if hasattr(self, "taxonomyPackage"): # attempt to unmap the filename to original file # will be mapped again in loading, but this allows schemaLocation to be unmapped for prefix, remapping in self.taxonomyPackage[ "remappings"].items(): if isHttpUrl(remapping): remapStart = remapping else: remapStart = self.metadataFilePrefix + remapping if filename.startswith(remapStart): # set unmmapped file filename = prefix + filename[len(remapStart):] break if self.openType in (PLUGIN, PACKAGE): self.filesource.selection = filename else: self.filesource.select(filename) self.accepted = True self.close() def close(self, event=None): self.parent.focus_set() self.destroy() def showAltView(self, event=None): if self.openType == ENTRY_POINTS: self.loadTreeView(ARCHIVE, _("Select Entry Point"), _("File")) else: self.loadTreeView(ENTRY_POINTS, _("Select Archive File"), _("File")) def leave(self, *args): self.toolTipRowId = None def motion(self, *args): tvRowId = self.treeView.identify_row(args[0].y) if tvRowId != self.toolTipRowId: text = None if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM, PLUGIN, PACKAGE): self.toolTipRowId = tvRowId if tvRowId and len(tvRowId) > 4: try: text = self.filenames[int(tvRowId[4:])] if isinstance(text, tuple): text = (text[1] or "").replace("\\n", "\n") except (KeyError, ValueError): pass elif self.openType == ENTRY_POINTS: try: text = "{0}\n{1}".format( tvRowId, "\n".join( url[1] for url in self.taxonomyPackage["entryPoints"][tvRowId])) except KeyError: pass self.setToolTip(text) def setToolTip(self, text): self.toolTip._hide() if text: self.toolTipText.set(text) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled")
class DialogOpenArchive(Toplevel): def __init__(self, mainWin, openType, filesource, filenames, title, colHeader, showAltViewButton=False): parent = mainWin.parent super(DialogOpenArchive, self).__init__(parent) self.parent = parent self.showAltViewButton = showAltViewButton parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)", parent.geometry()) dialogX = int(parentGeometry.group(3)) dialogY = int(parentGeometry.group(4)) self.accepted = False self.transient(self.parent) frame = Frame(self) treeFrame = Frame(frame, width=500) vScrollbar = Scrollbar(treeFrame, orient=VERTICAL) hScrollbar = Scrollbar(treeFrame, orient=HORIZONTAL) self.treeView = Treeview(treeFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set) self.treeView.grid(row=0, column=0, sticky=(N, S, E, W)) hScrollbar["command"] = self.treeView.xview hScrollbar.grid(row=1, column=0, sticky=(E,W)) vScrollbar["command"] = self.treeView.yview vScrollbar.grid(row=0, column=1, sticky=(N,S)) treeFrame.columnconfigure(0, weight=1) treeFrame.rowconfigure(0, weight=1) treeFrame.grid(row=0, column=0, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.treeView.focus_set() mainWin.showStatus(_("loading archive {0}").format(filesource.url)) self.filesource = filesource self.filenames = filenames self.selection = filesource.selection self.hasToolTip = False selectedNode = None if openType == ENTRY_POINTS: try: metadataFiles = filesource.taxonomyPackageMetadataFiles if len(metadataFiles) > 1: raise IOError(_("Taxonomy package contained more than one metadata file: {0}.") .format(', '.join(metadataFiles))) metadataFile = metadataFiles[0] metadata = filesource.file(filesource.url + os.sep + metadataFile)[0] self.metadataFilePrefix = os.sep.join(os.path.split(metadataFile)[:-1]) if self.metadataFilePrefix: self.metadataFilePrefix += os.sep self.nameToUrls, self.remappings = parseTxmyPkg(mainWin, metadata) except Exception as e: self.close() err = _("Failed to parse metadata; the underlying error was: {0}").format(e) messagebox.showerror(_("Malformed taxonomy package"), err) mainWin.addToLog(err) return mainWin.showStatus(None) if openType == DISCLOSURE_SYSTEM: y = 3 else: y = 1 okButton = Button(frame, text=_("OK"), command=self.ok) cancelButton = Button(frame, text=_("Cancel"), command=self.close) okButton.grid(row=y, column=2, sticky=(S,E,W), pady=3) cancelButton.grid(row=y, column=3, sticky=(S,E,W), pady=3, padx=3) if showAltViewButton: self.altViewButton = Button(frame, command=self.showAltView) self.altViewButton.grid(row=y, column=0, sticky=(S,W), pady=3, padx=3) self.loadTreeView(openType, colHeader, title) frame.grid(row=0, column=0, sticky=(N,S,E,W)) frame.columnconfigure(0, weight=1) window = self.winfo_toplevel() window.columnconfigure(0, weight=1) self.geometry("+{0}+{1}".format(dialogX+50,dialogY+100)) self.bind("<Return>", self.ok) self.bind("<Escape>", self.close) self.toolTipText = StringVar() if self.hasToolTip: self.treeView.bind("<Motion>", self.motion, '+') self.treeView.bind("<Leave>", self.leave, '+') self.toolTipText = StringVar() self.toolTip = ToolTip(self.treeView, textvariable=self.toolTipText, wraplength=640, follow_mouse=True, state="disabled") self.toolTipRowId = None self.protocol("WM_DELETE_WINDOW", self.close) self.grab_set() self.wait_window(self) def loadTreeView(self, openType, title, colHeader): self.title(title) self.openType = openType selectedNode = None # clear previous treeview entries for previousNode in self.treeView.get_children(""): self.treeView.delete(previousNode) # set up treeView widget and tabbed pane if openType in (ARCHIVE, DISCLOSURE_SYSTEM): self.treeView.column("#0", width=500, anchor="w") self.treeView.heading("#0", text=colHeader) try: self.isRss = self.filesource.isRss if self.isRss: self.treeView.column("#0", width=350, anchor="w") self.treeView["columns"] = ("descr", "date", "instDoc") self.treeView.column("descr", width=50, anchor="center", stretch=False) self.treeView.heading("descr", text="Form") self.treeView.column("date", width=170, anchor="w", stretch=False) self.treeView.heading("date", text="Pub Date") self.treeView.column("instDoc", width=200, anchor="w", stretch=False) self.treeView.heading("instDoc", text="Instance Document") except AttributeError: self.isRss = False self.treeView["columns"] = tuple() loadedPaths = [] for i, filename in enumerate(self.filenames): if isinstance(filename,tuple): if self.isRss: form, date, instDoc = filename[2:5] filename = filename[0] # ignore tooltip self.hasToolTip = True if filename.endswith("/"): filename = filename[:-1] path = filename.split("/") if not self.isRss and len(path) > 1 and path[:-1] in loadedPaths: parent = "file{0}".format(loadedPaths.index(path[:-1])) else: parent = "" node = self.treeView.insert(parent, "end", "file{0}".format(i), text=path[-1]) if self.isRss: self.treeView.set(node, "descr", form) self.treeView.set(node, "date", date) self.treeView.set(node, "instDoc", os.path.basename(instDoc)) if self.selection == filename: selectedNode = node loadedPaths.append(path) elif openType == ENTRY_POINTS: self.treeView.column("#0", width=150, anchor="w") self.treeView.heading("#0", text="Name") self.treeView["columns"] = ("url",) self.treeView.column("url", width=350, anchor="w") self.treeView.heading("url", text="URL") for name, urls in self.nameToUrls.items(): displayUrl = urls[1] # display the canonical URL self.treeView.insert("", "end", name, values=[displayUrl], text=name) self.hasToolTip = True else: # unknown openType return None if selectedNode: self.treeView.see(selectedNode) self.treeView.selection_set(selectedNode) if self.showAltViewButton: self.altViewButton.config(text=_("Show Files") if openType == ENTRY_POINTS else _("Show Entries")) def ok(self, event=None): selection = self.treeView.selection() if len(selection) > 0: if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM): filename = self.filenames[int(selection[0][4:])] if isinstance(filename,tuple): if self.isRss: filename = filename[4] else: filename = filename[0] if not filename.endswith("/"): self.filesource.select(filename) self.accepted = True self.close() elif self.openType == ENTRY_POINTS: epName = selection[0] #index 0 is the remapped Url, as opposed to the canonical one used for display urlOrFile = self.nameToUrls[epName][0] # load file source remappings self.filesource.mappedPaths = \ dict((prefix, remapping if isHttpUrl(remapping) else (self.filesource.baseurl + os.sep + self.metadataFilePrefix +remapping.replace("/", os.sep))) for prefix, remapping in self.remappings.items()) if not urlOrFile.endswith("/"): # check if it's an absolute URL rather than a path into the archive if isHttpUrl(urlOrFile): self.filesource.select(urlOrFile) # absolute path selection else: # assume it's a path inside the archive: self.filesource.select(self.metadataFilePrefix + urlOrFile) self.accepted = True self.close() def close(self, event=None): self.parent.focus_set() self.destroy() def showAltView(self, event=None): if self.openType == ENTRY_POINTS: self.loadTreeView(ARCHIVE, _("Select Entry Point"), _("File")) else: self.loadTreeView(ENTRY_POINTS, _("Select Archive File"), _("File")) def leave(self, *args): self.toolTipRowId = None def motion(self, *args): tvRowId = self.treeView.identify_row(args[0].y) if tvRowId != self.toolTipRowId: text = None if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM): self.toolTipRowId = tvRowId if tvRowId and len(tvRowId) > 4: try: text = self.filenames[ int(tvRowId[4:]) ] if isinstance(text, tuple): text = text[1].replace("\\n","\n") except (KeyError, ValueError): pass elif self.openType == ENTRY_POINTS: try: epUrl = self.nameToUrls[tvRowId][1] text = "{0}\n{1}".format(tvRowId, epUrl) except KeyError: pass self.setToolTip(text) def setToolTip(self, text): self.toolTip._hide() if text: self.toolTipText.set(text) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled")
class RightTree(Frame): def get_size_in_pixels(self, text): """ Returns the length of the String 'text' in pixels. """ font = ft.Font() w = font.measure(text) return w def __init__(self, parent, dispatch_event): """ Builds the lower right tree, which informs the user about the metadata information. Initialisation creates a frame, a treeview and two scrollbars for the treeview element. On Inform, if there is a dataset selected it will build a Treeview with the metadata. """ super().__init__(parent) self.dispatch_event = dispatch_event self.tree = Treeview(self, columns=["value"], show="tree") #self.configure(height=1000) self.scrollbar_y = Scrollbar(self.tree, orient="vertical") self.scrollbar = Scrollbar(self.tree, orient="horizontal") self.scrollbar.config(command=self.tree.xview) self.scrollbar_y.config(command=self.tree.yview) self.tree.configure(yscrollcommand=self.scrollbar_y.set, xscrollcommand=self.scrollbar.set) self.tree.pack(fill="both", expand=True) self.scrollbar.pack(side="bottom", fill="x") self.scrollbar_y.pack(side="right", fill="y") self.pack(expand=1, fill='both') self.bind("<Configure>", self.on_resize) def on_resize(self, event): """ Sets the width of column 0 to an arbitrary, long enough value, to fix issue nr.005. """ self.scrollbar.config(command=self.tree.xview) self.scrollbar.pack(side="bottom", fill="x") self.tree.column(0, width=600) self.update() pass def inform(self, data): """ Inform function of the RightTree class. Loads available data. If there is a project, it clears the Treeview. If there is exactly 1 selection, it will build a tree with the metadata shown in it. If there is no selection or more than 1, it will show an appropriate message. """ project = data["project"] if project: # First delete everything - Selection might have changed self.tree.delete(*self.tree.get_children()) # 3 ifs : no selection, 1 selected, multiple selections sel = project.selection if len(sel) == 0: self.tree.column("#0", width=1100) self.tree.insert("", tkinter.END, "Project information", text="Please add and select a dataset") elif len(sel) == 1: index = sel[0] # For legacy reasons variable named name self.tree.insert("", tkinter.END, "Project information", text="Project information") self.tree.insert("Project information", tkinter.END, "Project Path", text="Path", values=[project.path]) self.tree.insert("", tkinter.END, "Dataset information", text="Dataset information") self.tree.insert("Dataset information", tkinter.END, "Dataset Path", text="Path", values=[project.datasets[index].path]) self.tree.insert( "Dataset information", tkinter.END, "Rows", text="Rows", values=[ len(project.datasets[index].data) ]) # example: 120000 rows with time from 0 to 59.9995 s. # HERE I AM textlines = textwrap.wrap( (project.datasets[index].metadata["Description"]), width=70) if textlines == []: textlines.append("No description given.") self.tree.insert("Dataset information", tkinter.END, "Dataset Description", text="Description", values=[textlines[0]]) if len(textlines) > 1: for i in range(1, len(textlines)): self.tree.insert("Dataset information", tkinter.END, "Dataset Description %d" % (i), text="", values=[textlines[i]]) self.tree.insert("", tkinter.END, "Method", text="Method") if project.datasets[index].metadata[ "Method"] == "HILDE-Homogeneous": self.tree.insert( "Method", tkinter.END, value=textwrap.wrap("HILDE (homogeneous noise)")) elif project.datasets[index].metadata[ "Method"] == "HILDE-Heterogeneous": self.tree.insert( "Method", tkinter.END, value=textwrap.wrap("HILDE (heterogeneous noise)")) elif project.datasets[index].metadata[ "Method"] == "JULES-Homogeneous": self.tree.insert( "Method", tkinter.END, value=textwrap.wrap("JULES (homogeneous noise)")) elif project.datasets[index].metadata[ "Method"] == "JSMURF-Homogeneous": self.tree.insert( "Method", tkinter.END, value=textwrap.wrap("JSMURF (homogeneous noise)")) else: self.tree.insert( "Method", tkinter.END, value=textwrap.wrap("JSMURF (heterogeneous noise)")) # Here i will go self.tree.insert("", tkinter.END, "Dataset parameters", text="Dataset parameters") self.tree.insert("Dataset parameters", tkinter.END, "Sampling rate in Hz", text="Sampling rate in Hz", values=project.datasets[index]. metadata["Sampling rate in Hz"]) self.tree.insert("Dataset parameters", tkinter.END, "Cut-off frequency in Hz", text="Cut-off frequency in Hz", values=[ project.datasets[index]. metadata["Cut-off frequency in Hz"] ]) self.tree.insert( "Dataset parameters", tkinter.END, "Filter type", text="Filter type", values=[project.datasets[index].metadata["Filter type"]]) if project.datasets[index].metadata[ "Method"] == "HILDE-Homogeneous": self.tree.insert( "Dataset parameters", tkinter.END, "Quantile 1", text="Quantile 1", values=["will be computed by MC simulation"]) self.tree.insert("Quantile 1", tkinter.END, "Significance level 1", text="Alpha1", values=[ project.datasets[index]. metadata["Significance level 1"] ]) # self.tree.insert("Quantile 1", tkinter.END, "Repetitions 1", text="Repetitions", values=[ # project.datasets[index].metadata["Repetitions"]]) self.tree.insert("Quantile 1", tkinter.END, "Repetitions ", text="Repetitions", values=[ project.datasets[index]. metadata["Repetitions_Hilde"] ]) self.tree.insert( "Dataset parameters", tkinter.END, "Quantile 2", text="Quantile 2", values=["will be computed by MC simulation"]) self.tree.insert("Quantile 2", tkinter.END, "Significance level 2", text="Alpha2", values=[ project.datasets[index]. metadata["Significance level 2"] ]) self.tree.insert("Quantile 2", tkinter.END, "Repetitions", text="Repetitions", values=[ project.datasets[index]. metadata["Repetitions_Hilde"] ]) elif project.datasets[index].metadata[ "Method"] == "HILDE-Heterogeneous": self.tree.insert( "Dataset parameters", tkinter.END, "Quantile 1", text="Quantile 1", values=["will be computed by MC simulation"]) self.tree.insert("Quantile 1", tkinter.END, "Significance level 1", text="Alpha1", values=[ project.datasets[index]. metadata["Significance level 1"] ]) self.tree.insert("Quantile 1", tkinter.END, "Repetitions ", text="Repetitions", values=[ project.datasets[index]. metadata["Repetitions_Hilde"] ]) self.tree.insert( "Dataset parameters", tkinter.END, "Quantile 2", text="Quantile 2", values=["will be computed by MC simulation"]) self.tree.insert("Quantile 2", tkinter.END, "Significance level 2", text="Alpha2", values=[ project.datasets[index]. metadata["Significance level 2"] ]) self.tree.insert("Quantile 2", tkinter.END, "Repetitions", text="Repetitions", values=[ project.datasets[index]. metadata["Repetitions_Hilde"] ]) elif project.datasets[index].metadata[ "Method"] == "JULES-Homogeneous": if project.datasets[index].metadata[ "Quantile_JULES_HOMOGENEOUS provided"]: self.tree.insert( "Dataset parameters", tkinter.END, "Quantile", text="Quantile", values=[ project.datasets[index]. metadata["Quantile_JULES_HOMOGENEOUS"] ]) else: self.tree.insert( "Dataset parameters", tkinter.END, "Quantile", text="Quantile", values=["will be computed by MC simulation"]) self.tree.insert("Quantile", tkinter.END, "Significance level", text="Alpha", values=[ project.datasets[index]. metadata["Significance level"] ]) self.tree.insert( "Quantile", tkinter.END, "Repetitions", text="Repetitions", values=[ project.datasets[index].metadata["Repetitions"] ]) elif project.datasets[index].metadata[ "Method"] == "JSMURF-Homogeneous": if project.datasets[index].metadata[ "Quantile_JSMURF_HOMOGENEOUS provided"]: self.tree.insert( "Dataset parameters", tkinter.END, "Quantile", text="Quantile", values=[ project.datasets[index]. metadata["Quantile_JSMURF_HOMOGENEOUS"] ]) else: self.tree.insert( "Dataset parameters", tkinter.END, "Quantile", text="Quantile", values=["will be computed by MC simulation"]) self.tree.insert("Quantile", tkinter.END, "Significance level", text="Alpha", values=[ project.datasets[index]. metadata["Significance level"] ]) self.tree.insert( "Quantile", tkinter.END, "Repetitions", text="Repetitions", values=[ project.datasets[index].metadata["Repetitions"] ]) else: self.tree.insert( "Dataset parameters", tkinter.END, "Quantile", text="Quantile", values=["will be computed by MC simulation"]) self.tree.insert("Quantile", tkinter.END, "Significance level", text="Alpha", values=[ project.datasets[index]. metadata["Significance level"] ]) self.tree.insert( "Quantile", tkinter.END, "Repetitions", text="Repetitions", values=[ project.datasets[index].metadata["Repetitions"] ]) maxw = 600 #600 for child in self.tree.get_children(): self.tree.see(child) w = self.get_size_in_pixels( str(self.tree.item(child)['values'])) if (w > maxw): maxw = w for grandchild in self.tree.get_children(child): self.tree.see(grandchild) w = self.get_size_in_pixels( str(self.tree.item(grandchild)['values'])) if (w > maxw): maxw = w for ggrandchild in self.tree.get_children(grandchild): self.tree.see(ggrandchild) w = self.get_size_in_pixels( str(self.tree.item(ggrandchild)['values'])) if (w > maxw): maxw = w self.tree.column(0, width=maxw) self.tree.column("#0", width=200, stretch=False) #200 else: self.tree.column("#0", width=1000) #1000 self.tree.insert( "", tkinter.END, "Project information", text= "Multiple Datasets have been selected, select single dataset to show project information." )
class NameView(object): """Shows a treeview of unique names.""" def __init__(self, master, names): self.widget = Frame(master) self._tree = Treeview(self.widget, columns='name') self._tree.grid(row=0, column=0, sticky=(N, S, W, E)) self._tree.view = self self.widget.columnconfigure(0, weight=1) self.widget.rowconfigure(0, weight=1) self._tree.column('name', width=50) self._tree['show'] = 'tree' actions = { 'edit': lambda e: self.edit(), 'search': lambda e: self.search(), 'focus_next': lambda e: self.focus_next(), 'focus_prev': lambda e: self.focus_prev(), 'select': lambda e: self._tree.selection_toggle(self._tree.focus()), 'clear_selection': lambda e: self._tree.selection_set([]) } kb.make_bindings(kb.tagview, actions, self._tree.bind) self._iids = dict() self._names = dict() logger.debug('Names: %s', names) self.widget.focus_set = self._tree.focus_set for name in sorted(names): iid = self._tree.insert('', 'end', text=name) self._names[iid] = name self._iids[name] = iid self._scroll = Scrollbar(self.widget, command=self._tree.yview) self._tree['yscrollcommand'] = self._scroll.set self._scroll.grid(row=0, column=1, sticky=(N, S)) self.widget.columnconfigure(1, weight=0) def selection(self): logger.debug('Selection: %s', self._tree.selection()) return [self._names[iid] for iid in self._tree.selection()] def edit(self): self._tree.event_generate('<<NameViewEdit>>') def search(self): if len(self._tree.selection()) == 0: self._tree.selection_add(self._tree.focus()) self._tree.event_generate('<<NameViewSearch>>') def append(self, names): logger.debug('Append names: %s', names) for name in names: if name not in self._names.values(): iid = self._tree.insert('', 'end', text=name) self._names[iid] = name self._iids[name] = iid def delete(self, name): self._tree.delete(self._iids[name]) del self._names[self._iids[name]] del self._iids[name] def _focus(self, iid): self._tree.focus(iid) self._tree.see(iid) def focus_next(self): cur_iid = self._tree.focus() next_iid = self._tree.next(cur_iid) if next_iid == '': iids = self._tree.get_children() next_iid = iids[0] self._focus(next_iid) def focus_prev(self): cur_iid = self._tree.focus() prev_iid = self._tree.prev(cur_iid) if prev_iid == '': iids = self._tree.get_children() prev_iid = iids[-1] self._focus(prev_iid) def jump_to(self, name): try: iid = self._iids[name] self._focus(iid) except KeyError: pass def get_names(self): return tuple(self._names.values()) def set(self, names): self._tree.delete(*self._iids.values()) self._iids.clear() self._names.clear() for name in sorted(names): iid = self._tree.insert('', 'end', text=name) self._names[iid] = name self._iids[name] = iid
class DialogOpenArchive(Toplevel): def __init__(self, mainWin, openType, filesource, filenames, title, colHeader, showAltViewButton=False): parent = mainWin.parent super(DialogOpenArchive, self).__init__(parent) self.parent = parent self.showAltViewButton = showAltViewButton parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)", parent.geometry()) dialogX = int(parentGeometry.group(3)) dialogY = int(parentGeometry.group(4)) self.accepted = False self.transient(self.parent) frame = Frame(self) treeFrame = Frame(frame, width=500) vScrollbar = Scrollbar(treeFrame, orient=VERTICAL) hScrollbar = Scrollbar(treeFrame, orient=HORIZONTAL) self.treeView = Treeview(treeFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set) self.treeView.grid(row=0, column=0, sticky=(N, S, E, W)) hScrollbar["command"] = self.treeView.xview hScrollbar.grid(row=1, column=0, sticky=(E,W)) vScrollbar["command"] = self.treeView.yview vScrollbar.grid(row=0, column=1, sticky=(N,S)) treeFrame.columnconfigure(0, weight=1) treeFrame.rowconfigure(0, weight=1) treeFrame.grid(row=0, column=0, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.treeView.focus_set() mainWin.showStatus(_("loading archive {0}").format(filesource.url)) self.filesource = filesource self.filenames = filenames self.selection = filesource.selection self.hasToolTip = False selectedNode = None if openType == ENTRY_POINTS: try: metadataFiles = filesource.taxonomyPackageMetadataFiles ''' take first for now if len(metadataFiles) != 1: raise IOError(_("Taxonomy package contained more than one metadata file: {0}.") .format(', '.join(metadataFiles))) ''' metadataFile = metadataFiles[0] metadata = filesource.url + os.sep + metadataFile self.metadataFilePrefix = os.sep.join(os.path.split(metadataFile)[:-1]) if self.metadataFilePrefix: self.metadataFilePrefix += "/" # zip contents have /, never \ file seps self.taxonomyPkgMetaInf = '{}/META-INF/'.format( os.path.splitext(os.path.basename(filesource.url))[0]) self.taxonomyPackage = parsePackage(mainWin, filesource, metadata, os.sep.join(os.path.split(metadata)[:-1]) + os.sep) # may be a catalog file with no entry oint names if not self.taxonomyPackage["nameToUrls"]: openType = ARCHIVE # no entry points to show, just archive self.showAltViewButton = False except Exception as e: self.close() err = _("Failed to parse metadata; the underlying error was: {0}").format(e) messagebox.showerror(_("Malformed taxonomy package"), err) mainWin.addToLog(err) return mainWin.showStatus(None) if openType == DISCLOSURE_SYSTEM: y = 3 else: y = 1 okButton = Button(frame, text=_("OK"), command=self.ok) cancelButton = Button(frame, text=_("Cancel"), command=self.close) okButton.grid(row=y, column=2, sticky=(S,E,W), pady=3) cancelButton.grid(row=y, column=3, sticky=(S,E,W), pady=3, padx=3) if self.showAltViewButton: self.altViewButton = Button(frame, command=self.showAltView) self.altViewButton.grid(row=y, column=0, sticky=(S,W), pady=3, padx=3) self.loadTreeView(openType, colHeader, title) self.geometry("+{0}+{1}".format(dialogX+50,dialogY+100)) frame.grid(row=0, column=0, sticky=(N,S,E,W)) frame.columnconfigure(0, weight=1) frame.rowconfigure(0, weight=1) window = self.winfo_toplevel() window.columnconfigure(0, weight=1) window.rowconfigure(0, weight=1) self.bind("<Return>", self.ok) self.bind("<Escape>", self.close) self.toolTipText = StringVar() if self.hasToolTip: self.treeView.bind("<Motion>", self.motion, '+') self.treeView.bind("<Leave>", self.leave, '+') self.toolTipText = StringVar() self.toolTip = ToolTip(self.treeView, textvariable=self.toolTipText, wraplength=640, follow_mouse=True, state="disabled") self.toolTipRowId = None self.protocol("WM_DELETE_WINDOW", self.close) self.grab_set() self.wait_window(self) def loadTreeView(self, openType, title, colHeader): self.title(title) self.openType = openType selectedNode = None # clear previous treeview entries for previousNode in self.treeView.get_children(""): self.treeView.delete(previousNode) # set up treeView widget and tabbed pane if openType in (ARCHIVE, DISCLOSURE_SYSTEM): self.treeView.column("#0", width=500, anchor="w") self.treeView.heading("#0", text=colHeader) try: self.isRss = self.filesource.isRss if self.isRss: self.treeView.column("#0", width=350, anchor="w") self.treeView["columns"] = ("descr", "date", "instDoc") self.treeView.column("descr", width=50, anchor="center", stretch=False) self.treeView.heading("descr", text="Form") self.treeView.column("date", width=170, anchor="w", stretch=False) self.treeView.heading("date", text="Pub Date") self.treeView.column("instDoc", width=200, anchor="w", stretch=False) self.treeView.heading("instDoc", text="Instance Document") except AttributeError: self.isRss = False self.treeView["columns"] = tuple() loadedPaths = [] for i, filename in enumerate(self.filenames): if isinstance(filename,tuple): if self.isRss: form, date, instDoc = filename[2:5] filename = filename[0] # ignore tooltip self.hasToolTip = True if filename.endswith("/"): filename = filename[:-1] path = filename.split("/") if not self.isRss and len(path) > 1 and path[:-1] in loadedPaths: parent = "file{0}".format(loadedPaths.index(path[:-1])) else: parent = "" node = self.treeView.insert(parent, "end", "file{0}".format(i), text=path[-1]) if self.isRss: self.treeView.set(node, "descr", form) self.treeView.set(node, "date", date) self.treeView.set(node, "instDoc", os.path.basename(instDoc)) if self.selection == filename: selectedNode = node loadedPaths.append(path) elif openType == ENTRY_POINTS: self.treeView.column("#0", width=150, anchor="w") self.treeView.heading("#0", text="Name") self.treeView["columns"] = ("url",) self.treeView.column("url", width=350, anchor="w") self.treeView.heading("url", text="URL") for name, urls in self.taxonomyPackage["nameToUrls"].items(): displayUrl = urls[1] # display the canonical URL self.treeView.insert("", "end", name, values=[displayUrl], text=name) self.hasToolTip = True else: # unknown openType return None if selectedNode: self.treeView.see(selectedNode) self.treeView.selection_set(selectedNode) if self.showAltViewButton: self.altViewButton.config(text=_("Show Files") if openType == ENTRY_POINTS else _("Show Entries")) def ok(self, event=None): selection = self.treeView.selection() if len(selection) > 0: if hasattr(self, "taxonomyPackage"): # load file source remappings self.filesource.mappedPaths = self.taxonomyPackage["remappings"] filename = None if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM): filename = self.filenames[int(selection[0][4:])] if isinstance(filename,tuple): if self.isRss: filename = filename[4] else: filename = filename[0] elif self.openType == ENTRY_POINTS: epName = selection[0] #index 0 is the remapped Url, as opposed to the canonical one used for display filename = self.taxonomyPackage["nameToUrls"][epName][0] if not filename.endswith("/"): # check if it's an absolute URL rather than a path into the archive if not isHttpUrl(filename) and self.metadataFilePrefix != self.taxonomyPkgMetaInf: # assume it's a path inside the archive: filename = self.metadataFilePrefix + filename if filename is not None and not filename.endswith("/"): if hasattr(self, "taxonomyPackage"): # attempt to unmap the filename to original file # will be mapped again in loading, but this allows schemaLocation to be unmapped for prefix, remapping in self.taxonomyPackage["remappings"].items(): if isHttpUrl(remapping): remapStart = remapping else: remapStart = self.metadataFilePrefix + remapping if filename.startswith(remapStart): # set unmmapped file filename = prefix + filename[len(remapStart):] break self.filesource.select(filename) self.accepted = True self.close() def close(self, event=None): self.parent.focus_set() self.destroy() def showAltView(self, event=None): if self.openType == ENTRY_POINTS: self.loadTreeView(ARCHIVE, _("Select Entry Point"), _("File")) else: self.loadTreeView(ENTRY_POINTS, _("Select Archive File"), _("File")) def leave(self, *args): self.toolTipRowId = None def motion(self, *args): tvRowId = self.treeView.identify_row(args[0].y) if tvRowId != self.toolTipRowId: text = None if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM): self.toolTipRowId = tvRowId if tvRowId and len(tvRowId) > 4: try: text = self.filenames[ int(tvRowId[4:]) ] if isinstance(text, tuple): text = text[1].replace("\\n","\n") except (KeyError, ValueError): pass elif self.openType == ENTRY_POINTS: try: epUrl = self.taxonomyPackage["nameToUrls"][tvRowId][1] text = "{0}\n{1}".format(tvRowId, epUrl) except KeyError: pass self.setToolTip(text) def setToolTip(self, text): self.toolTip._hide() if text: self.toolTipText.set(text) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled")
def listchans(self, index=None, tagsearch="", archived=0, ob=Channel.displayname, so=asc): self.center = Frame(root, bg=config.bgcolor, width=50, height=40, padx=3, pady=3) # layout all of the main containers root.grid_rowconfigure(1, weight=1) root.grid_columnconfigure(0, weight=1) self.center.grid(row=1, sticky="nsew") channels = database.get_channels(archived, ob, so) if so == desc: so = asc else: so = desc tree = Treeview(self.center) sstring = Entry(self.center, width=config.textBoxWidth) sstring.bind( "<KeyRelease-Return>", lambda e: self.listchans(None, sstring.get(), archived, ob, so)) sstring.grid(column=0, row=0) if len(tagsearch) >= 1: sstring.focus() sstring.insert(0, tagsearch) searchbutton = Button(self.center, text="Search", command=lambda: self.listchans( None, sstring.get(), archived, ob, so)) searchbutton.grid(column=1, row=0) clearbutton = Button(self.center, text="Clear Search") clearbutton.configure(command=lambda: self.listchans(archived)) clearbutton.grid(column=3, row=0) tree["columns"] = ("one", "two") tree.column("#0", width=210, minwidth=10, stretch=YES) tree.column("one", width=350, minwidth=250, stretch=YES) tree.column("two", width=210, minwidth=10, stretch=YES) tree.heading("#0", text="Last Check", anchor=W, command=lambda: self.listchans(None, sstring.get( ), archived, Channel.lastcheck, so)) tree.heading("one", text="Channel Name", anchor=E, command=lambda: self.listchans(None, sstring.get( ), archived, Channel.displayname, so)) tree.heading("two", text="Last Published", command=lambda: self.listchans(None, sstring.get( ), archived, Channel.lastpub, so)) i = 0 tree.tag_configure('oddrow', background='#88DD88') tree.tag_configure('evenrow', background='#FFFFFF') tree.tag_configure('archivedodd', background="#88DD88", foreground="#aaaaaa") tree.tag_configure('archivedeven', background='#FFFFFF', foreground="#cccccc") for item in channels: foldername = "folder" + str(i) if i % 2 == 0: color = "evenrow" else: color = "oddrow" if item.archive == True: if i % 2 == 0: color = "archivedeven" else: color = "archivedodd" if tagsearch.lower() in str( item.displayname).lower() or tagsearch.lower() in str( item.dldir).lower() or tagsearch.lower() in str( item.yt_channelid).lower(): if item.lastpub == None: lastpub = "N/A" else: lastpub = time.ctime(item.lastpub) foldername = tree.insert("", "end", text=time.ctime(item.lastcheck), values=(item.displayname, lastpub), tags=(color, item.displayname, item.dldir, item.yt_channelid)) tree.insert(foldername, "end", text="Directory", values=(item.dldir, ), tags=(color)) tree.insert(foldername, "end", text="Last Published", values=(lastpub, ), tags=(color)) i = i + 1 vertscroll = Scrollbar(self.center) vertscroll.config(command=tree.yview) tree.config(yscrollcommand=vertscroll.set, height=20) vertscroll.grid(column=4, row=1, sticky='NSE') tree.bind("<Double-1>", self.item_selected) tree.grid(row=1, columnspan=4, sticky="NSEW") tree.focus(index) tree.selection_set(index) tree.see(index)
class SearchApplication(GenericFrame): FAVICON = "../assets/favicon.ico" def __init__(self, parent=None, app_window=None): self.lastValue = None self.category_option = StringVar("") self.column_id = [ 'ProductDescription', 'ManufacturerName', 'ManufacturerPartNumber', 'DigiKeyPartNumber', 'Category' ] Frame.__init__(self, parent) self.pack() self.parent = parent self.app_window = app_window self.selectedField = None self.parent.title("Partlocater - Advanced Database Search") self.parent.iconbitmap(self.FAVICON) self.menubar = Frame(self, background='white') self.menubar.pack(side=TOP, fill=X, expand=YES) self.win_frame = Frame(self) self.win_frame.pack(side=TOP, fill=BOTH, expand=YES) self.editbutton = Menubutton(self.menubar, text='Edit', background='grey98') self.editbutton.pack(side=LEFT, fill=X) self.editmenu = Menu(self.editbutton, tearoff=0) self.editbutton.config(menu=self.editmenu) self.copySourcesMenu = Menu(self.editbutton, tearoff=0) self.editmenu.add_cascade(label='Copy', menu=self.copySourcesMenu) self.copySourcesMenu.add_command(label='Part Number', state=DISABLED, command=self.on_copy_partnumber) self.partnumber_index = 0 self.copySourcesMenu.add_command(label='Selected Parameter', state=DISABLED, command=self.on_copy_parameters) self.selectedParameter_index = 1 self.copySourcesMenu.add_command(label='Selected Part All Parameters', state=DISABLED, command=self.on_copy_all_parameters) self.allParameters_index = 2 self.editmenu.add_command(label='Delete Part', state=DISABLED, command=self.on_delete) self.searchLF = LabelFrame(self.win_frame, text="Search") self.searchLF.pack(side=LEFT, fill=X, expand=YES, pady=4, padx=6) self.searchLeftF = Frame(self.searchLF) self.searchLeftF.pack(side=LEFT, anchor=W) self.searchRightF = Frame(self.searchLF) self.searchRightF.pack(side=LEFT, anchor=N) self.searchLabelWidth = 20 self.catF = Frame(self.searchLeftF) self.catF.pack(side=TOP, anchor=W) self.catL = Label(self.catF, text='Category', width=self.searchLabelWidth, anchor=W, justify=LEFT) self.catL.pack(side=LEFT, fill=X, expand=YES) self.cat = StringVar() self.catE = Entry(self.catF, textvariable=self.cat, width=50, state=DISABLED) self.catE.config(disabledbackground=self.catE.cget("bg")) self.catE.config(disabledforeground=self.catE.cget("fg")) self.catE.pack(side=LEFT, fill=X, expand=YES, pady=4) self.category_option = StringVar() self.cat.set("All") option_list = ['All', 'All'] + Config().tables self.catM = OptionMenu(self.searchRightF, self.category_option, *option_list, command=self.on_category) self.catM.pack(side=TOP, anchor=N, fill=X, expand=YES) self.manF = Frame(self.searchLeftF) self.manF.pack(side=TOP, anchor=W) self.manL = Label(self.manF, text='ManufacturerName', width=self.searchLabelWidth, anchor=W, justify=LEFT) self.manL.pack(side=LEFT, fill=X, expand=YES, pady=4) self.man = StringVar() self.manE = Entry(self.manF, width=50, textvariable=self.man) self.manE.pack(side=LEFT, fill=X, expand=YES, pady=4) self.mpnF = Frame(self.searchLeftF) self.mpnF.pack(side=TOP, anchor=W) self.mpnL = Label(self.mpnF, text='ManufacturerPartNumber', width=self.searchLabelWidth, anchor=W, justify=LEFT) self.mpnL.pack(side=LEFT, fill=X, expand=YES, pady=4) self.mpn = StringVar() self.mpnE = Entry(self.mpnF, width=50, textvariable=self.mpn) self.mpnE.pack(side=LEFT, fill=X, expand=YES, pady=4) self.spnF = Frame(self.searchLeftF) self.spnF.pack(side=TOP, anchor=W) self.spnL = Label(self.spnF, text='DigiKeyPartNumber', width=self.searchLabelWidth, anchor=W, justify=LEFT) self.spnL.pack(side=LEFT, fill=X, expand=YES, pady=4) self.spn = StringVar() self.spnE = Entry(self.spnF, width=50, textvariable=self.spn) self.spnE.pack(side=LEFT, fill=X, expand=YES, pady=4) self.descF = Frame(self.searchLeftF) self.descF.pack(side=TOP, anchor=W) self.descL = Label(self.descF, text='ProductDescription', width=self.searchLabelWidth, anchor=W, justify=LEFT) self.descL.pack(side=LEFT, fill=X, expand=YES, pady=4) self.desc = StringVar() self.descE = Entry(self.descF, width=50, textvariable=self.desc) self.descE.pack(side=LEFT, fill=X, expand=YES, pady=4) self.descE.focus_force() self.findF = Frame(self.searchLeftF) self.findF.pack(side=TOP, anchor=E) self.findB = ttk.Button(self.findF, text="Find", width=12, command=lambda event=None: self.do_find(event)) self.findB.pack(side=LEFT, pady=4) self.clearB = ttk.Button(self.findF, text="Clear", width=6, command=self.on_clear_search) self.clearB.pack(side=LEFT, pady=4) self.partsLF = LabelFrame(self, text="Found Components") self.partsLF.pack(side=TOP, fill=X, expand=YES, pady=4, padx=4) self.partsF = Frame(self.partsLF) self.partsF.pack(side=TOP, pady=4, padx=4) # change treeview for search here self.partsTV = Treeview(self.partsF, selectmode=BROWSE, show='tree headings', columns=self.column_id) self.partsTV.bind('<Double-Button-1>', self.on_edit_item) self.partsTV.bind('<<TreeviewSelect>>', self.fieldChanged) self.partsTV.bind('<Escape>', self.clearSelection) self.partsTV.bind('<MouseWheel>', self.mousewheel) self.partsTV.bind('<Button-4>', self.mousewheel) self.partsTV.bind('<Button-5>', self.mousewheel) vcmd = (self.register(self.validateEntry), '%P') self.editfield = ttk.Entry(self.partsTV, validate='key', validatecommand=vcmd) self.editfield.bind('<Return>', self.updateField) self.editfield.bind('<Escape>', self.clearSelection) self.partsTV.bind('<Control-c>', self.on_copy_element) self.partsTV.column("#0", minwidth=0, width=18, stretch=NO) for t in self.column_id: self.partsTV.heading(t, text=Config().parameter[t]) self.partsTV.column('Category', width=60) self.scrollbar = Scrollbar(self.partsF, orient='vertical', command=self.partsTV.yview) self.scrollbar.pack(side=RIGHT, fill=Y, expand=YES, anchor=E) self.partsTV.configure(yscroll=self.scrollbar.set) self.scrollbar.config(command=self.yview) self.partsTV.pack(side=TOP, anchor=W, fill=X, expand=YES) self.partsTV.delete(*self.partsTV.get_children()) # end change of treeview # change the following to menu item #self.part_buttonF = Frame(self.partsLF) #self.delete_partB = ttk.Button(self.partsLF, text="Delete Part from Database", command=self.on_delete, #state=DISABLED) #self.delete_partB.pack(side=RIGHT, anchor=W, expand=NO, pady=4, padx=6) #self.partsB = ttk.Button(self.partsLF, text="Copy Selected To Part Find", command=self.on_copy, state=DISABLED) #self.partsB.pack(side=RIGHT, anchor=W, expand=NO, pady=4, padx=6) #self.part_buttonF.pack(side=BOTTOM) # start remove vvv #self.element_labelframe = LabelFrame(self, text="Modify Name/Value") #self.element_labelframe.pack(side=TOP, fill=X, expand=YES, pady=4, padx=6) #self.element_frame = Frame(self.element_labelframe) #self.element_frame.pack(side=TOP) #self.element_name = StringVar() #self.element_label = Label(self.element_frame, textvariable=self.element_name, width=30, anchor=W, justify=LEFT) #self.element_label.pack(side=LEFT, anchor=W, fill=X, expand=YES, pady=4) #self.element_value = StringVar() #self.element_entry = Entry(self.element_frame, width=50, textvariable=self.element_value) #self.element_entry.pack(side=LEFT, fill=X, expand=YES, pady=4) #self.default_color = self.element_entry.cget('background') #self.element_update = ttk.Button(self.element_frame, text="Update", command=self.on_update_element, #state=DISABLED) #self.element_update.pack(side=LEFT, fill=X, expand=YES, pady=4) #self.element_cancel = ttk.Button(self.element_frame, text="Cancel", command=self.on_clear_element, #state=DISABLED) #self.element_cancel.pack(side=LEFT, fill=X, expand=YES, pady=4) # end remove ^^^ self.statusLF = LabelFrame(self, text="Status") self.statusLF.pack(side=BOTTOM, fill=X, expand=YES, pady=4, padx=6) self.statusF = Frame(self.statusLF) self.statusF.pack(side=TOP, fill=X, expand=YES, padx=6) self.status = self.StatusBar(self.statusF, self) def validateEntry(self, P): if (len(P) <= 120): return True else: self.bell() return False # scroll bar event def yview(self, *args): if self.selectedField is not None: self.editfield.place_forget() self.selectedField = None self.partsTV.yview(*args) # mousewheel and button4/5 event def mousewheel(self, event): if self.selectedField is not None: self.editfield.place_forget() self.selectedField = None # escape event in treeview or editfield def clearSelection(self, event): self.editfield.place_forget() self.selectedField = None self.partsTV.selection_remove(self.partsTV.selection()) self.status.set("") # double button event def on_edit_item(self, event): if self.partsTV.parent(self.partsTV.selection() ) == '': # testing should not edit a parent self.selectedField = None return if (self.partsTV.identify_region(event.x, event.y) == 'cell'): self.selectedField = self.partsTV.identify_row(event.y) x, y, width, height = self.partsTV.bbox(self.selectedField, '#2') v = self.partsTV.set(self.selectedField, 1) self.editfield.pack() self.editfield.delete(0, len(self.editfield.get())) self.editfield.insert(0, v) self.editfield.selection_range(0, 'end') self.editfield.focus_force() self.editfield.place(x=x, y=y, width=width, height=height) # find button event def on_find(self): category = self.cat.get() search_list = [] col_list = [] search_str = self.man.get() if not (validate(search_str)): raise Exception("Invalid Manufacture Name") search_list.append(search_str) col_list.append(Config().parameter['ManufacturerName']) search_str = self.mpn.get() if not (validate(search_str)): raise Exception("Invalid Manufacture Part Number") search_list.append(search_str) col_list.append(Config().parameter['ManufacturerPartNumber']) search_str = self.spn.get() if not (validate(search_str)): raise Exception("Invalid Supplier Part Number") search_list.append(search_str) col_list.append(Config().parameter['DigiKeyPartNumber']) search_str = self.desc.get().split() if not (validate(search_str)): raise Exception("Invalid Description") search_list += search_str col_list.append(Config().parameter['ProductDescription']) select = "SELECT * FROM `" + Config().loaded_db.name + "`." where = "WHERE" like = "" i = 0 for item in search_list: if len(item) > 0: item = item.replace('%', '\\%') item = item.replace('"', '') item = item.replace("'", "") if i < 3: like += where + " `" + col_list[ i] + "` LIKE '" + item + "%'" else: like += where + " (`" + col_list[i] + "` LIKE '" + item + "%' OR `" + \ col_list[i] + "` LIKE '% " + item + "%')" where = " AND" i = i + 1 if (i < 3) else i self.partsTV.delete(*self.partsTV.get_children()) count = 0 if category == "All": for table in Config().tables: qry = select + "`" + table + "` " + like result = Config().loaded_db.query(qry) for record in result: v = [] spn = record[Config().parameter['DigiKeyPartNumber']] count += 1 for id in self.column_id: if id == 'Category': v.append(table) else: v.append(record[Config().parameter[id]]) id = self.partsTV.insert('', 'end', iid=spn, text=spn, values=v) for params in record: if record[params] is not None: self.partsTV.insert(id, 'end', text=spn, values=(params, record[params])) else: qry = select + "`" + category + "` " + like result = Config().loaded_db.query(qry) for record in result: v = [] count += 1 spn = record[Config().parameter['DigiKeyPartNumber']] for id in self.column_id: if id == 'Category': v.append(category) else: v.append(record[Config().parameter[id]]) id = self.partsTV.insert('', 'end', iid=spn, text=spn, values=v) for params in record: if record[params] is not None: self.partsTV.insert(id, 'end', text=spn, values=(params, record[params])) self.status.set(("No" if count == 0 else str(count)) + " items found") # return event def updateField(self, event): value = self.editfield.get() self.editfield.place_forget() name = self.partsTV.item(self.selectedField, "text") if not validate(value): self.status.seterror("Invalid value, must not have quotes") return self.partsTV.set(self.selectedField, "#2", value) key = self.partsTV.set(self.selectedField, "#1") self.editfield.place_forget() element_parent = self.partsTV.parent(self.selectedField) table_name = self.partsTV.item( element_parent, "values")[self.column_id.index('Category')] part_number = self.partsTV.item( element_parent, "values")[self.column_id.index('DigiKeyPartNumber')] set_param = "SET `" + key + "` = '" + value + "' " where = "WHERE `" + Config( ).parameter['DigiKeyPartNumber'] + "` = '" + part_number + "'" qry = "UPDATE `" + Config( ).loaded_db.name + "`.`" + table_name + "` " + set_param + where print(qry) try: Config().loaded_db.query(qry) except Exception as e: self.status.seterror("Database query failed: %s", e) return self.status.set("Changed " + key + " to " + value + " for part " + part_number + ".") self.partsTV.see(self.selectedField) # clear button in search frame def on_clear_search(self): self.man.set("") self.mpn.set("") self.spn.set("") self.desc.set("") self.cat.set("All") self.category_option.set("All") self.partsTV.delete(*self.partsTV.get_children()) def do_flash(self): current_color = self.element_entry.cget("background") if current_color == self.default_color: self.element_entry.config(background="red") else: self.element_entry.config(background=self.default_color) return self.after(250, self.do_flash) # category option menu def on_category(self, value): self.catE.config(state=NORMAL) self.cat.set(value) self.catE.config(state=DISABLED) #def on_copy(self): #selected = self.partsTV.selection()[0] #key = self.partsTV.item(selected, "values")[self.column_id.index('DigiKeyPartNumber')] #self.app_window.part_num_string.set(key) #self.status.set("Part Number '" + key + "' copied to Part Find") # Edit -> Delete menu def on_delete(self): selected = self.partsTV.selection()[0] key = self.partsTV.item( selected, "values")[self.column_id.index('DigiKeyPartNumber')] table = self.partsTV.item(selected, "values")[self.column_id.index('Category')] if messagebox.askokcancel( "Delete", "Click OK if you really want to delete '" + key + "' from database?"): Config().loaded_db.query("DELETE FROM `" + table + "` WHERE `" + Config().parameter['DigiKeyPartNumber'] + "` = '" + key + "'") self.status.set("Part Number '" + key + "' deleted from database") # treeview select event def fieldChanged(self, event): selected = self.partsTV.selection() if len(selected) > 0: self.copySourcesMenu.entryconfig(self.partnumber_index, state=NORMAL) self.copySourcesMenu.entryconfig(self.allParameters_index, state=NORMAL) else: self.copySourcesMenu.entryconfig(self.partnumber_index, state=DISABLED) self.copySourcesMenu.entryconfig(self.allParameters_index, state=DISABLED) return if self.partsTV.parent(selected) == '': self.copySourcesMenu.entryconfig(self.selectedParameter_index, state=DISABLED) else: self.copySourcesMenu.entryconfig(self.selectedParameter_index, state=NORMAL) if selected != self.selectedField: self.editfield.place_forget() self.selectedField = None def on_copy_parameters(self): selected = self.partsTV.selection() if len(selected) == 0 or self.partsTV.parent(selected) == '': return try: property = self.partsTV.item(selected, "values") self.parent.clipboard_clear() self.parent.clipboard_append(property[0] + '\t' + property[1]) self.parent.update() self.status.set(property[0] + ' ' + property[1] + " copied to clipboard") except Exception as e: pass def on_copy_partnumber(self): selected = self.partsTV.selection() if len(selected) == 0 or self.partsTV.parent(selected) == '': return try: if self.partsTV.parent(selected) != '': selected = self.partsTV.parent(selected) partnumber = self.partsTV.item( selected, "values")[self.column_id.index('DigiKeyPartNumber')] self.parent.clipboard_clear() self.parent.clipboard_append(partnumber) self.parent.update() self.status.set(" '" + partnumber + "' copied to clipboard") except Exception as e: pass def on_copy_all_parameters(self): selected = self.partsTV.selection() if len(selected) == 0: return try: if self.partsTV.parent(selected) != '': selected = self.partsTV.parent(selected) partnumber = self.partsTV.item( selected, "values")[self.column_id.index('DigiKeyPartNumber')] elements = self.partsTV.get_children(selected) self.parent.clipboard_clear() self.parent.clipboard_clear() for i in elements: element = self.partsTV.item(i, "values") self.parent.clipboard_append(element[0] + "\t" + element[1] + "\n") self.parent.update() self.status.set("All properties of " + partnumber + " copied to clipboard") except Exception as e: pass # deprecate def on_copy_element(self, event): try: selected = self.partsTV.selection()[0] if self.partsTV.parent(selected) == '': partnumber = self.partsTV.item elements = self.partsTV.get_children(selected) self.parent.clipboard_clear() for i in elements: element = self.partsTV.item(i, "values") self.parent.clipboard_append(element[0] + "\t" + element[1] + "\n") self.parent.update() self.status.set("All properties of " + self.partsTV.item(selected, "values")[3] + " copied to clipboard") else: key = self.partsTV.item(selected, "values")[0] val = self.partsTV.item(selected, "values")[1] self.parent.clipboard_clear() self.parent.clipboard_append(val) self.parent.update() self.status.set(key + " '" + val + "' copied to clipboard") except Exception as e: pass def do_find(self, event): try: self.on_find() except Exception as e: self.status.seterror(e)
class DialogOpenArchive(Toplevel): def __init__(self, parent, openType, filesource, filenames, title, colHeader, showAltViewButton=False): if isinstance(parent, Cntlr): cntlr = parent parent = parent.parent # parent is cntlrWinMain else: # parent is a Toplevel dialog cntlr = parent.cntlr super(DialogOpenArchive, self).__init__(parent) self.parent = parent self.showAltViewButton = showAltViewButton parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)", parent.geometry()) dialogX = int(parentGeometry.group(3)) dialogY = int(parentGeometry.group(4)) self.accepted = False self.transient(self.parent) frame = Frame(self) treeFrame = Frame(frame, width=500) vScrollbar = Scrollbar(treeFrame, orient=VERTICAL) hScrollbar = Scrollbar(treeFrame, orient=HORIZONTAL) self.treeView = Treeview(treeFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set) self.treeView.grid(row=0, column=0, sticky=(N, S, E, W)) hScrollbar["command"] = self.treeView.xview hScrollbar.grid(row=1, column=0, sticky=(E,W)) vScrollbar["command"] = self.treeView.yview vScrollbar.grid(row=0, column=1, sticky=(N,S)) treeFrame.columnconfigure(0, weight=1) treeFrame.rowconfigure(0, weight=1) treeFrame.grid(row=0, column=0, columnspan=4, sticky=(N, S, E, W), padx=3, pady=3) self.treeView.focus_set() if openType not in (PLUGIN, PACKAGE): cntlr.showStatus(_("loading archive {0}").format(filesource.url)) self.filesource = filesource self.filenames = filenames self.selection = filesource.selection self.hasToolTip = False selectedNode = None if openType == ENTRY_POINTS: try: metadataFiles = filesource.taxonomyPackageMetadataFiles ''' take first for now if len(metadataFiles) != 1: raise IOError(_("Taxonomy package contained more than one metadata file: {0}.") .format(', '.join(metadataFiles))) ''' metadataFile = metadataFiles[0] metadata = filesource.url + os.sep + metadataFile self.metadataFilePrefix = os.sep.join(os.path.split(metadataFile)[:-1]) if self.metadataFilePrefix: self.metadataFilePrefix += "/" # zip contents have /, never \ file seps self.taxonomyPkgMetaInf = '{}/META-INF/'.format( os.path.splitext(os.path.basename(filesource.url))[0]) self.taxonomyPackage = parsePackage(cntlr, filesource, metadata, os.sep.join(os.path.split(metadata)[:-1]) + os.sep) if self.taxonomyPackage["entryPoints"]: # may have instance documents too self.packageContainedInstances = [] packageContentTypeCounts = {} for suffix in (".xhtml", ".htm", ".html"): for potentialInstance in filesource.dir: if potentialInstance.endswith(".xhtml"): _type = "Inline Instance" self.packageContainedInstances.append([potentialInstance, _type]) packageContentTypeCounts[potentialInstance] = packageContentTypeCounts.get(potentialInstance, 0) + 1 if self.packageContainedInstances: break if self.packageContainedInstances: # add sequences to any duplicated entry types for _type, count in packageContentTypeCounts.items(): if count > 1: _dupNo = 0 for i in range(len(self.packageContainedInstances)): if self.packageContainedInstances[i][0] == _type: _dupNo += 1 self.packageContainedInstances[i][0] = "{} {}".format(_type, _dupNo) else: # may be a catalog file with no entry oint names openType = ARCHIVE # no entry points to show, just archive self.showAltViewButton = False except Exception as e: self.close() err = _("Failed to parse metadata; the underlying error was: {0}").format(e) messagebox.showerror(_("Malformed taxonomy package"), err) cntlr.addToLog(err) return if openType not in (PLUGIN, PACKAGE): cntlr.showStatus(None) if openType in (DISCLOSURE_SYSTEM, PLUGIN, PACKAGE): y = 3 else: y = 1 okButton = Button(frame, text=_("OK"), command=self.ok) cancelButton = Button(frame, text=_("Cancel"), command=self.close) okButton.grid(row=y, column=2, sticky=(S,E,W), pady=3) cancelButton.grid(row=y, column=3, sticky=(S,E,W), pady=3, padx=3) if self.showAltViewButton: self.altViewButton = Button(frame, command=self.showAltView) self.altViewButton.grid(row=y, column=0, sticky=(S,W), pady=3, padx=3) self.loadTreeView(openType, colHeader, title) self.geometry("+{0}+{1}".format(dialogX+50,dialogY+100)) frame.grid(row=0, column=0, sticky=(N,S,E,W)) frame.columnconfigure(0, weight=1) frame.rowconfigure(0, weight=1) window = self.winfo_toplevel() window.columnconfigure(0, weight=1) window.rowconfigure(0, weight=1) self.bind("<Return>", self.ok) self.bind("<Escape>", self.close) self.toolTipText = StringVar() if self.hasToolTip: self.treeView.bind("<Motion>", self.motion, '+') self.treeView.bind("<Leave>", self.leave, '+') self.toolTipText = StringVar() self.toolTip = ToolTip(self.treeView, textvariable=self.toolTipText, wraplength=640, follow_mouse=True, state="disabled") self.toolTipRowId = None self.protocol("WM_DELETE_WINDOW", self.close) self.grab_set() self.wait_window(self) def loadTreeView(self, openType, title, colHeader): self.title(title) self.openType = openType selectedNode = None # clear previous treeview entries for previousNode in self.treeView.get_children(""): self.treeView.delete(previousNode) # set up treeView widget and tabbed pane if openType in (ARCHIVE, DISCLOSURE_SYSTEM, PLUGIN, PACKAGE): if openType in (PLUGIN, PACKAGE): width = 770 else: width = 500 self.treeView.column("#0", width=width, anchor="w") self.treeView.heading("#0", text=colHeader) self.isRss = getattr(self.filesource, "isRss", False) if self.isRss: self.treeView.column("#0", width=350, anchor="w") self.treeView["columns"] = ("descr", "date", "instDoc") self.treeView.column("descr", width=50, anchor="center", stretch=False) self.treeView.heading("descr", text="Form") self.treeView.column("date", width=170, anchor="w", stretch=False) self.treeView.heading("date", text="Pub Date") self.treeView.column("instDoc", width=200, anchor="w", stretch=False) self.treeView.heading("instDoc", text="Instance Document") elif openType == PLUGIN: self.treeView.column("#0", width=150, anchor="w") self.treeView["columns"] = ("name", "vers", "descr", "license") self.treeView.column("name", width=150, anchor="w", stretch=False) self.treeView.heading("name", text="Name") self.treeView.column("vers", width=60, anchor="w", stretch=False) self.treeView.heading("vers", text="Version") self.treeView.column("descr", width=300, anchor="w", stretch=False) self.treeView.heading("descr", text="Description") self.treeView.column("license", width=60, anchor="w", stretch=False) self.treeView.heading("license", text="License") elif openType == PACKAGE: self.treeView.column("#0", width=200, anchor="w") self.treeView["columns"] = ("vers", "descr", "license") self.treeView.column("vers", width=100, anchor="w", stretch=False) self.treeView.heading("vers", text="Version") self.treeView.column("descr", width=400, anchor="w", stretch=False) self.treeView.heading("descr", text="Description") self.treeView.column("license", width=70, anchor="w", stretch=False) self.treeView.heading("license", text="License") else: self.treeView["columns"] = tuple() loadedPaths = [] for i, filename in enumerate(self.filenames): if isinstance(filename,tuple): if self.isRss: form, date, instDoc = filename[2:5] elif openType == PLUGIN: name, vers, descr, license = filename[3:7] elif openType == PACKAGE: vers, descr, license = filename[3:6] filename = filename[0] # ignore tooltip self.hasToolTip = True if filename.endswith("/"): filename = filename[:-1] path = filename.split("/") if not self.isRss and len(path) > 1 and path[:-1] in loadedPaths: parent = "file{0}".format(loadedPaths.index(path[:-1])) else: parent = "" node = self.treeView.insert(parent, "end", "file{0}".format(i), text=path[-1]) if self.isRss: self.treeView.set(node, "descr", form) self.treeView.set(node, "date", date) self.treeView.set(node, "instDoc", os.path.basename(instDoc)) elif openType == PLUGIN: self.treeView.set(node, "name", name) self.treeView.set(node, "vers", vers) self.treeView.set(node, "descr", descr) self.treeView.set(node, "license", license) elif openType == PACKAGE: self.treeView.set(node, "vers", vers) self.treeView.set(node, "descr", descr) self.treeView.set(node, "license", license) if self.selection == filename: selectedNode = node loadedPaths.append(path) elif openType == ENTRY_POINTS: self.treeView.column("#0", width=200, anchor="w") self.treeView.heading("#0", text="Name") self.treeView["columns"] = ("url",) self.treeView.column("url", width=300, anchor="w") self.treeView.heading("url", text="URL") for fileType, fileUrl in getattr(self, "packageContainedInstances", ()): self.treeView.insert("", "end", fileUrl, values=fileType, text=fileUrl or urls[0][2]) for name, urls in sorted(self.taxonomyPackage["entryPoints"].items(), key=lambda i:i[0][2]): self.treeView.insert("", "end", name, values="\n".join(url[1] for url in urls), text=name or urls[0][2]) self.hasToolTip = True else: # unknown openType return None if selectedNode: self.treeView.see(selectedNode) self.treeView.selection_set(selectedNode) if self.showAltViewButton: self.altViewButton.config(text=_("Show Files") if openType == ENTRY_POINTS else _("Show Entries")) def ok(self, event=None): selection = self.treeView.selection() if len(selection) > 0: if hasattr(self, "taxonomyPackage"): # load file source remappings self.filesource.mappedPaths = self.taxonomyPackage["remappings"] filename = None if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM): filename = self.filenames[int(selection[0][4:])] if isinstance(filename,tuple): if self.isRss: filename = filename[4] else: filename = filename[0] elif self.openType == ENTRY_POINTS: epName = selection[0] #index 0 is the remapped Url, as opposed to the canonical one used for display # Greg Acsone reports [0] does not work for Corep 1.6 pkgs, need [1], old style packages filenames = [] for _url, _type in self.packageContainedInstances: # check if selection was an inline instance if _type == epName: filenames.append(_url) if not filenames: # else if it's a named taxonomy entry point for url in self.taxonomyPackage["entryPoints"][epName]: filename = url[0] if not filename.endswith("/"): # check if it's an absolute URL rather than a path into the archive if not isHttpUrl(filename) and self.metadataFilePrefix != self.taxonomyPkgMetaInf: # assume it's a path inside the archive: filename = self.metadataFilePrefix + filename filenames.append(filename) if filenames: self.filesource.select(filenames) self.accepted = True self.close() return elif self.openType in (PLUGIN, PACKAGE): filename = self.filenames[int(selection[0][4:])][2] if filename is not None and not filename.endswith("/"): if hasattr(self, "taxonomyPackage"): # attempt to unmap the filename to original file # will be mapped again in loading, but this allows schemaLocation to be unmapped for prefix, remapping in self.taxonomyPackage["remappings"].items(): if isHttpUrl(remapping): remapStart = remapping else: remapStart = self.metadataFilePrefix + remapping if filename.startswith(remapStart): # set unmmapped file filename = prefix + filename[len(remapStart):] break if self.openType in (PLUGIN, PACKAGE): self.filesource.selection = filename else: self.filesource.select(filename) self.accepted = True self.close() def close(self, event=None): self.parent.focus_set() self.destroy() def showAltView(self, event=None): if self.openType == ENTRY_POINTS: self.loadTreeView(ARCHIVE, _("Select Entry Point"), _("File")) else: self.loadTreeView(ENTRY_POINTS, _("Select Archive File"), _("File")) def leave(self, *args): self.toolTipRowId = None def motion(self, *args): tvRowId = self.treeView.identify_row(args[0].y) if tvRowId != self.toolTipRowId: text = None if self.openType in (ARCHIVE, DISCLOSURE_SYSTEM, PLUGIN, PACKAGE): self.toolTipRowId = tvRowId if tvRowId and len(tvRowId) > 4: try: text = self.filenames[ int(tvRowId[4:]) ] if isinstance(text, tuple): text = (text[1] or "").replace("\\n","\n") except (KeyError, ValueError): pass elif self.openType == ENTRY_POINTS: try: text = "{0}\n{1}".format(tvRowId, "\n".join(url[1] for url in self.taxonomyPackage["entryPoints"][tvRowId])) except KeyError: pass self.setToolTip(text) def setToolTip(self, text): self.toolTip._hide() if text: self.toolTipText.set(text) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled")
class App(Frame): def __init__(self, parent): # screen_width = 768 screen_width = parent.winfo_screenwidth() print('Screen width: ' + str(screen_width)) # screen_height = 1366 screen_height = parent.winfo_screenheight() print('Screen height: ' + str(screen_height)) # font_factor = 28 font_factor = 27 if screen_width <= screen_height: # font_factor = 15 font_factor = 16 print('Font factor: ' + str(font_factor)) self.default_font_size = int(screen_width/font_factor) print('Font size: ' + str(self.default_font_size)) self.team = 0 self.dir = path.dirname(__file__) self.start_list_file = None self.start_list_file_time = None self.add_prewarnings_to_bottom = False # self.start_list_observer = Observer() # self.start_list_observer.schedule(self, '.') # self.start_list_observer.start() self.punches_url = None self.response_encoding = 'utf-8' self.competition_id = None self.last_received_punch_id = 0 self.competition_date = 0 self.competition_zero_time = 0 self.use_competition_date = False self.use_competition_time = False self.fetch_punch_interval = 10 self.prewarn_codes = {} self.sound_enabled = True self.default_language = 'sv' self.last_sound_time = None self.intro_sound_delay = timedelta(seconds=15) self.intro_sound = 'sounds/ding.mp3' self.test_sound = 'sounds/en/Testing.mp3' self.startlist_update_sound = 'sounds/half_ding.mp3' self.config_update_sound = 'sounds/half_ding.mp3' self.announce_ip = True self.team_names = dict() self.teams = dict() self.runners = dict() self.config_file = 'prewarning.ini' self.config_file_time = None self.read_config() self.data_file = 'prewarning.dat' self.read_data() self.punch_queue = Queue() self.sound_queue = Queue() self.font_size = self.default_font_size self.last_item = None self.parent = parent self.style = Style(parent) self.style.configure('Treeview', rowheight=int(self.font_size*1.5)) self.main_container = Frame(parent) self.main_container.pack(side=TOP, fill=BOTH, expand=True) self.top_frame = Frame(self.main_container) self.prewarn = Label(self.top_frame, text='Förvarning', font=('Arial', self.font_size, 'bold')) self.prewarn.pack(anchor=CENTER, side=LEFT, fill=BOTH, expand=True) self.clock = Label(self.top_frame, font=('times', self.font_size, 'bold')) self.clock.pack(side=RIGHT, fill=BOTH, ipadx=10, expand=False) self.tick() self.top_frame.pack(side=TOP, fill=X, anchor=N, expand=False) self.treeview = Treeview(self.main_container) self.treeview['columns'] = ('team', 'leg') self.treeview.heading("#0", text='Tid', anchor=W) # self.treeview.column("#0", minwidth=int(screen_width/2), width=int(screen_width/2), anchor="w", stretch=False) self.treeview.column("#0", anchor=W, stretch=True) self.treeview.heading('team', text='Lag', anchor=W) self.treeview.column('team', anchor=W, stretch=False) self.treeview.heading('leg', text='Sträcka', anchor=W) self.treeview.column('leg', minwidth=100, width=100, anchor=W, stretch=False) self.treeview.tag_configure('T', font=('Arial', self.font_size, 'bold')) self.treeview.pack(side=BOTTOM, fill=BOTH, anchor=N, expand=True) self.punch_fetcher = Thread(target=self.fetch_punches) self.punch_fetcher.setDaemon(True) self.punch_processor = Thread(target=self.process_punches) self.punch_processor.setDaemon(True) self.sound_player = Thread(target=self.play_sound) self.sound_player.setDaemon(True) self.file_watcher = Thread(target=self.check_files) self.file_watcher.setDaemon(True) self.webapp = None def set_webapp(self, webapp): self.webapp = webapp def notify_ip(self): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect(('8.8.8.8', 0)) # connecting to a UDP address doesn't send packets local_ip_address = s.getsockname()[0] print(local_ip_address) if self.announce_ip: for number in local_ip_address.split("."): call(['mpg123', '-q', self.add_path('sounds/' + self.default_language + '/' + number + '.mp3')]) s.close() def start(self): #self.read_startlist() self.punch_fetcher.start() self.punch_processor.start() self.sound_player.start() self.file_watcher.start() def add_path(self, file): file_path = path.join(self.dir, file) return file_path def read_config(self): config = ConfigParser() config.read(self.add_path(self.config_file)) common = config['Common'] new_start_list_file = common.get('StartListFile', fallback='startlist.zip') self.add_prewarnings_to_bottom = common.getboolean('AddPrewarningsToBottom', fallback=False) punch_source = config['PunchSource'] self.punches_url = punch_source.get('PunchSourceUrl', fallback='http://roc.olresultat.se/getpunches.asp') self.competition_id = punch_source['CompetitionId'] self.use_competition_date = punch_source.getboolean('UseCompetitionDate', fallback=True) self.use_competition_time = punch_source.getboolean('UseCompetitionTime', fallback=True) self.fetch_punch_interval = punch_source.getint('FetchPunchesIntervalSeconds', fallback=10) self.prewarn_codes = punch_source['PreWarningCodes'].split(',') sound = config['Sound'] self.sound_enabled = sound.getboolean('SoundEnabled', fallback=True) self.default_language = sound.get('DefaultLanguage', fallback='sv') self.announce_ip = sound.getboolean('AnnounceIp', fallback=True) self.intro_sound_delay = timedelta(seconds=sound.getint('IntroSoundDelaySeconds', fallback=10)) self.intro_sound = sound.get('IntroSoundFile', fallback='sounds/ding.mp3') self.test_sound = sound.get('TestSoundFile', fallback='sounds/en/Testing.mp3') # print(self.intro_sound) call(['mpg123', '-q', self.add_path(self.config_update_sound)]) if self.config_file_time == None: self.notify_ip() self.config_file_time = stat(self.add_path(self.config_file)).st_mtime if self.start_list_file != new_start_list_file: self.start_list_file = new_start_list_file self.read_startlist() def read_data(self): data = ConfigParser() data.read(self.add_path(self.data_file)) punch_source = data['PunchSource'] self.last_received_punch_id = punch_source.getint('LastReceivedPunchId', fallback=self.last_received_punch_id) def write_data(self): data = ConfigParser() data.read(self.add_path(self.data_file)) punch_source = data['PunchSource'] punch_source['LastReceivedPunchId'] = str(self.last_received_punch_id) with open(self.add_path(self.data_file), 'w') as datafile: data.write(datafile) def update_size(self): self.style.configure('Treeview', rowheight=int(self.font_size*1.5)) self.prewarn['font'] = ('Arial', self.font_size, 'bold') self.clock['font'] = ('times', self.font_size, 'bold') self.treeview.tag_configure('T', font=('Arial', self.font_size, 'bold')) self.scroll_to_last() def add_prewarning(self, time, team): # last_item = None # if self.last_item is not None: # last_item = self.treeview.item(self.last_item) # # if last_item is not None: # if last_item['text'] == time: # new_value = '' # for tt in last_item['values']: # if len(new_value) is not 0: # new_value += ', ' # new_value += str(tt) # new_value = '"' + new_value + ', ' + team + '"' # self.treeview.item(self.last_item, values=new_value) # else: # self.last_item = self.treeview.insert('', 'end', text=time, values=team, tags='T') # else: # self.last_item = self.treeview.insert('', 'end', text=time, values=team, tags='T') if self.add_prewarnings_to_bottom: self.last_item = self.treeview.insert('', 'end', text=time, values=team, tags='T') else: self.last_item = self.treeview.insert('', 0, text=time, values=team, tags='T') self.scroll_to_last() def scroll_to_last(self): if self.last_item is not None: self.treeview.see(self.last_item) def clear(self): self.treeview.delete(*self.treeview.get_children()) self.last_item = None def tick(self): # get the current local time from the PC new_time = strftime('%H:%M:%S') # if time string has changed, update it if new_time != self.clock["text"]: self.clock["text"] = new_time # calls itself every 200 milliseconds # to update the time display as needed # could use >200 ms, but display gets jerky # self.clock.after(200, self.tick) self.clock.after(200, self.tick) def fetch_punches(self): while True: date = 0 time = 0 if self.use_competition_date: date = self.competition_date if self.use_competition_time: time = self.competition_zero_time values = {'unitId': self.competition_id, 'lastId': self.last_received_punch_id, 'date': date, 'time': time} url_values = urlencode(values) url = self.punches_url + '?' + url_values # print(url) req = Request(url) try: response = urlopen(req) response_encoding = response.info().get_content_charset() if response_encoding is None: response_encoding = self.response_encoding data = response.read().decode(response_encoding) splitlines = data.splitlines() if splitlines: print(data) for line in splitlines: punch_dict = dict(zip(('id', 'code', 'card', 'time'), line.split(';'))) print(punch_dict) self.punch_queue.put(punch_dict) self.last_received_punch_id = punch_dict['id'] print(self.last_received_punch_id) self.write_data() except HTTPError as e: print('The server couldn\'t fulfill the request.') print('Error code: ', e.code) except URLError as e: print('We failed to reach a server.') print('Reason: ', e.reason) sleep(self.fetch_punch_interval) def process_punches(self): while True: punch = self.punch_queue.get() print('Processing: ' + punch['card'] + ' from: ' + punch['code']) if punch['code'] in self.prewarn_codes: runner = self.runners.get(punch['card']) if runner is not None: time = punch['time'].rpartition(' ')[2] bib_number = runner['team_bib_number'] leg = runner['leg'] self.add_prewarning(time, (bib_number, leg)) self.sound_queue.put('sounds/' + self.default_language + '/' + bib_number + '.mp3') # if time.endswith('6'): # self.add_prewarning(time, (str(int(bib_number) + 1), leg)) # self.add_prewarning(time, (str(int(bib_number) + 2), leg)) # self.add_prewarning(time, (str(int(bib_number) + 3), leg)) # self.add_prewarning(time, (str(int(bib_number) + 4), leg)) # self.add_prewarning(time, (str(int(bib_number) + 5), leg)) # self.add_prewarning(time, (str(int(bib_number) + 6), leg)) else: print('Not found') else: print('Wrong code') def play_sound(self): while True: # print('play_sound') sound = self.sound_queue.get() if self.sound_enabled: # print(self.last_sound_time) if self.last_sound_time is None or (datetime.now()-self.last_sound_time).total_seconds() >= self.intro_sound_delay.total_seconds(): # print(self.intro_sound) call(['mpg123', '-q', self.add_path(self.intro_sound)]) # print(sound) call(['mpg123', '-q', self.add_path(sound)]) self.last_sound_time = datetime.now() # print(self.last_sound_time) def on_modified(self, event): print(event) if self.add_path(self.start_list_file) in event.src_path: self.read_startlist() elif self.add_path('test.txt') in event.src_path: print('TEST!') def check_files(self): while True: if stat(self.add_path(self.config_file)).st_mtime != self.config_file_time: print('config_file changed!') self.read_config() if stat(self.add_path(self.start_list_file)).st_mtime != self.start_list_file_time: print('start_list_file changed!') self.read_startlist() sleep(1) def read_startlist(self): if self.start_list_file.lower().endswith('.zip'): archive = ZipFile(self.add_path(self.start_list_file), 'r') data = archive.read('SOFTSTRT.XML') else: f = open(self.add_path(self.start_list_file), 'r', encoding='windows-1252') data = f.read() startlist = ElementTree.fromstring(data) ns = {'ns': 'http://www.orienteering.org/datastandard/3.0'} event_id = self.get_data(startlist, 'ns:Event/ns:Id', ns) event_name = self.get_data(startlist, 'ns:Event/ns:Name', ns) event_date = self.get_data(startlist, 'ns:Event/ns:StartTime/ns:Date', ns) organiser_id = self.get_data(startlist, 'ns:Event/ns:Organiser/ns:Id', ns) organiser_name = self.get_data(startlist, 'ns:Event/ns:Organiser/ns:Name', ns) if event_date is not None: self.competition_date = event_date print('Event: ' + str(event_name) + ' (' + str(event_id) + ') ' + str(event_date)) print('Organiser: ' + str(organiser_name) + ' (' + str(organiser_id) + ')') self.team_names.clear() self.teams.clear() self.runners.clear() xml_teams = startlist.findall('ns:ClassStart/ns:TeamStart', ns) for xml_team in xml_teams: team_name = self.get_data(xml_team, 'ns:Name', ns) team_bib_number = self.get_data(xml_team, 'ns:BibNumber', ns) self.team_names[team_bib_number] = team_name team = dict() team_members = xml_team.findall('ns:TeamMemberStart', ns) for team_member in team_members: team_member_id = self.get_data(team_member, 'ns:Person/ns:Id', ns) team_member_name_family = self.get_data(team_member, 'ns:Person/ns:Name/ns:Family', ns) team_member_name_given = self.get_data(team_member, 'ns:Person/ns:Name/ns:Given', ns) team_member_leg = self.get_data(team_member, 'ns:Start/ns:Leg', ns) team_member_leg_order = self.get_data(team_member, 'ns:Start/ns:LegOrder', ns) team_member_bib_number = self.get_data(team_member, 'ns:Start/ns:BibNumber', ns) team_member_control_card = self.get_data(team_member, 'ns:Start/ns:ControlCard', ns) if team_member_control_card is not None: self.runners[team_member_control_card] = {'id': team_member_id, 'family': team_member_name_family, 'given': team_member_name_given, 'leg': team_member_leg, 'leg_order': team_member_leg_order, 'team_bib_number': team_bib_number, 'bib_number': team_member_bib_number, 'control_card': team_member_control_card} if team_member_leg not in team: team[team_member_leg] = dict() leg = team[team_member_leg] leg[team_member_leg_order] = self.runners[team_member_control_card] team = OrderedDict(natsorted(team.items())) self.teams[team_bib_number] = team # for leg in team.items(): # for subleg in leg: # self.team_names = OrderedDict(natsorted(self.team_names.items())) self.teams = OrderedDict(natsorted(self.teams.items())) self.start_list_file_time = stat(self.add_path(self.start_list_file)).st_mtime # print('Teams: ' + str(self.team_names)) # print('Runners: ' + str(self.runners)) # print(strftime('%H:%M:%S')) # print(self.intro_sound) call(['mpg123', '-q', self.add_path(self.startlist_update_sound)]) def web_index(self): return render_template('index.html') def web_prewarning(self): return render_template('prewarning.html') def web_config(self): config = ConfigParser() config.read(self.add_path(self.config_file)) # config_dict = {s: dict(config.items(s)) for s in config.sections()} return render_template('config.html', config=config) def web_config_post(self): config = ConfigParser() config.read(self.add_path(self.config_file)) value_changed = False for section in config.sections(): print(section) for key, old_value in config.items(section): name = "%s@%s" % (key, section) value = request.form[name] print("\t%s: %s" % (key, value)) if value != old_value: print("\t\tchanged!") config.set(section, key, value) value_changed = True if value_changed: with open(self.add_path(self.config_file), 'w') as configfile: config.write(configfile) return render_template('config.html', config=config) def web_startlist(self): return render_template('startlist.html', teams=self.team_names) def web_team(self, team_nr): if team_nr not in self.teams: return redirect('/team/') return render_template('team.html', team=self.teams[team_nr], team_name=self.team_names[team_nr], team_nr=team_nr) @staticmethod def get_data(element, selector, ns): data = element.find(selector, ns) if data is not None: return data.text else: return None def on_key_press(self, event: Event): print('Key symbol: ' + str(event.keysym)) if event.keysym == 'space' or event.keysym == 'p': self.team += 1 self.add_prewarning(strftime('%H:%M:%S'), (self.team, 1)) self.sound_queue.put('sounds/' + self.default_language + '/' + str(self.team) + '.mp3') if event.keysym == 't': self.sound_queue.put(self.test_sound) if event.keysym == 'i': self.notify_ip() elif event.keysym == 'c': self.clear() elif event.keysym == 'q': exit() elif event.keysym == 'plus' or event.keysym == 'KP_Add': self.font_size += 1 print('Font size: ' + str(self.font_size)) self.update_size() elif event.keysym == 'minus' or event.keysym == 'KP_Subtract': self.font_size -= 1 print('Font size: ' + str(self.font_size)) self.update_size() elif event.keysym == '0' or event.keysym == 'KP_0': self.font_size = self.default_font_size print('Font size: ' + str(self.font_size)) self.update_size()
class App(Tk): DEFAULT_SIGN_WIDTH = 150.0 DEFAULT_SIGN_HEIGHT = 22.0 DEFAULT_SHEET_WIDHT = 300.0 DEFAULT_SHEET_HEIGHT = 300.0 DEFAULT_SHEETS_PER_FILE = 0 MAX_SHEET_WIDTH = 470 MAX_SHEET_HEIGHT = 310 MAX_SHEETS_PER_FILE = 100 SPINBOX_WIDTH = 8 PADDING = 2 DXF_VERSIONS = ('R2000', 'R2004', 'R2007', 'R2010', 'R2013', 'R2018') # Initialize GUI layout. def __init__(self) -> None: super().__init__() self.title('KylttiMaker') self.minsize(640, 480) # Tree widget that displays fields and their relative marks in a hierarchy. self.tree = Treeview(self, selectmode='browse') self.tree.heading('#0', text='Fields', command=self.remove_selection) self.tree.bind('<Button-3>', self.tree_right_click) self.tree.bind('<<TreeviewSelect>>', self.tree_selection_changed) self.tree.bind('<Double-Button-1>', self.rename) self.bind('<Escape>', self.remove_selection) self.bind('<Delete>', self.remove) self.tree.pack(side=LEFT, fill=BOTH) self.properties = LabelFrame(self, text='Properties') self.properties.pack(side=RIGHT, fill=BOTH, expand=1) self.fields = {} self.selected_iid = None # Entry field that get's temporarily shown to the user whilst renaming a field or a mark. self.new_name = StringVar(self.tree) self.new_name_entry = Entry(self.tree, textvariable=self.new_name) self.new_name_entry.bind('<Key-Return>', self.new_name_entered) # Output options that get's shown to the user when nothing else is selected from the hierarchy. self.frame = Frame(self.properties) Label(self.frame, text='Sheet size').grid(column=0, row=0, sticky='E', pady=App.PADDING) self.sheet_width_var = StringVar(self.frame) self.sheet_width_var.set(App.DEFAULT_SHEET_WIDHT) Spinbox(self.frame, to=App.MAX_SHEET_WIDTH, textvariable=self.sheet_width_var, width=App.SPINBOX_WIDTH).grid(column=1, row=0, sticky='WE') Label(self.frame, text='x').grid(column=2, row=0) self.sheet_height_var = StringVar(self.frame) self.sheet_height_var.set(App.DEFAULT_SHEET_HEIGHT) Spinbox(self.frame, to=App.MAX_SHEET_HEIGHT, textvariable=self.sheet_height_var, width=App.SPINBOX_WIDTH).grid(column=3, row=0, sticky='WE') Label(self.frame, text='Sign size').grid(column=0, row=1, sticky='E', pady=App.PADDING) self.sign_width_var = StringVar(self.frame) self.sign_width_var.set(App.DEFAULT_SIGN_WIDTH) Spinbox(self.frame, to=App.MAX_SHEET_WIDTH, textvariable=self.sign_width_var, width=App.SPINBOX_WIDTH).grid(column=1, row=1, sticky='WE') Label(self.frame, text='x').grid(column=2, row=1) self.sign_height_var = StringVar(self.frame) self.sign_height_var.set(App.DEFAULT_SIGN_HEIGHT) Spinbox(self.frame, to=App.MAX_SHEET_HEIGHT, textvariable=self.sign_height_var, width=App.SPINBOX_WIDTH).grid(column=3, row=1, sticky='WE') Label(self.frame, text='Layers per sheet').grid(column=0, row=2, sticky='W', pady=App.PADDING) self.layers_per_sheet_var = StringVar(self.frame) self.layers_per_sheet_var.set(App.DEFAULT_SHEETS_PER_FILE) Spinbox(self.frame, to=App.MAX_SHEETS_PER_FILE, textvariable=self.layers_per_sheet_var, width=App.SPINBOX_WIDTH).grid(column=1, row=2, sticky='WE') Label(self.frame, text='(0 = No limit)').grid(column=2, row=2, columnspan=2, sticky='W') Label(self.frame, text='DXF version').grid(column=0, row=4, sticky='E', pady=App.PADDING) self.dxf_version = StringVar(self.frame) OptionMenu(self.frame, self.dxf_version, App.DXF_VERSIONS[0], *App.DXF_VERSIONS).grid(column=1, row=4, sticky='W') Button(self.frame, text='Create', command=self.create).grid(column=2, row=4, columnspan=2) self.frame.pack() # Display a popup menu with relevant options when right clicking on the tree widget item. def tree_right_click(self, event: Event) -> None: menu = Menu(self, tearoff=0) iid = self.tree.identify_row(event.y) if iid: if iid in self.fields: menu.add_command(label='Add QR', command=lambda: self.add_mark(QR, iid)) menu.add_command(label='Add Text', command=lambda: self.add_mark(Text, iid)) menu.add_command(label='Add Hole', command=lambda: self.add_mark(Hole, iid)) menu.add_command(label='Rename', command=lambda: self.rename(iid=iid)) menu.add_command(label='Remove', command=lambda: self.remove(iid=iid)) else: menu.add_command(label='Add field', command=self.add_field) menu.tk_popup(event.x_root, event.y_root) # Display the properties of the selected item. def tree_selection_changed(self, event: Event) -> None: # Hide the items previously shown in the properties pane. self.new_name_entry.place_forget() for child in self.properties.winfo_children(): child.pack_forget() selected_items = self.tree.selection() if selected_items: self.selected_iid = selected_items[0] # Check if the selected item is a field or a mark object, in which case show its properties. if self.selected_iid in self.fields: self.fields[self.selected_iid].frame.pack() else: for field_iid in self.fields: if self.selected_iid in self.fields[field_iid].marks: self.fields[field_iid].marks[ self.selected_iid].frame.pack() else: # Clear the properties pane. self.selected_iid = None self.frame.pack() # Create a new field object and add a corresponding node to the hierarchy. def add_field(self) -> None: iid = self.tree.insert('', END, text='Field') self.fields[iid] = Field(self.properties) # Display a entry for the user to input a new name for the item to be renamed. def rename(self, event: Event = None, iid: int = None) -> None: if not iid: if self.selected_iid: iid = self.selected_iid else: return self.editing_iid = iid self.new_name.set(self.tree.item(iid)['text']) self.new_name_entry.place(x=20, y=0) self.new_name_entry.focus_set() self.new_name_entry.select_range(0, END) # Display the renamed item in the hierarchy. def new_name_entered(self, event: Event) -> None: self.tree.item(self.editing_iid, text=self.new_name.get()) self.new_name_entry.place_forget() # Link a new mark speciefied by mark_type parameter to the field speciefied by field_iid parameter. def add_mark(self, mark_type: Union[QR, Text, Hole], field_iid: int = None) -> None: if not field_iid: if self.selected_iid in self.fields: field_iid = self.selected_iid else: print('Select a field first.') return iid = self.tree.insert(field_iid, END, text=mark_type.__name__) self.fields[field_iid].marks[iid] = mark_type(self.properties) self.tree.see(iid) # Remove a tree item speciefied by iid parameter, else removes the currently selected item. def remove(self, event: Event = None, iid: int = None) -> None: if not iid: if self.selected_iid: iid = self.selected_iid else: print('Select something first.') return # Check if the item to be removed is a field item, else check if it is a mark item. if iid in self.fields: self.remove_selection() self.tree.delete(iid) del self.fields[iid] else: for field_iid in self.fields: if iid in self.fields[field_iid].marks: self.remove_selection() self.tree.delete(iid) del self.fields[field_iid].marks[iid] # Clear the selection. def remove_selection(self, event: Event = None) -> None: for item in self.tree.selection(): self.tree.selection_remove(item) # Create sheets according to entered settings. def create(self) -> None: if not self.fields: print('No fields.') return # Calculate the length of the longest field (some fields can have less values than others). total_signs = 0 for field_iid in self.fields: total_signs = max(total_signs, len(self.fields[field_iid].data)) if total_signs == 0: print('No fields with data.') return try: sheet_width = float(self.sheet_width_var.get()) sheet_height = float(self.sheet_height_var.get()) sign_width = float(self.sign_width_var.get()) sign_height = float(self.sign_height_var.get()) layers_per_sheet = int(self.layers_per_sheet_var.get()) assert sign_width > 0, 'Sign width must be greater than 0.' assert sign_height > 0, 'Sign height must be greater than 0.' assert sheet_width >= sign_width, 'Sheet width must be greater than sign width.' assert sheet_height >= sign_height, 'Sheet height must be greater than sign height.' except ValueError: print('Invalid dimensions.') return except AssertionError as e: print(e) return # Show progress bar. progress_bar = Progressbar(self.frame) progress_bar.grid(column=0, row=5, columnspan=4, sticky='WE') # Calculate the needed values to define sheet layout. signs_per_row = int(sheet_width // sign_width) signs_per_column = int(sheet_height // sign_height) signs_per_layer = signs_per_row * signs_per_column # Ceiling division. total_layers = -int(-total_signs // signs_per_layer) if layers_per_sheet > 0: total_sheets = -int(-total_layers // layers_per_sheet) else: total_sheets = 1 print( f'Marking total of {total_signs} signs ({sign_width} x {sign_height}).' ) print( f'Sheet size of {sheet_width} x {sheet_height} fits {signs_per_row} x {signs_per_column} signs,' ) print( f'so the effective sheet size is {signs_per_row * sign_width} x {signs_per_column * sign_height}.' ) print(f'Total of {total_layers} layer(s) are needed.') if layers_per_sheet == 0: print( 'There is no limit on the maximum amount of layers per sheet,') else: print( f'There are maximum of {layers_per_sheet} layer(s) per sheet,') print(f'so total of {total_sheets} sheet(s) are needed.') # Create needed sheet objects. print('Creating sheets.') sheets = [] for _ in range(total_sheets): sheets.append(ezdxf.new(self.dxf_version.get())) # Iterate over all layers and draw their outline based on how many signs that layer will have. print('Drawing layer outlines.') for layer in range(total_layers): max_x = sign_width * signs_per_row max_y = -sign_height * signs_per_column if layer == total_layers - 1: # If last layer. signs_in_last_sheet = total_signs - layer * signs_per_layer if signs_in_last_sheet < signs_per_row: max_x = sign_width * signs_in_last_sheet max_y = sign_height * (-signs_in_last_sheet // signs_per_row) if layers_per_sheet > 0: sheet_index = layer // layers_per_sheet else: sheet_index = 0 # Draw layer outline (left and top side bounds). sheets[sheet_index].modelspace().add_lwpolyline( [(0, max_y), (0, 0), (max_x, 0)], dxfattribs={'layer': str(layer)}) # Iterate over each sign. print('Drawing marks.') for sign_index in range(total_signs): # Update progress bar value. progress_bar['value'] = (sign_index + 1) / total_signs * 100 progress_bar.update() # Calculate in which position, in which layer of which sheet the current sign should be drawn. layer = sign_index // signs_per_layer layer_position = sign_index % signs_per_layer sign_origin_x = (layer_position % signs_per_row) * sign_width sign_origin_y = -(layer_position // signs_per_row) * sign_height if layers_per_sheet > 0: sheet_index = layer // layers_per_sheet else: sheet_index = 0 sheet = sheets[sheet_index] # Draw marks (QR, Text and Hole objects). for field_iid in self.fields: try: self.fields[field_iid].draw(sign_index, sheet, layer, sign_origin_x, sign_origin_y, sign_width, sign_height) except Exception as e: print(e) progress_bar.grid_forget() return # Draw sign outline (right and bottom side bounds). sign_outline = [(sign_origin_x, sign_origin_y - sign_height), (sign_origin_x + sign_width, sign_origin_y - sign_height), (sign_origin_x + sign_width, sign_origin_y)] sheet.modelspace().add_lwpolyline(sign_outline, dxfattribs={'layer': str(layer)}) # Save sheets. # Get a output directory if there are multiple sheets to be saved, otherwise get path for the single output (.dxf) file. print('Saving.') if total_sheets > 1: if directory := tkinter.filedialog.askdirectory(): for index, sheet in enumerate(sheets): # Indicate save progress. progress_bar['value'] = (index + 1) / len(sheets) * 100 progress_bar.update() sheet.saveas(Path(directory) / f'sheet{index}.dxf') elif path := tkinter.filedialog.asksaveasfilename( defaultextension='.dxf', filetypes=(('DXF', '*.dxf'), ('All files', '*.*'))): sheets[0].saveas(path)
class YoutubeClient(Frame): def __init__(self, dark_theme=False, master=None): super().__init__(master) self.pack(fill=FILLBOTH, expand=1) if dark_theme: Style().configure(".", background="#111111", foreground="white") Style().configure("Treeview", background="#222222", fieldbackground="#222222", foreground="orange") Style().map("Treeview.Heading", background=[('active', '#111111')], foreground=[('active', 'orange')]) Style().configure("Treeview.Heading", font=("TkDefaultFont", 18)) Style().map("TButton", background=[('pressed', '#555555')], foreground=[('active', "orange")]) Style().configure("TButton", font=("TkDefaultFont", 18)) Style().configure("TLabel", font=("TkDefaultFont", 18)) # results tree self.results = Treeview(self) self.results["columns"] = ("video") self.results.column("#0", width=175, stretch=False) self.results.heading("#0", text="channel") self.results.column("video") self.results.heading("video", text="video") self.results.bind("<Double-Button-1>", self.clipboard) self.results.pack(side="top", fill=FILLBOTH, expand=1) # I/O row self.button_bar = Frame(self) self.button_bar.pack(side="top", fill=FILLX) self.progressLabel = Label(self.button_bar, text="progress") self.progressLabel.pack(side="left") self.progress = Progressbar(self.button_bar, orient="horizontal", length=200, mode="determinate") self.progress.pack(side="left") self.update = Button(self.button_bar, text="Update", command=self.update_vids) self.update.pack(side="right") self.show_today = Button(self.button_bar, text="show todays vids", command=self.show_todays_vids) self.show_today.pack(side="right") ######################### ## callback functions ## ######################### def update_vids(self): self.clear_results() t = threading.Thread(target=self.get_recent_videos) t.daemon = True t.start() def show_todays_vids(self): self.clear_results() for a in get_today_videos(): channel = a.split()[0] title = " ".join(a.split()[1:]) self.add_video(channel, title) def clipboard(self, event): index = self.results.focus() if index and "values" in self.results.item(index) and len( self.results.item(index)["values"]): video_title = self.results.item(index)["values"][0] self.clipboard_clear() self.clipboard_append(video_title) ########################## ### utility functions ### ########################## def clear_results(self): if self.results.get_children(): for a in self.results.get_children(): self.results.delete(a) def add_video(self, channel, video_title): # since tkinter can't display unicode over 0xFFFF, they are removed # before being displayed on tkinter channel = clean_unicode(channel) video_title = clean_unicode(video_title) channel_tree = [b for b in self.results.get_children() if b == channel] if channel_tree: video_leaf = self.results.insert(channel_tree[0], 0, values=(video_title, )) self.results.see(video_leaf) else: channel_tree_branch = self.results.insert("", 0, channel, text=channel) video_leaf = self.results.insert(channel_tree_branch, 0, values=(video_title, )) self.results.see(video_leaf) def clear_box(self): for i in range(self.results.size()): self.results.delete(0) def get_recent_videos(self): history_file = expanduser(pjoin("~", ".config", "ytsub", "history.txt")) url_file = expanduser(pjoin("~", ".config", "ytsub", "channels.txt")) TODAY = datetime.date.today().strftime("%m/%d/%y") with open(history_file) as f: old_videos = [a.split()[0].strip() for a in f] with open(url_file) as f: channels = [a.split() for a in f] self.progress["maximum"] = len(channels) for i, channel in enumerate(channels): channel_url, channel_title = channel self.progressLabel["text"] = "{0} / {1}".format( i + 1, len(channels)) time.sleep(3) for video in get_videos(channel_url): video_link, video_title = video if video_link not in old_videos: self.add_video(channel_title, video_title) with open(history_file, "a") as f: struct = [ video_link, TODAY, channel_title, video_title ] f.write(" ".join(struct) + "\n") # after values are added, increment the progress bar. self.progress["value"] = i + 1
class NameView(object): """Shows a treeview of unique names.""" def __init__(self, master, names): self.widget = Frame(master) self._tree = Treeview(self.widget, columns='name') self._tree.grid(row=0,column=0, sticky=(N,S,W,E)) self._tree.view = self self.widget.columnconfigure(0, weight=1) self.widget.rowconfigure(0,weight=1) self._tree.column('name', width=50) self._tree['show'] = 'tree' actions = {'edit': lambda e: self.edit(), 'search': lambda e: self.search(), 'focus_next': lambda e: self.focus_next(), 'focus_prev': lambda e: self.focus_prev(), 'select': lambda e: self._tree.selection_toggle(self._tree.focus()), 'clear_selection': lambda e: self._tree.selection_set([]) } kb.make_bindings(kb.tagview, actions, self._tree.bind) self._iids = dict() self._names = dict() logger.debug('Names: %s', names) self.widget.focus_set = self._tree.focus_set for name in sorted(names): iid = self._tree.insert('', 'end', text=name) self._names[iid] = name self._iids[name] = iid self._scroll = Scrollbar(self.widget, command=self._tree.yview) self._tree['yscrollcommand'] = self._scroll.set self._scroll.grid(row=0, column=1, sticky=(N, S)) self.widget.columnconfigure(1, weight=0) def selection(self): logger.debug('Selection: %s', self._tree.selection()) return [self._names[iid] for iid in self._tree.selection()] def edit(self): self._tree.event_generate('<<NameViewEdit>>') def search(self): if len(self._tree.selection()) == 0: self._tree.selection_add(self._tree.focus()) self._tree.event_generate('<<NameViewSearch>>') def append(self, names): logger.debug('Append names: %s', names) for name in names: if name not in self._names.values(): iid = self._tree.insert('', 'end', text=name) self._names[iid] = name self._iids[name] = iid def delete(self, name): self._tree.delete(self._iids[name]) del self._names[self._iids[name]] del self._iids[name] def _focus(self, iid): self._tree.focus(iid) self._tree.see(iid) def focus_next(self): cur_iid = self._tree.focus() next_iid = self._tree.next(cur_iid) if next_iid == '': iids = self._tree.get_children() next_iid = iids[0] self._focus(next_iid) def focus_prev(self): cur_iid = self._tree.focus() prev_iid = self._tree.prev(cur_iid) if prev_iid == '': iids = self._tree.get_children() prev_iid = iids[-1] self._focus(prev_iid) def jump_to(self, name): try: iid = self._iids[name] self._focus(iid) except KeyError: pass def get_names(self): return tuple(self._names.values()) def set(self, names): self._tree.delete(*self._iids.values()) self._iids.clear() self._names.clear() for name in sorted(names): iid = self._tree.insert('', 'end', text=name) self._names[iid] = name self._iids[name] = iid