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): parent = mainWin.parent super().__init__(parent) self.parent = parent 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) self.title(title) 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() # set up treeView widget and tabbed pane self.treeView.column("#0", width=500, anchor="w") self.treeView.heading("#0", text=colHeader) try: self.isRss = 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 mainWin.showStatus(_("loading archive {0}").format(filesource.url)) self.filesource = filesource self.filenames = filenames selection = filesource.selection hasToolTip = False loadedPaths = [] i = 0 selectedNode = None for filename in self.filenames: if isinstance(filename,tuple): if self.isRss: form, date, instDoc = filename[2:5] filename = filename[0] # ignore tooltip 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 selection == filename: selectedNode = node loadedPaths.append(path) i += 1 if selectedNode: self.treeView.see(selectedNode) self.treeView.selection_set(selectedNode) 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) 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 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 ok(self, event=None): selection = self.treeView.selection() if len(selection) > 0: 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() def close(self, event=None): self.parent.focus_set() self.destroy() def leave(self, *args): self.toolTipRowId = None def motion(self, *args): tvRowId = self.treeView.identify_row(args[0].y) if tvRowId != self.toolTipRowId: self.toolTipRowId = tvRowId newFileIndex = -1 if tvRowId and len(tvRowId) > 4: try: newFileIndex = int(tvRowId[4:]) except ValueError: pass self.setToolTip(newFileIndex) def setToolTip(self, fileIndex): self.toolTip._hide() if fileIndex >= 0 and fileIndex < len(self.filenames): filenameItem = self.filenames[fileIndex] if isinstance(filenameItem, tuple): self.toolTipText.set(filenameItem[1].replace("\\n","\n")) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled") else: self.toolTipText.set("") self.toolTip.configure(state="disabled")
class ViewTree: def __init__(self, modelXbrl, tabWin, tabTitle, hasToolTip=False, lang=None): self.tabWin = tabWin self.viewFrame = Frame(tabWin) self.viewFrame.grid(row=0, column=0, sticky=(N, S, E, W)) tabWin.add(self.viewFrame,text=tabTitle) vScrollbar = Scrollbar(self.viewFrame, orient=VERTICAL) hScrollbar = Scrollbar(self.viewFrame, orient=HORIZONTAL) self.treeView = Treeview(self.viewFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set) self.treeView.grid(row=0, column=0, sticky=(N, S, E, W)) self.treeView.tag_configure("ELR", background="#E0F0FF") self.treeView.tag_configure("even", background="#F0F0F0") self.treeView.tag_configure("odd", background="#FFFFFF") highlightColor = "#%04x%04x%04x" % self.treeView.winfo_rgb("SystemHighlight") self.treeView.tag_configure("selected-ELR", background=highlightColor) self.treeView.tag_configure("selected-even", background=highlightColor) self.treeView.tag_configure("selected-odd", background=highlightColor) self.treeViewSelection = () self.treeView.bind("<<TreeviewSelect>>", self.treeViewSelectionChange, '+') 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)) self.viewFrame.columnconfigure(0, weight=1) self.viewFrame.rowconfigure(0, weight=1) self.modelXbrl = modelXbrl self.hasToolTip = hasToolTip self.toolTipText = StringVar() if 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=480, follow_mouse=True, state="disabled") self.toolTipColId = None self.toolTipRowId = None self.modelXbrl = modelXbrl self.lang = lang self.labelrole = None if modelXbrl: modelXbrl.views.append(self) if not lang: self.lang = modelXbrl.modelManager.defaultLang def treeViewSelectionChange(self, event=None): for node in self.treeViewSelection: priorTags = self.treeView.item(node)["tags"] if priorTags: priorBgTag = priorTags[0] if priorBgTag.startswith("selected-"): self.treeView.item(node, tags=(priorBgTag[9:],)) self.treeViewSelection = self.treeView.selection() for node in self.treeViewSelection: priorTags = self.treeView.item(node)["tags"] if priorTags: self.treeView.item(node, tags=("selected-" + priorTags[0],)) def close(self): if self.modelXbrl: self.tabWin.forget(self.viewFrame) self.modelXbrl.views.remove(self) self.modelXbrl = None def leave(self, *args): self.toolTipColId = None self.toolTipRowId = None def motion(self, *args): tvColId = self.treeView.identify_column(args[0].x) tvRowId = self.treeView.identify_row(args[0].y) if tvColId != self.toolTipColId or tvRowId != self.toolTipRowId: self.toolTipColId = tvColId self.toolTipRowId = tvRowId newValue = None if tvRowId and len(tvRowId) > 0: try: col = int(tvColId[1:]) if col == 0: newValue = self.treeView.item(tvRowId,"text") else: values = self.treeView.item(tvRowId,"values") if col <= len(values): newValue = values[col - 1] except ValueError: pass self.setToolTip(newValue, tvColId) def setToolTip(self, text, colId="#0"): self.toolTip._hide() if isinstance(text,str) and len(text) > 0: width = self.treeView.column(colId,"width") if len(text) * 8 > width or '\n' in text: self.toolTipText.set(text) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled") else: self.toolTipText.set("") self.toolTip.configure(state="disabled") def contextMenu(self): try: return self.menu except AttributeError: self.menu = Menu( self.viewFrame, tearoff = 0 ) self.treeView.bind( self.modelXbrl.modelManager.cntlr.contextMenuClick, self.popUpMenu, '+' ) return self.menu def popUpMenu(self, event): self.menuRow = self.treeView.identify_row(event.y) self.menuCol = self.treeView.identify_column(event.x) self.menu.post( event.x_root, event.y_root ) def expand(self): self.setTreeItemOpen(self.menuRow,open=True) def expandAll(self): self.setTreeItemOpen("",open=True) def collapse(self): self.setTreeItemOpen(self.menuRow,open=False) def collapseAll(self): self.setTreeItemOpen("",open=False) def setTreeItemOpen(self, node, open=True): if node: self.treeView.item(node, open=open) for childNode in self.treeView.get_children(node): self.setTreeItemOpen(childNode, open) def menuAddExpandCollapse(self): self.menu.add_cascade(label=_("Expand"), underline=0, command=self.expand) self.menu.add_cascade(label=_("Collapse"), underline=0, command=self.collapse) self.menu.add_cascade(label=_("Expand All"), underline=0, command=self.expandAll) self.menu.add_cascade(label=_("Collapse All"), underline=0, command=self.collapseAll) def menuAddClipboard(self): if self.modelXbrl.modelManager.cntlr.hasClipboard: clipboardMenu = Menu(self.viewFrame, tearoff=0) clipboardMenu.add_cascade(label=_("Cell"), underline=0, command=self.copyCellToClipboard) clipboardMenu.add_cascade(label=_("Row"), underline=0, command=self.copyRowToClipboard) clipboardMenu.add_cascade(label=_("Table"), underline=0, command=self.copyTableToClipboard) self.menu.add_cascade(label=_("Copy to clipboard"), menu=clipboardMenu, underline=0) def menuAddLangs(self): langsMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=_("Language"), menu=langsMenu, underline=0) for lang in sorted(self.modelXbrl.langs): langsMenu.add_cascade(label=lang, underline=0, command=lambda l=lang: self.setLang(l)) def menuAddLabelRoles(self, includeConceptName=False, menulabel=None): if menulabel is None: menulabel = _("Label Role") rolesMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=menulabel, menu=rolesMenu, underline=0) from arelle.ModelRelationshipSet import labelroles for x in labelroles(self.modelXbrl, includeConceptName): rolesMenu.add_cascade(label=x[0][1:], underline=0, command=lambda a=x[1]: self.setLabelrole(a)) def menuAddUnitDisplay(self): rolesMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=_("Units"), menu=rolesMenu, underline=0) rolesMenu.add_cascade(label=_("Unit ID"), underline=0, command=lambda: self.setUnitDisplay(unitDisplayID=True)) rolesMenu.add_cascade(label=_("Measures"), underline=0, command=lambda: self.setUnitDisplay(unitDisplayID=False)) def menuAddViews(self): viewMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=_("View"), menu=viewMenu, underline=0) newViewsMenu = Menu(self.viewFrame, tearoff=0) viewMenu.add_cascade(label=_("Close"), underline=0, command=self.close) viewMenu.add_cascade(label=_("Additional view"), menu=newViewsMenu, underline=0) from arelle.ModelRelationshipSet import baseSetArcroles for x in baseSetArcroles(self.modelXbrl): newViewsMenu.add_cascade(label=x[0][1:], underline=0, command=lambda a=x[1]: self.newView(a)) def newView(self, arcrole): from arelle import ViewWinRelationshipSet ViewWinRelationshipSet.viewRelationshipSet(self.modelXbrl, self.tabWin, arcrole, lang=self.lang) def setLang(self, lang): self.lang = lang self.view() def setLabelrole(self, labelrole): self.labelrole = labelrole self.view() def setUnitDisplay(self, unitDisplayID=False): self.unitDisplayID = unitDisplayID self.view() def setColumnsSortable(self, treeColIsInt=False, startUnsorted=False, initialSortCol="#0", initialSortDirForward=True): self.lastSortColumn = None if startUnsorted else initialSortCol self.lastSortColumnForward = initialSortDirForward self.treeColIsInt = treeColIsInt if not hasattr(self, "sortImages"): self.sortImages = (PhotoImage(file=os.path.join(self.modelXbrl.modelManager.cntlr.imagesDir, "columnSortUp.gif")), PhotoImage(file=os.path.join(self.modelXbrl.modelManager.cntlr.imagesDir, "columnSortDown.gif")), PhotoImage()) for col in ("#0",) + self.treeView["columns"]: self.treeView.heading(col, command=lambda c=col: self.sortColumn(c)) if not startUnsorted: self.treeView.heading(initialSortCol, image=self.sortImages[not initialSortDirForward]) def colSortVal(self, node, col): if col == "#0": treeColVal = self.treeView.item(node)["text"] if self.treeColIsInt: return int(treeColVal) else: treeColVal = self.treeView.set(node, col) if col == "sequence": try: return int(treeColVal) except: return 0 return treeColVal def sortNestedRows(self, parentNode, col, reverse): l = [(self.colSortVal(node, col), node) for node in self.treeView.get_children(parentNode)] l.sort(reverse=reverse) # rearrange items in sorted positions for i, (cell, node) in enumerate(l): self.treeView.move(node, parentNode, i) # reset even/odd tags for i, node in enumerate(self.treeView.get_children(parentNode)): self.treeView.item(node, tags=('even' if i & 1 else 'odd',)) self.sortNestedRows(node, col, reverse) def sortColumn(self, col): if col == self.lastSortColumn: reverse = self.lastSortColumnForward self.lastSortColumnForward = not reverse else: if self.lastSortColumn: self.treeView.heading(self.lastSortColumn, image=self.sortImages[2]) reverse = False self.lastSortColumnForward = True self.lastSortColumn = col self.treeView.heading(col, image=self.sortImages[reverse]) self.sortNestedRows('', col, reverse) self.treeViewSelectionChange() # reselect selected rows def copyCellToClipboard(self, *ignore): self.modelXbrl.modelManager.cntlr.clipboardData( text=self.treeView.item(self.menuRow)['text'] if self.menuCol == '#0' else self.treeView.set(self.menuRow,self.menuCol)) def copyRowToClipboard(self, *ignore): self.modelXbrl.modelManager.cntlr.clipboardData( text='\t'.join([self.treeView.item(self.menuRow)['text']] + [self.treeView.set(self.menuRow,c) for c in self.treeView['columns']])) def copyTableToClipboard(self, *ignore): cols = self.treeView['columns'] lines = ['\t'.join([self.treeView.heading('#0')['text']] + [self.treeView.heading(h)['text'] for h in cols])] self.tabLines('', '', cols, lines) self.modelXbrl.modelManager.cntlr.clipboardData(text='\n'.join(lines)) def tabLines(self, parentNode, indent, cols, lines): for node in self.treeView.get_children(parentNode): lines.append('\t'.join([indent + self.treeView.item(node)['text']] + [self.treeView.set(node,c) for c in cols])) self.tabLines(node, indent+' ', cols, lines)
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 ViewList(): def __init__(self, modelXbrl, tabWin, tabTitle, hasToolTip=False): self.tabWin = tabWin self.viewFrame = Frame(tabWin) self.viewFrame.grid(row=0, column=0, sticky=(N, S, E, W)) tabWin.add(self.viewFrame,text=tabTitle) xmlScrollbar = Scrollbar(self.viewFrame, orient=VERTICAL) self.listBox = Listbox(self.viewFrame, yscrollcommand=xmlScrollbar.set) self.listBox.grid(row=0, column=0, sticky=(N, S, E, W)) #self.listBox.focus_set() self.listBox.bind("<Motion>", self.listBoxMotion, '+') self.listBox.bind("<Leave>", self.listBoxLeave, '+') xmlScrollbar["command"] = self.listBox.yview xmlScrollbar.grid(row=0, column=1, sticky=(N,S)) self.viewFrame.columnconfigure(0, weight=1) self.viewFrame.rowconfigure(0, weight=1) self.listBoxToolTipText = StringVar() if hasToolTip: self.listBoxToolTip = ToolTip(self.listBox, textvariable=self.listBoxToolTipText, wraplength=480, follow_mouse=True, state="disabled") self.listBoxRow = -9999999 self.modelXbrl = modelXbrl if modelXbrl: modelXbrl.views.append(self) def close(self): self.tabWin.forget(self.viewFrame) self.modelXbrl.views.remove(self) self.modelXbrl = None def select(self): self.tabWin.select(self.viewFrame) def append(self, line): self.listBox.insert(END, line) def clear(self): self.listBox.delete(0,END) def listBoxLeave(self, *args): self.listBoxRow = -9999999 def lines(self): return self.listBox.get(0,END) def lineText(self, lineNumber): return self.listBox.get(lineNumber) def selectLine(self, lineNumber): self.listBox.selection_clear(0,END) self.listBox.selection_set(lineNumber) def saveToFile(self, filename): with open(filename, "w") as fh: fh.writelines([logEntry + '\n' for logEntry in self.listBox.get(0,END)]) def copyToClipboard(self, cntlr=None, *ignore): if cntlr is None: cntlr = self.modelXbrl.modelManager.cntlr cntlr.clipboardData(text='\n'.join(self.listBox.get(0,END))) def listBoxMotion(self, *args): lbRow = self.listBox.nearest(args[0].y) if lbRow != self.listBoxRow: self.listBoxRow = lbRow text = self.listBox.get(lbRow) self.listBoxToolTip._hide() if text and len(text) > 0: if len(text) * 8 > 200: self.listBoxToolTipText.set(text) self.listBoxToolTip.configure(state="normal") self.listBoxToolTip._schedule() else: self.listBoxToolTipText.set("") self.listBoxToolTip.configure(state="disabled") else: self.listBoxToolTipText.set("") self.listBoxToolTip.configure(state="disabled") def contextMenu(self,contextMenuClick=None): try: return self.menu except AttributeError: if contextMenuClick is None: contextMenuClick = self.modelXbrl.modelManager.cntlr.contextMenuClick self.menu = Menu( self.viewFrame, tearoff = 0 ) self.listBox.bind( contextMenuClick, self.popUpMenu ) return self.menu def popUpMenu(self, event): self.menu.post( event.x_root, event.y_root ) def menuAddSaveClipboard(self): self.menu.add_command(label=_("Save to file"), underline=0, command=self.modelXbrl.modelManager.cntlr.fileSave) if self.modelXbrl.modelManager.cntlr.hasClipboard: self.menu.add_command(label=_("Copy to clipboard"), underline=0, command=self.copyToClipboard)
class ViewTree: def __init__(self, modelXbrl, tabWin, tabTitle, hasToolTip=False, lang=None): self.tabWin = tabWin self.viewFrame = Frame(tabWin) self.viewFrame.view = self self.viewFrame.grid(row=0, column=0, sticky=(N, S, E, W)) tabWin.add(self.viewFrame, text=tabTitle) self.tabTitle = tabTitle # for error messages vScrollbar = Scrollbar(self.viewFrame, orient=VERTICAL) hScrollbar = Scrollbar(self.viewFrame, orient=HORIZONTAL) self.treeView = Treeview(self.viewFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set) self.treeView.grid(row=0, column=0, sticky=(N, S, E, W)) self.treeView.tag_configure("ELR", background="#E0F0FF") self.treeView.tag_configure("even", background="#F0F0F0") self.treeView.tag_configure("odd", background="#FFFFFF") if modelXbrl.modelManager.cntlr.isMac or modelXbrl.modelManager.cntlr.isMSW: highlightColor = "#%04x%04x%04x" % self.treeView.winfo_rgb( "SystemHighlight") else: highlightColor = "#33339999ffff" # using MSW value for Unix/Linux which has no named colors self.treeView.tag_configure("selected-ELR", background=highlightColor) self.treeView.tag_configure("selected-even", background=highlightColor) self.treeView.tag_configure("selected-odd", background=highlightColor) self.treeViewSelection = () self.treeView.bind("<<TreeviewSelect>>", self.viewSelectionChange, '+') self.treeView.bind("<1>", self.onViewClick, '+') 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)) self.viewFrame.columnconfigure(0, weight=1) self.viewFrame.rowconfigure(0, weight=1) self.modelXbrl = modelXbrl self.hasToolTip = hasToolTip self.toolTipText = StringVar() if 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=480, follow_mouse=True, state="disabled") self.toolTipColId = None self.toolTipRowId = None self.modelXbrl = modelXbrl self.lang = lang self.labelrole = None self.nameIsPrefixed = False if modelXbrl: modelXbrl.views.append(self) if not lang: self.lang = modelXbrl.modelManager.defaultLang def clearTreeView(self): self.treeViewSelection = () for node in self.treeView.get_children(): self.treeView.delete(node) def viewSelectionChange(self, event=None): for node in self.treeViewSelection: if self.treeView.exists(node): priorTags = self.treeView.item(node)["tags"] if priorTags: priorBgTag = priorTags[0] if priorBgTag.startswith("selected-"): self.treeView.item(node, tags=(priorBgTag[9:], )) self.treeViewSelection = self.treeView.selection() for node in self.treeViewSelection: priorTags = self.treeView.item(node)["tags"] if priorTags: self.treeView.item(node, tags=("selected-" + priorTags[0], )) def onViewClick(self, *args): self.modelXbrl.modelManager.cntlr.currentView = self def close(self): del self.viewFrame.view if self.modelXbrl: self.tabWin.forget(self.viewFrame) self.modelXbrl.views.remove(self) self.modelXbrl = None self.view = None def select(self): self.tabWin.select(self.viewFrame) def leave(self, *args): self.toolTipColId = None self.toolTipRowId = None def motion(self, *args): tvColId = self.treeView.identify_column(args[0].x) tvRowId = self.treeView.identify_row(args[0].y) if tvColId != self.toolTipColId or tvRowId != self.toolTipRowId: self.toolTipColId = tvColId self.toolTipRowId = tvRowId newValue = self.getToolTip(tvRowId, tvColId) if newValue is None and tvRowId and len(tvRowId) > 0: try: col = int(tvColId[1:]) if col == 0: newValue = self.treeView.item(tvRowId, "text") else: values = self.treeView.item(tvRowId, "values") if col <= len(values): newValue = values[col - 1] except ValueError: pass self.setToolTip(newValue, tvColId) def getToolTip(self, rowId, colId): return None def setToolTip(self, text, colId="#0"): self.toolTip._hide() if isinstance(text, str) and len(text) > 0: width = self.treeView.column(colId, "width") if len(text) * 8 > width or '\n' in text: self.toolTipText.set(text) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled") else: self.toolTipText.set("") self.toolTip.configure(state="disabled") def contextMenu(self): try: return self.menu except AttributeError: try: self.menu = Menu(self.viewFrame, tearoff=0) self.treeView.bind( self.modelXbrl.modelManager.cntlr.contextMenuClick, self.popUpMenu, '+') return self.menu except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info( "arelle:internalException", _("Exception creating context menu in %(title)s: %(error)s" ), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None return None def popUpMenu(self, event): if self.menu: self.menuRow = self.treeView.identify_row(event.y) self.menuCol = self.treeView.identify_column(event.x) self.menu.post(event.x_root, event.y_root) def expand(self): self.setTreeItemOpen(self.menuRow, open=True) def expandAll(self): self.setTreeItemOpen("", open=True) def collapse(self): self.setTreeItemOpen(self.menuRow, open=False) def collapseAll(self): self.setTreeItemOpen("", open=False) def setTreeItemOpen(self, node, open=True): if node: self.treeView.item(node, open=open) for childNode in self.treeView.get_children(node): self.setTreeItemOpen(childNode, open) def menuAddExpandCollapse(self): if self.menu: self.menu.add_command(label=_("Expand"), underline=0, command=self.expand) self.menu.add_command(label=_("Collapse"), underline=0, command=self.collapse) self.menu.add_command(label=_("Expand all"), underline=0, command=self.expandAll) self.menu.add_command(label=_("Collapse all"), underline=0, command=self.collapseAll) def menuAddClipboard(self): if self.menu and self.modelXbrl.modelManager.cntlr.hasClipboard: try: clipboardMenu = Menu(self.viewFrame, tearoff=0) clipboardMenu.add_command(label=_("Cell"), underline=0, command=self.copyCellToClipboard) clipboardMenu.add_command(label=_("Row"), underline=0, command=self.copyRowToClipboard) clipboardMenu.add_command(label=_("Table"), underline=0, command=self.copyTableToClipboard) self.menu.add_cascade(label=_("Copy to clipboard"), menu=clipboardMenu, underline=0) except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info( "arelle:internalException", _("Exception creating clipboard menu in %(title)s: %(error)s" ), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None def menuAddLangs(self): if self.menu: try: langsMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=_("Language"), menu=langsMenu, underline=0) for lang in sorted(self.modelXbrl.langs): langsMenu.add_command( label=lang, underline=0, command=lambda l=lang: self.setLang(l)) except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info( "arelle:internalException", _("Exception creating context languages menu in %(title)s: %(error)s" ), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None def menuAddLabelRoles(self, includeConceptName=False, menulabel=None): if self.menu: try: if menulabel is None: menulabel = _("Label role") rolesMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=menulabel, menu=rolesMenu, underline=0) from arelle.ModelRelationshipSet import labelroles for x in labelroles(self.modelXbrl, includeConceptName): rolesMenu.add_command( label=x[0][1:], underline=0, command=lambda a=x[1]: self.setLabelrole(a)) except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info( "arelle:internalException", _("Exception creating context label roles menu in %(title)s: %(error)s" ), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None def menuAddNameStyle(self, menulabel=None): if self.menu: try: if menulabel is None: menulabel = _("Name Style") nameStyleMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=menulabel, menu=nameStyleMenu, underline=0) from arelle.ModelRelationshipSet import labelroles nameStyleMenu.add_command( label=_("Prefixed"), underline=0, command=lambda a=True: self.setNamestyle(a)) nameStyleMenu.add_command( label=_("No prefix"), underline=0, command=lambda a=False: self.setNamestyle(a)) except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info( "arelle:internalException", _("Exception creating context name style menu in %(title)s: %(error)s" ), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None def menuAddUnitDisplay(self): if self.menu: try: rolesMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=_("Units"), menu=rolesMenu, underline=0) rolesMenu.add_command( label=_("Unit ID"), underline=0, command=lambda: self.setUnitDisplay(unitDisplayID=True)) rolesMenu.add_command( label=_("Measures"), underline=0, command=lambda: self.setUnitDisplay(unitDisplayID=False)) except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info( "arelle:internalException", _("Exception creating context unit menu in %(title)s: %(error)s" ), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None def menuAddViews(self, addClose=True, tabWin=None): if self.menu: try: if tabWin is None: tabWin = self.tabWin viewMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=_("View"), menu=viewMenu, underline=0) newViewsMenu = Menu(self.viewFrame, tearoff=0) if addClose: viewMenu.add_command(label=_("Close"), underline=0, command=self.close) viewMenu.add_cascade(label=_("Additional view"), menu=newViewsMenu, underline=0) newViewsMenu.add_command( label=_("Arcrole group..."), underline=0, command=lambda: self.newArcroleGroupView(tabWin)) from arelle.ModelRelationshipSet import baseSetArcroles for x in baseSetArcroles(self.modelXbrl) + [ (" Role Types", "!CustomRoleTypes!"), (" Arcrole Types", "!CustomArcroleTypes!") ]: newViewsMenu.add_command( label=x[0][1:], underline=0, command=lambda a=x[1]: self.newView(a, tabWin)) except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info( "arelle:internalException", _("Exception creating context add-views menu in %(title)s: %(error)s" ), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None def newView(self, arcrole, tabWin): if arcrole in ("!CustomRoleTypes!", "!CustomArcroleTypes!"): from arelle import ViewWinRoleTypes ViewWinRoleTypes.viewRoleTypes(self.modelXbrl, tabWin, arcrole == "!CustomArcroleTypes!", lang=self.lang) else: from arelle import ViewWinRelationshipSet ViewWinRelationshipSet.viewRelationshipSet(self.modelXbrl, tabWin, arcrole, lang=self.lang) def newArcroleGroupView(self, tabWin): from arelle.DialogArcroleGroup import getArcroleGroup from arelle import ViewWinRelationshipSet arcroleGroup = getArcroleGroup(self.modelXbrl.modelManager.cntlr, self.modelXbrl) if arcroleGroup: ViewWinRelationshipSet.viewRelationshipSet(self.modelXbrl, tabWin, arcroleGroup, lang=self.lang) def setLang(self, lang): self.lang = lang self.view() def setLabelrole(self, labelrole): self.labelrole = labelrole self.view() def setNamestyle(self, isPrefixed): self.nameIsPrefixed = isPrefixed self.view() def setUnitDisplay(self, unitDisplayID=False): self.unitDisplayID = unitDisplayID self.view() def setColumnsSortable(self, treeColIsInt=False, startUnsorted=False, initialSortCol="#0", initialSortDirForward=True): if hasattr(self, 'lastSortColumn') and self.lastSortColumn: self.treeView.heading(self.lastSortColumn, image=self.sortImages[2]) self.lastSortColumn = None if startUnsorted else initialSortCol self.lastSortColumnForward = initialSortDirForward self.treeColIsInt = treeColIsInt if not hasattr(self, "sortImages"): self.sortImages = (PhotoImage( file=os.path.join(self.modelXbrl.modelManager.cntlr.imagesDir, "columnSortUp.gif")), PhotoImage(file=os.path.join( self.modelXbrl.modelManager.cntlr.imagesDir, "columnSortDown.gif")), PhotoImage()) for col in ("#0", ) + self.treeView["columns"]: self.treeView.heading(col, command=lambda c=col: self.sortColumn(c)) if not startUnsorted: self.treeView.heading( initialSortCol, image=self.sortImages[not initialSortDirForward]) def colSortVal(self, node, col): if col == "#0": treeColVal = self.treeView.item(node)["text"] if self.treeColIsInt: return int(treeColVal) else: treeColVal = self.treeView.set(node, col) if col == "sequence": try: return int(treeColVal) except: return 0 return treeColVal def sortNestedRows(self, parentNode, col, reverse): l = [(self.colSortVal(node, col), node) for node in self.treeView.get_children(parentNode)] l.sort(reverse=reverse) # rearrange items in sorted positions for i, (cell, node) in enumerate(l): self.treeView.move(node, parentNode, i) # reset even/odd tags for i, node in enumerate(self.treeView.get_children(parentNode)): self.treeView.item(node, tags=('even' if i & 1 else 'odd', )) self.sortNestedRows(node, col, reverse) def sortColumn(self, col): if col == self.lastSortColumn: reverse = self.lastSortColumnForward self.lastSortColumnForward = not reverse else: if self.lastSortColumn: self.treeView.heading(self.lastSortColumn, image=self.sortImages[2]) reverse = False self.lastSortColumnForward = True self.lastSortColumn = col self.treeView.heading(col, image=self.sortImages[reverse]) self.sortNestedRows('', col, reverse) self.viewSelectionChange() # reselect selected rows def copyCellToClipboard(self, *ignore): self.modelXbrl.modelManager.cntlr.clipboardData( text=self.treeView.item(self.menuRow)['text'] if self.menuCol == '#0' else self.treeView.set(self.menuRow, self.menuCol)) def copyRowToClipboard(self, *ignore): self.modelXbrl.modelManager.cntlr.clipboardData( text='\t'.join([self.treeView.item(self.menuRow)['text']] + [ self.treeView.set(self.menuRow, c) for c in self.treeView['columns'] ])) def copyTableToClipboard(self, *ignore): cols = self.treeView['columns'] lines = [ '\t'.join([self.treeView.heading('#0')['text']] + [self.treeView.heading(h)['text'] for h in cols]) ] self.tabLines('', '', cols, lines) self.modelXbrl.modelManager.cntlr.clipboardData(text='\n'.join(lines)) def tabLines(self, parentNode, indent, cols, lines): for node in self.treeView.get_children(parentNode): lines.append('\t'.join( '"{}"'.format(c.replace('"', '""')) if ( isinstance(c, str) and "\n" in c) else c for c in ([indent + self.treeView.item(node)['text']] + [self.treeView.set(node, c) for c in cols]))) self.tabLines(node, indent + ' ', cols, lines)
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")
class ViewGrid: def __init__(self, modelXbrl, tabWin, tabTitle, hasToolTip=False, lang=None): self.tabWin = tabWin #self.viewFrame = Frame(tabWin) #self.viewFrame.grid(row=0, column=0, sticky=(N, S, E, W)) ''' paneWin = PanedWindow(self.viewFrame, orient=VERTICAL) paneWin.grid(row=1, column=0, sticky=(N, S, E, W)) self.zGrid = scrollgrid(paneWin) self.zGrid.grid(row=0, column=0, sticky=(N, S, E, W)) self.xyGrid = scrollgrid(paneWin) self.xyGrid.grid(row=1, column=0, sticky=(N, S, E, W)) ''' ''' self.gridBody = scrollgrid(self.viewFrame) self.gridBody.grid(row=0, column=0, sticky=(N, S, E, W)) ''' self.viewFrame = scrolledHeaderedFrame(tabWin) self.gridTblHdr = self.viewFrame.tblHdrInterior self.gridColHdr = self.viewFrame.colHdrInterior self.gridRowHdr = self.viewFrame.rowHdrInterior self.gridBody = self.viewFrame.bodyInterior ''' self.viewFrame = scrolledFrame(tabWin) self.gridTblHdr = self.gridRowHdr = self.gridColHdr = self.gridBody = self.viewFrame.interior ''' tabWin.add(self.viewFrame,text=tabTitle) self.modelXbrl = modelXbrl self.hasToolTip = hasToolTip self.toolTipText = StringVar() if hasToolTip: self.gridBody.bind("<Motion>", self.motion, '+') self.gridBody.bind("<Leave>", self.leave, '+') self.toolTipText = StringVar() self.toolTip = ToolTip(self.gridBody, textvariable=self.toolTipText, wraplength=480, follow_mouse=True, state="disabled") self.toolTipColId = None self.toolTipRowId = None self.modelXbrl = modelXbrl self.contextMenuClick = self.modelXbrl.modelManager.cntlr.contextMenuClick self.gridTblHdr.contextMenuClick = self.contextMenuClick self.gridColHdr.contextMenuClick = self.contextMenuClick self.gridRowHdr.contextMenuClick = self.contextMenuClick self.gridBody.contextMenuClick = self.contextMenuClick self.lang = lang if modelXbrl: modelXbrl.views.append(self) if not lang: self.lang = modelXbrl.modelManager.defaultLang def close(self): self.tabWin.forget(self.viewFrame) self.modelXbrl.views.remove(self) self.modelXbrl = None def leave(self, *args): self.toolTipColId = None self.toolTipRowId = None def motion(self, *args): ''' tvColId = self.gridBody.identify_column(args[0].x) tvRowId = self.gridBody.identify_row(args[0].y) if tvColId != self.toolTipColId or tvRowId != self.toolTipRowId: self.toolTipColId = tvColId self.toolTipRowId = tvRowId newValue = None if tvRowId and len(tvRowId) > 0: try: col = int(tvColId[1:]) if col == 0: newValue = self.gridBody.item(tvRowId,"text") else: values = self.gridBody.item(tvRowId,"values") if col <= len(values): newValue = values[col - 1] except ValueError: pass self.setToolTip(newValue, tvColId) ''' def setToolTip(self, text, colId="#0"): self.toolTip._hide() if isinstance(text,str) and len(text) > 0: width = self.gridBody.column(colId,"width") if len(text) * 8 > width or '\n' in text: self.toolTipText.set(text) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled") else: self.toolTipText.set("") self.toolTip.configure(state="disabled") def contextMenu(self): try: return self.menu except AttributeError: self.menu = Menu( self.viewFrame, tearoff = 0 ) self.gridBody.bind( self.contextMenuClick, self.popUpMenu ) if not self.gridTblHdr.bind(self.contextMenuClick): self.gridTblHdr.bind( self.contextMenuClick, self.popUpMenu ) if not self.gridColHdr.bind(self.contextMenuClick): self.gridColHdr.bind( self.contextMenuClick, self.popUpMenu ) if not self.gridRowHdr.bind(self.contextMenuClick): self.gridRowHdr.bind( self.contextMenuClick, self.popUpMenu ) return self.menu def popUpMenu(self, event): self.menu.post( event.x_root, event.y_root ) def menuAddLangs(self): langsMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=_("Language"), menu=langsMenu, underline=0) for lang in sorted(self.modelXbrl.langs): langsMenu.add_cascade(label=lang, underline=0, command=lambda l=lang: self.setLang(l)) def setLang(self, lang): self.lang = lang self.view()
class ViewGrid: def __init__(self, modelXbrl, tabWin, tabTitle, hasToolTip=False, lang=None): self.tabWin = tabWin #self.viewFrame = Frame(tabWin) #self.viewFrame.grid(row=0, column=0, sticky=(N, S, E, W)) ''' paneWin = PanedWindow(self.viewFrame, orient=VERTICAL) paneWin.grid(row=1, column=0, sticky=(N, S, E, W)) self.zGrid = scrollgrid(paneWin) self.zGrid.grid(row=0, column=0, sticky=(N, S, E, W)) self.xyGrid = scrollgrid(paneWin) self.xyGrid.grid(row=1, column=0, sticky=(N, S, E, W)) ''' ''' self.gridBody = scrollgrid(self.viewFrame) self.gridBody.grid(row=0, column=0, sticky=(N, S, E, W)) ''' self.viewFrame = scrolledHeaderedFrame(tabWin) self.gridTblHdr = self.viewFrame.tblHdrInterior self.gridColHdr = self.viewFrame.colHdrInterior self.gridRowHdr = self.viewFrame.rowHdrInterior self.gridBody = self.viewFrame.bodyInterior ''' self.viewFrame = scrolledFrame(tabWin) self.gridTblHdr = self.gridRowHdr = self.gridColHdr = self.gridBody = self.viewFrame.interior ''' tabWin.add(self.viewFrame, text=tabTitle) self.modelXbrl = modelXbrl self.hasToolTip = hasToolTip self.toolTipText = StringVar() if hasToolTip: self.gridBody.bind("<Motion>", self.motion, '+') self.gridBody.bind("<Leave>", self.leave, '+') self.toolTipText = StringVar() self.toolTip = ToolTip(self.gridBody, textvariable=self.toolTipText, wraplength=480, follow_mouse=True, state="disabled") self.toolTipColId = None self.toolTipRowId = None self.modelXbrl = modelXbrl self.contextMenuClick = self.modelXbrl.modelManager.cntlr.contextMenuClick self.gridTblHdr.contextMenuClick = self.contextMenuClick self.gridColHdr.contextMenuClick = self.contextMenuClick self.gridRowHdr.contextMenuClick = self.contextMenuClick self.gridBody.contextMenuClick = self.contextMenuClick self.lang = lang if modelXbrl: modelXbrl.views.append(self) if not lang: self.lang = modelXbrl.modelManager.defaultLang def close(self): self.tabWin.forget(self.viewFrame) if self in self.modelXbrl.views: self.modelXbrl.views.remove(self) self.modelXbrl = None def select(self): self.tabWin.select(self.viewFrame) def leave(self, *args): self.toolTipColId = None self.toolTipRowId = None def motion(self, *args): ''' tvColId = self.gridBody.identify_column(args[0].x) tvRowId = self.gridBody.identify_row(args[0].y) if tvColId != self.toolTipColId or tvRowId != self.toolTipRowId: self.toolTipColId = tvColId self.toolTipRowId = tvRowId newValue = None if tvRowId and len(tvRowId) > 0: try: col = int(tvColId[1:]) if col == 0: newValue = self.gridBody.item(tvRowId,"text") else: values = self.gridBody.item(tvRowId,"values") if col <= len(values): newValue = values[col - 1] except ValueError: pass self.setToolTip(newValue, tvColId) ''' def setToolTip(self, text, colId="#0"): self.toolTip._hide() if isinstance(text, str) and len(text) > 0: width = self.gridBody.column(colId, "width") if len(text) * 8 > width or '\n' in text: self.toolTipText.set(text) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled") else: self.toolTipText.set("") self.toolTip.configure(state="disabled") def contextMenu(self): try: return self.menu except AttributeError: self.menu = Menu(self.viewFrame, tearoff=0) self.gridBody.bind(self.contextMenuClick, self.popUpMenu) if not self.gridTblHdr.bind(self.contextMenuClick): self.gridTblHdr.bind(self.contextMenuClick, self.popUpMenu) if not self.gridColHdr.bind(self.contextMenuClick): self.gridColHdr.bind(self.contextMenuClick, self.popUpMenu) if not self.gridRowHdr.bind(self.contextMenuClick): self.gridRowHdr.bind(self.contextMenuClick, self.popUpMenu) return self.menu def popUpMenu(self, event): self.menu.post(event.x_root, event.y_root) def menuAddLangs(self): langsMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=_("Language"), menu=langsMenu, underline=0) for lang in sorted(self.modelXbrl.langs): langsMenu.add_cascade(label=lang, underline=0, command=lambda l=lang: self.setLang(l)) def setLang(self, lang): self.lang = lang self.view()
class ViewList(): def __init__(self, modelXbrl, tabWin, tabTitle, hasToolTip=False): self.tabWin = tabWin self.viewFrame = Frame(tabWin) self.viewFrame.view = self self.viewFrame.grid(row=0, column=0, sticky=(N, S, E, W)) tabWin.add(self.viewFrame, text=tabTitle) xmlScrollbar = Scrollbar(self.viewFrame, orient=VERTICAL) self.listBox = Listbox(self.viewFrame, yscrollcommand=xmlScrollbar.set) self.listBox.grid(row=0, column=0, sticky=(N, S, E, W)) #self.listBox.focus_set() self.listBox.bind("<Motion>", self.listBoxMotion, '+') self.listBox.bind("<1>", self.listBoxClick, '+') self.listBox.bind("<Leave>", self.listBoxLeave, '+') xmlScrollbar["command"] = self.listBox.yview xmlScrollbar.grid(row=0, column=1, sticky=(N, S)) self.viewFrame.columnconfigure(0, weight=1) self.viewFrame.rowconfigure(0, weight=1) self.listBoxToolTipText = StringVar() if hasToolTip: self.listBoxToolTip = ToolTip(self.listBox, textvariable=self.listBoxToolTipText, wraplength=480, follow_mouse=True, state="disabled") self.listBoxRow = -9999999 self.modelXbrl = modelXbrl if modelXbrl: modelXbrl.views.append(self) def close(self): del self.viewFrame.view self.tabWin.forget(self.viewFrame) self.modelXbrl.views.remove(self) self.modelXbrl = None def select(self): self.tabWin.select(self.viewFrame) def append(self, line): self.listBox.insert(END, line) def clear(self): self.listBox.delete(0, END) def listBoxClick(self, *args): if self.modelXbrl: self.modelXbrl.modelManager.cntlr.currentView = self def listBoxLeave(self, *args): self.listBoxRow = -9999999 def lines(self): return self.listBox.get(0, END) def lineText(self, lineNumber): return self.listBox.get(lineNumber) def selectLine(self, lineNumber): self.listBox.selection_clear(0, END) self.listBox.selection_set(lineNumber) def saveToFile(self, filename): with open(filename, "w") as fh: fh.writelines( [logEntry + '\n' for logEntry in self.listBox.get(0, END)]) def copyToClipboard(self, cntlr=None, *ignore): if cntlr is None: cntlr = self.modelXbrl.modelManager.cntlr cntlr.clipboardData(text='\n'.join(self.listBox.get(0, END))) def listBoxMotion(self, *args): lbRow = self.listBox.nearest(args[0].y) if lbRow != self.listBoxRow: self.listBoxRow = lbRow text = self.listBox.get(lbRow) self.listBoxToolTip._hide() if text and len(text) > 0: if len(text) * 8 > 200: self.listBoxToolTipText.set( text[:2048] + "..." if len(text) > 2048 else text) self.listBoxToolTip.configure(state="normal") self.listBoxToolTip._schedule() else: self.listBoxToolTipText.set("") self.listBoxToolTip.configure(state="disabled") else: self.listBoxToolTipText.set("") self.listBoxToolTip.configure(state="disabled") def contextMenu(self, contextMenuClick=None): try: return self.menu except AttributeError: if contextMenuClick is None: contextMenuClick = self.modelXbrl.modelManager.cntlr.contextMenuClick self.menu = Menu(self.viewFrame, tearoff=0) self.listBox.bind(contextMenuClick, self.popUpMenu) return self.menu def popUpMenu(self, event): self.menu.post(event.x_root, event.y_root) def menuAddSaveClipboard(self): self.menu.add_command( label=_("Save to file"), underline=0, command=self.modelXbrl.modelManager.cntlr.fileSave) if self.modelXbrl.modelManager.cntlr.hasClipboard: self.menu.add_command(label=_("Copy to clipboard"), underline=0, command=self.copyToClipboard)
class DialogOpenTaxonomyPackage(Toplevel): def __init__(self, mainWin, openType, filesource, filenames, title): parent = mainWin.parent super().__init__(parent) self.parent = parent parentGeometry = re.match("(\d+)x(\d+)[+]?([-]?\d+)[+]?([-]?\d+)", parent.geometry()) dialogX = int(parentGeometry.group(3)) dialogY = int(parentGeometry.group(4)) self.accepted = False self.webUrl = None self.transient(self.parent) self.title(title) 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, columns=2) 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() # set up treeView widget and tabbed pane self.treeView.column("#0", width=150, anchor="w") self.treeView.heading("#0", text="Name") self.treeView.column("#1", width=350, anchor="w") self.treeView.heading("#1", text="URL") mainWin.showStatus(_("loading archive {0}").format(filesource.url)) self.filesource = filesource self.filenames = filenames selectedNode = None metadata = filesource.file(filesource.url + os.sep + TAXONOMY_PACKAGE_FILE_NAME)[0] try: self.nameToUrls = 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 for name, urls in self.nameToUrls.items(): displayUrl = urls[1] # display the canonical URL self.treeView.insert("", "end", name, values=[displayUrl], text=name) if selectedNode: self.treeView.see(selectedNode) self.treeView.selection_set(selectedNode) 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) 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() 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.toolTipEpName = None self.protocol("WM_DELETE_WINDOW", self.close) self.grab_set() self.wait_window(self) def ok(self, event=None): selection = self.treeView.selection() if len(selection) > 0: epName = selection[0] #index 0 is the remapped Url, as opposed to the canonical one used for display urlOrFile = self.nameToUrls[epName][0] if not urlOrFile.endswith("/"): # check if it's an absolute URL rather than a path into the archive if urlOrFile.startswith("http://") or urlOrFile.startswith("https://"): self.webUrl = urlOrFile else: # assume it's a path inside the archive: self.filesource.select(urlOrFile) self.accepted = True self.close() def close(self, event=None): self.parent.focus_set() self.destroy() def leave(self, *args): self.toolTipRowId = None def motion(self, *args): epName = self.treeView.identify_row(args[0].y) if epName != self.toolTipEpName: self.toolTipEpName = epName try: epUrl = self.nameToUrls[epName][1] except KeyError: epUrl = None self.toolTip._hide() if epName and epUrl: self.toolTipText.set("{0}\n{1}".format(epName, epUrl)) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled")
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 ViewTree: def __init__(self, modelXbrl, tabWin, tabTitle, hasToolTip=False, lang=None, editableColumns=[], valueChangedCallback=None): self.tabWin = tabWin self.viewFrame = Frame(tabWin) self.viewFrame.view = self self.viewFrame.grid(row=0, column=0, sticky=(N, S, E, W)) tabWin.add(self.viewFrame,text=tabTitle) self.tabTitle = tabTitle # for error messages vScrollbar = Scrollbar(self.viewFrame, orient=VERTICAL) hScrollbar = Scrollbar(self.viewFrame, orient=HORIZONTAL) self.isEbaTableIndex = False if tabTitle.startswith('Tables'): for pluginXbrlMethod in pluginClassMethods("CntlrWinMain.Modeling.LoadFilingIndicators"): self.isEbaTableIndex = True # for EBA and in case of table index, add a second column with the filing indicator # (OK, it is not really sound to base this test on the title) self.treeView = Treeview(self.viewFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set, columns="Filing") break if not self.isEbaTableIndex: self.treeView = Treeview(self.viewFrame, xscrollcommand=hScrollbar.set, yscrollcommand=vScrollbar.set) self.treeView.grid(row=0, column=0, sticky=(N, S, E, W)) self.treeView.tag_configure("ELR", background="#E0F0FF") self.treeView.tag_configure("even", background="#F0F0F0") self.treeView.tag_configure("odd", background="#FFFFFF") if modelXbrl.modelManager.cntlr.isMac or modelXbrl.modelManager.cntlr.isMSW: highlightColor = "#%04x%04x%04x" % self.treeView.winfo_rgb("SystemHighlight") else: highlightColor = "#33339999ffff" # using MSW value for Unix/Linux which has no named colors self.treeView.tag_configure("selected-ELR", background=highlightColor) self.treeView.tag_configure("selected-even", background=highlightColor) self.treeView.tag_configure("selected-odd", background=highlightColor) self.treeViewSelection = () self.treeView.bind("<<TreeviewSelect>>", self.viewSelectionChange, '+') self.treeView.bind("<1>", self.onViewClick, '+') self.treeView.bind("<Double-1>", self.onDoubleClick, '+') 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)) self.viewFrame.columnconfigure(0, weight=1) self.viewFrame.rowconfigure(0, weight=1) self.modelXbrl = modelXbrl self.hasToolTip = hasToolTip self.toolTipText = StringVar() if 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=480, follow_mouse=True, state="disabled") self.toolTipColId = None self.toolTipRowId = None self.modelXbrl = modelXbrl self.lang = lang self.labelrole = None self.nameIsPrefixed = False if modelXbrl: modelXbrl.views.append(self) if not lang: self.lang = modelXbrl.modelManager.defaultLang self.editableColumns = editableColumns self.valueChangedCallback = valueChangedCallback self.entryPopup = None def refreshTitle(self): tid = str(self.viewFrame) text = "Tables (" + self.modelXbrl.getInstanceFilenameForView() + ")" self.tabWin.tab(tid, text=text) self.tabTitle = text def clearTreeView(self): self.treeViewSelection = () for node in self.treeView.get_children(): self.treeView.delete(node) def viewSelectionChange(self, event=None): for node in self.treeViewSelection: self.removeSelection(node) self.treeViewSelection = self.treeView.selection() for node in self.treeViewSelection: self.addSelection(node) def removeSelection(self, node): if self.treeView.exists(node): priorTags = self.treeView.item(node)["tags"] if priorTags: newTags = tuple((i[9:] if i.startswith("selected-") else i) for i in priorTags) self.treeView.item(node, tags=newTags) def addSelection(self, node): priorTags = self.treeView.item(node)["tags"] if priorTags: newTags = tuple(("selected-"+i if i in ['even', 'odd'] else i) for i in priorTags) self.treeView.item(node, tags=newTags) def onViewClick(self, *args): self.modelXbrl.modelManager.cntlr.currentView = self def close(self): del self.viewFrame.view if self.modelXbrl: self.tabWin.forget(self.viewFrame) self.modelXbrl.views.remove(self) self.modelXbrl = None self.view = None def select(self): self.tabWin.select(self.viewFrame) def leave(self, *args): self.toolTipColId = None self.toolTipRowId = None def motion(self, *args): tvColId = self.treeView.identify_column(args[0].x) tvRowId = self.treeView.identify_row(args[0].y) if tvColId != self.toolTipColId or tvRowId != self.toolTipRowId: self.toolTipColId = tvColId self.toolTipRowId = tvRowId newValue = self.getToolTip(tvRowId, tvColId) if newValue is None and tvRowId and len(tvRowId) > 0: try: col = int(tvColId[1:]) if col == 0: newValue = self.treeView.item(tvRowId,"text") else: values = self.treeView.item(tvRowId,"values") if col <= len(values): newValue = values[col - 1] except ValueError: pass self.setToolTip(newValue, tvColId) def getToolTip(self, rowId, colId): return None def setToolTip(self, text, colId="#0"): self.toolTip._hide() if isinstance(text,str) and len(text) > 0: width = self.treeView.column(colId,"width") if len(text) * 8 > width or '\n' in text: self.toolTipText.set(text) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled") else: self.toolTipText.set("") self.toolTip.configure(state="disabled") def contextMenu(self): try: return self.menu except AttributeError: try: self.menu = Menu( self.viewFrame, tearoff = 0 ) self.treeView.bind( self.modelXbrl.modelManager.cntlr.contextMenuClick, self.popUpMenu, '+' ) return self.menu except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info("arelle:internalException", _("Exception creating context menu in %(title)s: %(error)s"), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None return None def popUpMenu(self, event): if self.menu: self.menuRow = self.treeView.identify_row(event.y) self.menuCol = self.treeView.identify_column(event.x) self.menu.post( event.x_root, event.y_root ) def expand(self): self.setTreeItemOpen(self.menuRow,open=True) def setFiling(self, filingIndicator): # Check if there is a custom method to set filing indicators for pluginXbrlMethod in pluginClassMethods("CntlrWinMain.Rendering.SetFilingIndicator"): stopPlugin = pluginXbrlMethod(self, self.modelXbrl, filingIndicator) if stopPlugin: break; def setFilingTrue(self): self.setFiling(True) def setFilingFalse(self): self.setFiling(False) def resetFiling(self): self.setFiling(None) def expandAll(self): self.setTreeItemOpen("",open=True) def collapse(self): self.setTreeItemOpen(self.menuRow,open=False) def collapseAll(self): self.setTreeItemOpen("",open=False) def setTreeItemOpen(self, node, open=True): if node: self.treeView.item(node, open=open) for childNode in self.treeView.get_children(node): self.setTreeItemOpen(childNode, open) def menuAddExpandCollapse(self): if self.menu: self.menu.add_command(label=_("Expand"), underline=0, command=self.expand) self.menu.add_command(label=_("Collapse"), underline=0, command=self.collapse) self.menu.add_command(label=_("Expand all"), underline=0, command=self.expandAll) self.menu.add_command(label=_("Collapse all"), underline=0, command=self.collapseAll) def menuAddFilingChoice(self): if self.menu: self.menu.add_command(label=_("Filing: set filed"), underline=0, command=self.setFilingTrue) self.menu.add_command(label=_("Filing: set not filed"), underline=0, command=self.setFilingFalse) self.menu.add_command(label=_("Filing: clear"), underline=0, command=self.resetFiling) def menuAddClipboard(self): if self.menu and self.modelXbrl.modelManager.cntlr.hasClipboard: try: clipboardMenu = Menu(self.viewFrame, tearoff=0) clipboardMenu.add_command(label=_("Cell"), underline=0, command=self.copyCellToClipboard) clipboardMenu.add_command(label=_("Row"), underline=0, command=self.copyRowToClipboard) clipboardMenu.add_command(label=_("Table"), underline=0, command=self.copyTableToClipboard) self.menu.add_cascade(label=_("Copy to clipboard"), menu=clipboardMenu, underline=0) except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info("arelle:internalException", _("Exception creating clipboard menu in %(title)s: %(error)s"), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None def menuAddLangs(self): if self.menu: try: langsMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=_("Language"), menu=langsMenu, underline=0) for lang in sorted(self.modelXbrl.langs): langsMenu.add_command(label=lang, underline=0, command=lambda l=lang: self.setLang(l)) except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info("arelle:internalException", _("Exception creating context languages menu in %(title)s: %(error)s"), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None def menuAddLabelRoles(self, includeConceptName=False, menulabel=None): if self.menu: try: if menulabel is None: menulabel = _("Label role") rolesMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=menulabel, menu=rolesMenu, underline=0) from arelle.ModelRelationshipSet import labelroles for x in labelroles(self.modelXbrl, includeConceptName): rolesMenu.add_command(label=x[0][1:], underline=0, command=lambda a=x[1]: self.setLabelrole(a)) except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info("arelle:internalException", _("Exception creating context label roles menu in %(title)s: %(error)s"), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None def menuAddNameStyle(self, menulabel=None): if self.menu: try: if menulabel is None: menulabel = _("Name Style") nameStyleMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=menulabel, menu=nameStyleMenu, underline=0) from arelle.ModelRelationshipSet import labelroles nameStyleMenu.add_command(label=_("Prefixed"), underline=0, command=lambda a=True: self.setNamestyle(a)) nameStyleMenu.add_command(label=_("No prefix"), underline=0, command=lambda a=False: self.setNamestyle(a)) except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info("arelle:internalException", _("Exception creating context name style menu in %(title)s: %(error)s"), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None def menuAddUnitDisplay(self): if self.menu: try: rolesMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=_("Units"), menu=rolesMenu, underline=0) rolesMenu.add_command(label=_("Unit ID"), underline=0, command=lambda: self.setUnitDisplay(unitDisplayID=True)) rolesMenu.add_command(label=_("Measures"), underline=0, command=lambda: self.setUnitDisplay(unitDisplayID=False)) except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info("arelle:internalException", _("Exception creating context unit menu in %(title)s: %(error)s"), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None def menuAddViews(self, addClose=True, tabWin=None): if self.menu: try: if tabWin is None: tabWin = self.tabWin viewMenu = Menu(self.viewFrame, tearoff=0) self.menu.add_cascade(label=_("View"), menu=viewMenu, underline=0) newViewsMenu = Menu(self.viewFrame, tearoff=0) if addClose: viewMenu.add_command(label=_("Close"), underline=0, command=self.close) viewMenu.add_cascade(label=_("Additional view"), menu=newViewsMenu, underline=0) newViewsMenu.add_command(label=_("Arcrole group..."), underline=0, command=lambda: self.newArcroleGroupView(tabWin)) from arelle.ModelRelationshipSet import baseSetArcroles for x in baseSetArcroles(self.modelXbrl) + [( " Role Types","!CustomRoleTypes!"), (" Arcrole Types", "!CustomArcroleTypes!")]: newViewsMenu.add_command(label=x[0][1:], underline=0, command=lambda a=x[1]: self.newView(a, tabWin)) except Exception as ex: # tkinter menu problem maybe self.modelXbrl.info("arelle:internalException", _("Exception creating context add-views menu in %(title)s: %(error)s"), modelObject=self.modelXbrl.modelDocument, title=self.tabTitle, error=str(ex)) self.menu = None def newView(self, arcrole, tabWin): if arcrole in ("!CustomRoleTypes!", "!CustomArcroleTypes!"): from arelle import ViewWinRoleTypes ViewWinRoleTypes.viewRoleTypes(self.modelXbrl, tabWin, arcrole=="!CustomArcroleTypes!", lang=self.lang) else: from arelle import ViewWinRelationshipSet ViewWinRelationshipSet.viewRelationshipSet(self.modelXbrl, tabWin, arcrole, lang=self.lang) def newArcroleGroupView(self, tabWin): from arelle.DialogArcroleGroup import getArcroleGroup from arelle import ViewWinRelationshipSet arcroleGroup = getArcroleGroup(self.modelXbrl.modelManager.cntlr, self.modelXbrl) if arcroleGroup: ViewWinRelationshipSet.viewRelationshipSet(self.modelXbrl, tabWin, arcroleGroup, lang=self.lang) def setLang(self, lang): self.lang = lang self.view() def setLabelrole(self, labelrole): self.labelrole = labelrole self.view() def setNamestyle(self, isPrefixed): self.nameIsPrefixed = isPrefixed self.view() def setUnitDisplay(self, unitDisplayID=False): self.unitDisplayID = unitDisplayID self.view() def setColumnsSortable(self, treeColIsInt=False, startUnsorted=False, initialSortCol="#0", initialSortDirForward=True): if hasattr(self, 'lastSortColumn') and self.lastSortColumn: self.treeView.heading(self.lastSortColumn, image=self.sortImages[2]) self.lastSortColumn = None if startUnsorted else initialSortCol self.lastSortColumnForward = initialSortDirForward self.treeColIsInt = treeColIsInt if not hasattr(self, "sortImages"): self.sortImages = (PhotoImage(file=os.path.join(self.modelXbrl.modelManager.cntlr.imagesDir, "columnSortUp.gif")), PhotoImage(file=os.path.join(self.modelXbrl.modelManager.cntlr.imagesDir, "columnSortDown.gif")), PhotoImage()) for col in ("#0",) + self.treeView["columns"]: self.treeView.heading(col, command=lambda c=col: self.sortColumn(c)) if not startUnsorted: self.treeView.heading(initialSortCol, image=self.sortImages[not initialSortDirForward]) def colSortVal(self, node, col): if col == "#0": treeColVal = self.treeView.item(node)["text"] if self.treeColIsInt: return int(treeColVal) else: treeColVal = self.treeView.set(node, col) if col == "sequence": try: return int(treeColVal) except: return 0 return treeColVal def sortNestedRows(self, parentNode, col, reverse): l = [(self.colSortVal(node, col), node) for node in self.treeView.get_children(parentNode)] l.sort(reverse=reverse) # rearrange items in sorted positions for i, (cell, node) in enumerate(l): self.treeView.move(node, parentNode, i) # reset even/odd tags for i, node in enumerate(self.treeView.get_children(parentNode)): self.treeView.item(node, tags=('even' if i & 1 else 'odd',)) self.sortNestedRows(node, col, reverse) def sortColumn(self, col): if col == self.lastSortColumn: reverse = self.lastSortColumnForward self.lastSortColumnForward = not reverse else: if self.lastSortColumn: self.treeView.heading(self.lastSortColumn, image=self.sortImages[2]) reverse = False self.lastSortColumnForward = True self.lastSortColumn = col self.treeView.heading(col, image=self.sortImages[reverse]) self.sortNestedRows('', col, reverse) self.viewSelectionChange() # reselect selected rows def copyCellToClipboard(self, *ignore): self.modelXbrl.modelManager.cntlr.clipboardData( text=self.treeView.item(self.menuRow)['text'] if self.menuCol == '#0' else self.treeView.set(self.menuRow,self.menuCol)) def copyRowToClipboard(self, *ignore): self.modelXbrl.modelManager.cntlr.clipboardData( text='\t'.join([self.treeView.item(self.menuRow)['text']] + [self.treeView.set(self.menuRow,c) for c in self.treeView['columns']])) def copyTableToClipboard(self, *ignore): cols = self.treeView['columns'] lines = ['\t'.join([self.treeView.heading('#0')['text']] + [self.treeView.heading(h)['text'] for h in cols])] self.tabLines('', '', cols, lines) self.modelXbrl.modelManager.cntlr.clipboardData(text='\n'.join(lines)) def tabLines(self, parentNode, indent, cols, lines): for node in self.treeView.get_children(parentNode): lines.append('\t'.join([indent + self.treeView.item(node)['text']] + [self.treeView.set(node,c) for c in cols])) self.tabLines(node, indent+' ', cols, lines) def onDoubleClick(self, event): ''' Executed, when a row is double-clicked. Opens a EntryPopup above the item's column, so it is possible to edit the text ''' # do nothing if no column is editable if len(self.editableColumns)<=0: return # delete any open Entry Popup if self.entryPopup: self.entryPopup.destroy() self.entryPopup = None # what row and column was clicked on rowID = self.treeView.identify_row(event.y) column = self.treeView.identify_column(event.x) if not (column in self.editableColumns and (self.treeView.tag_has("editable", rowID))): return # get column position info x,y,width,height = self.treeView.bbox(rowID, column) # y-axis offset pady = height // 2 # place Entry popup properly data = self.treeView.set(rowID, column=column) self.entryPopup = EntryPopup(self.treeView, rowID, column, data, self.valueChanged) self.entryPopup.place( x=x, y=y+pady, anchor=W, relwidth=1) def valueChanged(self, rowID, column, value): if self.valueChangedCallback is not None: self.valueChangedCallback(rowID, column, value)
class DialogOpenArchive(Toplevel): def __init__(self, mainWin, openType, filesource, filenames, title, colHeader): parent = mainWin.parent super().__init__(parent) self.parent = parent 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) self.title(title) 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() # set up treeView widget and tabbed pane self.treeView.column("#0", width=500, anchor="w") self.treeView.heading("#0", text=colHeader) try: self.isRss = 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 mainWin.showStatus(_("loading archive {0}").format(filesource.url)) self.filesource = filesource self.filenames = filenames selection = filesource.selection hasToolTip = False loadedPaths = [] i = 0 selectedNode = None for filename in self.filenames: if isinstance(filename, tuple): if self.isRss: form, date, instDoc = filename[2:5] filename = filename[0] # ignore tooltip 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 selection == filename: selectedNode = node loadedPaths.append(path) i += 1 if selectedNode: self.treeView.see(selectedNode) self.treeView.selection_set(selectedNode) 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) 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 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 ok(self, event=None): selection = self.treeView.selection() if len(selection) > 0: 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() def close(self, event=None): self.parent.focus_set() self.destroy() def leave(self, *args): self.toolTipRowId = None def motion(self, *args): tvRowId = self.treeView.identify_row(args[0].y) if tvRowId != self.toolTipRowId: self.toolTipRowId = tvRowId newFileIndex = -1 if tvRowId and len(tvRowId) > 4: try: newFileIndex = int(tvRowId[4:]) except ValueError: pass self.setToolTip(newFileIndex) def setToolTip(self, fileIndex): self.toolTip._hide() if fileIndex >= 0 and fileIndex < len(self.filenames): filenameItem = self.filenames[fileIndex] if isinstance(filenameItem, tuple): self.toolTipText.set(filenameItem[1].replace("\\n", "\n")) self.toolTip.configure(state="normal") self.toolTip._schedule() else: self.toolTipText.set("") self.toolTip.configure(state="disabled") else: self.toolTipText.set("") self.toolTip.configure(state="disabled")