Example #1
0
 def handle_starttag(self, tag, attrs):
     """Called by the reader at each open tag"""
     if tag == 'dt' or tag == 'h1':  # start any entry
         self.text = ''
     elif tag == 'dl':  # start indent
         self.currentParent = self.currentItem
         self.currentItem = None
     elif tag == 'h3':  # start folder
         if not self.currentParent:
             raise HtmlParseError, 'No valid parent folder'
         self.currentItem = TreeItem(self.currentParent,
                                     self.folderFormat.name)
         self.currentParent.childList.append(self.currentItem)
     elif tag == 'a':  # start link
         if not self.currentParent:
             raise HtmlParseError, 'No valid parent folder'
         self.currentItem = TreeItem(self.currentParent,
                                     self.bookmarkFormat.name)
         self.currentParent.childList.append(self.currentItem)
         for name, value in attrs:
             if name == 'href':
                 self.currentItem.data[TreeFormats.linkFieldName] = value
     elif tag == 'hr':  # separator
         if not self.currentParent:
             raise HtmlParseError, 'No valid parent folder'
         item = TreeItem(self.currentParent, self.separatorFormat.name)
         self.currentParent.childList.append(item)
         self.currentItem = None
Example #2
0
 def readLines(self, fileRef, errors='strict'):
     """Import plain text, node per line"""
     try:
         f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                    errors)
         filePath = unicode(f.name, sys.getfilesystemencoding())
         textList = f.readlines()
     except UnicodeError:
         print 'Warning - bad unicode characters were replaced'
         if errors == 'strict':
             self.readLines(fileRef, 'replace')
         else:
             f.close()
         return
     f.close()
     self.treeFormats = TreeFormats({}, True)  # set defaults ROOT & DEFAULT
     newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
     defaultFormat = self.treeFormats[TreeFormats.formatDefault]
     defaultFormat.fieldList = []
     defaultFormat.lineList = []
     defaultFormat.addTableFields([TreeFormats.textFieldName])
     newRoot.setTitle(TreeDoc.rootTitleDefault)
     for line in textList:
         line = line.strip()
         if line:
             newItem = TreeItem(newRoot, TreeFormats.formatDefault)
             newRoot.childList.append(newItem)
             newItem.data[TreeFormats.textFieldName] = line
     self.root = newRoot
     self.fileName = filePath
Example #3
0
 def readLines(self, fileRef, errors='strict'):
     """Import plain text, node per line"""
     try:
         f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                    errors)
         filePath = unicode(f.name, sys.getfilesystemencoding())
         textList = f.readlines()
     except UnicodeError:
         print 'Warning - bad unicode characters were replaced'
         if errors == 'strict':
             self.readLines(fileRef, 'replace')
         else:
             f.close()
         return
     f.close()
     self.treeFormats = TreeFormats({}, True)  # set defaults ROOT & DEFAULT
     newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
     defaultFormat = self.treeFormats[TreeFormats.formatDefault]
     defaultFormat.fieldList = []
     defaultFormat.lineList = []
     defaultFormat.addTableFields([TreeFormats.textFieldName])
     newRoot.setTitle(TreeDoc.rootTitleDefault)
     for line in textList:
         line = line.strip()
         if line:
             newItem = TreeItem(newRoot, TreeFormats.formatDefault)
             newRoot.childList.append(newItem)
             newItem.data[TreeFormats.textFieldName] = line
     self.root = newRoot
     self.fileName = filePath
Example #4
0
 def readPara(self, fileRef, errors='strict'):
     """Import plain text, blank line delimitted"""
     try:
         f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                    errors)
         filePath = unicode(f.name, sys.getfilesystemencoding())
         fullText = f.read().replace('\r', '')
     except UnicodeError:
         print 'Warning - bad unicode characters were replaced'
         if errors == 'strict':
             self.readPara(fileRef, 'replace')
         else:
             f.close()
         return
     textList = fullText.split('\n\n')
     f.close()
     self.treeFormats = TreeFormats({}, True)  # set defaults ROOT & DEFAULT
     newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
     defaultFormat = self.treeFormats[TreeFormats.formatDefault]
     defaultFormat.fieldList = []
     defaultFormat.lineList = []
     defaultFormat.iconName = 'doc'
     defaultFormat.addTableFields([TreeFormats.textFieldName])
     defaultFormat.fieldList[0].numLines = globalref.options.\
                                            intData('MaxEditLines', 1,
                                                 optiondefaults.maxNumLines)
     newRoot.setTitle(TreeDoc.rootTitleDefault)
     for line in textList:
         line = line.strip()
         if line:
             newItem = TreeItem(newRoot, TreeFormats.formatDefault)
             newRoot.childList.append(newItem)
             newItem.data[TreeFormats.textFieldName] = line
     self.root = newRoot
     self.fileName = filePath
Example #5
0
 def readTable(self, fileRef, errors='strict'):
     """Import table data into a flat tree - raise exception on failure"""
     try:
         f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                    errors)
         filePath = unicode(f.name, sys.getfilesystemencoding())
         textList = f.readlines()
     except UnicodeError:
         print 'Warning - bad unicode characters were replaced'
         if errors == 'strict':
             self.readTable(fileRef, 'replace')
         else:
             f.close()
         return
     f.close()
     self.treeFormats = TreeFormats({}, True)  # set defaults ROOT & DEFAULT
     newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
     defaultFormat = self.treeFormats[TreeFormats.formatDefault]
     defaultFormat.fieldList = []
     defaultFormat.lineList = []
     defaultFormat.addTableFields(textList.pop(0).strip().split('\t'))
     newRoot.setTitle(TreeDoc.rootTitleDefault)
     for line in textList:
         newItem = TreeItem(newRoot, TreeFormats.formatDefault)
         newRoot.childList.append(newItem)
         lineList = line.strip().split('\t')
         try:
             for num in range(len(lineList)):
                 newItem.data[self.treeFormats[TreeFormats.formatDefault].
                         fieldList[num].name] = lineList[num].strip()
         except IndexError:
             print 'Too few headings to read data as a table'
             raise ReadFileError(_('Too few headings to read data as table'))
     self.root = newRoot
     self.fileName = filePath
Example #6
0
 def exportDirPage(self, dirName, nodeList):
     """Write tree to nested direct struct with html page for each node"""
     oldDir = os.getcwd()
     os.chdir(dirName.encode(sys.getfilesystemencoding()))
     cssLines = ['#sidebar {', 'width: 16em;', 'float: left;',
                 'clear: left;', 'border-right: 1px solid black;',
                 'margin-right: 1em;', '}']
     try:
         f = codecs.open('default.css', 'w', 'utf-8')
         f.writelines([(line + '\n').encode('utf-8') for line in cssLines])
     except (IOError, UnicodeError):
         print 'Error - could not write file to default.css'
         raise IOError(_('Error - cannot write file to %s') % 'default.css')
     f.close()
     if len(nodeList) > 1:
         self.treeFormats.addIfMissing(TreeDoc.copyFormat)
         item = TreeItem(None, TreeDoc.copyFormat.name)
         item.data[TreeFormats.fieldDefault] = TreeDoc.rootTitleDefault
         for child in nodeList:
             item.childList.append(child)
             child.parent = item
     else:
         item = nodeList[0]
     linkDict = {}
     item.createDirPageLinkDict(linkDict, os.getcwd())
     item.exportDirPage(linkDict)
     self.treeFormats.removeQuiet(TreeDoc.copyFormat)
     os.chdir(oldDir)
Example #7
0
 def exportTrlSubtree(self, fileRef, nodeList, addBranches=True):
     """Write subtree TRL file starting form item"""
     lines = [u'<?xml version="1.0" encoding="utf-8" ?>']
     if self.xlstLink:
         lines.append(u'<?%s?>' % self.xlstLink)
     if not addBranches:
         newList = []
         for item in nodeList:  # replace items with childless items
             newItem = TreeItem(item.parent, item.formatName)
             newItem.data = item.data
             newList.append(newItem)
         nodeList = newList
     if len(nodeList) > 1:
         format = nodeformat.NodeFormat(TreeFormats.rootFormatDefault, {},
                                        TreeFormats.fieldDefault)
         self.treeFormats.addIfMissing(format)
         item = TreeItem(None, format.name)
         item.data[TreeFormats.fieldDefault] = TreeDoc.rootTitleDefault
         for child in nodeList:
             item.childList.append(child)
             child.parent = item
     else:
         item = nodeList[0]
     lines.extend(item.branchXml([], True))
     try:
         f = self.getWriteFileObj(fileRef, self.compressFile)
         f.writelines([(line + '\n').encode('utf-8') for line in lines])
     except IOError:
         print 'Error - could not write file'
         self.treeFormats.removeQuiet(TreeDoc.copyFormat)
         raise
     f.close()
     self.treeFormats.removeQuiet(TreeDoc.copyFormat)
Example #8
0
 def readTabbed(self, fileRef, errors='strict'):
     """Import tabbed data into a flat tree - raise exception on failure"""
     try:
         f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                    errors)
         filePath = unicode(f.name, sys.getfilesystemencoding())
         textList = f.readlines()
     except UnicodeError:
         print 'Warning - bad unicode characters were replaced'
         if errors == 'strict':
             self.readTabbed(fileRef, 'replace')
         else:
             f.close()
         return
     f.close()
     bufList = [(text.count('\t', 0, len(text) - len(text.lstrip())),
                 text.strip()) for text in textList if text.strip()]
     if bufList:
         buf = bufList.pop(0)
         if buf[0] == 0:
             # set default formats ROOT & DEFAULT
             self.treeFormats = TreeFormats({}, True)
             newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
             newRoot.setTitle(buf[1])
             if newRoot.loadTabbedChildren(bufList):
                 self.root = newRoot
                 self.fileName = filePath
                 return
     raise ReadFileError(_('Error in tabbed list'))
 def startElement(self, name, attrs):
     """Called by the reader at the open tag of each element"""
     if name == u'folder' or name == u'xbel':
         newItem = TreeItem(self.currentItem, self.folderFormat.name)
         if self.currentItem:
             self.currentItem.childList.append(newItem)
         else:
             self.rootItem = newItem
         if attrs.get(u'folded', '') == 'no':
             newItem.open = True
         self.currentItem = newItem
     elif name == u'bookmark':
         newItem = TreeItem(self.currentItem, self.bookmarkFormat.name)
         if self.currentItem:
             self.currentItem.childList.append(newItem)
         else:
             raise xml.sax.SAXException, 'No valid parent folder'
         newItem.data[TreeFormats.linkFieldName] = attrs.get(u'href', '')
         self.currentItem = newItem
     elif name == u'title':
         self.text = ''
     elif name == u'separator':
         newItem = TreeItem(self.currentItem, self.separatorFormat.name)
         if self.currentItem:
             self.currentItem.childList.append(newItem)
         else:
             raise xml.sax.SAXException, 'No valid parent folder'
         self.currentItem = newItem
     else:   # unsupported tags
         pass
Example #10
0
 def readPara(self, fileRef, errors='strict'):
     """Import plain text, blank line delimitted"""
     try:
         f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                    errors)
         filePath = unicode(f.name, sys.getfilesystemencoding())
         fullText = f.read().replace('\r', '')
     except UnicodeError:
         print 'Warning - bad unicode characters were replaced'
         if errors == 'strict':
             self.readPara(fileRef, 'replace')
         else:
             f.close()
         return
     textList = fullText.split('\n\n')
     f.close()
     self.treeFormats = TreeFormats({}, True)  # set defaults ROOT & DEFAULT
     newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
     defaultFormat = self.treeFormats[TreeFormats.formatDefault]
     defaultFormat.fieldList = []
     defaultFormat.lineList = []
     defaultFormat.iconName = 'doc'
     defaultFormat.addTableFields([TreeFormats.textFieldName])
     defaultFormat.fieldList[0].numLines = globalref.options.\
                                            intData('MaxEditLines', 1,
                                                 optiondefaults.maxNumLines)
     newRoot.setTitle(TreeDoc.rootTitleDefault)
     for line in textList:
         line = line.strip()
         if line:
             newItem = TreeItem(newRoot, TreeFormats.formatDefault)
             newRoot.childList.append(newItem)
             newItem.data[TreeFormats.textFieldName] = line
     self.root = newRoot
     self.fileName = filePath
Example #11
0
 def readTabbed(self, fileRef, errors='strict'):
     """Import tabbed data into a flat tree - raise exception on failure"""
     try:
         f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                    errors)
         filePath = unicode(f.name, sys.getfilesystemencoding())
         textList = f.readlines()
     except UnicodeError:
         print 'Warning - bad unicode characters were replaced'
         if errors == 'strict':
             self.readTabbed(fileRef, 'replace')
         else:
             f.close()
         return
     f.close()
     bufList = [(text.count('\t', 0,
                            len(text) - len(text.lstrip())), text.strip())
                for text in textList if text.strip()]
     if bufList:
         buf = bufList.pop(0)
         if buf[0] == 0:
             # set default formats ROOT & DEFAULT
             self.treeFormats = TreeFormats({}, True)
             newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
             newRoot.setTitle(buf[1])
             if newRoot.loadTabbedChildren(bufList):
                 self.root = newRoot
                 self.fileName = filePath
                 return
     raise ReadFileError(_('Error in tabbed list'))
Example #12
0
    def __init__(self, headers, data, parent=None) -> None:
        super(TreeModel, self).__init__(parent)

        rootData = []
        for header in headers:
            rootData.append(header)

        self._rootItem = TreeItem(rootData)
Example #13
0
    def __init__(self, headers, data, tablemodel, parent=None):
        super(TreeModel, self).__init__(parent)

        rootData = [header for header in headers]
        self.rootItem = TreeItem(rootData)
        self.treeDict = data
        self.tablemodel = tablemodel
        self.setupModelData(data, self.rootItem)
        self.examingParents = False
        self.examiningChildren = False
Example #14
0
 def readTreepad(self, fileRef, errors='strict'):
     """Read Treepad text-node file"""
     try:
         f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                    errors)
         filePath = unicode(f.name, sys.getfilesystemencoding())
         textList = f.read().split('<end node> 5P9i0s8y19Z')
         f.close()
     except UnicodeError:  # error common - broken unicode on windows
         print 'Warning - bad unicode characters were replaced'
         if errors == 'strict':
             self.readTreepad(fileRef, 'replace')
         else:
             f.close()
         return
     self.treeFormats = TreeFormats()
     format = nodeformat.NodeFormat(TreeFormats.formatDefault)
     titleFieldName = _('Title', 'title field name')
     format.addNewField(titleFieldName)
     format.addLine(u'{*%s*}' % titleFieldName)
     numLines = globalref.options.intData('MaxEditLines', 1,
                                          optiondefaults.maxNumLines)
     format.addNewField(TreeFormats.textFieldName,
                        {'lines': repr(numLines)})
     format.addLine(u'{*%s*}' % TreeFormats.textFieldName)
     self.treeFormats[format.name] = format
     itemList = []
     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):
                 print 'Error - bad file format in %s' % \
                       filePath.encode(globalref.localTextEncoding)
                 raise ReadFileError(_('Bad file format in %s') % filePath)
             item = TreeItem(None, format.name)
             item.data[titleFieldName] = title
             item.data[TreeFormats.textFieldName] = '\n'.join(lines)
             item.level = level
             itemList.append(item)
     self.root = itemList[0]
     parentList = []
     for item in itemList:
         if item.level != 0:
             parentList = parentList[:item.level]
             item.parent = parentList[-1]
             parentList[-1].childList.append(item)
         parentList.append(item)
     self.root = itemList[0]
     self.fileName = filePath
Example #15
0
 def readTreepad(self, fileRef, errors='strict'):
     """Read Treepad text-node file"""
     try:
         f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                    errors)
         filePath = unicode(f.name, sys.getfilesystemencoding())
         textList = f.read().split('<end node> 5P9i0s8y19Z')
         f.close()
     except UnicodeError:  # error common - broken unicode on windows
         print 'Warning - bad unicode characters were replaced'
         if errors == 'strict':
             self.readTreepad(fileRef, 'replace')
         else:
             f.close()
         return
     self.treeFormats = TreeFormats()
     format = nodeformat.NodeFormat(TreeFormats.formatDefault)
     titleFieldName = _('Title', 'title field name')
     format.addNewField(titleFieldName)
     format.addLine(u'{*%s*}' % titleFieldName)
     numLines = globalref.options.intData('MaxEditLines', 1,
                                          optiondefaults.maxNumLines)
     format.addNewField(TreeFormats.textFieldName,
                        {'lines': repr(numLines)})
     format.addLine(u'{*%s*}' % TreeFormats.textFieldName)
     self.treeFormats[format.name] = format
     itemList = []
     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):
                 print 'Error - bad file format in %s' % \
                       filePath.encode(globalref.localTextEncoding)
                 raise ReadFileError(_('Bad file format in %s') % filePath)
             item = TreeItem(None, format.name)
             item.data[titleFieldName] = title
             item.data[TreeFormats.textFieldName] = '\n'.join(lines)
             item.level = level
             itemList.append(item)
     self.root = itemList[0]
     parentList = []
     for item in itemList:
         if item.level != 0:
             parentList = parentList[:item.level]
             item.parent = parentList[-1]
             parentList[-1].childList.append(item)
         parentList.append(item)
     self.root = itemList[0]
     self.fileName = filePath
 def __set_card_treeview_status(self):
     card_list = []
     cards = pypulse.PULSE.get_cards()
     for idx in cards:
         active_profile = cards[idx]['active_profile']
         if active_profile:
             if active_profile['n_sinks'] > 1:
                 io_num = _("%d Outputs") % active_profile['n_sinks']
             else:
                 io_num = _("%d Output") % active_profile['n_sinks']
             if active_profile['n_sources'] > 1:
                 io_num += " / " + _("%d Inputs") % active_profile['n_sources']
             else:
                 io_num += " / " + _("%d Input") % active_profile['n_sources']
             if 'device.description' in cards[idx]['proplist']:
                 description = cards[idx]['proplist']['device.description'].strip('\x00')
             else:
                 description = ""
             card_info = "%s(%s)[%s]" % (description, io_num, active_profile['description'])
         else:
             if 'device.description' in cards[idx]['proplist']:
                 card_info = cards[idx]['proplist']['device.description']
             else:
                 card_info = " "
         card_list.append(TreeItem(self.image_widgets["device"], card_info, cards[idx]['name'], idx))
     self.view_widgets["ad_hardware"].add_items(card_list, clear_first=True)
     if card_list:
         self.view_widgets["ad_hardware"].set_select_rows([0])
Example #17
0
 def readOdf(self, fileRef):
     """Read an Open Document Format (ODF) file"""
     self.treeFormats = TreeFormats(None, True)
     rootItem = TreeItem(None, TreeFormats.rootFormatDefault,
                         TreeDoc.rootTitleDefault)
     defaultFormat = self.treeFormats[TreeFormats.formatDefault]
     defaultFormat.addNewField(TreeFormats.textFieldName, {
         u'html': 'n',
         u'lines': '6'
     })
     defaultFormat.changeOutputLines([
         u'<b>{*%s*}</b>' % TreeFormats.fieldDefault,
         u'{*%s*}' % TreeFormats.textFieldName
     ])
     try:
         f = self.getReadFileObj(fileRef)
         filePath = unicode(f.name, sys.getfilesystemencoding())
         zip = zipfile.ZipFile(f, 'r')
         text = zip.read('content.xml')
         handler = treexmlparse.OdfSaxHandler(rootItem, defaultFormat)
         xml.sax.parseString(text, handler)
     except (zipfile.BadZipfile, KeyError):
         f.close()
         raise ReadFileError(_('Could not unzip ODF file'))
     except UnicodeError:
         f.close()
         raise ReadFileError(_('Problem with Unicode characters in file'))
     except xml.sax.SAXException:
         f.close()
         raise ReadFileError(_('Could not open corrupt ODF file'))
     f.close()
     self.root = rootItem
     self.fileName = filePath
Example #18
0
 def startElement(self, name, attrs):
     """Called by the reader at the open tag of each element"""
     format = self.formats.get(name, None)
     if not format:
         format = nodeformat.NodeFormat(name)
         self.formats[name] = format
     newItem = TreeItem(self.currentItem, name)
     if self.currentItem:
         self.currentItem.childList.append(newItem)
     elif self.rootItem:
         raise xml.sax.SAXException, 'Invalid XML file'
     else:
         self.rootItem = newItem
     self.currentItem = newItem
     for key in attrs.keys():
         format.addFieldIfNew(key)
         newItem.data[key] = attrs[key]
Example #19
0
 def startElement(self, name, attrs):
     """Called by the reader at the open tag of each element"""
     format = self.formats.get(name, None)
     if not format:
         format = nodeformat.NodeFormat(name)
         self.formats[name] = format
     newItem = TreeItem(self.currentItem, name)
     if self.currentItem:
         self.currentItem.childList.append(newItem)
     elif self.rootItem:
         raise xml.sax.SAXException, 'Invalid XML file'
     else:
         self.rootItem = newItem
     self.currentItem = newItem
     for key in attrs.keys():
         format.addFieldIfNew(key)
         newItem.data[key] = attrs[key]
Example #20
0
 def startElement(self, name, attrs):
     """Called by the reader at the open tag of each element"""
     if name == u'folder' or name == u'xbel':
         newItem = TreeItem(self.currentItem, self.folderFormat.name)
         if self.currentItem:
             self.currentItem.childList.append(newItem)
         else:
             self.rootItem = newItem
         if attrs.get(u'folded', '') == 'no':
             newItem.open = True
         self.currentItem = newItem
     elif name == u'bookmark':
         newItem = TreeItem(self.currentItem, self.bookmarkFormat.name)
         if self.currentItem:
             self.currentItem.childList.append(newItem)
         else:
             raise xml.sax.SAXException, 'No valid parent folder'
         newItem.data[TreeFormats.linkFieldName] = attrs.get(u'href', '')
         self.currentItem = newItem
     elif name == u'title':
         self.text = ''
     elif name == u'separator':
         newItem = TreeItem(self.currentItem, self.separatorFormat.name)
         if self.currentItem:
             self.currentItem.childList.append(newItem)
         else:
             raise xml.sax.SAXException, 'No valid parent folder'
         self.currentItem = newItem
     else:  # unsupported tags
         pass
Example #21
0
 def __init__(self, folderFormat, bookmarkFormat, separatorFormat):
     HTMLParser.HTMLParser.__init__(self)
     self.folderFormat = folderFormat
     self.bookmarkFormat = bookmarkFormat
     self.separatorFormat = separatorFormat
     self.rootItem = TreeItem(None, self.folderFormat.name)
     self.rootItem.data[TreeFormats.fieldDefault] = _('Bookmarks')
     self.currentItem = self.rootItem
     self.currentParent = None
     self.text = ''
Example #22
0
 def __init__(self, filePath=None, setNewDefaults=False, importType=None):
     """Open filePath (can also be file ref) if given,
        setNewDefaults uses user defaults for compression & encryption,
        importType gives an import method to read the file"""
     globalref.docRef = self
     self.root = None
     self.treeFormats = TreeFormats()
     self.fileInfoItem = TreeItem(None, nodeformat.FileInfoFormat.name)
     self.fileInfoFormat = None
     TreeDoc.copyFormat = nodeformat.NodeFormat('_DUMMY__ROOT_', {},
                                                TreeFormats.fieldDefault)
     self.undoStore = undo.UndoRedoStore()
     self.redoStore = undo.UndoRedoStore()
     self.sortFields = ['']
     self.fileName = ''
     self.spaceBetween = True
     self.lineBreaks = True
     self.formHtml = True
     self.childFieldSep = TreeDoc.childFieldSepDflt
     self.spellChkLang = ''
     self.xlstLink = ''
     self.xslCssLink = ''
     self.tlVersion = __version__
     self.fileInfoFormat = nodeformat.FileInfoFormat()
     if filePath:
         if importType:
             getattr(self, importType)(filePath)
         else:
             self.readFile(filePath)
     else:
         self.treeFormats = TreeFormats({}, True)
         self.root = TreeItem(None, TreeFormats.rootFormatDefault)
         self.root.setTitle(TreeDoc.rootTitleDefault)
     self.modified = False
     if setNewDefaults or not hasattr(self, 'compressFile'):
         self.compressFile = globalref.options.boolData('CompressNewFiles')
         self.encryptFile = globalref.options.boolData('EncryptNewFiles')
     elif not hasattr(self, 'encryptFile'):
         self.encryptFile = False
     self.selection = treeselection.TreeSelection([self.root])
     self.fileInfoFormat.translateFields()
     self.fileInfoFormat.updateFileInfo()
Example #23
0
 def exportDirPage(self, dirName, nodeList):
     """Write tree to nested direct struct with html page for each node"""
     oldDir = os.getcwd()
     os.chdir(dirName.encode(sys.getfilesystemencoding()))
     cssLines = [
         '#sidebar {', 'width: 16em;', 'float: left;', 'clear: left;',
         'border-right: 1px solid black;', 'margin-right: 1em;', '}'
     ]
     try:
         f = codecs.open('default.css', 'w', 'utf-8')
         f.writelines([(line + '\n').encode('utf-8') for line in cssLines])
     except (IOError, UnicodeError):
         print 'Error - could not write file to default.css'
         raise IOError(_('Error - cannot write file to %s') % 'default.css')
     f.close()
     if len(nodeList) > 1:
         self.treeFormats.addIfMissing(TreeDoc.copyFormat)
         item = TreeItem(None, TreeDoc.copyFormat.name)
         item.data[TreeFormats.fieldDefault] = TreeDoc.rootTitleDefault
         for child in nodeList:
             item.childList.append(child)
             child.parent = item
     else:
         item = nodeList[0]
     linkDict = {}
     item.createDirPageLinkDict(linkDict, os.getcwd())
     item.exportDirPage(linkDict)
     self.treeFormats.removeQuiet(TreeDoc.copyFormat)
     os.chdir(oldDir)
Example #24
0
 def exportTrlSubtree(self, fileRef, nodeList, addBranches=True):
     """Write subtree TRL file starting form item"""
     lines = [u'<?xml version="1.0" encoding="utf-8" ?>']
     if self.xlstLink:
         lines.append(u'<?%s?>' % self.xlstLink)
     if not addBranches:
         newList = []
         for item in nodeList:  # replace items with childless items
             newItem = TreeItem(item.parent, item.formatName)
             newItem.data = item.data
             newList.append(newItem)
         nodeList = newList
     if len(nodeList) > 1:
         format = nodeformat.NodeFormat(TreeFormats.rootFormatDefault, {},
                                        TreeFormats.fieldDefault)
         self.treeFormats.addIfMissing(format)
         item = TreeItem(None, format.name)
         item.data[TreeFormats.fieldDefault] = TreeDoc.rootTitleDefault
         for child in nodeList:
             item.childList.append(child)
             child.parent = item
     else:
         item = nodeList[0]
     lines.extend(item.branchXml([], True))
     try:
         f = self.getWriteFileObj(fileRef, self.compressFile)
         f.writelines([(line + '\n').encode('utf-8') for line in lines])
     except IOError:
         print 'Error - could not write file'
         self.treeFormats.removeQuiet(TreeDoc.copyFormat)
         raise
     f.close()
     self.treeFormats.removeQuiet(TreeDoc.copyFormat)
Example #25
0
 def exportDirTable(self, dirName, nodeList, addHeader=False):
     """Write tree to nested directory struct with html tables"""
     oldDir = os.getcwd()
     os.chdir(dirName.encode(sys.getfilesystemencoding()))
     if addHeader:
         header = self.fileInfoFormat.getHeaderFooter(True)
         footer = self.fileInfoFormat.getHeaderFooter(False)
     else:
         header = footer = ''
     if len(nodeList) > 1:
         self.treeFormats.addIfMissing(TreeDoc.copyFormat)
         item = TreeItem(None, TreeDoc.copyFormat.name)
         item.data[TreeFormats.fieldDefault] = TreeDoc.rootTitleDefault
         for child in nodeList:
             item.childList.append(child)
             child.parent = item
     else:
         item = nodeList[0]
     linkDict = {}
     item.createDirTableLinkDict(linkDict, os.getcwd())
     item.exportDirTable(linkDict, None, header, footer)
     self.treeFormats.removeQuiet(TreeDoc.copyFormat)
     os.chdir(oldDir)
Example #26
0
 def readTable(self, fileRef, errors='strict'):
     """Import table data into a flat tree - raise exception on failure"""
     try:
         f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                    errors)
         filePath = unicode(f.name, sys.getfilesystemencoding())
         textList = f.readlines()
     except UnicodeError:
         print 'Warning - bad unicode characters were replaced'
         if errors == 'strict':
             self.readTable(fileRef, 'replace')
         else:
             f.close()
         return
     f.close()
     self.treeFormats = TreeFormats({}, True)  # set defaults ROOT & DEFAULT
     newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
     defaultFormat = self.treeFormats[TreeFormats.formatDefault]
     defaultFormat.fieldList = []
     defaultFormat.lineList = []
     defaultFormat.addTableFields(textList.pop(0).strip().split('\t'))
     newRoot.setTitle(TreeDoc.rootTitleDefault)
     for line in textList:
         newItem = TreeItem(newRoot, TreeFormats.formatDefault)
         newRoot.childList.append(newItem)
         lineList = line.strip().split('\t')
         try:
             for num in range(len(lineList)):
                 newItem.data[self.treeFormats[TreeFormats.formatDefault].
                              fieldList[num].name] = lineList[num].strip()
         except IndexError:
             print 'Too few headings to read data as a table'
             raise ReadFileError(
                 _('Too few headings to read data as table'))
     self.root = newRoot
     self.fileName = filePath
Example #27
0
    def startElement(self, name, attrs):
        """Called by the reader at the open tag of each element"""
        if attrs.get(u'item', ''):  # reading TreeItem or bare format
            format = self.formats.get(name, None)
            if not format:
                format = nodeformat.NodeFormat(name, attrs)
                self.formats[name] = format

            if attrs.get(u'item', '') == 'y':  # reading TreeItem
                newItem = TreeItem(self.currentItem, name)
                if self.currentItem:
                    self.currentItem.childList.append(newItem)
                else:
                    self.rootItem = newItem
                    if attrs.get(u'nospace', '').startswith('y'):
                        self.docRef.spaceBetween = False
                    if attrs.get(u'nobreaks', '').startswith('y'):
                        self.docRef.lineBreaks = False
                    if attrs.get(u'nohtml', '').startswith('y'):
                        self.docRef.formHtml = False
                    if attrs.get(u'childsep', ''):
                        self.docRef.childFieldSep = attrs.get(u'childsep', '')
                    self.docRef.spellChkLang = attrs.get(u'spellchk', '')
                    self.docRef.xslCssLink = attrs.get(u'xslcss', '')
                    self.docRef.tlVersion = attrs.get(u'tlversion', '')
                self.currentItem = newItem
            else:  # reading bare format
                self.bareFormat = format

        else:  # reading data
            self.text = ''
            self.dataEntry = name
            if not self.currentItem:
                raise xml.sax.SAXException, 'No valid item'
            currentFormat = self.bareFormat
            if not currentFormat:
                try:
                    currentFormat = self.formats[self.currentItem.formatName]
                except KeyError:
                    raise xml.sax.SAXException, 'Invalid node type'
            if name not in currentFormat.fieldNames(
            ):  # add new field to format
                try:
                    currentFormat.addNewField(name, attrs)
                except (NameError, KeyError):
                    raise xml.sax.SAXException, 'Invalid field type'
 def __set_input_treeview_status(self):
     current_source = pypulse.get_fallback_source_index()
     sources = pypulse.PULSE.get_input_devices()
     input_list = []
     i = 0
     selected_row = -1
     for idx in sources:
         if current_source is not None and current_source == idx:
             selected_row = i
         if 'device.description' in sources[idx]['proplist']:
             description = sources[idx]['proplist']['device.description'].strip('\x00')
         else:
             description = ""
         input_list.append(TreeItem(self.image_widgets["device"], description, sources[idx]['name'], idx))
         i += 1
     self.view_widgets["ad_input"].add_items(input_list, clear_first=True)
     if not (selected_row < 0):
         self.view_widgets["ad_input"].set_select_rows([selected_row])
Example #29
0
 def __init__(self, filePath=None, setNewDefaults=False, importType=None):
     """Open filePath (can also be file ref) if given,
        setNewDefaults uses user defaults for compression & encryption,
        importType gives an import method to read the file"""
     globalref.docRef = self
     self.root = None
     self.treeFormats = TreeFormats()
     self.fileInfoItem = TreeItem(None, nodeformat.FileInfoFormat.name)
     self.fileInfoFormat = None
     TreeDoc.copyFormat = nodeformat.NodeFormat('_DUMMY__ROOT_', {},
                                                TreeFormats.fieldDefault)
     self.undoStore = undo.UndoRedoStore()
     self.redoStore =  undo.UndoRedoStore()
     self.sortFields = ['']
     self.fileName = ''
     self.spaceBetween = True
     self.lineBreaks = True
     self.formHtml = True
     self.childFieldSep = TreeDoc.childFieldSepDflt
     self.spellChkLang = ''
     self.xlstLink = ''
     self.xslCssLink = ''
     self.tlVersion = __version__
     self.fileInfoFormat = nodeformat.FileInfoFormat()
     if filePath:
         if importType:
             getattr(self, importType)(filePath)
         else:
             self.readFile(filePath)
     else:
         self.treeFormats = TreeFormats({}, True)
         self.root = TreeItem(None, TreeFormats.rootFormatDefault)
         self.root.setTitle(TreeDoc.rootTitleDefault)
     self.modified = False
     if setNewDefaults or not hasattr(self, 'compressFile'):
         self.compressFile = globalref.options.boolData('CompressNewFiles')
         self.encryptFile = globalref.options.boolData('EncryptNewFiles')
     self.selection = treeselection.TreeSelection([self.root])
     self.fileInfoFormat.translateFields()
     self.fileInfoFormat.updateFileInfo()
Example #30
0
    def setupModelData(self, lines, parent):
        parents = []
        indentations = []
        parents.append(parent)
        indentations.append(0)

        number = 0
        while number < len(lines):
            position = 0
            while position < len(lines[number]):
                if lines[number][position] != ' ':
                    break
                position = position + 1

            lineData = lines[number][position:].strip()

            if lineData:
                # Read the column data from the rest of the line.
                columnStrings = [x for x in lineData.split('\t') if x]
                columnData = [None] * len(columnStrings)

                for i, columnString in enumerate(columnStrings):
                    columnData[i] = columnString
                if position > indentations[-1]:
                    # The last child of the current parent is now the new parent
                    # unless the current parent has no children.
                    if parents[-1].childCount() > 0:
                        parents.append(parents[-1].child(parents[-1].childCount() - 1))
                        indentations.append(position)
                else:
                    while position < indentations[-1] and len(parents) > 0:
                        parents.pop(-1)
                        indentations.pop(-1)

                # Append a new item to the current parent's list of children.
                parents[-1].appendChild(TreeItem(columnData, parents[-1]))
            number = number + 1
Example #31
0
 def exportDirTable(self, dirName, nodeList, addHeader=False):
     """Write tree to nested directory struct with html tables"""
     oldDir = os.getcwd()
     os.chdir(dirName.encode(sys.getfilesystemencoding()))
     if addHeader:
         header = self.fileInfoFormat.getHeaderFooter(True)
         footer = self.fileInfoFormat.getHeaderFooter(False)
     else:
         header = footer = ''
     if len(nodeList) > 1:
         self.treeFormats.addIfMissing(TreeDoc.copyFormat)
         item = TreeItem(None, TreeDoc.copyFormat.name)
         item.data[TreeFormats.fieldDefault] = TreeDoc.rootTitleDefault
         for child in nodeList:
             item.childList.append(child)
             child.parent = item
     else:
         item = nodeList[0]
     linkDict = {}
     item.createDirTableLinkDict(linkDict, os.getcwd())
     item.exportDirTable(linkDict, None, header, footer)
     self.treeFormats.removeQuiet(TreeDoc.copyFormat)
     os.chdir(oldDir)
Example #32
0
class TreeModel(QAbstractItemModel):
    #Roles to filter input and output view
    Item_Role = Qt.UserRole

    def __init__(self, headers, data, parent=None) -> None:
        super(TreeModel, self).__init__(parent)

        rootData = []
        for header in headers:
            rootData.append(header)

        self._rootItem = TreeItem(rootData)

        #self._setupModelData(data.split('\n'), self._rootItem)

    def rootItem(self) -> TreeItem:
        """
        Return the root item of this model
        """
        return self._rootItem

    def getItem(self, index) -> TreeItem:
        """
        Return the TreeItem from model using the index
        """
        if index.isValid():
            item = index.internalPointer()
            if item:
                return item
        return self._rootItem

    def data(self, index, role) -> object:
        """
        Return data from model to the view
        """
        if not index.isValid():
            return None

        item = self.getItem(index)

        if role == Qt.DisplayRole or role == Qt.EditRole:
            return item.data(index.column())

        if role == TreeModel.Item_Role:
            return item

        return QVariant()

    def headerData(self, section, orientation, role) -> object:
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self._rootItem.data(section)

    def index(self, row, column, parent=QModelIndex()) -> QModelIndex:
        """
        Obtain model indexes corresponding to children of given parent item
        """
        #Only return model indexes for child items if the parent index in invalid (root item)
        #or if it has a zero column number
        if parent.isValid() and parent.column() != 0:
            return QModelIndex()

        parentItem = self.getItem(parent)
        if not parentItem:
            return QModelIndex()

        #Create a model index to uniquely with the row and column numbers
        #and a pointer to the item
        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem)

        return QModelIndex()

    def parent(self, index) -> QModelIndex:
        """
        Return the model indexes for parents of item by finding the correspoinding item for a
        give model index, using its parent() function to obtain its parent item, then
        creating a model index to represent the parent.

        Item without parents, including the root item, are handled by returning a null model index.
        Otherwise, a model index ins created and returned as in the index() function, with a suitable row number,
        but with a zero column
        """
        if not index.isValid():
            return QModelIndex()

        childItem = self.getItem(index)
        parentItem = None
        if childItem:
            parentItem = childItem.parent()

        if parentItem == self._rootItem or not parentItem:
            return QModelIndex()

        return self.createIndex(parentItem.childNumber(), 0, parentItem)

    def rowCount(self, parent=QModelIndex()) -> int:
        """
        Return the children that parent has
        """
        parentItem = self.getItem(parent)

        if parentItem:
            return parentItem.childCount()
        else:
            return 0

    def columnCount(self, parent=QModelIndex()) -> int:
        """
        All items are defined to have the same number of columns associated with them
        """
        return self._rootItem.columnCount()

    def flags(self, index) -> Qt.ItemFlags:
        """
        Return flags ItemIsEditable, ItemIsSelectable and ItemIsEnable to be able to edit and select item
        """
        if not index.isValid():
            return Qt.NoItemFlags

        return Qt.ItemIsEditable | Qt.ItemIsSelectable | Qt.ItemIsEnabled

    def setData(self, index, value, role=Qt.EditRole) -> bool:
        """
        Set data from view back to the model
        """
        if role != Qt.EditRole:
            return False

        item = self.getItem(index)
        result = item.setData(index.column(), value)

        if result:
            self.dataChanged.emit(index, index, [Qt.DisplayRole, Qt.EditRole])

        return result

    def setHeaderData(self,
                      section,
                      orientation,
                      value,
                      role=Qt.EditRole) -> bool:
        if role != Qt.EditRole or orientation != Qt.Horizontal:
            return False

        result = self._rootItem.setData(section, value)

        if result:
            self.headerDataChanged.emit(orientation, section, section)

        return result

    def insertColumns(self, position, columns, parent=QModelIndex()) -> bool:
        """
        Insert columns into the model
        """
        self.beginInsertColumns(parent, position, position + columns - 1)
        success = self._rootItem.insertColumns(position, columns)
        self.endInsertColumns()

        return success

    def removeColumns(self, position, columns, parent=QModelIndex()) -> bool:
        """
        Remove columns from the model
        """
        self.beginRemoveColumns(parent, position, position + columns - 1)
        success = self._rootItem.removeColumns(position, columns)
        self.endRemoveColumns()

        if self._rootItem.columnCount() == 0:
            self.removeRows(0, self.rowCount())

        return success

    def insertRows(self, position, rows, parent=QModelIndex()) -> bool:
        """
        Insert rows into model
        """
        parentItem = self.getItem(parent)
        if not parentItem:
            return False

        self.beginInsertRows(parent, position, position + rows - 1)
        success = parentItem.insertChildren(position, rows,
                                            self._rootItem.columnCount())
        self.endInsertRows()

        return success

    def removeRows(self, position, rows, parent=QModelIndex()) -> bool:
        """
        Remove rows from model
        """
        parentItem = self.getItem(parent)
        if not parentItem:
            return False

        self.beginRemoveRows(parent, position, position + rows - 1)
        success = parentItem.removeChildren(position, rows)
        self.endRemoveRows()

        return success
Example #33
0
 def __init__(self):
     TreeItem.__init__(self)
Example #34
0
class TreeModel(QAbstractItemModel):
    checkChanged = Signal(int, str)
    def __init__(self, headers, data, tablemodel, parent=None):
        super(TreeModel, self).__init__(parent)

        rootData = [header for header in headers]
        self.rootItem = TreeItem(rootData)
        self.treeDict = data
        self.tablemodel = tablemodel
        self.setupModelData(data, self.rootItem)
        self.examingParents = False
        self.examiningChildren = False

    def changeLeafCheck(self, source):
        curNode = self.rootItem.child(0)
        keyNames = source.split("/")
        curRow = 0
        for key in keyNames:
            for i in range(curNode.childCount()):
                if curNode.child(i).itemData[0] == key:
                        curNode = curNode.child(i)
                        curRow = i
                        break
        anIndex = self.createIndex(curRow, curNode.columnCount(), curNode)
        self.setData(anIndex, 0, Qt.CheckStateRole)



    def columnCount(self, parent=QModelIndex()):
        return self.rootItem.columnCount()

    def data(self, index, role):
        if not index.isValid():
            return None

        item = self.getItem(index)
        if role == Qt.DisplayRole:
            return item.data(index.column())
        elif role == Qt.CheckStateRole:
            return item.checked

        return None


    def flags(self, index):
        if not index.isValid():
            return 0

        return Qt.ItemIsUserCheckable | super(TreeModel, self).flags(index)

    def getItem(self, index):
        if index.isValid():
            item = index.internalPointer()
            if item:
                return item

        return self.rootItem

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.rootItem.data(section)

        return None

    def index(self, row, column, parent=QModelIndex()):
        if parent.isValid() and parent.column() != 0:
            return QModelIndex()

        parentItem = self.getItem(parent)
        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem)
        else:
            return QModelIndex()

    def insertColumns(self, position, columns, parent=QModelIndex()):
        self.beginInsertColumns(parent, position, position + columns - 1)
        success = self.rootItem.insertColumns(position, columns)
        self.endInsertColumns()

        return success

    def insertRows(self, position, rows, parent=QModelIndex()):
        parentItem = self.getItem(parent)
        self.beginInsertRows(parent, position, position + rows - 1)
        success = parentItem.insertChildren(position, rows,
                self.rootItem.columnCount())
        self.endInsertRows()

        return success

    def parent(self, index):
        if not index.isValid():
            return QModelIndex()

        childItem = self.getItem(index)
        parentItem = childItem.parent()

        if parentItem == self.rootItem:
            return QModelIndex()

        return self.createIndex(parentItem.childNumber(), 0, parentItem)

    def removeColumns(self, position, columns, parent=QModelIndex()):
        self.beginRemoveColumns(parent, position, position + columns - 1)
        success = self.rootItem.removeColumns(position, columns)
        self.endRemoveColumns()

        if self.rootItem.columnCount() == 0:
            self.removeRows(0, self.rowCount())

        return success

    def removeRows(self, position, rows, parent=QModelIndex()):
        parentItem = self.getItem(parent)

        self.beginRemoveRows(parent, position, position + rows - 1)
        success = parentItem.removeChildren(position, rows)
        self.endRemoveRows()

        return success

    def rowCount(self, parent=QModelIndex()):
        parentItem = self.getItem(parent)

        return parentItem.childCount()

    def setData(self, index, value, role=Qt.EditRole):
        if role == Qt.EditRole:
           item = self.getItem(index)
           result = item.setData(index.column(), value)
           if result:
               self.dataChanged.emit(index, index)
               return result
        elif role == Qt.CheckStateRole:
            item = self.getItem(index)
            item.checked = value
            checked = item.checked
            source=""
            sourceList= []

            while item.parentItem:
                sourceList.insert(0,item.itemData[0]+"/")
                item = item.parentItem
            if self.examingParents == False:
                self.checkChanged.emit(checked,source.join(sourceList)[:-1])
            self.checkChildren(index,value)
            self.checkParent(index)
            self.dataChanged.emit(index, index)
            return True
        return False


    def setHeaderData(self, section, orientation, value, role=Qt.EditRole):
        if role != Qt.EditRole or orientation != Qt.Horizontal:
            return False

        result = self.rootItem.setData(section, value)
        if result:
            self.headerDataChanged.emit(orientation, section, section)

        return result

    def setupModelData(self, data, parent):
             visited={}
             queue=[]
             grandParents = {}

             for key in data.keys():
                 visited[(parent.itemData[0])]=[key]
                 queue.append((key,parent,""))
                 grandParents[key] = (data[key],parent)
             curDict = data
             tempSource= ""
             while queue:
                 poppedItem = queue.pop(0)
                 child = poppedItem[0]
                 parentOfChild = poppedItem[1]
                 childSource = poppedItem[2]
                 parent = parentOfChild
                 parent.insertChildren(parent.childCount(),1,self.rootItem.columnCount())
                 parent.child(parent.childCount() -1).setData(0,child)

                 if child in grandParents:

                     curDict =  grandParents[child][0]
                     tempSource = childSource+child+"/"
                     for curChild in range(grandParents[child][1].childCount()):
                         if child == grandParents[child][1].child(curChild).itemData[0]:
                            parent = grandParents[child][1].child(curChild)
                            visited[(parent.itemData[0])]=[]

                 if isinstance(curDict, dict):
                     for key in curDict.keys():
                         if key not in visited[(parent.itemData[0])]:
                             visited[(parent.itemData[0])].append(key)
                             queue.append((key,parent,tempSource))
                             if (isinstance(curDict[key],dict)):
                                grandParents[key]= (curDict[key],parent)
                             else:
                                self.tablemodel.addRow(curDict,tempSource,key)

    def checkChildren(self,index,value):
        self.examingChildren = True
        if not index.isValid() or self.examingParents:
            self.examingChildren = False
            return
        else:
            childCount = self.rowCount(index)
            for i in range(childCount):
                child = index.child(i, 0)
                if value == 1:
                    return
                self.setData(child, value, Qt.CheckStateRole)
                self.checkChildren(child,value)

    def checkParent(self,index):
        self.examingParents = True
        if not index.isValid() or self.examiningChildren:
            self.examingParents = False
            return
        else:
            parent = index.parent()
            if parent.data() == None:
                self.examingParents = False
                return
            value = self.checkChildrenStates(parent)
            self.setData(parent, value, Qt.CheckStateRole)

    def checkChildrenStates(self, index):
        childCount = self.rowCount(index)
        checkedChildrenCount = 0
        for i in range(childCount):
            child = index.child(i, 0)
            if child.data(Qt.CheckStateRole) == Qt.Checked or child.data(Qt.CheckStateRole) == Qt.PartiallyChecked:
                checkedChildrenCount += 1
        if checkedChildrenCount == 0:
            return 0
        elif checkedChildrenCount == childCount:
            return 2
        else:
            return 1
Example #35
0
class TreeModelU(TreeModel):
    checkChanged = Signal(int, str)

    def __init__(self, headers, data, tablemodel, editables, parent=None):
        super(TreeModel, self).__init__(parent)

        rootData = [header for header in headers]
        self.rootItem = TreeItem(rootData)
        self.treeDict = data
        self.tablemodel = tablemodel
        self.editableKeys = editables
        self.examingParents = False
        self.examiningChildren = False
        self.setupModelData(data, self.rootItem)
        self.checkList()

    def checkList(self):
        missingSources = []
        displayMessage = False
        for i in range(len(self.tablemodel.templatesources)):
            if "Custom Input" not in self.tablemodel.templatesources[i]:
                if self.tablemodel.templatesources[
                        i] not in self.tablemodel.newmetadatasources:
                    missingSources.append(self.tablemodel.templatesources[i])
                    displayMessage = True

        for i in range(len(self.tablemodel.newmetadataList)):
            self.tablemodel.addRow(self.tablemodel.newmetadataList[i])

        if displayMessage:
            QMessageBox.warning(
                None, QApplication.applicationDisplayName(),
                "Bad stuff happens. " +
                "The file extracted is missing Source: \n\n" +
                str(missingSources))

        self.tablemodel.newmetadataList = []
        self.tablemodel.newmetadatasources = []

    def setupModelData(self, data, parent):
        visited = {}
        queue = []
        grandParents = {}

        for key in data.keys():
            visited[(parent.itemData[0])] = [key]
            queue.append((key, parent, ""))
            grandParents[key] = (data[key], parent)
        curDict = data
        tempSource = ""
        while queue:
            poppedItem = queue.pop(0)
            child = poppedItem[0]
            parentOfChild = poppedItem[1]
            childSource = poppedItem[2]
            parent = parentOfChild
            parent.insertChildren(parent.childCount(), 1,
                                  self.rootItem.columnCount())
            parent.child(parent.childCount() - 1).setData(0, child)

            if child in grandParents:

                curDict = grandParents[child][0]
                tempSource = childSource + child + "/"
                for curChild in range(grandParents[child][1].childCount()):
                    if child == grandParents[child][1].child(
                            curChild).itemData[0]:
                        parent = grandParents[child][1].child(curChild)
                        visited[(parent.itemData[0])] = []

            if isinstance(curDict, dict):
                for key in curDict.keys():
                    if key not in visited[(parent.itemData[0])]:
                        visited[(parent.itemData[0])].append(key)
                        queue.append((key, parent, tempSource))
                        if (isinstance(curDict[key], dict)):
                            grandParents[key] = (curDict[key], parent)
                        else:
                            self.tablemodel.prepRow(curDict, tempSource, key)
Example #36
0
class TreeModelR(TreeModel):
    checkChanged = Signal(int, str)

    def __init__(self,
                 headers,
                 data,
                 tablemodel,
                 newList,
                 filterModel,
                 parent=None):
        super(TreeModel, self).__init__(parent)

        rootData = [header for header in headers]
        self.rootItem = TreeItem(rootData)
        self.treeDict = data
        self.tablemodel = tablemodel
        self.newList = newList
        self.filterModel = filterModel
        self.examingParents = False
        self.examiningChildren = False
        self.setupModelData(data, self.rootItem)

    def setupModelData(self, data, parent):
        visited = {}
        queue = []
        grandParents = {}

        for key in data.keys():
            visited[(parent.itemData[0])] = [key]
            queue.append((key, parent, ""))
            grandParents[key] = (data[key], parent)
        curDict = data
        tempSource = ""
        while queue:
            poppedItem = queue.pop(0)
            child = poppedItem[0]
            parentOfChild = poppedItem[1]
            childSource = poppedItem[2]
            parent = parentOfChild
            parent.insertChildren(parent.childCount(), 1,
                                  self.rootItem.columnCount())
            parent.child(parent.childCount() - 1).setData(0, child)
            for i in range(len(self.newList)):
                if child == self.newList[i]["Key"]:
                    self.tablemodel.beginInsertRows(
                        self.tablemodel.index(
                            len(self.tablemodel.metadataList), 0), i, i)
                    self.tablemodel.metadataList.append(self.newList[i])
                    self.tablemodel.endInsertRows()
                    parent.child(parent.childCount() -
                                 1).checked = self.newList[i]["Checked"]
                    self.filterModel.checkList(self.newList[i]["Checked"],
                                               self.newList[i]["Source"])

            if child in grandParents:

                curDict = grandParents[child][0]
                tempSource = childSource + child + "/"
                for curChild in range(grandParents[child][1].childCount()):
                    if child == grandParents[child][1].child(
                            curChild).itemData[0]:
                        parent = grandParents[child][1].child(curChild)
                        visited[(parent.itemData[0])] = []

            if isinstance(curDict, dict):
                for key in curDict.keys():
                    if key not in visited[(parent.itemData[0])]:
                        visited[(parent.itemData[0])].append(key)
                        queue.append((key, parent, tempSource))
                        if (isinstance(curDict[key], dict)):
                            grandParents[key] = (curDict[key], parent)
                        else:
                            pass
Example #37
0
 def addItem(self, level):
     """Add a child of the current item"""
     item = TreeItem(self.currentItem, self.defaultFormat.name)
     self.currentItem.childList.append(item)
     self.currentItem = item
     self.currentLevel = level
Example #38
0
class TreeModel(QAbstractItemModel):

    def __init__(self, data, parent=None):
        super(TreeModel, self).__init__(parent)
        self.rootItem = TreeItem(['Date', 'Data (KB)', 'Data (MB)'], None)
        self.setupModel(data)

    def columnCount(self, parent):
        if parent.isValid():
            return parent.internalPointer().columnCount()
        return self.rootItem.columnCount()

    def data(self, index, role):
        if not index.isValid():
            return None

        if role == Qt.TextAlignmentRole:
            return Qt.AlignRight

        if role == Qt.DisplayRole:
            return index.internalPointer().data(index.column())

        return None

    def headerData(self, section, orientation, role):
        if role == Qt.TextAlignmentRole:
            return Qt.AlignRight

        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.rootItem.data(section)

    def index(self, row, column, parent):
        if not self.hasIndex(row, column, parent):
            return QModelIndex()

        if not parent.isValid():
            parentItem = self.rootItem
        else:
            parentItem = parent.internalPointer()

        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem)
        else:
            return QModelIndex()

    def parent(self, index):
        if not index.isValid():
            return QModelIndex()

        parentItem = index.internalPointer().parent()
        if parentItem == self.rootItem:
            return QModelIndex()

        return self.createIndex(parentItem.row(), 0, parentItem)

    def rowCount(self, parent):
        if parent.column() > 0:
            return 0

        if not parent.isValid():
            parentItem = self.rootItem
        else:
            parentItem = parent.internalPointer()

        return parentItem.childCount()

    def setupModel(self, data):
        for daily in data:
            items = [daily.day, str(daily.dataUsed), "%.02f" % (daily.dataUsed / 1024.0,)]
            child = TreeItem(items, self.rootItem)
            self.rootItem.childItems.append(child)
            for detail in daily.detail:
                detail.append('')
                child.childItems.append(TreeItem(detail, child))
Example #39
0
 def __init__(self, data, parent=None):
     super().__init__(parent)
     self.rootItem = TreeItem([self.tr('title'), self.tr('summary')])
     self.setupModelData(data.split('\n'), self.rootItem)
Example #40
0
class TreeDoc(object):
    """Tree document class - stores root and has tree utilities"""
    passwordDict = {}
    childFieldSepDflt = ', '
    rootTitleDefault = _('Main', 'default root title')
    folderName = _('FOLDER', 'bookmark format folder name')
    bookmarkName = _('BOOKMARK', 'bookmark format name')
    separatorName = _('SEPARATOR', 'bookmark format separator name')
    bookmarkRootTitle = _('Bookmarks')
    copyFormat = None
    def __init__(self, filePath=None, setNewDefaults=False, importType=None):
        """Open filePath (can also be file ref) if given,
           setNewDefaults uses user defaults for compression & encryption,
           importType gives an import method to read the file"""
        globalref.docRef = self
        self.root = None
        self.treeFormats = TreeFormats()
        self.fileInfoItem = TreeItem(None, nodeformat.FileInfoFormat.name)
        self.fileInfoFormat = None
        TreeDoc.copyFormat = nodeformat.NodeFormat('_DUMMY__ROOT_', {},
                                                   TreeFormats.fieldDefault)
        self.undoStore = undo.UndoRedoStore()
        self.redoStore =  undo.UndoRedoStore()
        self.sortFields = ['']
        self.fileName = ''
        self.spaceBetween = True
        self.lineBreaks = True
        self.formHtml = True
        self.childFieldSep = TreeDoc.childFieldSepDflt
        self.spellChkLang = ''
        self.xlstLink = ''
        self.xslCssLink = ''
        self.tlVersion = __version__
        self.fileInfoFormat = nodeformat.FileInfoFormat()
        if filePath:
            if importType:
                getattr(self, importType)(filePath)
            else:
                self.readFile(filePath)
        else:
            self.treeFormats = TreeFormats({}, True)
            self.root = TreeItem(None, TreeFormats.rootFormatDefault)
            self.root.setTitle(TreeDoc.rootTitleDefault)
        self.modified = False
        if setNewDefaults or not hasattr(self, 'compressFile'):
            self.compressFile = globalref.options.boolData('CompressNewFiles')
            self.encryptFile = globalref.options.boolData('EncryptNewFiles')
        self.selection = treeselection.TreeSelection([self.root])
        self.fileInfoFormat.translateFields()
        self.fileInfoFormat.updateFileInfo()

    def hasPassword(self, filePath):
        """Return True if a password is available for filePath"""
        key = filePath.encode(sys.getfilesystemencoding())
        return TreeDoc.passwordDict.has_key(key)

    def setPassword(self, filePath, password):
        """Set encrytion password for the filePath"""
        key = filePath.encode(sys.getfilesystemencoding())
        TreeDoc.passwordDict[key] = password.encode('utf-8')

    def clearPassword(self, filePath):
        """Remove password for filePath if present"""
        key = filePath.encode(sys.getfilesystemencoding())
        try:
            del TreeDoc.passwordDict[key]
        except KeyError:
            pass

    def getReadFileObj(self, fileRef):
        """Return file object and set self.compressFile to False/True,
           fileRef is either file path or file object"""
        if not hasattr(fileRef, 'read'):
            fileRef = file(fileRef.encode(sys.getfilesystemencoding()), 'rb')
            # binary mode req'd for encryption
        if hasattr(fileRef, 'seek'):
            fileRef.seek(0)
        prefix = fileRef.read(2)
        if hasattr(fileRef, 'seek'):
            fileRef.seek(0)
        else:
            oldFileRef = fileRef
            fileRef = StringIO.StringIO(prefix + oldFileRef.read())
            fileRef.name = oldFileRef.name
            oldFileRef.close()
        if prefix == '\037\213':
            name = fileRef.name
            fileRef = gzip.GzipFile(fileobj=fileRef)
            fileRef.name = name
        # may already be a gzip object from before password prompt
        self.compressFile = isinstance(fileRef, gzip.GzipFile)
        return fileRef

    def decryptFile(self, fileObj):
        """Decrypt file if was encrypted"""
        name = fileObj.name
        prefix = fileObj.read(len(encryptPrefix))
        self.encryptFile = prefix == encryptPrefix
        if self.encryptFile:
            password = TreeDoc.passwordDict.get(fileObj.name, '')
            if not password:
                fileObj.close()
                raise PasswordError, 'Missing password'
            try:
                text = p3.p3_decrypt(fileObj.read(), password)
            except p3.CryptError:
                fileObj.close()
                raise PasswordError, 'Incorrect password'
            fileObj.close()
            fileObj = StringIO.StringIO(text)
            fileObj.name = name
        else:
            fileObj.seek(0)
        return fileObj

    def getEncodedFileObj(self, fileRef, encoding, errors):
        """Return open file object with specified encoding"""
        return codecs.getreader(encoding)(self.getReadFileObj(fileRef), errors)

    def getWriteFileObj(self, fileRef, forceCompress):
        """Return write file object, compressed or not based on forceCompress,
           but always compress if has .gz extension,
           fileRef is either file path or file object"""
        if not hasattr(fileRef, 'read'):
            fileRef = file(fileRef.encode(sys.getfilesystemencoding()), 'wb')
        if fileRef.name.endswith('.gz') or forceCompress:
            name = fileRef.name
            fileRef = gzip.GzipFile(fileobj=fileRef)
            fileRef.name = name
        return fileRef

    def readFile(self, fileRef):
        """Open and read file - raise exception on failure,
           fileRef is either file path or file object"""
        filePath = hasattr(fileRef, 'read') and \
                   unicode(fileRef.name, sys.getfilesystemencoding()) or \
                   fileRef
        try:
            f = self.getReadFileObj(fileRef)
            f = self.decryptFile(f)
            handler = treexmlparse.TreeSaxHandler(self)
            input = xml.sax.InputSource()
            input.setByteStream(f)
            input.setEncoding('utf-8')
            reader = xml.sax.make_parser()
            reader.setContentHandler(handler)
            reader.setFeature(xml.sax.handler.feature_external_ges, 0)
            reader.parse(input)
        except IOError:
            print 'Error - could not read file', \
                  filePath.encode(globalref.localTextEncoding)
            raise
        except UnicodeError:
            print 'Error - bad Unicode in file', \
                  filePath.encode(globalref.localTextEncoding)
            f.close()
            raise
        except xml.sax.SAXException:
            f.close()
            raise ReadFileError(_('Could not open as treeline file'))
        f.close()
        self.root = handler.rootItem
        self.fileName = filePath
        self.treeFormats = TreeFormats(handler.formats)
        self.fileInfoFormat.replaceListFormat()
        self.treeFormats.updateAutoChoices()
        self.treeFormats.updateUniqueID()
        self.treeFormats.updateDerivedTypes()
        if not self.tlVersion:  # file from before 0.12.80, fix number format
            for format in self.treeFormats.values():
                for field in format.fieldList:
                    if field.typeName == 'Number':
                        field.format = field.format.replace(',', '\,')

    def readTabbed(self, fileRef, errors='strict'):
        """Import tabbed data into a flat tree - raise exception on failure"""
        try:
            f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                       errors)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            textList = f.readlines()
        except UnicodeError:
            print 'Warning - bad unicode characters were replaced'
            if errors == 'strict':
                self.readTabbed(fileRef, 'replace')
            else:
                f.close()
            return
        f.close()
        bufList = [(text.count('\t', 0, len(text) - len(text.lstrip())),
                    text.strip()) for text in textList if text.strip()]
        if bufList:
            buf = bufList.pop(0)
            if buf[0] == 0:
                # set default formats ROOT & DEFAULT
                self.treeFormats = TreeFormats({}, True)
                newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
                newRoot.setTitle(buf[1])
                if newRoot.loadTabbedChildren(bufList):
                    self.root = newRoot
                    self.fileName = filePath
                    return
        raise ReadFileError(_('Error in tabbed list'))

    def readTable(self, fileRef, errors='strict'):
        """Import table data into a flat tree - raise exception on failure"""
        try:
            f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                       errors)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            textList = f.readlines()
        except UnicodeError:
            print 'Warning - bad unicode characters were replaced'
            if errors == 'strict':
                self.readTable(fileRef, 'replace')
            else:
                f.close()
            return
        f.close()
        self.treeFormats = TreeFormats({}, True)  # set defaults ROOT & DEFAULT
        newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
        defaultFormat = self.treeFormats[TreeFormats.formatDefault]
        defaultFormat.fieldList = []
        defaultFormat.lineList = []
        defaultFormat.addTableFields(textList.pop(0).strip().split('\t'))
        newRoot.setTitle(TreeDoc.rootTitleDefault)
        for line in textList:
            newItem = TreeItem(newRoot, TreeFormats.formatDefault)
            newRoot.childList.append(newItem)
            lineList = line.strip().split('\t')
            try:
                for num in range(len(lineList)):
                    newItem.data[self.treeFormats[TreeFormats.formatDefault].
                            fieldList[num].name] = lineList[num].strip()
            except IndexError:
                print 'Too few headings to read data as a table'
                raise ReadFileError(_('Too few headings to read data as table'))
        self.root = newRoot
        self.fileName = filePath

    def readLines(self, fileRef, errors='strict'):
        """Import plain text, node per line"""
        try:
            f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                       errors)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            textList = f.readlines()
        except UnicodeError:
            print 'Warning - bad unicode characters were replaced'
            if errors == 'strict':
                self.readLines(fileRef, 'replace')
            else:
                f.close()
            return
        f.close()
        self.treeFormats = TreeFormats({}, True)  # set defaults ROOT & DEFAULT
        newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
        defaultFormat = self.treeFormats[TreeFormats.formatDefault]
        defaultFormat.fieldList = []
        defaultFormat.lineList = []
        defaultFormat.addTableFields([TreeFormats.textFieldName])
        newRoot.setTitle(TreeDoc.rootTitleDefault)
        for line in textList:
            line = line.strip()
            if line:
                newItem = TreeItem(newRoot, TreeFormats.formatDefault)
                newRoot.childList.append(newItem)
                newItem.data[TreeFormats.textFieldName] = line
        self.root = newRoot
        self.fileName = filePath

    def readPara(self, fileRef, errors='strict'):
        """Import plain text, blank line delimitted"""
        try:
            f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                       errors)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            fullText = f.read().replace('\r', '')
        except UnicodeError:
            print 'Warning - bad unicode characters were replaced'
            if errors == 'strict':
                self.readPara(fileRef, 'replace')
            else:
                f.close()
            return
        textList = fullText.split('\n\n')
        f.close()
        self.treeFormats = TreeFormats({}, True)  # set defaults ROOT & DEFAULT
        newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
        defaultFormat = self.treeFormats[TreeFormats.formatDefault]
        defaultFormat.fieldList = []
        defaultFormat.lineList = []
        defaultFormat.iconName = 'doc'
        defaultFormat.addTableFields([TreeFormats.textFieldName])
        defaultFormat.fieldList[0].numLines = globalref.options.\
                                               intData('MaxEditLines', 1,
                                                    optiondefaults.maxNumLines)
        newRoot.setTitle(TreeDoc.rootTitleDefault)
        for line in textList:
            line = line.strip()
            if line:
                newItem = TreeItem(newRoot, TreeFormats.formatDefault)
                newRoot.childList.append(newItem)
                newItem.data[TreeFormats.textFieldName] = line
        self.root = newRoot
        self.fileName = filePath

    def readTreepad(self, fileRef, errors='strict'):
        """Read Treepad text-node file"""
        try:
            f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                       errors)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            textList = f.read().split('<end node> 5P9i0s8y19Z')
            f.close()
        except UnicodeError:  # error common - broken unicode on windows
            print 'Warning - bad unicode characters were replaced'
            if errors == 'strict':
                self.readTreepad(fileRef, 'replace')
            else:
                f.close()
            return
        self.treeFormats = TreeFormats()
        format = nodeformat.NodeFormat(TreeFormats.formatDefault)
        titleFieldName = _('Title', 'title field name')
        format.addNewField(titleFieldName)
        format.addLine(u'{*%s*}' % titleFieldName)
        numLines = globalref.options.intData('MaxEditLines', 1,
                                             optiondefaults.maxNumLines)
        format.addNewField(TreeFormats.textFieldName,
                           {'lines': repr(numLines)})
        format.addLine(u'{*%s*}' % TreeFormats.textFieldName)
        self.treeFormats[format.name] = format
        itemList = []
        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):
                    print 'Error - bad file format in %s' % \
                          filePath.encode(globalref.localTextEncoding)
                    raise ReadFileError(_('Bad file format in %s') % filePath)
                item = TreeItem(None, format.name)
                item.data[titleFieldName] = title
                item.data[TreeFormats.textFieldName] = '\n'.join(lines)
                item.level = level
                itemList.append(item)
        self.root = itemList[0]
        parentList = []
        for item in itemList:
            if item.level != 0:
                parentList = parentList[:item.level]
                item.parent = parentList[-1]
                parentList[-1].childList.append(item)
            parentList.append(item)
        self.root = itemList[0]
        self.fileName = filePath

    def createBookmarkFormat(self):
        """Return a set of formats for bookmark imports"""
        treeFormats = TreeFormats()
        format = nodeformat.NodeFormat(TreeDoc.folderName)
        format.addNewField(TreeFormats.fieldDefault)
        format.addLine(u'{*%s*}' % TreeFormats.fieldDefault)
        format.addLine(u'{*%s*}' % TreeFormats.fieldDefault)
        format.iconName = 'folder_3'
        treeFormats[format.name] = format
        format = nodeformat.NodeFormat(TreeDoc.bookmarkName)
        format.addNewField(TreeFormats.fieldDefault)
        format.addLine(u'{*%s*}' % TreeFormats.fieldDefault)
        format.addLine(u'{*%s*}' % TreeFormats.fieldDefault)
        format.addNewField(TreeFormats.linkFieldName, {'type': 'URL'})
        format.addLine(u'{*%s*}' % TreeFormats.linkFieldName)
        format.iconName = 'bookmark'
        treeFormats[format.name] = format
        format = nodeformat.NodeFormat(TreeDoc.separatorName)
        format.addNewField(TreeFormats.fieldDefault)
        format.addLine(u'------------------')
        format.addLine(u'<hr>')
        treeFormats[format.name] = format
        return treeFormats

    def readXbel(self, fileRef):
        """Read XBEL format bookmarks"""
        formats = self.createBookmarkFormat()
        try:
            f = self.getReadFileObj(fileRef)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            handler = treexmlparse.\
                      XbelSaxHandler(formats[TreeDoc.folderName],
                                     formats[TreeDoc.bookmarkName],
                                     formats[TreeDoc.separatorName])
            input = xml.sax.InputSource()
            input.setByteStream(f)
            input.setEncoding('utf-8')
            reader = xml.sax.make_parser()
            reader.setContentHandler(handler)
            reader.setFeature(xml.sax.handler.feature_external_ges, 0)
            reader.parse(input)
        except UnicodeError:
            print 'Error - bad Unicode in file', \
                  filePath.encode(globalref.localTextEncoding)
            f.close()
            raise ReadFileError(_('Problem with Unicode characters in file'))
        except xml.sax.SAXException:
            f.close()
            raise ReadFileError(_('Could not open as XBEL file'))
        f.close()
        if not handler.rootItem:
            raise ReadFileError(_('Could not open as XBEL file'))
        self.root = handler.rootItem
        if not self.root.data.get(TreeFormats.fieldDefault, ''):
            self.root.data[TreeFormats.fieldDefault] = \
                      TreeDoc.bookmarkRootTitle
        self.fileName = filePath
        self.treeFormats = formats

    def readMozilla(self, fileRef, errors='strict'):
        """Read Mozilla HTML format bookmarks"""
        formats = self.createBookmarkFormat()
        try:
            f = self.getEncodedFileObj(fileRef, 'utf-8', errors)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            fullText = f.read()
        except UnicodeError:
            print 'Warning - bad unicode characters were replaced'
            if errors == 'strict':
                self.readMozilla(fileRef, 'replace')
            else:
                f.close()
            return
        try:
            handler = treexmlparse.\
                      HtmlBookmarkHandler(formats[TreeDoc.folderName],
                                          formats[TreeDoc.bookmarkName],
                                          formats[TreeDoc.separatorName])
            handler.feed(fullText)
            handler.close()
        except treexmlparse.HtmlParseError:
            raise ReadFileError(_('Could not open as HTML bookmark file'))
        if not handler.rootItem:
            raise ReadFileError(_('Could not open as HTML bookmark file'))
        self.root = handler.rootItem
        if not self.root.data.get(TreeFormats.fieldDefault, ''):
            self.root.data[TreeFormats.fieldDefault] = \
                      TreeDoc.bookmarkRootTitle
        self.fileName = filePath
        self.treeFormats = formats

    def readXml(self, fileRef):
        """Read a generic (non-TreeLine) XML file"""
        try:
            f = self.getReadFileObj(fileRef)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            handler = treexmlparse.GenericXmlHandler()
            input = xml.sax.InputSource()
            input.setByteStream(f)
            input.setEncoding('utf-8')
            reader = xml.sax.make_parser()
            reader.setContentHandler(handler)
            reader.setFeature(xml.sax.handler.feature_external_ges, 0)
            reader.parse(input)
        except UnicodeError:
            print 'Error - bad Unicode in file', \
                  filePath.encode(globalref.localTextEncoding)
            f.close()
            raise ReadFileError(_('Problem with Unicode characters in file'))
        except xml.sax.SAXException:
            f.close()
            raise ReadFileError(_('Could not open XML file'))
        f.close()
        if not handler.rootItem:
            raise ReadFileError(_('Could not open XML file'))
        self.root = handler.rootItem
        self.fileName = filePath
        self.treeFormats = TreeFormats(handler.formats)
        for format in self.treeFormats.values():
            format.fixImportedFormat(treexmlparse.GenericXmlHandler.
                                                  textFieldName)

    def readOdf(self, fileRef):
        """Read an Open Document Format (ODF) file"""
        self.treeFormats = TreeFormats(None, True)
        rootItem = TreeItem(None, TreeFormats.rootFormatDefault,
                            TreeDoc.rootTitleDefault)
        defaultFormat = self.treeFormats[TreeFormats.formatDefault]
        defaultFormat.addNewField(TreeFormats.textFieldName,
                                  {u'html': 'n', u'lines': '6'})
        defaultFormat.changeOutputLines([u'<b>{*%s*}</b>' %
                                         TreeFormats.fieldDefault,
                                         u'{*%s*}' %
                                         TreeFormats.textFieldName])
        try:
            f = self.getReadFileObj(fileRef)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            zip = zipfile.ZipFile(f, 'r')
            text = zip.read('content.xml')
            handler = treexmlparse.OdfSaxHandler(rootItem, defaultFormat)
            xml.sax.parseString(text, handler)
        except (zipfile.BadZipfile, KeyError):
            f.close()
            raise ReadFileError(_('Could not unzip ODF file'))
        except UnicodeError:
            f.close()
            raise ReadFileError(_('Problem with Unicode characters in file'))
        except xml.sax.SAXException:
            f.close()
            raise ReadFileError(_('Could not open corrupt ODF file'))
        f.close()
        self.root = rootItem
        self.fileName = filePath

    def readXmlString(self, string):
        """Read xml string and return top item or None"""
        try:
            handler = treexmlparse.TreeSaxHandler(self)
            xml.sax.parseString(string.encode('utf-8'), handler)
        except xml.sax.SAXException:
            return None
        return handler.rootItem

    def readXmlStringAndFormat(self, string):
        """Read xml string and return tuple of top item and new formats"""
        try:
            handler = treexmlparse.TreeSaxHandler(self)
            xml.sax.parseString(string.encode('utf-8'), handler)
        except xml.sax.SAXException:
            return (None, [])
        formats = [format for format in handler.formats.values()
                   if format.name not in self.treeFormats]
        try:
            formats.remove(TreeDoc.copyFormat)
        except ValueError:
            pass
        formatNames = [format.name for format in formats] + \
                       self.treeFormats.keys()
        for format in formats:
            if format.genericType not in formatNames:
                format.genericType = ''
        return (handler.rootItem, formats)

    def writeFile(self, fileRef, updateInfo=True):
        """Write file - raises IOError on failure"""
        lines = [u'<?xml version="1.0" encoding="utf-8" ?>']
        if self.xlstLink:
            lines.append(u'<?%s?>' % self.xlstLink)
        lines.extend(self.root.branchXml([], True))
        text = '\n'.join(lines).encode('utf-8')
        try:
            f = self.getWriteFileObj(fileRef, self.compressFile)
        except IOError:
            print 'Error - could not write file'
            raise
        filePath = unicode(f.name, sys.getfilesystemencoding())
        if self.encryptFile:
            key = filePath.encode(sys.getfilesystemencoding())
            password = TreeDoc.passwordDict.get(key, '')
            if not password:
                if key.endswith('~'):   # for auto-save filename
                    password = TreeDoc.passwordDict.get(key[:-1], '')
                if not password:
                    raise PasswordError, 'Missing password'
            text = encryptPrefix + p3.p3_encrypt(text, password)
        try:
            f.write(text)
        except IOError:
            print 'Error - could not write file', \
                  filePath.encode(globalref.localTextEncoding)
            raise
        f.close()
        if filePath.endswith('.gz'):
            self.compressFile = True
        if updateInfo:
            self.modified = False
            self.tlVersion = __version__
            self.fileName = filePath
            self.fileInfoFormat.updateFileInfo()

    def exportHtml(self, fileRef, item, includeRoot, openOnly=False,
                   indent=20, addHeader=False):
        """Save branch as html to file w/o columns"""
        outGroup = item.outputItemList(includeRoot, openOnly, True)
        self.exportHtmlColumns(fileRef, outGroup, 1, indent, addHeader)

    def exportHtmlColumns(self, fileRef, outGroup, numCol=1, indent=20,
                          addHeader=False):
        """Save contents of outGroup as html to file in columns"""
        try:
            f = self.getWriteFileObj(fileRef, False)
        except IOError:
            print 'Error - could not write file'
            raise
        filePath = unicode(f.name, sys.getfilesystemencoding())
        if self.lineBreaks:
            outGroup.addBreaks()
        outGroups = outGroup.splitColumns(numCol)
        for group in outGroups:
            group.addPrefix()
            group.addIndents()
        htmlTitle = os.path.splitext(os.path.basename(filePath))[0]
        lines = [u'<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 '\
                 'Transitional//EN">', u'<html>', u'<head>',
                 u'<meta http-equiv="Content-Type" content="text/html; '\
                 'charset=utf-8">', u'<title>%s</title>' % htmlTitle,
                 u'<style type="text/css"><!--', u'div {margin-left: %dpx}'\
                 % indent, u'td {padding: 10px}',
                 u'tr {vertical-align: top}', u'--></style>',
                 u'</head>', u'<body>']
        if addHeader:
            header = self.fileInfoFormat.getHeaderFooter(True)
            if header:
                lines.append(header)
        lines.extend([u'<table>', u'<tr><td>'])
        for item in outGroups[0]:
            lines.extend(item.textLines)
        for group in outGroups[1:]:
            lines.append(u'</td><td>')
            for item in group:
                lines.extend(item.textLines)
        lines.extend([u'</td></tr>', u'</table>'])
        if addHeader:
            footer = self.fileInfoFormat.getHeaderFooter(False)
            if footer:
                lines.append(footer)
        lines.extend([u'</body>', u'</html>'])
        try:
            f.writelines([(line + '\n').encode('utf-8') for line in lines])
        except IOError:
            print 'Error - could not write file', \
                  filePath.encode(globalref.localTextEncoding)
            raise
        f.close()

    def exportDirTable(self, dirName, nodeList, addHeader=False):
        """Write tree to nested directory struct with html tables"""
        oldDir = os.getcwd()
        os.chdir(dirName.encode(sys.getfilesystemencoding()))
        if addHeader:
            header = self.fileInfoFormat.getHeaderFooter(True)
            footer = self.fileInfoFormat.getHeaderFooter(False)
        else:
            header = footer = ''
        if len(nodeList) > 1:
            self.treeFormats.addIfMissing(TreeDoc.copyFormat)
            item = TreeItem(None, TreeDoc.copyFormat.name)
            item.data[TreeFormats.fieldDefault] = TreeDoc.rootTitleDefault
            for child in nodeList:
                item.childList.append(child)
                child.parent = item
        else:
            item = nodeList[0]
        linkDict = {}
        item.createDirTableLinkDict(linkDict, os.getcwd())
        item.exportDirTable(linkDict, None, header, footer)
        self.treeFormats.removeQuiet(TreeDoc.copyFormat)
        os.chdir(oldDir)

    def exportDirPage(self, dirName, nodeList):
        """Write tree to nested direct struct with html page for each node"""
        oldDir = os.getcwd()
        os.chdir(dirName.encode(sys.getfilesystemencoding()))
        cssLines = ['#sidebar {', 'width: 16em;', 'float: left;',
                    'clear: left;', 'border-right: 1px solid black;',
                    'margin-right: 1em;', '}']
        try:
            f = codecs.open('default.css', 'w', 'utf-8')
            f.writelines([(line + '\n').encode('utf-8') for line in cssLines])
        except (IOError, UnicodeError):
            print 'Error - could not write file to default.css'
            raise IOError(_('Error - cannot write file to %s') % 'default.css')
        f.close()
        if len(nodeList) > 1:
            self.treeFormats.addIfMissing(TreeDoc.copyFormat)
            item = TreeItem(None, TreeDoc.copyFormat.name)
            item.data[TreeFormats.fieldDefault] = TreeDoc.rootTitleDefault
            for child in nodeList:
                item.childList.append(child)
                child.parent = item
        else:
            item = nodeList[0]
        linkDict = {}
        item.createDirPageLinkDict(linkDict, os.getcwd())
        item.exportDirPage(linkDict)
        self.treeFormats.removeQuiet(TreeDoc.copyFormat)
        os.chdir(oldDir)

    def exportXslt(self, fileRef, includeRoot, indent=20):
        """Write XSLT file and add link in treeline file"""
        try:
            f = self.getWriteFileObj(fileRef, False)
        except IOError:
            print 'Error - could not write file'
            raise
        filePath = unicode(f.name, sys.getfilesystemencoding())
        title = os.path.splitext(os.path.basename(filePath))[0]
        lines = [u'<xsl:stylesheet version="1.0" '\
                 u'xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
                 u"<xsl:output method='html'/>", u'<xsl:template match="/">',
                 u'<html>', u'<head>']
        if self.xslCssLink:
            lines.append('<link rel="stylesheet" href="%s" type="text/css"/>'
                         % self.xslCssLink)
        lines.extend([u'<title>%s</title>' % title, u'</head>', u'<body>',
                     u'<xsl:apply-templates/>', u'</body>', u'</html>',
                     u'</xsl:template>'])
        if not includeRoot:
            lines.extend([u'', u'<xsl:template match="/%s">'
                          % self.root.formatName,
                          u'<xsl:apply-templates/>', u'</xsl:template>'])
        for formatName in self.treeFormats:
            lines.extend(self.treeFormats[formatName].
                         xsltTemplate(indent, True))
        lines.extend([u'', u'<xsl:template match="*" />', u'',
                      u'</xsl:stylesheet>'])
        try:
            f.writelines([(line + '\n').encode('utf-8') for line in lines])
        except IOError:
            print 'Error - could not write file', \
                  filePath.encode(globalref.localTextEncoding)
            raise
        f.close()
        # find relative link path
        trlPath = os.path.abspath(self.fileName).split(os.sep)
        xslPath = os.path.abspath(filePath).split(os.sep)
        while trlPath[0] == xslPath[0]:
            del trlPath[0]
            del xslPath[0]
        xslPath = '/'.join(['..'] * (len(trlPath) - len(xslPath)) + xslPath)
        link = u'xml-stylesheet type="text/xsl" href="%s"' % xslPath
        if self.xlstLink != link:
            self.xlstLink = link
            self.modified = True

    def exportTrlSubtree(self, fileRef, nodeList, addBranches=True):
        """Write subtree TRL file starting form item"""
        lines = [u'<?xml version="1.0" encoding="utf-8" ?>']
        if self.xlstLink:
            lines.append(u'<?%s?>' % self.xlstLink)
        if not addBranches:
            newList = []
            for item in nodeList:  # replace items with childless items
                newItem = TreeItem(item.parent, item.formatName)
                newItem.data = item.data
                newList.append(newItem)
            nodeList = newList
        if len(nodeList) > 1:
            format = nodeformat.NodeFormat(TreeFormats.rootFormatDefault, {},
                                           TreeFormats.fieldDefault)
            self.treeFormats.addIfMissing(format)
            item = TreeItem(None, format.name)
            item.data[TreeFormats.fieldDefault] = TreeDoc.rootTitleDefault
            for child in nodeList:
                item.childList.append(child)
                child.parent = item
        else:
            item = nodeList[0]
        lines.extend(item.branchXml([], True))
        try:
            f = self.getWriteFileObj(fileRef, self.compressFile)
            f.writelines([(line + '\n').encode('utf-8') for line in lines])
        except IOError:
            print 'Error - could not write file'
            self.treeFormats.removeQuiet(TreeDoc.copyFormat)
            raise
        f.close()
        self.treeFormats.removeQuiet(TreeDoc.copyFormat)

    def exportTable(self, fileRef, nodeList, addBranches=True):
        """Write data to table for nodes or children of nodes"""
        if addBranches:
            newList = []
            for item in nodeList:
                newList.extend(item.childList)
            nodeList = newList
        typeList = []
        headings = []
        tableList = []
        for item in nodeList:
            itemFormat = item.nodeFormat()
            if itemFormat not in typeList:
                for field in itemFormat.fieldNames():
                    if field not in headings:
                        headings.append(field)
                typeList.append(itemFormat)
            tableList.append(u'\t'.join([item.data.get(head, '') for
                                        head in headings]))
        tableList.insert(0, u'\t'.join([head for head in headings]))
        try:
            text = os.linesep.join(tableList).\
                      encode(globalref.localTextEncoding, 'strict')
        except (ValueError, UnicodeError):
            print 'Warning - bad unicode characters were replaced'
            text = os.linesep.join(tableList).\
                      encode(globalref.localTextEncoding, 'replace')
        try:
            f = self.getWriteFileObj(fileRef, False)
            f.write(text)
        except IOError:
            print 'Error - could not write file'
            raise
        f.close()

    def exportTabbedTitles(self, fileRef, nodeList, addBranches=True,
                           includeRoot=True, openOnly=False):
        """Write tabbed titles for descendants of item"""
        if addBranches:
            initLevel = not includeRoot and -1 or 0
            titleList = []
            for item in nodeList:
                itemList = item.exportToText(initLevel, openOnly)
                if not includeRoot:
                    del itemList[0]
                titleList.extend(itemList)
        else:
            titleList = [item.title() for item in nodeList]
        try:
            text = os.linesep.join(titleList).\
                      encode(globalref.localTextEncoding, 'strict')
        except (ValueError, UnicodeError):
            print 'Warning - bad unicode characters were replaced'
            text = os.linesep.join(titleList).\
                      encode(globalref.localTextEncoding, 'replace')
        try:
            f = self.getWriteFileObj(fileRef, False)
            f.write(text)
        except IOError:
            print 'Error - could not write file'
            raise
        f.close()

    def exportXbel(self, fileRef, nodeList, addBranches=True):
        """Export XBEL bookmarks"""
        if len(nodeList) > 1 or not addBranches:
            title = TreeDoc.bookmarkRootTitle
            level = 1
        else:
            title = xml.sax.saxutils.escape(nodeList[0].title(), escDict)
            level = 0
        lines = [u'<!DOCTYPE xbel>', u'<xbel>', u'<title>%s</title>' % title]
        for item in nodeList:
            lines.extend(item.exportXbelBookmarks(level, addBranches))
        lines.append(u'</xbel>')
        try:
            f = self.getWriteFileObj(fileRef, False)
            f.writelines([(line + '\n').encode('utf-8') for line in lines])
        except IOError:
            print 'Error - could not write file'
            raise
        f.close()

    def exportHtmlBookmarks(self, fileRef, nodeList, addBranches=True):
        """Export HTML bookmarks"""
        if len(nodeList) > 1 or not addBranches:
            title = TreeDoc.bookmarkRootTitle
            level = 1
        else:
            title = xml.sax.saxutils.escape(nodeList[0].title())
            level = 0
        lines = [u'<!DOCTYPE NETSCAPE-Bookmark-file-1>',
                 u'<META HTTP-EQUIV="Content-Type" CONTENT="text/html; '\
                  'charset=UTF-8">', u'<TITLE>%s</TITLE>' % title,
                 u'<H1>%s</H1>' % title, '']
        for item in nodeList:
            lines.extend(item.exportHtmlBookmarks(level, addBranches))
        try:
            f = self.getWriteFileObj(fileRef, False)
            f.writelines([(line + '\n').encode('utf-8') for line in lines])
        except IOError:
            print 'Error - could not write file'
            raise
        f.close()

    def exportGenericXml(self, fileRef, nodeList, addBranches=True):
        """Export generic XML"""
        lines = [u'<?xml version="1.0" encoding="utf-8" ?>']
        level = 0
        if len(nodeList) > 1:
            lines.append(u'<%s>' % TreeFormats.rootFormatDefault)
            level = 1
        for item in nodeList:
            lines.extend(item.exportGenericXml(treexmlparse.GenericXmlHandler.
                                               textFieldName, level))
        if len(nodeList) > 1:
            lines.append(u'</%s>' % TreeFormats.rootFormatDefault)
        try:
            f = self.getWriteFileObj(fileRef, False)
            f.writelines([(line + '\n').encode('utf-8') for line in lines])
        except IOError:
            print 'Error - could not write file'
            raise
        f.close()

    def exportOdf(self, fileRef, nodeList, fontName, fontSize, fontFixed=False,
                  addBranches=True, includeRoot=True, openOnly=False):
        """Export an ODF format text file"""
        TreeItem.maxLevel = 0
        commonHeader = u'<?xml version="1.0" encoding="utf-8" ?>'
        commonAttr = u' office:version="1.0" '\
                      'xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:'\
                      'xsl-fo-compatible:1.0" '\
                      'xmlns:office="urn:oasis:names:tc:opendocument:'\
                      'xmlns:office:1.0" '\
                      'xmlns:style="urn:oasis:names:tc:opendocument:xmlns:'\
                      'style:1.0" '\
                      'xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:'\
                      'svg-compatible:1.0" '\
                      'xmlns:text="urn:oasis:names:tc:opendocument:'\
                      'xmlns:text:1.0">'
        pitch = fontFixed and 'fixed' or 'variable'
        sizeDelta = 2
        fontDecl = [u'<office:font-face-decls>',
                    u'<style:font-face style:font-pitch="%s" style:name="%s" '\
                     'svg:font-family="%s"/>' % (pitch, fontName, fontName),
                    u'</office:font-face-decls>']
        lines = [commonHeader, u'<office:document-content' + commonAttr]
        lines.extend(fontDecl)
        lines.extend([u'<office:body>', u'<office:text>'])
        for item in nodeList:
            lines.extend(item.exportOdf(1, addBranches, includeRoot, openOnly))
        lines.extend([u'</office:text>', u'</office:body>',
                      u'</office:document-content>'])
        manifest = [commonHeader,
                    u'<manifest:manifest xmlns:manifest="urn:oasis:names:tc:'\
                     'opendocument:xmlns:manifest:1.0">',
                    u'<manifest:file-entry manifest:media-type="application/'\
                     'vnd.oasis.opendocument.text" manifest:full-path="/"/>',
                    u'<manifest:file-entry manifest:media-type="text/xml" '\
                     'manifest:full-path="content.xml"/>',
                    u'<manifest:file-entry manifest:media-type="text/xml" '\
                     'manifest:full-path="styles.xml"/>',
                    u'</manifest:manifest>']
        styles = [commonHeader, u'<office:document-styles' + commonAttr]
        styles.extend(fontDecl)
        styles.extend([u'<office:styles>',
                       u'<style:default-style style:family="paragraph">',
                       u'<style:paragraph-properties '\
                        'style:writing-mode="page"/>',
                       u'<style:text-properties fo:font-size="%dpt" '\
                        'fo:hyphenate="false" style:font-name="%s"/>' %
                        (fontSize, fontName),
                       u'</style:default-style>',
                       u'<style:style style:name="Standard" '\
                        'style:class="text" style:family="paragraph"/>',
                       u'<style:style style:name="Text_20_body" '\
                        'style:display-name="Text body" style:class="text" '\
                        'style:family="paragraph" '\
                        'style:parent-style-name="Standard">',
                       u'<style:paragraph-properties '\
                        'fo:margin-bottom="6.0pt"/>',
                       u'</style:style>',
                       u'<style:style style:name="Heading" '\
                        'style:class="text" style:family="paragraph" '\
                        'style:next-style-name="Text_20_body" '\
                        'style:parent-style-name="Standard">',
                       u'<style:paragraph-properties '\
                        'fo:keep-with-next="always" fo:margin-bottom="6.0pt" '\
                        'fo:margin-top="12.0pt"/>',
                       u'<style:text-properties fo:font-size="%dpt" '\
                        'style:font-name="%s"/>' % (fontSize + sizeDelta,
                                                    fontName),
                       u'</style:style>'])
        outline = [u'<text:outline-style>']
        for level in range(1, TreeItem.maxLevel + 1):
            size = fontSize
            if level <= 2:
                size += 2 * sizeDelta
            elif level <=4:
                size += sizeDelta
            italic = ' '
            if level % 2 == 0:
                italic = 'fo:font-style="italic" '
            styles.extend([u'<style:style style:name="Heading_20_%d" '\
                            'style:display-name="Heading %d" '\
                            'style:class="text" style:family="paragraph" '\
                            'style:parent-style-name="Heading" '\
                            'style:default-outline-level="%d">' % \
                            (level, level, level),
                           u'<style:text-properties fo:font-size="%dpt" '\
                            '%s fo:font-weight="bold"/>' % \
                            (size, italic),
                           u'</style:style>'])
            outline.append(u'<text:outline-level-style text:level="%d" '\
                            'style:num-format=""/>' % level)
        styles.extend(outline)
        styles.extend([u'</text:outline-style>', u'</office:styles>',
                       u'<office:automatic-styles>',
                       u'<style:page-layout style:name="pm1">',
                       u'<style:page-layout-properties '\
                        'fo:margin-bottom="0.75in" fo:margin-left="0.75in" '\
                        'fo:margin-right="0.75in" fo:margin-top="0.75in" '\
                        'fo:page-height="11in" fo:page-width="8.5in" '\
                        'style:print-orientation="portrait"/>',
                       u'</style:page-layout>',
                       u'</office:automatic-styles>',
                       u'<office:master-styles>',
                       u'<style:master-page style:name="Standard" '\
                        'style:page-layout-name="pm1"/>',
                       u'</office:master-styles>',
                       u'</office:document-styles>'])
        try:
            f = zipfile.ZipFile(fileRef, 'w', zipfile.ZIP_DEFLATED)
            f.writestr('content.xml', u'\n'.join(lines).encode('utf-8') + '\n')
            f.writestr('META-INF/manifest.xml', u'\n'.join(manifest) + '\n')
            f.writestr('styles.xml', u'\n'.join(styles) + '\n')
        except IOError:
            print 'Error - could not write file'
            raise
        f.close()
Example #41
0
class TreeDoc(object):
    """Tree document class - stores root and has tree utilities"""
    passwordDict = {}
    childFieldSepDflt = ', '
    rootTitleDefault = _('Main', 'default root title')
    folderName = _('FOLDER', 'bookmark format folder name')
    bookmarkName = _('BOOKMARK', 'bookmark format name')
    separatorName = _('SEPARATOR', 'bookmark format separator name')
    bookmarkRootTitle = _('Bookmarks')
    copyFormat = None

    def __init__(self, filePath=None, setNewDefaults=False, importType=None):
        """Open filePath (can also be file ref) if given,
           setNewDefaults uses user defaults for compression & encryption,
           importType gives an import method to read the file"""
        globalref.docRef = self
        self.root = None
        self.treeFormats = TreeFormats()
        self.fileInfoItem = TreeItem(None, nodeformat.FileInfoFormat.name)
        self.fileInfoFormat = None
        TreeDoc.copyFormat = nodeformat.NodeFormat('_DUMMY__ROOT_', {},
                                                   TreeFormats.fieldDefault)
        self.undoStore = undo.UndoRedoStore()
        self.redoStore = undo.UndoRedoStore()
        self.sortFields = ['']
        self.fileName = ''
        self.spaceBetween = True
        self.lineBreaks = True
        self.formHtml = True
        self.childFieldSep = TreeDoc.childFieldSepDflt
        self.spellChkLang = ''
        self.xlstLink = ''
        self.xslCssLink = ''
        self.tlVersion = __version__
        self.fileInfoFormat = nodeformat.FileInfoFormat()
        if filePath:
            if importType:
                getattr(self, importType)(filePath)
            else:
                self.readFile(filePath)
        else:
            self.treeFormats = TreeFormats({}, True)
            self.root = TreeItem(None, TreeFormats.rootFormatDefault)
            self.root.setTitle(TreeDoc.rootTitleDefault)
        self.modified = False
        if setNewDefaults or not hasattr(self, 'compressFile'):
            self.compressFile = globalref.options.boolData('CompressNewFiles')
            self.encryptFile = globalref.options.boolData('EncryptNewFiles')
        elif not hasattr(self, 'encryptFile'):
            self.encryptFile = False
        self.selection = treeselection.TreeSelection([self.root])
        self.fileInfoFormat.translateFields()
        self.fileInfoFormat.updateFileInfo()

    def hasPassword(self, filePath):
        """Return True if a password is available for filePath"""
        key = filePath.encode(sys.getfilesystemencoding())
        return TreeDoc.passwordDict.has_key(key)

    def setPassword(self, filePath, password):
        """Set encrytion password for the filePath"""
        key = filePath.encode(sys.getfilesystemencoding())
        TreeDoc.passwordDict[key] = password.encode('utf-8')

    def clearPassword(self, filePath):
        """Remove password for filePath if present"""
        key = filePath.encode(sys.getfilesystemencoding())
        try:
            del TreeDoc.passwordDict[key]
        except KeyError:
            pass

    def getReadFileObj(self, fileRef):
        """Return file object and set self.compressFile to False/True,
           fileRef is either file path or file object"""
        if not hasattr(fileRef, 'read'):
            fileRef = file(fileRef.encode(sys.getfilesystemencoding()), 'rb')
            # binary mode req'd for encryption
        if hasattr(fileRef, 'seek'):
            fileRef.seek(0)
        prefix = fileRef.read(2)
        if hasattr(fileRef, 'seek'):
            fileRef.seek(0)
        else:
            oldFileRef = fileRef
            fileRef = StringIO.StringIO(prefix + oldFileRef.read())
            fileRef.name = oldFileRef.name
            oldFileRef.close()
        if prefix == '\037\213':
            name = fileRef.name
            fileRef = gzip.GzipFile(fileobj=fileRef)
            fileRef.name = name
        # may already be a gzip object from before password prompt
        self.compressFile = isinstance(fileRef, gzip.GzipFile)
        return fileRef

    def decryptFile(self, fileObj):
        """Decrypt file if was encrypted"""
        name = fileObj.name
        prefix = fileObj.read(len(encryptPrefix))
        self.encryptFile = prefix == encryptPrefix
        if self.encryptFile:
            password = TreeDoc.passwordDict.get(fileObj.name, '')
            if not password:
                fileObj.close()
                raise PasswordError, 'Missing password'
            try:
                text = p3.p3_decrypt(fileObj.read(), password)
            except p3.CryptError:
                fileObj.close()
                raise PasswordError, 'Incorrect password'
            fileObj.close()
            fileObj = StringIO.StringIO(text)
            fileObj.name = name
        else:
            fileObj.seek(0)
        return fileObj

    def getEncodedFileObj(self, fileRef, encoding, errors):
        """Return open file object with specified encoding"""
        return codecs.getreader(encoding)(self.getReadFileObj(fileRef), errors)

    def getWriteFileObj(self, fileRef, forceCompress):
        """Return write file object, compressed or not based on forceCompress,
           but always compress if has .gz extension,
           fileRef is either file path or file object"""
        if not hasattr(fileRef, 'read'):
            fileRef = file(fileRef.encode(sys.getfilesystemencoding()), 'wb')
        if fileRef.name.endswith('.gz') or forceCompress:
            name = fileRef.name
            fileRef = gzip.GzipFile(fileobj=fileRef)
            fileRef.name = name
        return fileRef

    def readFile(self, fileRef):
        """Open and read file - raise exception on failure,
           fileRef is either file path or file object"""
        filePath = hasattr(fileRef, 'read') and \
                   unicode(fileRef.name, sys.getfilesystemencoding()) or \
                   fileRef
        try:
            f = self.getReadFileObj(fileRef)
            f = self.decryptFile(f)
            handler = treexmlparse.TreeSaxHandler(self)
            input = xml.sax.InputSource()
            input.setByteStream(f)
            input.setEncoding('utf-8')
            reader = xml.sax.make_parser()
            reader.setContentHandler(handler)
            reader.setFeature(xml.sax.handler.feature_external_ges, 0)
            reader.parse(input)
        except IOError:
            print 'Error - could not read file', \
                  filePath.encode(globalref.localTextEncoding)
            raise
        except UnicodeError:
            print 'Error - bad Unicode in file', \
                  filePath.encode(globalref.localTextEncoding)
            f.close()
            raise
        except xml.sax.SAXException:
            f.close()
            raise ReadFileError(_('Could not open as treeline file'))
        f.close()
        self.root = handler.rootItem
        self.fileName = filePath
        self.treeFormats = TreeFormats(handler.formats)
        self.fileInfoFormat.replaceListFormat()
        self.treeFormats.updateAutoChoices()
        self.treeFormats.updateUniqueID()
        self.treeFormats.updateDerivedTypes()
        if not self.tlVersion:  # file from before 0.12.80, fix number format
            for format in self.treeFormats.values():
                for field in format.fieldList:
                    if field.typeName == 'Number':
                        field.format = field.format.replace(',', '\,')

    def readTabbed(self, fileRef, errors='strict'):
        """Import tabbed data into a flat tree - raise exception on failure"""
        try:
            f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                       errors)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            textList = f.readlines()
        except UnicodeError:
            print 'Warning - bad unicode characters were replaced'
            if errors == 'strict':
                self.readTabbed(fileRef, 'replace')
            else:
                f.close()
            return
        f.close()
        bufList = [(text.count('\t', 0,
                               len(text) - len(text.lstrip())), text.strip())
                   for text in textList if text.strip()]
        if bufList:
            buf = bufList.pop(0)
            if buf[0] == 0:
                # set default formats ROOT & DEFAULT
                self.treeFormats = TreeFormats({}, True)
                newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
                newRoot.setTitle(buf[1])
                if newRoot.loadTabbedChildren(bufList):
                    self.root = newRoot
                    self.fileName = filePath
                    return
        raise ReadFileError(_('Error in tabbed list'))

    def readTable(self, fileRef, errors='strict'):
        """Import table data into a flat tree - raise exception on failure"""
        try:
            f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                       errors)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            textList = f.readlines()
        except UnicodeError:
            print 'Warning - bad unicode characters were replaced'
            if errors == 'strict':
                self.readTable(fileRef, 'replace')
            else:
                f.close()
            return
        f.close()
        self.treeFormats = TreeFormats({}, True)  # set defaults ROOT & DEFAULT
        newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
        defaultFormat = self.treeFormats[TreeFormats.formatDefault]
        defaultFormat.fieldList = []
        defaultFormat.lineList = []
        defaultFormat.addTableFields(textList.pop(0).strip().split('\t'))
        newRoot.setTitle(TreeDoc.rootTitleDefault)
        for line in textList:
            newItem = TreeItem(newRoot, TreeFormats.formatDefault)
            newRoot.childList.append(newItem)
            lineList = line.strip().split('\t')
            try:
                for num in range(len(lineList)):
                    newItem.data[self.treeFormats[TreeFormats.formatDefault].
                                 fieldList[num].name] = lineList[num].strip()
            except IndexError:
                print 'Too few headings to read data as a table'
                raise ReadFileError(
                    _('Too few headings to read data as table'))
        self.root = newRoot
        self.fileName = filePath

    def readLines(self, fileRef, errors='strict'):
        """Import plain text, node per line"""
        try:
            f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                       errors)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            textList = f.readlines()
        except UnicodeError:
            print 'Warning - bad unicode characters were replaced'
            if errors == 'strict':
                self.readLines(fileRef, 'replace')
            else:
                f.close()
            return
        f.close()
        self.treeFormats = TreeFormats({}, True)  # set defaults ROOT & DEFAULT
        newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
        defaultFormat = self.treeFormats[TreeFormats.formatDefault]
        defaultFormat.fieldList = []
        defaultFormat.lineList = []
        defaultFormat.addTableFields([TreeFormats.textFieldName])
        newRoot.setTitle(TreeDoc.rootTitleDefault)
        for line in textList:
            line = line.strip()
            if line:
                newItem = TreeItem(newRoot, TreeFormats.formatDefault)
                newRoot.childList.append(newItem)
                newItem.data[TreeFormats.textFieldName] = line
        self.root = newRoot
        self.fileName = filePath

    def readPara(self, fileRef, errors='strict'):
        """Import plain text, blank line delimitted"""
        try:
            f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                       errors)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            fullText = f.read().replace('\r', '')
        except UnicodeError:
            print 'Warning - bad unicode characters were replaced'
            if errors == 'strict':
                self.readPara(fileRef, 'replace')
            else:
                f.close()
            return
        textList = fullText.split('\n\n')
        f.close()
        self.treeFormats = TreeFormats({}, True)  # set defaults ROOT & DEFAULT
        newRoot = TreeItem(None, TreeFormats.rootFormatDefault)
        defaultFormat = self.treeFormats[TreeFormats.formatDefault]
        defaultFormat.fieldList = []
        defaultFormat.lineList = []
        defaultFormat.iconName = 'doc'
        defaultFormat.addTableFields([TreeFormats.textFieldName])
        defaultFormat.fieldList[0].numLines = globalref.options.\
                                               intData('MaxEditLines', 1,
                                                    optiondefaults.maxNumLines)
        newRoot.setTitle(TreeDoc.rootTitleDefault)
        for line in textList:
            line = line.strip()
            if line:
                newItem = TreeItem(newRoot, TreeFormats.formatDefault)
                newRoot.childList.append(newItem)
                newItem.data[TreeFormats.textFieldName] = line
        self.root = newRoot
        self.fileName = filePath

    def readTreepad(self, fileRef, errors='strict'):
        """Read Treepad text-node file"""
        try:
            f = self.getEncodedFileObj(fileRef, globalref.localTextEncoding,
                                       errors)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            textList = f.read().split('<end node> 5P9i0s8y19Z')
            f.close()
        except UnicodeError:  # error common - broken unicode on windows
            print 'Warning - bad unicode characters were replaced'
            if errors == 'strict':
                self.readTreepad(fileRef, 'replace')
            else:
                f.close()
            return
        self.treeFormats = TreeFormats()
        format = nodeformat.NodeFormat(TreeFormats.formatDefault)
        titleFieldName = _('Title', 'title field name')
        format.addNewField(titleFieldName)
        format.addLine(u'{*%s*}' % titleFieldName)
        numLines = globalref.options.intData('MaxEditLines', 1,
                                             optiondefaults.maxNumLines)
        format.addNewField(TreeFormats.textFieldName,
                           {'lines': repr(numLines)})
        format.addLine(u'{*%s*}' % TreeFormats.textFieldName)
        self.treeFormats[format.name] = format
        itemList = []
        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):
                    print 'Error - bad file format in %s' % \
                          filePath.encode(globalref.localTextEncoding)
                    raise ReadFileError(_('Bad file format in %s') % filePath)
                item = TreeItem(None, format.name)
                item.data[titleFieldName] = title
                item.data[TreeFormats.textFieldName] = '\n'.join(lines)
                item.level = level
                itemList.append(item)
        self.root = itemList[0]
        parentList = []
        for item in itemList:
            if item.level != 0:
                parentList = parentList[:item.level]
                item.parent = parentList[-1]
                parentList[-1].childList.append(item)
            parentList.append(item)
        self.root = itemList[0]
        self.fileName = filePath

    def createBookmarkFormat(self):
        """Return a set of formats for bookmark imports"""
        treeFormats = TreeFormats()
        format = nodeformat.NodeFormat(TreeDoc.folderName)
        format.addNewField(TreeFormats.fieldDefault)
        format.addLine(u'{*%s*}' % TreeFormats.fieldDefault)
        format.addLine(u'{*%s*}' % TreeFormats.fieldDefault)
        format.iconName = 'folder_3'
        treeFormats[format.name] = format
        format = nodeformat.NodeFormat(TreeDoc.bookmarkName)
        format.addNewField(TreeFormats.fieldDefault)
        format.addLine(u'{*%s*}' % TreeFormats.fieldDefault)
        format.addLine(u'{*%s*}' % TreeFormats.fieldDefault)
        format.addNewField(TreeFormats.linkFieldName, {'type': 'URL'})
        format.addLine(u'{*%s*}' % TreeFormats.linkFieldName)
        format.iconName = 'bookmark'
        treeFormats[format.name] = format
        format = nodeformat.NodeFormat(TreeDoc.separatorName)
        format.addNewField(TreeFormats.fieldDefault)
        format.addLine(u'------------------')
        format.addLine(u'<hr>')
        treeFormats[format.name] = format
        return treeFormats

    def readXbel(self, fileRef):
        """Read XBEL format bookmarks"""
        formats = self.createBookmarkFormat()
        try:
            f = self.getReadFileObj(fileRef)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            handler = treexmlparse.\
                      XbelSaxHandler(formats[TreeDoc.folderName],
                                     formats[TreeDoc.bookmarkName],
                                     formats[TreeDoc.separatorName])
            input = xml.sax.InputSource()
            input.setByteStream(f)
            input.setEncoding('utf-8')
            reader = xml.sax.make_parser()
            reader.setContentHandler(handler)
            reader.setFeature(xml.sax.handler.feature_external_ges, 0)
            reader.parse(input)
        except UnicodeError:
            print 'Error - bad Unicode in file', \
                  filePath.encode(globalref.localTextEncoding)
            f.close()
            raise ReadFileError(_('Problem with Unicode characters in file'))
        except xml.sax.SAXException:
            f.close()
            raise ReadFileError(_('Could not open as XBEL file'))
        f.close()
        if not handler.rootItem:
            raise ReadFileError(_('Could not open as XBEL file'))
        self.root = handler.rootItem
        if not self.root.data.get(TreeFormats.fieldDefault, ''):
            self.root.data[TreeFormats.fieldDefault] = \
                      TreeDoc.bookmarkRootTitle
        self.fileName = filePath
        self.treeFormats = formats

    def readMozilla(self, fileRef, errors='strict'):
        """Read Mozilla HTML format bookmarks"""
        formats = self.createBookmarkFormat()
        try:
            f = self.getEncodedFileObj(fileRef, 'utf-8', errors)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            fullText = f.read()
        except UnicodeError:
            print 'Warning - bad unicode characters were replaced'
            if errors == 'strict':
                self.readMozilla(fileRef, 'replace')
            else:
                f.close()
            return
        try:
            handler = treexmlparse.\
                      HtmlBookmarkHandler(formats[TreeDoc.folderName],
                                          formats[TreeDoc.bookmarkName],
                                          formats[TreeDoc.separatorName])
            handler.feed(fullText)
            handler.close()
        except treexmlparse.HtmlParseError:
            raise ReadFileError(_('Could not open as HTML bookmark file'))
        if not handler.rootItem:
            raise ReadFileError(_('Could not open as HTML bookmark file'))
        self.root = handler.rootItem
        if not self.root.data.get(TreeFormats.fieldDefault, ''):
            self.root.data[TreeFormats.fieldDefault] = \
                      TreeDoc.bookmarkRootTitle
        self.fileName = filePath
        self.treeFormats = formats

    def readXml(self, fileRef):
        """Read a generic (non-TreeLine) XML file"""
        try:
            f = self.getReadFileObj(fileRef)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            handler = treexmlparse.GenericXmlHandler()
            input = xml.sax.InputSource()
            input.setByteStream(f)
            input.setEncoding('utf-8')
            reader = xml.sax.make_parser()
            reader.setContentHandler(handler)
            reader.setFeature(xml.sax.handler.feature_external_ges, 0)
            reader.parse(input)
        except UnicodeError:
            print 'Error - bad Unicode in file', \
                  filePath.encode(globalref.localTextEncoding)
            f.close()
            raise ReadFileError(_('Problem with Unicode characters in file'))
        except xml.sax.SAXException:
            f.close()
            raise ReadFileError(_('Could not open XML file'))
        f.close()
        if not handler.rootItem:
            raise ReadFileError(_('Could not open XML file'))
        self.root = handler.rootItem
        self.fileName = filePath
        self.treeFormats = TreeFormats(handler.formats)
        for format in self.treeFormats.values():
            format.fixImportedFormat(
                treexmlparse.GenericXmlHandler.textFieldName)

    def readOdf(self, fileRef):
        """Read an Open Document Format (ODF) file"""
        self.treeFormats = TreeFormats(None, True)
        rootItem = TreeItem(None, TreeFormats.rootFormatDefault,
                            TreeDoc.rootTitleDefault)
        defaultFormat = self.treeFormats[TreeFormats.formatDefault]
        defaultFormat.addNewField(TreeFormats.textFieldName, {
            u'html': 'n',
            u'lines': '6'
        })
        defaultFormat.changeOutputLines([
            u'<b>{*%s*}</b>' % TreeFormats.fieldDefault,
            u'{*%s*}' % TreeFormats.textFieldName
        ])
        try:
            f = self.getReadFileObj(fileRef)
            filePath = unicode(f.name, sys.getfilesystemencoding())
            zip = zipfile.ZipFile(f, 'r')
            text = zip.read('content.xml')
            handler = treexmlparse.OdfSaxHandler(rootItem, defaultFormat)
            xml.sax.parseString(text, handler)
        except (zipfile.BadZipfile, KeyError):
            f.close()
            raise ReadFileError(_('Could not unzip ODF file'))
        except UnicodeError:
            f.close()
            raise ReadFileError(_('Problem with Unicode characters in file'))
        except xml.sax.SAXException:
            f.close()
            raise ReadFileError(_('Could not open corrupt ODF file'))
        f.close()
        self.root = rootItem
        self.fileName = filePath

    def readXmlString(self, string):
        """Read xml string and return top item or None"""
        try:
            handler = treexmlparse.TreeSaxHandler(self)
            xml.sax.parseString(string.encode('utf-8'), handler)
        except xml.sax.SAXException:
            return None
        return handler.rootItem

    def readXmlStringAndFormat(self, string):
        """Read xml string and return tuple of top item and new formats"""
        try:
            handler = treexmlparse.TreeSaxHandler(self)
            xml.sax.parseString(string.encode('utf-8'), handler)
        except xml.sax.SAXException:
            return (None, [])
        formats = [
            format for format in handler.formats.values()
            if format.name not in self.treeFormats
        ]
        try:
            formats.remove(TreeDoc.copyFormat)
        except ValueError:
            pass
        formatNames = [format.name for format in formats] + \
                       self.treeFormats.keys()
        for format in formats:
            if format.genericType not in formatNames:
                format.genericType = ''
        return (handler.rootItem, formats)

    def writeFile(self, fileRef, updateInfo=True):
        """Write file - raises IOError on failure"""
        lines = [u'<?xml version="1.0" encoding="utf-8" ?>']
        if self.xlstLink:
            lines.append(u'<?%s?>' % self.xlstLink)
        lines.extend(self.root.branchXml([], True))
        text = '\n'.join(lines).encode('utf-8')
        try:
            f = self.getWriteFileObj(fileRef, self.compressFile)
        except IOError:
            print 'Error - could not write file'
            raise
        filePath = unicode(f.name, sys.getfilesystemencoding())
        if self.encryptFile:
            key = filePath.encode(sys.getfilesystemencoding())
            password = TreeDoc.passwordDict.get(key, '')
            if not password:
                if key.endswith('~'):  # for auto-save filename
                    password = TreeDoc.passwordDict.get(key[:-1], '')
                if not password:
                    raise PasswordError, 'Missing password'
            text = encryptPrefix + p3.p3_encrypt(text, password)
        try:
            f.write(text)
        except IOError:
            print 'Error - could not write file', \
                  filePath.encode(globalref.localTextEncoding)
            raise
        f.close()
        if filePath.endswith('.gz'):
            self.compressFile = True
        if updateInfo:
            self.modified = False
            self.tlVersion = __version__
            self.fileName = filePath
            self.fileInfoFormat.updateFileInfo()

    def exportHtml(self,
                   fileRef,
                   item,
                   includeRoot,
                   openOnly=False,
                   indent=20,
                   addHeader=False):
        """Save branch as html to file w/o columns"""
        outGroup = item.outputItemList(includeRoot, openOnly, True)
        self.exportHtmlColumns(fileRef, outGroup, 1, indent, addHeader)

    def exportHtmlColumns(self,
                          fileRef,
                          outGroup,
                          numCol=1,
                          indent=20,
                          addHeader=False):
        """Save contents of outGroup as html to file in columns"""
        try:
            f = self.getWriteFileObj(fileRef, False)
        except IOError:
            print 'Error - could not write file'
            raise
        filePath = unicode(f.name, sys.getfilesystemencoding())
        if self.lineBreaks:
            outGroup.addBreaks()
        outGroups = outGroup.splitColumns(numCol)
        for group in outGroups:
            group.addPrefix()
            group.addIndents()
        htmlTitle = os.path.splitext(os.path.basename(filePath))[0]
        lines = [u'<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 '\
                 'Transitional//EN">', u'<html>', u'<head>',
                 u'<meta http-equiv="Content-Type" content="text/html; '\
                 'charset=utf-8">', u'<title>%s</title>' % htmlTitle,
                 u'<style type="text/css"><!--', u'div {margin-left: %dpx}'\
                 % indent, u'td {padding: 10px}',
                 u'tr {vertical-align: top}', u'--></style>',
                 u'</head>', u'<body>']
        if addHeader:
            header = self.fileInfoFormat.getHeaderFooter(True)
            if header:
                lines.append(header)
        lines.extend([u'<table>', u'<tr><td>'])
        for item in outGroups[0]:
            lines.extend(item.textLines)
        for group in outGroups[1:]:
            lines.append(u'</td><td>')
            for item in group:
                lines.extend(item.textLines)
        lines.extend([u'</td></tr>', u'</table>'])
        if addHeader:
            footer = self.fileInfoFormat.getHeaderFooter(False)
            if footer:
                lines.append(footer)
        lines.extend([u'</body>', u'</html>'])
        try:
            f.writelines([(line + '\n').encode('utf-8') for line in lines])
        except IOError:
            print 'Error - could not write file', \
                  filePath.encode(globalref.localTextEncoding)
            raise
        f.close()

    def exportDirTable(self, dirName, nodeList, addHeader=False):
        """Write tree to nested directory struct with html tables"""
        oldDir = os.getcwd()
        os.chdir(dirName.encode(sys.getfilesystemencoding()))
        if addHeader:
            header = self.fileInfoFormat.getHeaderFooter(True)
            footer = self.fileInfoFormat.getHeaderFooter(False)
        else:
            header = footer = ''
        if len(nodeList) > 1:
            self.treeFormats.addIfMissing(TreeDoc.copyFormat)
            item = TreeItem(None, TreeDoc.copyFormat.name)
            item.data[TreeFormats.fieldDefault] = TreeDoc.rootTitleDefault
            for child in nodeList:
                item.childList.append(child)
                child.parent = item
        else:
            item = nodeList[0]
        linkDict = {}
        item.createDirTableLinkDict(linkDict, os.getcwd())
        item.exportDirTable(linkDict, None, header, footer)
        self.treeFormats.removeQuiet(TreeDoc.copyFormat)
        os.chdir(oldDir)

    def exportDirPage(self, dirName, nodeList):
        """Write tree to nested direct struct with html page for each node"""
        oldDir = os.getcwd()
        os.chdir(dirName.encode(sys.getfilesystemencoding()))
        cssLines = [
            '#sidebar {', 'width: 16em;', 'float: left;', 'clear: left;',
            'border-right: 1px solid black;', 'margin-right: 1em;', '}'
        ]
        try:
            f = codecs.open('default.css', 'w', 'utf-8')
            f.writelines([(line + '\n').encode('utf-8') for line in cssLines])
        except (IOError, UnicodeError):
            print 'Error - could not write file to default.css'
            raise IOError(_('Error - cannot write file to %s') % 'default.css')
        f.close()
        if len(nodeList) > 1:
            self.treeFormats.addIfMissing(TreeDoc.copyFormat)
            item = TreeItem(None, TreeDoc.copyFormat.name)
            item.data[TreeFormats.fieldDefault] = TreeDoc.rootTitleDefault
            for child in nodeList:
                item.childList.append(child)
                child.parent = item
        else:
            item = nodeList[0]
        linkDict = {}
        item.createDirPageLinkDict(linkDict, os.getcwd())
        item.exportDirPage(linkDict)
        self.treeFormats.removeQuiet(TreeDoc.copyFormat)
        os.chdir(oldDir)

    def exportXslt(self, fileRef, includeRoot, indent=20):
        """Write XSLT file and add link in treeline file"""
        try:
            f = self.getWriteFileObj(fileRef, False)
        except IOError:
            print 'Error - could not write file'
            raise
        filePath = unicode(f.name, sys.getfilesystemencoding())
        title = os.path.splitext(os.path.basename(filePath))[0]
        lines = [u'<xsl:stylesheet version="1.0" '\
                 u'xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
                 u"<xsl:output method='html'/>", u'<xsl:template match="/">',
                 u'<html>', u'<head>']
        if self.xslCssLink:
            lines.append('<link rel="stylesheet" href="%s" type="text/css"/>' %
                         self.xslCssLink)
        lines.extend([
            u'<title>%s</title>' % title, u'</head>', u'<body>',
            u'<xsl:apply-templates/>', u'</body>', u'</html>',
            u'</xsl:template>'
        ])
        if not includeRoot:
            lines.extend([
                u'',
                u'<xsl:template match="/%s">' % self.root.formatName,
                u'<xsl:apply-templates/>', u'</xsl:template>'
            ])
        for formatName in self.treeFormats:
            lines.extend(self.treeFormats[formatName].xsltTemplate(
                indent, True))
        lines.extend(
            [u'', u'<xsl:template match="*" />', u'', u'</xsl:stylesheet>'])
        try:
            f.writelines([(line + '\n').encode('utf-8') for line in lines])
        except IOError:
            print 'Error - could not write file', \
                  filePath.encode(globalref.localTextEncoding)
            raise
        f.close()
        # find relative link path
        trlPath = os.path.abspath(self.fileName).split(os.sep)
        xslPath = os.path.abspath(filePath).split(os.sep)
        while trlPath[0] == xslPath[0]:
            del trlPath[0]
            del xslPath[0]
        xslPath = '/'.join(['..'] * (len(trlPath) - len(xslPath)) + xslPath)
        link = u'xml-stylesheet type="text/xsl" href="%s"' % xslPath
        if self.xlstLink != link:
            self.xlstLink = link
            self.modified = True

    def exportTrlSubtree(self, fileRef, nodeList, addBranches=True):
        """Write subtree TRL file starting form item"""
        lines = [u'<?xml version="1.0" encoding="utf-8" ?>']
        if self.xlstLink:
            lines.append(u'<?%s?>' % self.xlstLink)
        if not addBranches:
            newList = []
            for item in nodeList:  # replace items with childless items
                newItem = TreeItem(item.parent, item.formatName)
                newItem.data = item.data
                newList.append(newItem)
            nodeList = newList
        if len(nodeList) > 1:
            format = nodeformat.NodeFormat(TreeFormats.rootFormatDefault, {},
                                           TreeFormats.fieldDefault)
            self.treeFormats.addIfMissing(format)
            item = TreeItem(None, format.name)
            item.data[TreeFormats.fieldDefault] = TreeDoc.rootTitleDefault
            for child in nodeList:
                item.childList.append(child)
                child.parent = item
        else:
            item = nodeList[0]
        lines.extend(item.branchXml([], True))
        try:
            f = self.getWriteFileObj(fileRef, self.compressFile)
            f.writelines([(line + '\n').encode('utf-8') for line in lines])
        except IOError:
            print 'Error - could not write file'
            self.treeFormats.removeQuiet(TreeDoc.copyFormat)
            raise
        f.close()
        self.treeFormats.removeQuiet(TreeDoc.copyFormat)

    def exportTable(self, fileRef, nodeList, addBranches=True):
        """Write data to table for nodes or children of nodes"""
        if addBranches:
            newList = []
            for item in nodeList:
                newList.extend(item.childList)
            nodeList = newList
        typeList = []
        headings = []
        tableList = []
        for item in nodeList:
            itemFormat = item.nodeFormat()
            if itemFormat not in typeList:
                for field in itemFormat.fieldNames():
                    if field not in headings:
                        headings.append(field)
                typeList.append(itemFormat)
            tableList.append(u'\t'.join(
                [item.data.get(head, '') for head in headings]))
        tableList.insert(0, u'\t'.join([head for head in headings]))
        try:
            text = os.linesep.join(tableList).\
                      encode(globalref.localTextEncoding, 'strict')
        except (ValueError, UnicodeError):
            print 'Warning - bad unicode characters were replaced'
            text = os.linesep.join(tableList).\
                      encode(globalref.localTextEncoding, 'replace')
        try:
            f = self.getWriteFileObj(fileRef, False)
            f.write(text)
        except IOError:
            print 'Error - could not write file'
            raise
        f.close()

    def exportTabbedTitles(self,
                           fileRef,
                           nodeList,
                           addBranches=True,
                           includeRoot=True,
                           openOnly=False):
        """Write tabbed titles for descendants of item"""
        if addBranches:
            initLevel = not includeRoot and -1 or 0
            titleList = []
            for item in nodeList:
                itemList = item.exportToText(initLevel, openOnly)
                if not includeRoot:
                    del itemList[0]
                titleList.extend(itemList)
        else:
            titleList = [item.title() for item in nodeList]
        try:
            text = os.linesep.join(titleList).\
                      encode(globalref.localTextEncoding, 'strict')
        except (ValueError, UnicodeError):
            print 'Warning - bad unicode characters were replaced'
            text = os.linesep.join(titleList).\
                      encode(globalref.localTextEncoding, 'replace')
        try:
            f = self.getWriteFileObj(fileRef, False)
            f.write(text)
        except IOError:
            print 'Error - could not write file'
            raise
        f.close()

    def exportXbel(self, fileRef, nodeList, addBranches=True):
        """Export XBEL bookmarks"""
        if len(nodeList) > 1 or not addBranches:
            title = TreeDoc.bookmarkRootTitle
            level = 1
        else:
            title = xml.sax.saxutils.escape(nodeList[0].title(), escDict)
            level = 0
        lines = [u'<!DOCTYPE xbel>', u'<xbel>', u'<title>%s</title>' % title]
        for item in nodeList:
            lines.extend(item.exportXbelBookmarks(level, addBranches))
        lines.append(u'</xbel>')
        try:
            f = self.getWriteFileObj(fileRef, False)
            f.writelines([(line + '\n').encode('utf-8') for line in lines])
        except IOError:
            print 'Error - could not write file'
            raise
        f.close()

    def exportHtmlBookmarks(self, fileRef, nodeList, addBranches=True):
        """Export HTML bookmarks"""
        if len(nodeList) > 1 or not addBranches:
            title = TreeDoc.bookmarkRootTitle
            level = 1
        else:
            title = xml.sax.saxutils.escape(nodeList[0].title())
            level = 0
        lines = [u'<!DOCTYPE NETSCAPE-Bookmark-file-1>',
                 u'<META HTTP-EQUIV="Content-Type" CONTENT="text/html; '\
                  'charset=UTF-8">', u'<TITLE>%s</TITLE>' % title,
                 u'<H1>%s</H1>' % title, '']
        for item in nodeList:
            lines.extend(item.exportHtmlBookmarks(level, addBranches))
        try:
            f = self.getWriteFileObj(fileRef, False)
            f.writelines([(line + '\n').encode('utf-8') for line in lines])
        except IOError:
            print 'Error - could not write file'
            raise
        f.close()

    def exportGenericXml(self, fileRef, nodeList, addBranches=True):
        """Export generic XML"""
        lines = [u'<?xml version="1.0" encoding="utf-8" ?>']
        level = 0
        if len(nodeList) > 1:
            lines.append(u'<%s>' % TreeFormats.rootFormatDefault)
            level = 1
        for item in nodeList:
            lines.extend(
                item.exportGenericXml(
                    treexmlparse.GenericXmlHandler.textFieldName, level))
        if len(nodeList) > 1:
            lines.append(u'</%s>' % TreeFormats.rootFormatDefault)
        try:
            f = self.getWriteFileObj(fileRef, False)
            f.writelines([(line + '\n').encode('utf-8') for line in lines])
        except IOError:
            print 'Error - could not write file'
            raise
        f.close()

    def exportOdf(self,
                  fileRef,
                  nodeList,
                  fontName,
                  fontSize,
                  fontFixed=False,
                  addBranches=True,
                  includeRoot=True,
                  openOnly=False):
        """Export an ODF format text file"""
        TreeItem.maxLevel = 0
        commonHeader = u'<?xml version="1.0" encoding="utf-8" ?>'
        commonAttr = u' office:version="1.0" '\
                      'xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:'\
                      'xsl-fo-compatible:1.0" '\
                      'xmlns:office="urn:oasis:names:tc:opendocument:'\
                      'xmlns:office:1.0" '\
                      'xmlns:style="urn:oasis:names:tc:opendocument:xmlns:'\
                      'style:1.0" '\
                      'xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:'\
                      'svg-compatible:1.0" '\
                      'xmlns:text="urn:oasis:names:tc:opendocument:'\
                      'xmlns:text:1.0">'
        pitch = fontFixed and 'fixed' or 'variable'
        sizeDelta = 2
        fontDecl = [u'<office:font-face-decls>',
                    u'<style:font-face style:font-pitch="%s" style:name="%s" '\
                     'svg:font-family="%s"/>' % (pitch, fontName, fontName),
                    u'</office:font-face-decls>']
        lines = [commonHeader, u'<office:document-content' + commonAttr]
        lines.extend(fontDecl)
        lines.extend([u'<office:body>', u'<office:text>'])
        for item in nodeList:
            lines.extend(item.exportOdf(1, addBranches, includeRoot, openOnly))
        lines.extend([
            u'</office:text>', u'</office:body>', u'</office:document-content>'
        ])
        manifest = [commonHeader,
                    u'<manifest:manifest xmlns:manifest="urn:oasis:names:tc:'\
                     'opendocument:xmlns:manifest:1.0">',
                    u'<manifest:file-entry manifest:media-type="application/'\
                     'vnd.oasis.opendocument.text" manifest:full-path="/"/>',
                    u'<manifest:file-entry manifest:media-type="text/xml" '\
                     'manifest:full-path="content.xml"/>',
                    u'<manifest:file-entry manifest:media-type="text/xml" '\
                     'manifest:full-path="styles.xml"/>',
                    u'</manifest:manifest>']
        styles = [commonHeader, u'<office:document-styles' + commonAttr]
        styles.extend(fontDecl)
        styles.extend([u'<office:styles>',
                       u'<style:default-style style:family="paragraph">',
                       u'<style:paragraph-properties '\
                        'style:writing-mode="page"/>',
                       u'<style:text-properties fo:font-size="%dpt" '\
                        'fo:hyphenate="false" style:font-name="%s"/>' %
                        (fontSize, fontName),
                       u'</style:default-style>',
                       u'<style:style style:name="Standard" '\
                        'style:class="text" style:family="paragraph"/>',
                       u'<style:style style:name="Text_20_body" '\
                        'style:display-name="Text body" style:class="text" '\
                        'style:family="paragraph" '\
                        'style:parent-style-name="Standard">',
                       u'<style:paragraph-properties '\
                        'fo:margin-bottom="6.0pt"/>',
                       u'</style:style>',
                       u'<style:style style:name="Heading" '\
                        'style:class="text" style:family="paragraph" '\
                        'style:next-style-name="Text_20_body" '\
                        'style:parent-style-name="Standard">',
                       u'<style:paragraph-properties '\
                        'fo:keep-with-next="always" fo:margin-bottom="6.0pt" '\
                        'fo:margin-top="12.0pt"/>',
                       u'<style:text-properties fo:font-size="%dpt" '\
                        'style:font-name="%s"/>' % (fontSize + sizeDelta,
                                                    fontName),
                       u'</style:style>'])
        outline = [u'<text:outline-style>']
        for level in range(1, TreeItem.maxLevel + 1):
            size = fontSize
            if level <= 2:
                size += 2 * sizeDelta
            elif level <= 4:
                size += sizeDelta
            italic = ' '
            if level % 2 == 0:
                italic = 'fo:font-style="italic" '
            styles.extend([u'<style:style style:name="Heading_20_%d" '\
                            'style:display-name="Heading %d" '\
                            'style:class="text" style:family="paragraph" '\
                            'style:parent-style-name="Heading" '\
                            'style:default-outline-level="%d">' % \
                            (level, level, level),
                           u'<style:text-properties fo:font-size="%dpt" '\
                            '%s fo:font-weight="bold"/>' % \
                            (size, italic),
                           u'</style:style>'])
            outline.append(u'<text:outline-level-style text:level="%d" '\
                            'style:num-format=""/>' % level)
        styles.extend(outline)
        styles.extend([u'</text:outline-style>', u'</office:styles>',
                       u'<office:automatic-styles>',
                       u'<style:page-layout style:name="pm1">',
                       u'<style:page-layout-properties '\
                        'fo:margin-bottom="0.75in" fo:margin-left="0.75in" '\
                        'fo:margin-right="0.75in" fo:margin-top="0.75in" '\
                        'fo:page-height="11in" fo:page-width="8.5in" '\
                        'style:print-orientation="portrait"/>',
                       u'</style:page-layout>',
                       u'</office:automatic-styles>',
                       u'<office:master-styles>',
                       u'<style:master-page style:name="Standard" '\
                        'style:page-layout-name="pm1"/>',
                       u'</office:master-styles>',
                       u'</office:document-styles>'])
        try:
            f = zipfile.ZipFile(fileRef, 'w', zipfile.ZIP_DEFLATED)
            f.writestr('content.xml', u'\n'.join(lines).encode('utf-8') + '\n')
            f.writestr('META-INF/manifest.xml', u'\n'.join(manifest) + '\n')
            f.writestr('styles.xml', u'\n'.join(styles) + '\n')
        except IOError:
            print 'Error - could not write file'
            raise
        f.close()
Example #42
0
 def __init__(self, data, parent=None):
     super(TreeModel, self).__init__(parent)
     self.rootItem = TreeItem(['Date', 'Data (KB)', 'Data (MB)'], None)
     self.setupModel(data)
Example #43
0
class TreeModel(QAbstractItemModel):

    def __init__(self, data, parent=None):
        super().__init__(parent)
        self.rootItem = TreeItem([self.tr('title'), self.tr('summary')])
        self.setupModelData(data.split('\n'), self.rootItem)

    def __del__(self):
        # delete self.rootItem
        pass

    def columnCount(self, parent):
        '''
        QModelIndex.internalPointer() -> TreeItem
        Args:
            parent (QModelIndex): QModelIndex
        '''
        if parent.isValid():
            return parent.internalPointer().columnCount()
        return self.rootItem.columnCount()

    def data(self, index, role):
        if not index:
            return QVariant()
        if role != Qt.DisplayRole:
            return QVariant()
        item = index.internalPointer()

        return item.data(index.column())

    def flags(self, index):
        if not index.isValid():
            return Qt.NoItemFlags
        return QAbstractItemModel.flags(self, index)

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            return self.rootItem.data(section)
        return QVariant()

    def index(self, row, column, parent=QModelIndex()):
        if not self.hasIndex(row, column, parent):
            return QModelIndex()

        parentItem = None

        if not parent.isValid():
            parentItem = self.rootItem
        else:
            parentItem = parent.internalPointer()
        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem)
        return QModelIndex()

    def parent(self, index):
        if not index.isValid():
            return QModelIndex()
        childItem = index.internalPointer()
        parentItem = childItem.parentItem()
    
        if parentItem == self.rootItem:
            return QModelIndex()

        return self.createIndex(parentItem.row(), 0, parentItem)

    def rowCount(self, parent=QModelIndex()):
        parentItem = None
        if parent.column() > 0:
            return 0
        if not parent.isValid():
            parentItem = self.rootItem
        else:
            parentItem = parent.internalPointer()

        return parentItem.childCount()

    def setupModelData(self, lines, parent):
        parents = []
        indentations = []
        parents.append(parent)
        indentations.append(0)

        number = 0
        while number < len(lines):
            position = 0
            while position < len(lines[number]):
                if lines[number][position] != ' ':
                    break
                position = position + 1

            lineData = lines[number][position:].strip()

            if lineData:
                # Read the column data from the rest of the line.
                columnStrings = [x for x in lineData.split('\t') if x]
                columnData = [None] * len(columnStrings)

                for i, columnString in enumerate(columnStrings):
                    columnData[i] = columnString
                if position > indentations[-1]:
                    # The last child of the current parent is now the new parent
                    # unless the current parent has no children.
                    if parents[-1].childCount() > 0:
                        parents.append(parents[-1].child(parents[-1].childCount() - 1))
                        indentations.append(position)
                else:
                    while position < indentations[-1] and len(parents) > 0:
                        parents.pop(-1)
                        indentations.pop(-1)

                # Append a new item to the current parent's list of children.
                parents[-1].appendChild(TreeItem(columnData, parents[-1]))
            number = number + 1