def loadXbelNode(self, element, model, parent=None): """Recursively load an XBEL ElementTree node and its children. Arguments: element -- an XBEL ElementTree node model -- a ref to the TreeLine model parent -- the parent TreeNode (None for the root node only) """ if element.tag in ('xbel', 'folder'): node = treenode.TreeNode(parent, bookmarkFolderTypeName, model) if parent: parent.childList.append(node) else: model.root = node for child in element: self.loadXbelNode(child, model, node) elif element.tag == 'bookmark': node = treenode.TreeNode(parent, bookmarkLinkTypeName, model) parent.childList.append(node) link = element.get('href').strip() if link: node.data[bookmarkLinkFieldName] = ( '<a href="{0}">{1}</a>'.format(link, link)) for child in element: self.loadXbelNode(child, model, node) elif element.tag == 'title': parent.setTitle(element.text) elif element.tag == 'separator': node = treenode.TreeNode(parent, bookmarkSeparatorTypeName, model) parent.childList.append(node) node.setUniqueId(True) else: # unsupported tags pass
def __init__(self, newFile=False, parent=None): """Initialize a TreeModel. Arguments: newFile -- if true, adds default root node and formats parent -- optional QObject parent for the model """ super().__init__(parent) self.root = None self.configDialogFormats = None self.undoList = None self.redoList = None self.nodeIdDict = {} self.linkRefCollect = linkref.LinkRefCollection() self.mathZeroBlanks = True if newFile: self.formats = treeformats.TreeFormats(True) self.root = treenode.TreeNode(None, treeformats.defaultTypeName, self) self.root.setTitle(defaultRootName) else: self.formats = treeformats.TreeFormats() self.fileInfoNode = treenode.TreeNode(None, self.formats.fileInfoFormat.name, self)
def prune_tree(original_sub_tree, values_to_discard): ''' Returns a tree with any node whose label is in the list values_to_discard (and thus all of its children) pruned. This function should return a copy of the original tree and should not destructively modify the original tree. The pruning step must be recursive. Inputs: original_sub_tree: (TreeNode) a tree of type TreeNode whose internal counts have been computed. That is, compute_internal_counts() must have been run on this tree. values_to_discard: (list of strings) A list of strings specifying the labels of nodes to discard Variables: t: (TreeNode) variable representation of original_sub_tree child_array: (list of TreeNodes) holds the list of children for a given node of the tree Returns: a new TreeNode representing the pruned tree ''' t = original_sub_tree if t.num_children() == 0: return treenode.TreeNode(t.label, count=t.count) child_array = [] for child in t.children: if child.label not in values_to_discard: child_array.append(prune_tree(child, values_to_discard)) return treenode.TreeNode(t.label, t.count, child_array)
def __init__(self, fileData=None, topNodes=None, addDefaults=False, addSpots=True): """Create and store a tree structure from file data. If no file data is given, create an empty or a default new structure. Arguments: fileData -- a dict in JSON file format of a structure topNodes -- existing top-level nodes to add to a structure addDefaults -- if True, adds default new structure addSpots -- if True, adds parent spot references """ super().__init__(None) # init TreeNode, with no formatRef self.nodeDict = {} self.undoList = None self.redoList = None self.configDialogFormats = None self.mathZeroBlanks = True self.childRefErrorNodes = [] if fileData: self.treeFormats = treeformats.TreeFormats(fileData['formats']) self.treeFormats.loadGlobalSavedConditions(fileData['properties']) for nodeInfo in fileData['nodes']: formatRef = self.treeFormats[nodeInfo['format']] node = treenode.TreeNode(formatRef, nodeInfo) self.nodeDict[node.uId] = node for node in self.nodeDict.values(): node.assignRefs(self.nodeDict) if node.tmpChildRefs: self.childRefErrorNodes.append(node) node.tmpChildRefs = [] for uId in fileData['properties']['topnodes']: node = self.nodeDict[uId] self.childList.append(node) if 'zeroblanks' in fileData['properties']: self.mathZeroBlanks = fileData['properties']['zeroblanks'] if addSpots: self.generateSpots(None) elif topNodes: self.childList = topNodes self.treeFormats = treeformats.TreeFormats() for topNode in topNodes: for node in topNode.descendantGen(): self.nodeDict[node.uId] = node self.treeFormats.addTypeIfMissing(node.formatRef) if addSpots: self.generateSpots(None) elif addDefaults: self.treeFormats = treeformats.TreeFormats(setDefault=True) node = treenode.TreeNode(self.treeFormats[treeformats. defaultTypeName]) node.setTitle(defaultRootTitle) self.nodeDict[node.uId] = node self.childList.append(node) if addSpots: self.generateSpots(None) else: self.treeFormats = treeformats.TreeFormats() self.fileInfoNode = treenode.TreeNode(self.treeFormats.fileInfoFormat)
def _put(self, key, val, current_node): if key < current_node.key: if current_node.has_left_child(): self._put(key, val, current_node.left_child) else: current_node.left_child = tn.TreeNode(key, val, parent=current_node) else: if current_node.has_right_child(): self._put(key, val, current_node.right_child) else: current_node.right_child = tn.TreeNode(key, val, parent=current_node)
def prune_tree(original_sub_tree, values_to_discard): ''' Returns a tree with any node whose label is in the list values_to_discard (and thus all of its children) pruned. This function should return a copy of the original tree and should not destructively modify the original tree. The pruning step must be recursive. Inputs: original_sub_tree: (TreeNode) a tree of type TreeNode whose internal counts have been computed. That is, compute_internal_counts() must have been run on this tree. values_to_discard: (list of strings) A list of strings specifying the labels of nodes to discard Returns: a new TreeNode representing the pruned tree ''' good_child_list = [] t = original_sub_tree if t.num_children() == 0: if t.label not in values_to_discard: return t for child in t.children: if child.label not in values_to_discard: good_child = prune_tree(child, values_to_discard) good_child_list.append(good_child) pruned_tree = treenode.TreeNode(t.label, None, good_child_list) return pruned_tree
def loadL5XNode(self, element, model, parent=None): """Recursively load a generic XML ElementTree node and its children. Arguments: element -- an XML ElementTree node model -- a ref to the TreeLine model parent -- the parent TreeNode (None for the root node only) """ elemFormat = model.formats.get(element.tag, None) if not elemFormat: elemFormat = nodeformat.NodeFormat(element.tag, model.formats) model.formats[element.tag] = elemFormat node = treenode.TreeNode(parent, elemFormat.name, model) if parent: parent.childList.append(node) elif model.root: raise ElementTree.ParseError # invalid with two roots else: model.root = node if element.text and element.text.strip(): if genericXmlTextFieldName not in elemFormat.fieldDict: elemFormat.addFieldList([genericXmlTextFieldName], True, True) node.setTitle(element.text.strip()) for key, value in element.items(): elemFormat.addFieldIfNew(key) node.data[key] = value for child in element: self.loadL5XNode(child, model, node)
def loadXmlNode(self, element, structure, parent=None): """Recursively load a generic XML ElementTree node and its children. Arguments: element -- an XML ElementTree node structure -- a ref to the TreeLine structure parent -- the parent TreeNode (None for the root node only) """ elemFormat = structure.treeFormats.get(element.tag, None) if not elemFormat: elemFormat = nodeformat.NodeFormat(element.tag, structure.treeFormats) structure.treeFormats[element.tag] = elemFormat node = treenode.TreeNode(elemFormat) structure.addNodeDictRef(node) if not parent: parent = structure parent.childList.append(node) if element.text and element.text.strip(): if genericXmlTextFieldName not in elemFormat.fieldDict: elemFormat.addFieldList([genericXmlTextFieldName], True, True) node.setTitle(element.text.strip()) for key, value in element.items(): elemFormat.addFieldIfNew(key) node.data[key] = value for child in element: self.loadXmlNode(child, structure, node)
def importTableText(self): """Import a file with a tab-delimited table with header row. Return the model if import is successful, otherwise None. """ model = treemodel.TreeModel(True) typeName = _('TABLE') tableFormat = nodeformat.NodeFormat(typeName, model.formats) model.formats.addTypeIfMissing(tableFormat) with open(self.filePath, 'r', encoding=globalref.localTextEncoding) as f: headings = [ self.correctFieldName(name) for name in f.readline().split('\t') ] tableFormat.addFieldList(headings, True, True) lineNum = 1 for line in f: lineNum += 1 if line.strip(): entries = line.split('\t') node = treenode.TreeNode(model.root, typeName, model) model.root.childList.append(node) try: for heading in headings: node.data[heading] = entries.pop(0) except IndexError: pass # fewer entries than headings is OK if entries: self.errorMessage = ( _('Too many entries on Line {0}').format(lineNum)) return None # abort if too few headings node.setUniqueId(True) return model
def _insert(self, data, curr_node): # If entry node < current node, add as left child if null, or recursively call method on left child if not null if data < curr_node.data: if curr_node.left is None: curr_node.left = treenode.TreeNode(data) else: self._insert(data, curr_node.left) # If entry node > current node, same as above but for right side of tree elif data > curr_node.data: if curr_node.right is None: curr_node.right = treenode.TreeNode(data) else: self._insert(data, curr_node.right) # Otherwise value equals current tree node, and we do not add it to avoid duplicates else: print("Value is already present in BST")
def mimeData(self, indexList): """Return a mime data object for the given node index branches. Arguments: indexList -- a list of node indexes to convert """ allNodes = [index.internalPointer() for index in indexList] nodes = [] # accept only nodes on top of unique branches for node in allNodes: parent = node.parent while parent and parent not in allNodes: parent = parent.parent if not parent: nodes.append(node) TreeModel.storedDragNodes = nodes TreeModel.storedDragModel = self dummyFormat = None if len(nodes) > 1: dummyFormat = self.formats.addDummyRootType() root = treenode.TreeNode(None, dummyFormat.name, self) for node in nodes: root.childList.append(copy.copy(node)) root.childList[-1].parent = root else: root = nodes[0] text = ElementTree.tostring( root.elementXml({dummyFormat}, True, False), 'utf-8') self.formats.removeDummyRootType() mime = QtCore.QMimeData() mime.setData('text/xml', text) return mime
def importTableTabbed(self): """Import a file with a tab-delimited table with header row. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure(addDefaults=True, addSpots=False) tableFormat = nodeformat.NodeFormat(_('TABLE'), structure.treeFormats) structure.treeFormats.addTypeIfMissing(tableFormat) with self.pathObj.open(encoding=globalref.localTextEncoding) as f: headings = [ self.correctFieldName(name) for name in f.readline().split('\t') ] tableFormat.addFieldList(headings, True, True) lineNum = 1 for line in f: lineNum += 1 if line.strip(): entries = line.split('\t') node = treenode.TreeNode(tableFormat) structure.childList[0].childList.append(node) structure.addNodeDictRef(node) try: for heading in headings: node.data[heading] = entries.pop(0) except IndexError: pass # fewer entries than headings is OK if entries: self.errorMessage = ( _('Too many entries on Line {0}').format(lineNum)) return None # abort if too few headings structure.generateSpots(None) return structure
def loadOldTreeLineNode(self, element, structure, idRefDict, linkList, parent=None): """Recursively load an old TreeLine ElementTree node and its children. Arguments: element -- an ElementTree node structure -- a ref to the new tree structure idRefDict -- a dict to relate old to new unique node IDs linkList -- internal link list ref with (node, fieldname) tuples parent -- the parent TreeNode (None for the root node only) """ try: typeFormat = structure.treeFormats[element.tag] except KeyError: formatData = self.convertOldNodeFormat(element.attrib) typeFormat = nodeformat.NodeFormat(element.tag, structure.treeFormats, formatData) structure.treeFormats[element.tag] = typeFormat self.treeLineOldFieldAttr[typeFormat.name] = {} if element.get('item') == 'y': node = treenode.TreeNode(typeFormat) oldId = element.attrib.get('uniqueid', '') if oldId: idRefDict[oldId] = node.uId if parent: parent.childList.append(node) else: structure.childList.append(node) structure.nodeDict[node.uId] = node cloneAttr = element.attrib.get('clones', '') if cloneAttr: for cloneId in cloneAttr.split(','): if cloneId in idRefDict: cloneNode = structure.nodeDict[idRefDict[cloneId]] node.data = cloneNode.data.copy() break else: # bare format (no nodes) node = None for child in element: if child.get('item') and node: self.loadOldTreeLineNode(child, structure, idRefDict, linkList, node) else: if node and child.text: node.data[child.tag] = child.text if child.get('linkcount'): linkList.append((node, child.tag)) if child.tag not in typeFormat.fieldDict: fieldData = self.convertOldFieldFormat(child.attrib) oldFormatDict = self.treeLineOldFieldAttr[typeFormat.name] oldFormatDict[child.tag] = fieldData typeFormat.addField(child.tag, fieldData)
def create_st(relevant_rows, hierarchy, hierarchy_labels, level_label): ''' Recursively creates subtrees ''' if len(hierarchy) == 0: # Return leaf node with count of relevant rows return treenode.TreeNode(level_label, count=relevant_rows["count"].sum()) else: curr_children = [] curr_level = hierarchy[0] hierarchy = list(hierarchy[1:]) for level_value in hierarchy_labels[curr_level]: curr_rows = relevant_rows[relevant_rows[curr_level] == level_value] curr_children.append( create_st(curr_rows, hierarchy, hierarchy_labels, level_value)) return treenode.TreeNode(level_label, children=curr_children)
def importOdfText(self): """Import an ODF format text file outline. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure(addDefaults=True, addSpots=False) structure.removeNodeDictRef(structure.childList[0]) structure.childList = [] odfFormat = structure.treeFormats[treeformats.defaultTypeName] odfFormat.addField(textFieldName) odfFormat.changeOutputLines([ '<b>{{*{0}*}}</b>'.format(nodeformat.defaultFieldName), '{{*{0}*}}'.format(textFieldName) ]) odfFormat.formatHtml = True try: with zipfile.ZipFile(str(self.pathObj), 'r') as f: text = f.read('content.xml') except (zipfile.BadZipFile, KeyError): return None try: rootElement = ElementTree.fromstring(text) except ElementTree.ParseError: return None nameSpace = '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}' headerTag = '{0}h'.format(nameSpace) paraTag = '{0}p'.format(nameSpace) numRegExp = re.compile(r'.*?(\d+)$') parents = [structure] prevLevel = 0 for elem in rootElement.iter(): if elem.tag == headerTag: style = elem.get('{0}style-name'.format(nameSpace), '') try: level = int(numRegExp.match(style).group(1)) except AttributeError: return None if level < 1 or level > prevLevel + 1: return None parents = parents[:level] node = treenode.TreeNode(odfFormat) structure.addNodeDictRef(node) parents[-1].childList.append(node) node.data[nodeformat.defaultFieldName] = ''.join( elem.itertext()) parents.append(node) prevLevel = level elif elem.tag == paraTag: text = ''.join(elem.itertext()) origText = node.data.get(textFieldName, '') if origText: text = '{0}<br />{1}'.format(origText, text) node.data[textFieldName] = text structure.generateSpots(None) return structure
def importOdfText(self): """Import an ODF format text file outline. Return the model if import is successful, otherwise None. """ model = treemodel.TreeModel(True) odfFormat = model.formats[treeformats.defaultTypeName] odfFormat.addField(textFieldName) odfFormat.changeOutputLines([ '<b>{{*{0}*}}</b>'.format(nodeformat.defaultFieldName), '{{*{0}*}}'.format(textFieldName) ]) odfFormat.formatHtml = True try: with zipfile.ZipFile(self.filePath, 'r') as f: text = f.read('content.xml') except (zipfile.BadZipFile, KeyError): return None try: rootElement = ElementTree.fromstring(text) except ElementTree.ParseError: return None nameSpace = '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}' headerTag = '{0}h'.format(nameSpace) paraTag = '{0}p'.format(nameSpace) numRegExp = re.compile(r'.*?(\d+)$') currentNode = model.root currentLevel = 0 for elem in rootElement.iter(): if elem.tag == headerTag: style = elem.get('{0}style-name'.format(nameSpace), '') try: level = int(numRegExp.match(style).group(1)) except AttributeError: return None if level < 1 or level > currentLevel + 1: return None while (currentLevel >= level): currentNode = currentNode.parent currentLevel -= 1 node = treenode.TreeNode(currentNode, odfFormat.name, model) currentNode.childList.append(node) node.data[nodeformat.defaultFieldName] = ''.join( elem.itertext()) node.setUniqueId(True) currentNode = node currentLevel = level elif elem.tag == paraTag: text = ''.join(elem.itertext()) origText = currentNode.data.get(textFieldName, '') if origText: text = '{0}<br />{1}'.format(origText, text) node.data[textFieldName] = text return model
def handle_starttag(self, tag, attrs): """Called by the reader at each open tag. Arguments: tag -- the tag label attrs -- any tag attributes """ if tag == 'dt' or tag == 'h1': # start any entry self.text = '' elif tag == 'dl': # start indent self.currentParent = self.currentNode self.currentNode = None elif tag == 'h3': # start folder if not self.currentParent: raise html.parser.HTMLParseError self.currentNode = treenode.TreeNode(self.currentParent, bookmarkFolderTypeName, self.model) self.currentParent.childList.append(self.currentNode) elif tag == 'a': # start link if not self.currentParent: raise html.parser.HTMLParseError self.currentNode = treenode.TreeNode(self.currentParent, bookmarkLinkTypeName, self.model) self.currentParent.childList.append(self.currentNode) for name, value in attrs: if name == 'href': link = '<a href="{0}">{0}</a>'.format(value) self.currentNode.data[bookmarkLinkFieldName] = link elif tag == 'hr': # separator if not self.currentParent: raise html.parser.HTMLParseError node = treenode.TreeNode(self.currentParent, bookmarkSeparatorTypeName, self.model) node.setUniqueId(True) self.currentParent.childList.append(node) self.currentNode = None
def handle_starttag(self, tag, attrs): """Called by the reader at each open tag. Arguments: tag -- the tag label attrs -- any tag attributes """ if tag == 'dt' or tag == 'h1': # start any entry self.text = '' elif tag == 'dl': # start indent self.parents.append(self.currentNode) self.currentNode = None elif tag == 'h3': # start folder if not self.parents: raise ValueError self.currentNode = treenode.TreeNode( self.structure.treeFormats[bookmarkFolderTypeName]) self.structure.addNodeDictRef(self.currentNode) self.parents[-1].childList.append(self.currentNode) elif tag == 'a': # start link if not self.parents: raise ValueError self.currentNode = treenode.TreeNode( self.structure.treeFormats[bookmarkLinkTypeName]) self.structure.addNodeDictRef(self.currentNode) self.parents[-1].childList.append(self.currentNode) for name, value in attrs: if name == 'href': link = '<a href="{0}">{0}</a>'.format(value) self.currentNode.data[bookmarkLinkFieldName] = link elif tag == 'hr': # separator if not self.parents: raise ValueError node = treenode.TreeNode( self.structure.treeFormats[bookmarkSeparatorTypeName]) self.structure.addNodeDictRef(node) self.parents[-1].childList.append(node) self.currentNode = None
def __init__(self, model): """Initialize the HTML parser object. Arguments: model -- a reference to the tree model """ super().__init__() self.model = model self.model.root = treenode.TreeNode(None, bookmarkFolderTypeName, self.model) self.model.root.data[nodeformat.defaultFieldName] = _('Bookmarks') self.currentNode = self.model.root self.currentParent = None self.text = ''
def importTableCsvLevels(self): """Import a CSV-delimited table file with level column, header row. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure(addSpots=False) tableFormat = nodeformat.NodeFormat(_('TABLE'), structure.treeFormats) structure.treeFormats.addTypeIfMissing(tableFormat) nodeList = [] with self.pathObj.open(newline='', encoding=globalref.localTextEncoding) as f: reader = csv.reader(f) try: headings = [ self.correctFieldName(name) for name in next(reader) ][1:] tableFormat.addFieldList(headings, True, True) for entries in reader: if entries: node = treenode.TreeNode(tableFormat) structure.addNodeDictRef(node) try: level = int(entries.pop(0)) except ValueError: self.errorMessage = (_('Invalid level number on ' 'line {0}').format( reader.line_num)) return None # abort nodeList.append((node, level)) try: for heading in headings: node.data[heading] = entries.pop(0) except IndexError: pass # fewer entries than headings is OK if entries: self.errorMessage = (_('Too many entries on ' 'Line {0}').format( reader.line_num)) return None # abort if too few headings except csv.Error: self.errorMessage = (_('Bad CSV format on Line {0}').format( reader.line_num)) return None # abort if nodeList: if structure.loadChildNodeLevels(nodeList): structure.generateSpots(None) return structure self.errorMessage = (_('Invalid level structure')) return None
def importTreePad(self): """Import a Treepad file, text nodes only. Return the model if import is successful, otherwise None. """ structure = treestructure.TreeStructure(addDefaults=True, addSpots=False) structure.removeNodeDictRef(structure.childList[0]) structure.childList = [] tpFormat = structure.treeFormats[treeformats.defaultTypeName] tpFormat.addFieldList([textFieldName], False, True) tpFormat.fieldDict[textFieldName].changeType('SpacedText') try: with self.pathObj.open(encoding=globalref.localTextEncoding) as f: textList = f.read().split('<end node> 5P9i0s8y19Z') except UnicodeDecodeError: with self.pathObj.open(encoding='latin-1') as f: textList = f.read().split('<end node> 5P9i0s8y19Z') except UnicodeDecodeError: return None nodeList = [] for text in textList: text = text.strip() if text: try: text = text.split('<node>', 1)[1].lstrip() lines = text.split('\n') title = lines[0] level = int(lines[1]) lines = lines[2:] except (ValueError, IndexError): return None node = treenode.TreeNode(tpFormat) node.data[nodeformat.defaultFieldName] = title node.data[textFieldName] = '\n'.join(lines) node.level = level nodeList.append(node) structure.addNodeDictRef(node) parentList = [] for node in nodeList: if node.level != 0: parentList = parentList[:node.level] node.parent = parentList[-1] parentList[-1].childList.append(node) parentList.append(node) structure.childList = [nodeList[0]] structure.generateSpots(None) return structure
def __init__(self, structure): """Initialize the HTML parser object. Arguments: structure -- a reference to the tree structure """ super().__init__() self.structure = structure rootNode = treenode.TreeNode( self.structure.treeFormats[bookmarkFolderTypeName]) rootNode.data[nodeformat.defaultFieldName] = _('Bookmarks') self.structure.addNodeDictRef(rootNode) self.structure.childList = [rootNode] self.currentNode = rootNode self.parents = [] self.text = ''
def importTextLines(self): """Import a text file, creating one node per line. Return the model if import is successful, otherwise None. """ model = treemodel.TreeModel(True) with open(self.filePath, 'r', encoding=globalref.localTextEncoding) as f: for line in f: line = line.strip() if line: node = treenode.TreeNode(model.root, model.root.formatName, model) model.root.childList.append(node) node.data[nodeformat.defaultFieldName] = line node.setUniqueId(True) return model
def exportHtmlPages(self, filePath=''): """Export multiple web pages with navigation, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: filePath -- use if given, otherwise prompt user """ if not filePath: filePath = QtGui.QFileDialog.getExistingDirectory( QtGui.QApplication.activeWindow(), _('TreeLine - Export HTML'), self.defaultFilePath) if not filePath: return False QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) oldDir = os.getcwd() os.chdir(filePath) indent = globalref.genOptions.getValue('IndentOffset') cssLines = [ '#sidebar {', ' width: 16em;', ' float: left;', ' border-right: 1px solid black;', '}', '#sidebar div {{margin-left: {0}em;}}'.format(indent), '#content {', ' margin-left: 16em;', ' border-left: 1px solid black;', ' padding-left: 6px;', '}' ] with open('default.css', 'w', encoding='utf-8') as f: f.writelines([(line + '\n') for line in cssLines]) if ExportDialog.exportWhat == ExportDialog.entireTree: self.selectedNodes = [self.rootNode] if len(self.selectedNodes) > 1: modelRef = self.selectedNodes[0].modelRef dummyFormat = modelRef.formats.addDummyRootType() root = treenode.TreeNode(None, dummyFormat.name, modelRef) name = os.path.basename(self.defaultFilePath) if not name: name = treemodel.defaultRootName root.setTitle(name) for node in self.selectedNodes: root.childList.append(copy.copy(node)) root.childList[-1].parent = root else: root = self.selectedNodes[0] root.exportHtmlPage() root.modelRef.formats.removeDummyRootType() os.chdir(oldDir) return True
def importTextPara(self): """Import a text file, creating one node per paragraph. Blank line delimited. Return the model if import is successful, otherwise None. """ model = treemodel.TreeModel(True) with open(self.filePath, 'r', encoding=globalref.localTextEncoding) as f: text = f.read() paraList = text.split('\n\n') for para in paraList: para = para.strip() if para: node = treenode.TreeNode(model.root, model.root.formatName, model) model.root.childList.append(node) node.data[nodeformat.defaultFieldName] = para node.setUniqueId(True) return model
def importTextLines(self): """Import a text file, creating one node per line. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure(addDefaults=True, addSpots=False) nodeFormat = structure.childList[0].formatRef structure.removeNodeDictRef(structure.childList[0]) structure.childList = [] with self.pathObj.open(encoding=globalref.localTextEncoding) as f: for line in f: line = line.strip() if line: node = treenode.TreeNode(nodeFormat) structure.childList.append(node) structure.addNodeDictRef(node) node.data[nodeformat.defaultFieldName] = line structure.generateSpots(None) return structure
def loadNode(self, element, parent=None): """Recursively load an ElementTree node and its children. Arguments: element -- an ElementTree node parent -- the parent TreeNode (None for the root node only) """ try: typeFormat = self.model.formats[element.tag] except KeyError: typeFormat = nodeformat.NodeFormat(element.tag, self.model.formats, element.attrib) self.model.formats[element.tag] = typeFormat if element.get('item') == 'y': node = treenode.TreeNode(parent, element.tag, self.model, element.attrib) if parent: parent.childList.append(node) else: self.model.root = node else: # bare format (no nodes) node = None for child in element: if child.get('item') and node: self.loadNode(child, node) else: if node and child.text: node.data[child.tag] = child.text if child.get('linkcount'): self.model.linkRefCollect.searchForLinks(node, child.tag) typeFormat.addFieldIfNew(child.tag, child.attrib) if node and typeFormat.fieldDict: try: node.setUniqueId() except ValueError: oldId = node.uniqueId node.setUniqueId(True) self.duplicateIdList.append('{0} -> {1}'.format(oldId, node.uniqueId))
def importTreePad(self): """Import a Treepad file, text nodes only. Return the model if import is successful, otherwise None. """ model = treemodel.TreeModel(True) tpFormat = model.formats[treeformats.defaultTypeName] tpFormat.addFieldList([textFieldName], False, True) tpFormat.fieldDict[textFieldName].changeType('SpacedText') with open(self.filePath, 'r', encoding=globalref.localTextEncoding) as f: textList = f.read().split('<end node> 5P9i0s8y19Z') nodeList = [] for text in textList: text = text.strip() if text: try: text = text.split('<node>', 1)[1].lstrip() lines = text.split('\n') title = lines[0] level = int(lines[1]) lines = lines[2:] except (ValueError, IndexError): return None node = treenode.TreeNode(None, tpFormat.name, model) node.data[nodeformat.defaultFieldName] = title node.data[textFieldName] = '\n'.join(lines) node.level = level node.setUniqueId(True) nodeList.append(node) parentList = [] for node in nodeList: if node.level != 0: parentList = parentList[:node.level] node.parent = parentList[-1] parentList[-1].childList.append(node) parentList.append(node) model.root = nodeList[0] return model
def importTableCsv(self): """Import a file with a CSV-delimited table with header row. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure(addDefaults=True, addSpots=False) tableFormat = nodeformat.NodeFormat(_('TABLE'), structure.treeFormats) structure.treeFormats.addTypeIfMissing(tableFormat) with self.pathObj.open(newline='', encoding=globalref.localTextEncoding) as f: reader = csv.reader(f) try: headings = [ self.correctFieldName(name) for name in next(reader) ] tableFormat.addFieldList(headings, True, True) for entries in reader: if entries: node = treenode.TreeNode(tableFormat) structure.childList[0].childList.append(node) structure.addNodeDictRef(node) try: for heading in headings: node.data[heading] = entries.pop(0) except IndexError: pass # fewer entries than headings is OK if entries: self.errorMessage = (_('Too many entries on ' 'Line {0}').format( reader.line_num)) return None # abort if too few headings except csv.Error: self.errorMessage = (_('Bad CSV format on Line {0}').format( reader.line_num)) return None # abort structure.generateSpots(None) return structure
def exportXmlSubtree(self, filePath=''): """Export TreeLine subtree, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: filePath -- use if given, otherwise prompt user """ if not filePath: filePath = self.getFileName( _('TreeLine - Export TreeLine ' 'Subtree'), 'trl') if not filePath: return False QtGui.QApplication.setOverrideCursor(QtCore.Qt.WaitCursor) if ExportDialog.exportWhat == ExportDialog.entireTree: self.selectedNodes = [self.rootNode] addBranches = ExportDialog.exportWhat != ExportDialog.selectNode if len(self.selectedNodes) > 1: modelRef = self.selectedNodes[0].modelRef dummyFormat = modelRef.formats.addDummyRootType() root = treenode.TreeNode(None, dummyFormat.name, modelRef) name = os.path.basename(self.defaultFilePath) if not name: name = treemodel.defaultRootName root.setTitle(name) for node in self.selectedNodes: root.childList.append(copy.copy(node)) root.childList[-1].parent = root else: root = self.selectedNodes[0] rootElement = root.elementXml(addChildren=addBranches) rootElement.attrib.update( globalref.mainControl.activeControl.printData.xmlAttr()) elementTree = ElementTree.ElementTree(rootElement) elementTree.write(filePath, 'utf-8', True) root.modelRef.formats.removeDummyRootType() return True