fr.opensagres.poi.xwpf.converter.pdf.internal.elements.StylableDocument.java Source code

Java tutorial

Introduction

Here is the source code for fr.opensagres.poi.xwpf.converter.pdf.internal.elements.StylableDocument.java

Source

/**
 * Copyright (C) 2011-2015 The XDocReport Team <xdocreport@googlegroups.com>
 *
 * All rights reserved.
 *
 * Permission is hereby granted, free  of charge, to any person obtaining
 * a  copy  of this  software  and  associated  documentation files  (the
 * "Software"), to  deal in  the Software without  restriction, including
 * without limitation  the rights to  use, copy, modify,  merge, publish,
 * distribute,  sublicense, and/or sell  copies of  the Software,  and to
 * permit persons to whom the Software  is furnished to do so, subject to
 * the following conditions:
 *
 * The  above  copyright  notice  and  this permission  notice  shall  be
 * included in all copies or substantial portions of the Software.
 *
 * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
 * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
 * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package fr.opensagres.poi.xwpf.converter.pdf.internal.elements;

import static fr.opensagres.poi.xwpf.converter.core.utils.DxaUtil.dxa2points;

import java.io.OutputStream;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPageMar;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPageSz;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.ColumnText;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;

import fr.opensagres.poi.xwpf.converter.core.MasterPageManager;
import fr.opensagres.poi.xwpf.converter.core.PageOrientation;
import fr.opensagres.poi.xwpf.converter.core.XWPFConverterException;
import fr.opensagres.poi.xwpf.converter.core.utils.XWPFUtils;
import fr.opensagres.xdocreport.itext.extension.ExtendedDocument;
import fr.opensagres.xdocreport.itext.extension.ExtendedHeaderFooter;
import fr.opensagres.xdocreport.itext.extension.ExtendedPdfPTable;
import fr.opensagres.xdocreport.itext.extension.IITextContainer;
import fr.opensagres.xdocreport.itext.extension.IMasterPage;
import fr.opensagres.xdocreport.itext.extension.IMasterPageHeaderFooter;
import fr.opensagres.xdocreport.itext.extension.IPdfWriterConfiguration;

public class StylableDocument extends ExtendedDocument {

    private StylableMasterPage activeMasterPage;

    private boolean masterPageJustChanged;

    private boolean documentEmpty = true;

    private PdfPTable layoutTable;

    private ColumnText text;

    private int colIdx;

    private MasterPageManager masterPageManager;

    public StylableDocument(OutputStream out, IPdfWriterConfiguration configuration) throws DocumentException {
        super(out, configuration);
    }

    public void addElement(Element element) {
        if (!super.isOpen()) {
            super.open();
        }
        if (masterPageJustChanged) {
            // master page was changed but there was no explicit page break
            pageBreak();
        }
        text.addElement(element);
        StylableDocumentSection.getCell(layoutTable, colIdx).getColumn().addElement(element);
        simulateText();
        documentEmpty = false;
    }

    public void columnBreak() {
        if (colIdx + 1 < layoutTable.getNumberOfColumns()) {
            setColIdx(colIdx + 1);
            simulateText();
        } else {
            pageBreak();
        }
    }

    public void pageBreak() {
        if (documentEmpty) {
            // no element was added - ignore page break
        } else if (masterPageJustChanged) {
            // we are just after master page change
            // move to a new page but do not initialize column layout
            // because it is already done
            masterPageJustChanged = false;
            super.newPage();
        } else {
            // flush pending content
            flushTable();
            // check if master page change necessary
            // Style nextStyle = setNextActiveMasterPageIfNecessary();
            // document new page
            super.newPage();
            // initialize column layout for new page
            // if ( nextStyle == null )
            // {
            // ordinary page break
            layoutTable = StylableDocumentSection.cloneAndClearTable(layoutTable, false);
            // }
            // else
            // {
            // // page break with new master page activation
            // // style changed so recreate table
            // layoutTable =
            // StylableDocumentSection.createLayoutTable( getPageWidth(), getAdjustedPageHeight(), nextStyle );
            // }
            setColIdx(0);
            simulateText();
        }
    }

    @Override
    public boolean newPage() {
        throw new XWPFConverterException("internal error - do not call newPage directly");
    }

    @Override
    public void close() {
        flushTable();
        super.close();
    }

    public float getWidthLimit() {
        PdfPCell cell = StylableDocumentSection.getCell(layoutTable, colIdx);
        return cell.getRight() - cell.getPaddingRight() - cell.getLeft() - cell.getPaddingLeft();
    }

    public float getHeightLimit() {
        // yLine is negative
        return StylableDocumentSection.getCell(layoutTable, colIdx).getFixedHeight() + text.getYLine();
    }

    public float getPageWidth() {
        return right() - left();
    }

    private float getAdjustedPageHeight() {
        // subtract small value from height, otherwise table breaks to new page
        return top() - bottom() - 0.001f;
    }

    private void setColIdx(int idx) {
        colIdx = idx;
        PdfPCell cell = StylableDocumentSection.getCell(layoutTable, colIdx);
        text.setSimpleColumn(cell.getLeft() + cell.getPaddingLeft(), -getAdjustedPageHeight(),
                cell.getRight() - cell.getPaddingRight(), 0.0f);
        cell.setColumn(ColumnText.duplicate(text));
    }

    private void simulateText() {
        int res = 0;
        try {
            res = text.go(true);
        } catch (DocumentException e) {
            throw new XWPFConverterException(e);
        }
        if (ColumnText.hasMoreText(res)) {
            // text does not fit into current column
            // split it to a new column
            columnBreak();
        }
    }

    public StylableParagraph createParagraph(IITextContainer parent) {
        return new StylableParagraph(this, parent);
    }

    public Paragraph createParagraph() {
        return createParagraph((IITextContainer) null);
    }

    public Paragraph createParagraph(Paragraph title) {
        return new StylableParagraph(this, title, null);
    }

    // public StylablePhrase createPhrase( IITextContainer parent )
    // {
    // return new StylablePhrase( this, parent );
    // }
    //
    // public StylableAnchor createAnchor( IITextContainer parent )
    // {
    // return new StylableAnchor( this, parent );
    // }
    //
    // public StylableList createList( IITextContainer parent )
    // {
    // return new StylableList( this, parent );
    // }
    //
    // public StylableListItem createListItem( IITextContainer parent )
    // {
    // return new StylableListItem( this, parent );
    // }

    public StylableTable createTable(IITextContainer parent, int numColumns) {
        return new StylableTable(this, parent, numColumns);
    }

    public StylableTableCell createTableCell(IITextContainer parent) {
        return new StylableTableCell(this, parent);
    }

    public StylableTableCell createTableCell(IITextContainer parent, ExtendedPdfPTable table) {
        return new StylableTableCell(this, parent, table);
    }

    @Override
    public void setActiveMasterPage(IMasterPage m) {
        StylableMasterPage masterPage = (StylableMasterPage) m;
        if (activeMasterPage != null && XWPFUtils.isContinuousSection(masterPage.getSectPr())) {
            // ignore section with "continous" section <w:sectPr><w:type w:val="continuous" />
            // because continous section applies changes (ex: modify width/height)
            // for the paragraph and iText cannot support that (a new page must be added to
            // change the width/height of the page).

            // see explanation about "continous" at http://officeopenxml.com/WPsection.php
            return;
        }

        // flush pending content
        flushTable();
        // activate master page in three steps

        // Style style = getStyleMasterPage( masterPage );
        // if ( style != null )
        // {
        // step 1 - apply styles like page dimensions and orientation
        this.applySectPr(masterPage.getSectPr());
        // }
        // step 2 - set header/footer if any, it needs page dimensions from step 1
        super.setActiveMasterPage(masterPage);
        if (activeMasterPage != null) {
            // set a flag used by addElement/pageBreak
            masterPageJustChanged = true;
        }
        activeMasterPage = masterPage;
        // step 3 - initialize column layout, it needs page dimensions which may be lowered by header/footer in step 2
        layoutTable = StylableDocumentSection.createLayoutTable(getPageWidth(), getAdjustedPageHeight());
        text = StylableDocumentSection.createColumnText();
        setColIdx(0);
    }

    private void applySectPr(CTSectPr sectPr) {
        // Set page size
        CTPageSz pageSize = sectPr.getPgSz();
        Rectangle pdfPageSize = new Rectangle(dxa2points(pageSize.getW()), dxa2points(pageSize.getH()));
        super.setPageSize(pdfPageSize);

        // Orientation
        PageOrientation orientation = XWPFUtils.getPageOrientation(pageSize.getOrient());
        if (orientation != null) {
            switch (orientation) {
            case Landscape:
                super.setOrientation(fr.opensagres.xdocreport.itext.extension.PageOrientation.Landscape);
                break;
            case Portrait:
                super.setOrientation(fr.opensagres.xdocreport.itext.extension.PageOrientation.Portrait);
                break;
            }
        }

        // Set page margin
        CTPageMar pageMar = sectPr.getPgMar();
        if (pageMar != null) {
            super.setOriginalMargins(dxa2points(pageMar.getLeft()), dxa2points(pageMar.getRight()),
                    dxa2points(pageMar.getTop()), dxa2points(pageMar.getBottom()));
        }

    }

    private void flushTable() {
        if (layoutTable != null) {
            // force calculate height because it may be zero
            // and nothing will be flushed
            layoutTable.calculateHeights(true);
            try {
                super.add(layoutTable);
            } catch (DocumentException e) {
                throw new XWPFConverterException(e);
            }
        }
    }

    @Override
    protected ExtendedHeaderFooter createExtendedHeaderFooter() {
        return new ExtendedHeaderFooter(this) {
            @Override
            public void onStartPage(PdfWriter writer, Document doc) {
                super.onStartPage(writer, doc);
                StylableDocument.this.onStartPage();
            }

            @Override
            protected float getHeaderY(IMasterPageHeaderFooter header) {
                Float headerY = ((StylableHeaderFooter) header).getY();
                if (headerY != null) {
                    return document.getPageSize().getHeight() - headerY;
                }
                return super.getHeaderY(header);
            }

            @Override
            protected float getFooterY(IMasterPageHeaderFooter footer) {
                Float footerY = ((StylableHeaderFooter) footer).getY();
                if (footerY != null) {
                    return ((StylableHeaderFooter) footer).getTotalHeight();
                }
                return super.getFooterY(footer);
            }

            @Override
            protected float adjustMargin(float margin, IMasterPageHeaderFooter headerFooter) {
                if (((StylableHeaderFooter) headerFooter).getY() != null) {
                    // has page margin defined (PgMar)
                    if (headerFooter.getTotalHeight() > margin) {
                        return headerFooter.getTotalHeight();
                    }
                    return margin;
                }
                return super.adjustMargin(margin, headerFooter);
            }
        };
    }

    protected void onStartPage() {
        masterPageManager.onNewPage();
    }

    public void setMasterPageManager(MasterPageManager masterPageManager) {
        this.masterPageManager = masterPageManager;
    }
}