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

fr.opensagres.poi.xwpf.converter.pdf.internal.elements.StylableDocumentSection Maven / Gradle / Ivy

Go to download

The Apache Commons Codec package contains simple encoder and decoders for various formats such as Base64 and Hexadecimal. In addition to these widely used encoders and decoders, the codec package also maintains a collection of phonetic encoding utilities.

There is a newer version: 62
Show newest version
/**
 * Copyright (C) 2011-2015 The XDocReport Team 
 *
 * 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 java.util.ArrayList;
import java.util.List;

import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Table;
import com.lowagie.text.pdf.ColumnText;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPRow;
import com.lowagie.text.pdf.PdfPTable;

import fr.opensagres.poi.xwpf.converter.core.XWPFConverterException;
import fr.opensagres.xdocreport.itext.extension.IITextContainer;

//
// this amazing and awesome algorithm
// which lay out content in columns and do content balancing
// was written by Leszek Piotrowicz 
//
public class StylableDocumentSection
// implements IITextContainer, IBreakHandlingContainer
{
    private IITextContainer parent;

    private IBoundsLimitContainer sectionParent;

    private IBreakHandlingContainer breakHandlingParent;

    private PdfPTable layoutTable;

    private boolean balanceText = true;

    private List texts;

    private int colIdx;

    public StylableDocumentSection( StylableDocument ownerDocument, IITextContainer parent, boolean inHeaderFooter )
    {
        super();
        this.parent = parent;

        // find "real" parent which is first non section element in parent hierarchy
        // this section will be added to that parent, not to direct parent
        if ( parent instanceof StylableDocumentSection )
        {
            // special case - directly nested section
            StylableDocumentSection dc = (StylableDocumentSection) parent;
            // flush parent section to update vertical position on page
            dc.flushTable();
            this.sectionParent = dc.sectionParent;
        }
        else
        {
            this.sectionParent = (IBoundsLimitContainer) parent;
        }

        // find parent container which can handle breaks
        // if null, it means that page breaks are forbidden (ie in header/footer)
        this.breakHandlingParent = getIBreakHandlingContainer( parent );
    }

    // public void applyStyles( Style style )
    // {
    // this.lastStyleApplied = style;
    //
    // StyleSectionProperties sectionProperties = style.getSectionProperties();
    // if ( sectionProperties != null )
    // {
    // Boolean dontBalanceTextColumns = sectionProperties.getDontBalanceTextColumns();
    // if ( Boolean.TRUE.equals( dontBalanceTextColumns ) )
    // {
    // balanceText = false;
    // }
    // }
    //
    // // initialize layout table
    // float width = sectionParent.getWidthLimit();
    // float height = sectionParent.getHeightLimit();
    // layoutTable = createLayoutTable( width, height, style );
    //
    // // initialize simulated text
    // texts = new ArrayList();
    // setColIdx( 0 );
    // }

    public IITextContainer getParent()
    {
        return parent;
    }

    public Element getElement()
    {
        // force calculate height because it may be zero
        // and nothing will be flushed
        layoutTable.calculateHeights( true );
        return layoutTable;
    }

    public void addElement( Element element )
    {
        if ( element instanceof SectionPdfPTable )
        {
            // section is a specific container
            // it is not added to direct parent container
            // but to section parent container which may be
            // StylableDocument or StylableTableCell or StylableHeaderFooter table cell
            sectionParent.addElement( element );
        }
        else
        {
            // ordinary element
            texts.get( colIdx ).addElement( element );
            simulateText();
        }
    }

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

    public void pageBreak()
    {
        if ( breakHandlingParent != null )
        {
            if ( sectionParent.getHeightLimit() >= 0.0f )
            {
                // fill remaining space on page break
                fillTable( sectionParent.getHeightLimit() );
            }
            // flush
            flushTable();
            breakHandlingParent.columnBreak();
        }
        else
        {
            // more column breaks than available columns
            // but we cannot break to a new page
            // don't really know what to do in such situation
            // anyway it is logical error made by document creator
            setColIdx( colIdx + 1 );
        }
    }

    private void flushTable()
    {
        sectionParent.addElement( getElement() );

        // initialize layout table
        layoutTable = cloneAndClearTable( layoutTable, true );

        // initialize simulated text
        texts = new ArrayList();
        setColIdx( 0 );
    }

    private void simulateText()
    {
        float maxHeight = sectionParent.getHeightLimit();
        List splittedTexts = fillTable( maxHeight );
        if ( splittedTexts == null )
        {
            // fits in current column on page
            if ( balanceText )
            {
                float minHeight = 0f;
                if ( maxHeight < 0.0f )
                {
                    maxHeight = layoutTable.calculateHeights( true );
                }
                float currHeight = 0.0f;
                while ( Math.abs( maxHeight - minHeight ) > 0.1f )
                {
                    currHeight = ( minHeight + maxHeight ) / 2;
                    if ( fillTable( currHeight ) == null )
                    {
                        // try to lower height
                        maxHeight = currHeight;
                    }
                    else
                    {
                        // have to raise height
                        minHeight = currHeight;
                    }
                }
                // populate table with last height
                if ( currHeight != maxHeight )
                {
                    fillTable( maxHeight );
                }
            }
            else
            {
                if ( maxHeight >= 0.0f )
                {
                    // fill minimum space only
                    fillTable( -1.0f );
                }
            }
        }
        else
        {
            // overflow
            if ( breakHandlingParent != null )
            {
                flushTable();
                breakHandlingParent.columnBreak();
                //
                texts = splittedTexts;
                colIdx = texts.size() - 1;
                simulateText();
            }
        }
    }

    private List fillTable( float height )
    {
        // copy text for simulation
        List tt = null;
        if ( breakHandlingParent == null && colIdx >= layoutTable.getNumberOfColumns() )
        {
            // more column breaks than available column
            // we try not to lose content
            // but results may be different than in open office
            // anyway it is logical error made by document creator
            tt = new ArrayList();
            ColumnText t = createColumnText();
            tt.add( t );
            for ( int i = 0; i < texts.size(); i++ )
            {
                PdfPTable table = new PdfPTable( 1 );
                table.setWidthPercentage( 100.0f );
                PdfPCell cell = new PdfPCell();
                cell.setBorder( Table.NO_BORDER );
                cell.setPadding( 0.0f );
                cell.setColumn( ColumnText.duplicate( texts.get( i ) ) );
                table.addCell( cell );
                t.addElement( table );
            }
        }
        else
        {
            tt = new ArrayList( texts );
            for ( int i = 0; i < tt.size(); i++ )
            {
                tt.set( i, ColumnText.duplicate( tt.get( i ) ) );
            }
        }
        // clear layout table
        clearTable( layoutTable, true );
        setWidthIfNecessary();

        // try to fill cells with text
        ColumnText t = tt.get( 0 );
        for ( PdfPCell cell : layoutTable.getRow( 0 ).getCells() )
        {
            cell.setFixedHeight( height >= 0.0f ? height : -1.0f );
            cell.setColumn( ColumnText.duplicate( t ) );
            //
            t.setSimpleColumn( cell.getLeft() + cell.getPaddingLeft(), height >= 0.0f ? -height : PdfPRow.BOTTOM_LIMIT,
                               cell.getRight() - cell.getPaddingRight(), 0 );
            int res = 0;
            try
            {
                res = t.go( true );
            }
            catch ( DocumentException e )
            {
                throw new XWPFConverterException( e );
            }
            if ( !ColumnText.hasMoreText( res ) )
            {
                // no overflow in current column
                if ( tt.size() == 1 )
                {
                    // no more text
                    return null;
                }
                else
                {
                    // some text waiting for new column
                    tt.remove( 0 );
                    t = tt.get( 0 );
                }
            }
        }
        return tt;
    }

    private void setColIdx( int idx )
    {
        colIdx = idx;
        for ( int i = texts.size(); i <= idx; i++ )
        {
            ColumnText text = createColumnText();
            texts.add( text );
        }
    }

    private void setWidthIfNecessary()
    {
        if ( layoutTable.getTotalWidth() != sectionParent.getWidthLimit() )
        {
            layoutTable.setTotalWidth( sectionParent.getWidthLimit() );
        }
    }

    //
    // static helper functions
    //

    public static IBreakHandlingContainer getIBreakHandlingContainer( IITextContainer c )
    {
        // while ( c != null )
        // {
        // if ( c instanceof IBreakHandlingContainer )
        // {
        // return (IBreakHandlingContainer) c;
        // }
        // c = c.getParent();
        // }
        return null;
    }

    public static SectionPdfPTable createLayoutTable( float width, float height )
    {
        // create one row table which will layout section text
        // if ( style != null )
        // {
        // List columnPropertiesList = style.getColumnPropertiesList();
        // StyleColumnsProperties columnsProperties = style.getColumnsProperties();
        // if ( columnPropertiesList != null && !columnPropertiesList.isEmpty() )
        // {
        // // explicit column list
        // return createLayoutTable( width, height, columnPropertiesList );
        // }
        // else if ( columnsProperties != null )
        // {
        // // we have columns properties
        // // make table with columns of equal width
        // columnPropertiesList = new ArrayList();
        //
        // Integer columnCount = columnsProperties.getColumnCount();
        // int colCount = columnCount != null ? columnCount : 1;
        //
        // Float columnGap = columnsProperties.getColumnGap();
        // float halfGap = columnGap != null ? columnGap / 2.0f : 0.0f;
        //
        // for ( int i = 0; i < colCount; i++ )
        // {
        // StyleColumnProperties columnProperties = new StyleColumnProperties();
        // columnProperties.setRelWidth( 100 );
        // if ( halfGap > 0.0f )
        // {
        // columnProperties.setStartIndent( i == 0 ? null : halfGap );
        // columnProperties.setEndIndent( i == colCount - 1 ? null : halfGap );
        // }
        // columnPropertiesList.add( columnProperties );
        // }
        // return createLayoutTable( width, height, columnPropertiesList );
        // }
        // }
        // default is one column and no gap
        List columnPropertiesList = new ArrayList();
        StyleColumnProperties columnProperties = new StyleColumnProperties();
        columnProperties.setRelWidth( 100 );
        columnPropertiesList.add( columnProperties );
        return createLayoutTable( width, height, columnPropertiesList );
    }

    public static SectionPdfPTable createLayoutTable( float width, float height,
                                                      List columnPropertiesList )
    {
        // create one row table which will layout section text
        int colCount = columnPropertiesList.size();
        int relativeWidths[] = new int[colCount];
        SectionPdfPTable table = new SectionPdfPTable( colCount );
        // add cells
        for ( int i = 0; i < colCount; i++ )
        {
            PdfPCell cell = new PdfPCell();
            cell.setBorder( Table.NO_BORDER );
            cell.setPadding( 0.0f );
            cell.setColumn( createColumnText() );
            cell.setFixedHeight( height >= 0.0f ? height : -1.0f );
            // apply styles to cell
            StyleColumnProperties columnProperties = columnPropertiesList.get( i );
            relativeWidths[i] = columnProperties.getRelWidth();
            cell.setPaddingLeft( columnProperties.getStartIndent() != null ? columnProperties.getStartIndent() : 0.0f );
            cell.setPaddingRight( columnProperties.getEndIndent() != null ? columnProperties.getEndIndent() : 0.0f );
            table.addCell( cell );
        }
        replaceTableCells( table );
        // set width
        try
        {
            table.setWidths( relativeWidths );
        }
        catch ( DocumentException e )
        {
            throw new XWPFConverterException( e );
        }
        table.setTotalWidth( width );
        table.setLockedWidth( true );
        return table;
    }

    public static ColumnText createColumnText()
    {
        ColumnText text = new ColumnText( null );
        // make iText first line alignment compatible with open office
        text.setAdjustFirstLine( false );
        return text;
    }

    public static void replaceTableCells( PdfPTable table )
    {
        // replace default table cells
        // by fixed height cells
        PdfPCell[] cells = table.getRow( 0 ).getCells();
        for ( int i = 0; i < cells.length; i++ )
        {
            cells[i] = new FixedHeightPdfPCell( cells[i] );
        }
    }

    public static PdfPCell getCell( PdfPTable table, int idx )
    {
        return table.getRow( 0 ).getCells()[idx];
    }

    public static SectionPdfPTable cloneAndClearTable( PdfPTable table, boolean resetFixedHeight )
    {
        SectionPdfPTable clonedTable = new SectionPdfPTable( table );
        clearTable( clonedTable, resetFixedHeight );
        replaceTableCells( clonedTable );
        return clonedTable;
    }

    public static void clearTable( PdfPTable table, boolean resetFixedHeight )
    {
        for ( PdfPCell cell : table.getRow( 0 ).getCells() )
        {
            cell.setColumn( createColumnText() );
            if ( resetFixedHeight )
            {
                cell.setFixedHeight( -1.0f );
            }
        }
    }

    public static class SectionPdfPTable
        extends PdfPTable
    {
        public SectionPdfPTable( int numColumns )
        {
            super( numColumns );
        }

        public SectionPdfPTable( PdfPTable table )
        {
            super( table );
        }
    }

    public static class FixedHeightPdfPCell
        extends PdfPCell
    {

        public FixedHeightPdfPCell( PdfPCell cell )
        {
            super( cell );
        }

        @Override
        public float getMaxHeight()
        {
            // sometimes max height of a table cell is higher than desired height
            // such a situation occurs if paragraphs have space before or after
            // it is hard to say if it is a bug or a feature in iText
            // we want fixed height to avoid breaking table to a new page
            return getFixedHeight() >= 0.0f ? getFixedHeight() : super.getMaxHeight();
        }
    }

    //
    // probably not used
    //

    public IITextContainer getITextContainer()
    {
        return null;
    }

    public void setITextContainer( IITextContainer container )
    {
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy