Example #1
0
    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
Example #2
0
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