All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.craigburke.document.builder.render.TableRenderer.groovy Maven / Gradle / Ivy

package com.craigburke.document.builder.render

import com.craigburke.document.core.Document
import com.craigburke.document.core.Row
import com.craigburke.document.core.Table
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream

/**
 * Renders a table to the document
 * @author Craig Burke
 */
class TableRenderer {

    Document document
    Table table

    TableRenderer(Table table, Document document) {
        this.document = document
        this.table = table
    }

    void render() {
        table.children.each { renderRow(it) }
    }

    int translateY(int y) {
        document.item.translateY(y)
    }

    private void renderBorders(RowElement rowElement) {
        document.item.y = rowElement.startY

        int borderOffset = Math.floor(table.border.size.doubleValue() / 2)

        PDPageContentStream contentStream = document.item.contentStream
        setBorderOptions(contentStream)

        int xStart = document.margin.left + table.margin.left
        int xEnd = xStart + table.width

        int yTop = rowElement.startY

        if (shouldRenderTopBorder(rowElement)) {
            contentStream.drawLine(xStart, translateY(yTop), xEnd, translateY(yTop))
        }

        int yBottom
        if (rowElement.fullyRendered) {
            yBottom = document.item.y + rowElement.renderedHeight + table.border.size
            contentStream.drawLine(xStart, translateY(yBottom), xEnd, translateY(yBottom))
        }
        else {
           yBottom = document.item.y + document.item.remainingPageHeight
        }

        int offsetYBottom = yBottom + borderOffset

        int currentX = document.margin.left + table.margin.left + borderOffset
        rowElement.cellElements.eachWithIndex { cellElement, i ->
            if (i == 0) {
                contentStream.drawLine(currentX, translateY(yTop), currentX, translateY(offsetYBottom))
            }
            currentX += cellElement.node.width

            if (i == rowElement.cellElements.size() - 1) {
                currentX = xEnd - borderOffset
            }
            else {
                currentX += table.border.size
            }

            contentStream.drawLine(currentX, translateY(yTop), currentX, translateY(offsetYBottom))
        }

    }

    private boolean shouldRenderTopBorder(RowElement rowElement) {
        if (rowElement.node == table.children.first()) {
            true
        }
        else if (rowElement.startY == document.margin.top && !rowElement.spansMultiplePages) {
            true
        }
        else {
            false
        }

    }

    private setBorderOptions(PDPageContentStream contentStream) {
        def borderColor = table.border.color.rgb
        contentStream.setStrokingColor(*borderColor)
        contentStream.setLineWidth(table.border.size)
    }

   private void renderRow(Row row) {
       int rowStartX = document.margin.left + table.margin.left

       RowElement rowElement = new RowElement(row)

       rowElement.startY = document.item.y
       if (rowElement.firstRow) {
           rowElement.startY += table.border.size
       }

        while (!rowElement.fullyRendered) {
            document.item.x = rowStartX + table.border.size

            rowElement.cellElements.each {
                document.item.y = rowElement.startY
                renderContentUntilEndPoint(it)
            }

            if (rowElement.renderedHeight) {
                renderBorders(rowElement)
            }

            if (!rowElement.fullyRendered) {
                rowElement.startY = document.margin.top
                if (rowElement.renderedHeight) {
                    rowElement.spansMultiplePages = true
                }
                document.item.addPage()
                rowElement.renderedHeight = 0
            }
        }

        document.item.y = rowElement.startY + rowElement.renderedHeight + table.border.size
   }

    private void renderContentUntilEndPoint(CellElement cellElement) {
        boolean reachedBottomOfPage = false
        int cellStartX = document.item.x

        while (!reachedBottomOfPage && !cellElement.fullyRendered) {
            ParagraphLine line = cellElement.currentLine

            if (canRenderCurrentLineOnPage(cellElement)) {
                if (cellElement.onFirstLine) {
                    document.item.y += table.padding
                    cellElement.renderedHeight += table.padding
                }

                int renderStartX = cellStartX + table.padding
                ParagraphRenderer.renderLine(document, line, renderStartX)
                cellElement.renderedHeight += line.height

                if (cellElement.onLastLine) {
                    cellElement.renderedHeight += table.padding
                    cellElement.fullyRendered = true
                }
            }
            else {
                cellElement.moveToPreviousLine()
                reachedBottomOfPage = true
            }

            if (!reachedBottomOfPage && !cellElement.fullyRendered) {
                cellElement.moveToNextLine()
            }

        }

        document.item.x = cellStartX + cellElement.node.width + table.border.size
    }

    boolean canRenderCurrentLineOnPage(CellElement cellElement) {
        ParagraphLine line = cellElement.currentLine

        int remainingHeight = document.item.remainingPageHeight

        int totalRequiredHeight = line.height

        if (cellElement.onFirstLine) {
            totalRequiredHeight += table.padding + table.border.size
        }

        (totalRequiredHeight <= remainingHeight)
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy