def headerFooterDoc(self, header=True, pageNum=1, numPages=1): """Return a text document for the header or footer. Return None if no header/footer is defined. Arguments: header -- return header if True, footer if false """ text = self.formatHeaderFooter(header, pageNum, numPages) if text: doc = QTextDocument() doc.setHtml(text) doc.setDefaultFont(self.mainFont) frameFormat = doc.rootFrame().frameFormat() frameFormat.setBorder(0) frameFormat.setMargin(0) frameFormat.setPadding(0) doc.rootFrame().setFrameFormat(frameFormat) return doc return None
class OutputItem: """Class to store output for a single node. Stores text lines and original indent level. """ def __init__(self, spot, level): """Convert the spot's node into an output item. Create a blank item if spot is None. Arguments: spot -- the tree spot to convert level -- the node's original indent level """ if spot: node = spot.nodeRef nodeFormat = node.formatRef if not nodeFormat.useTables: self.textLines = [ line + '<br />' for line in node.output(spotRef=spot) ] else: self.textLines = node.output(keepBlanks=True, spotRef=spot) if not self.textLines: self.textLines = [''] self.addSpace = nodeFormat.spaceBetween self.siblingPrefix = nodeFormat.siblingPrefix self.siblingSuffix = nodeFormat.siblingSuffix if nodeFormat.useBullets and self.textLines: # remove <br /> extra space for bullets self.textLines[-1] = self.textLines[-1][:-6] self.uId = node.uId else: self.textLines = [''] self.addSpace = False self.siblingPrefix = '' self.siblingSuffix = '' self.uId = None self.level = level # following variables used by printdata only: self.height = 0 self.pageNum = 0 self.columnNum = 0 self.pagePos = 0 self.doc = None self.parentItem = None self.lastChildItem = None def duplicate(self): """Return an independent copy of this OutputItem. """ item = OutputItem(None, 0) item.textLines = self.textLines[:] item.addSpace = self.addSpace item.siblingPrefix = self.siblingPrefix item.siblingSuffix = self.siblingSuffix item.uId = self.uId item.level = self.level item.height = self.height item.pageNum = self.pageNum item.columnNum = self.columnNum item.pagePos = self.pagePos item.doc = None item.parentItem = self.parentItem item.lastChildItem = self.lastChildItem return item def addIndent(self, prevLevel, nextLevel): """Add <div> tags to define indent levels in the output. Arguments: prevLevel -- the level of the previous item in the list nextLevel -- the level of the next item in the list """ for num in range(self.level - prevLevel): self.textLines[0] = '<div>' + self.textLines[0] for num in range(self.level - nextLevel): self.textLines[-1] += '</div>' def addAbsoluteIndent(self, pixels): """Add tags for an individual indentation. Removes the <br /> tag from the last line to avoid excess space, since <div> starts a new line. The Qt output view does not fully support nested <div> tags. Arguments: pixels -- the amount to indent """ self.textLines[0] = ('<div style="margin-left: {0}">{1}'.format( pixels * self.level, self.textLines[0])) if not self.siblingPrefix and self.textLines[-1].endswith('<br />'): self.textLines[-1] = self.textLines[-1][:-6] self.textLines[-1] += '</div>' def addSiblingPrefix(self): """Add the sibling prefix before this output. """ if self.siblingPrefix: self.textLines[0] = self.siblingPrefix + self.textLines[0] def addSiblingSuffix(self): """Add the sibling suffix after this output. """ if self.siblingSuffix: self.textLines[-1] += self.siblingSuffix def addAnchor(self): """Add a link anchor to this item. """ self.textLines[0] = '<a id="{0}" />{1}'.format(self.uId, self.textLines[0]) def intLinkIds(self): """Return a set of uIDs from any internal links in this item. """ linkIds = set() for line in self.textLines: startPos = 0 while True: match = _linkRe.search(line, startPos) if not match: break uId = match.group(1) if uId: linkIds.add(uId) startPos = match.start(1) return linkIds def numLines(self): """Return the number of text lines in the item. """ return len(self.textLines) def equalPrefix(self, otherItem): """Return True if sibling prefixes and suffixes are equal. Arguments: otherItem -- the item to compare """ return (self.siblingPrefix == otherItem.siblingPrefix and self.siblingSuffix == otherItem.siblingSuffix) def setDocHeight(self, paintDevice, width, printFont, replaceDoc=False): """Set the height of this item for use in printer output. Creates an output document if not already created. Arguments: paintDevice -- the printer or other device for settings width -- the width available for the output text printFont -- the default font for the document replaceDoc -- if true, re-create the text document """ if not self.doc or replaceDoc: self.doc = QTextDocument() lines = '\n'.join(self.textLines) if lines.endswith('<br />'): # remove trailing <br /> tag to avoid excess space lines = lines[:-6] self.doc.setHtml(lines) self.doc.setDefaultFont(printFont) frameFormat = self.doc.rootFrame().frameFormat() frameFormat.setBorder(0) frameFormat.setMargin(0) frameFormat.setPadding(0) self.doc.rootFrame().setFrameFormat(frameFormat) layout = self.doc.documentLayout() layout.setPaintDevice(paintDevice) self.doc.setTextWidth(width) self.height = layout.documentSize().height() def splitDocHeight(self, initHeight, maxHeight, paintDevice, width, printFont): """Split this item into two items and return them. The first item will fit into initHeight if practical. Splits at line endings if posible. Arguments: initHeight -- the preferred height of the first page maxheight -- the max height of any pages paintDevice -- the printer or other device for settings width -- the width available for the output text printFont -- the default font for the document """ newItem = self.duplicate() fullHeight = self.height lines = '\n'.join(self.textLines) allLines = [line + '<br />' for line in lines.split('<br />')] self.textLines = [] prevHeight = 0 for line in allLines: self.textLines.append(line) self.setDocHeight(paintDevice, width, printFont, True) if ((prevHeight and self.height > initHeight and fullHeight - prevHeight > maxHeight) or (prevHeight and self.height > maxHeight)): self.textLines = self.textLines[:-1] self.setDocHeight(paintDevice, width, printFont, True) newItem.textLines = allLines[len(self.textLines):] newItem.setDocHeight(paintDevice, width, printFont, True) return (self, newItem) if self.height > maxHeight: break prevHeight = self.height # no line ending breaks found text = ' \n'.join(allLines) allWords = [word + ' ' for word in text.split(' ')] newWords = [] prevHeight = 0 for word in allWords: if word.strip() == '<img': break newWords.append(word) self.textLines = [''.join(newWords)] self.setDocHeight(paintDevice, width, printFont, True) if ((prevHeight and self.height > initHeight and fullHeight - prevHeight < maxHeight) or (prevHeight and self.height > maxHeight)): self.textLines = [''.join(newWords[:-1])] self.setDocHeight(paintDevice, width, printFont, True) newItem.textLines = [''.join(allWords[len(newWords):])] newItem.setDocHeight(paintDevice, width, printFont, True) return (self, newItem) if self.height > maxHeight: break prevHeight = self.height newItem.setDocHeight(paintDevice, width, printFont, True) return (newItem, None) # fail to split