Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.odftoolkit.odfdom.converter.pdf.internal.stylable.StylableDocument Maven / Gradle / Ivy
/**
* Copyright (C) 2011-2012 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 org.odftoolkit.odfdom.converter.pdf.internal.stylable;
import java.io.OutputStream;
import java.util.List;
import org.odftoolkit.odfdom.converter.core.ODFConverterException;
import org.odftoolkit.odfdom.converter.pdf.internal.StyleEngineForIText;
import org.odftoolkit.odfdom.converter.pdf.internal.styles.Style;
import org.odftoolkit.odfdom.converter.pdf.internal.styles.StylePageLayoutProperties;
import org.odftoolkit.odfdom.dom.style.OdfStyleFamily;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Image;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.ColumnText;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import fr.opensagres.xdocreport.itext.extension.ExtendedDocument;
import fr.opensagres.xdocreport.itext.extension.IMasterPage;
import fr.opensagres.xdocreport.itext.extension.IPdfWriterConfiguration;
import fr.opensagres.xdocreport.itext.extension.PageOrientation;
import fr.opensagres.xdocreport.itext.extension.font.FontGroup;
/**
* fixes for pdf conversion by Leszek Piotrowicz
*/
public class StylableDocument
extends ExtendedDocument
implements IStylableContainer, IBoundsLimitContainer, IBreakHandlingContainer, IStylableFactory
{
private final StyleEngineForIText styleEngine;
private Style lastStyleApplied = null;
private StylableMasterPage activeMasterPage;
private boolean masterPageJustChanged;
private boolean documentEmpty = true;
private PdfPTable layoutTable;
private ColumnText text;
private int colIdx;
public StylableDocument( OutputStream out, IPdfWriterConfiguration configuration, StyleEngineForIText styleEngine )
throws DocumentException
{
super( out, configuration );
this.styleEngine = styleEngine;
}
//
// IStylableFactory implementation
//
public StylableAnchor createAnchor( IStylableContainer parent )
{
return new StylableAnchor( this, parent );
}
public StylableChunk createChunk( IStylableContainer parent, String textContent, FontGroup fontGroup )
{
return new StylableChunk( this, parent, textContent, fontGroup );
}
public StylableDocumentSection createDocumentSection( IStylableContainer parent, boolean inHeaderFooter )
{
return new StylableDocumentSection( this, parent, inHeaderFooter );
}
public StylableHeaderFooter createHeaderFooter( boolean header )
{
return new StylableHeaderFooter( this, header );
}
public StylableHeading createHeading( IStylableContainer parent, List headingNumbering )
{
return new StylableHeading( this, parent, headingNumbering );
}
public StylableImage createImage( IStylableContainer parent, Image image, Float x, Float y, Float width,
Float height )
{
return new StylableImage( this, parent, image, x, y, width, height );
}
public StylableList createList( IStylableContainer parent, int listLevel )
{
return new StylableList( this, parent, listLevel );
}
public StylableListItem createListItem( IStylableContainer parent )
{
return new StylableListItem( this, parent );
}
public StylableParagraph createParagraph( IStylableContainer parent )
{
return new StylableParagraph( this, parent );
}
public StylablePhrase createPhrase( IStylableContainer parent )
{
return new StylablePhrase( this, parent );
}
public StylableTab createTab( IStylableContainer parent, boolean inTableOfContent )
{
return new StylableTab( this, parent, inTableOfContent );
}
public StylableTable createTable( IStylableContainer parent, int numColumns )
{
return new StylableTable( this, parent, numColumns );
}
public StylableTableCell createTableCell( IStylableContainer parent )
{
return new StylableTableCell( this, parent );
}
//
// master page handling
//
@Override
public void setActiveMasterPage( IMasterPage masterPage )
{
// flush pending content
flushTable();
// activate master page in three steps
Style style = getStyleMasterPage( (StylableMasterPage) masterPage );
if ( style != null )
{
// step 1 - apply styles like page dimensions and orientation
this.applyStyles( style );
}
// 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 = (StylableMasterPage) 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(), style );
text = StylableDocumentSection.createColumnText();
setColIdx( 0 );
}
private Style setNextActiveMasterPageIfNecessary()
{
// called on page break
// return new page style if changed
if ( activeMasterPage != null )
{
String nextMasterPageStyleName = activeMasterPage.getNextStyleName();
if ( nextMasterPageStyleName != null && nextMasterPageStyleName.length() > 0 )
{
StylableMasterPage nextMasterPage = getMasterPage( nextMasterPageStyleName );
if ( nextMasterPage != null )
{
// activate next master page
Style style = getStyleMasterPage( nextMasterPage );
if ( style != null )
{
// step 1 - apply styles like page dimensions and orientation
this.applyStyles( style );
}
// step 2 - set header/footer if any, it needs page dimensions from step 1
super.setActiveMasterPage( nextMasterPage );
//
activeMasterPage = nextMasterPage;
return style;
}
}
}
return null;
}
public StylableMasterPage getActiveMasterPage()
{
return activeMasterPage;
}
public Style getStyleMasterPage( StylableMasterPage masterPage )
{
Style style = styleEngine.getStyle( OdfStyleFamily.List.getName(), masterPage.getPageLayoutName(), null );
return style;
}
@Override
public StylableMasterPage getMasterPage( String masterPageName )
{
return (StylableMasterPage) super.getMasterPage( masterPageName );
}
@Override
public StylableMasterPage getDefaultMasterPage()
{
return (StylableMasterPage) super.getDefaultMasterPage();
}
//
// IStylableContainer implementation
//
public void applyStyles( Style style )
{
this.lastStyleApplied = style;
StylePageLayoutProperties pageLayoutProperties = style.getPageLayoutProperties();
if ( pageLayoutProperties != null )
{
// width/height
Float width = pageLayoutProperties.getWidth();
Float height = pageLayoutProperties.getHeight();
if ( width != null && height != null )
{
Rectangle pageSize = new Rectangle( width, height );
super.setPageSize( pageSize );
}
// margin
if ( pageLayoutProperties.getMarginTop() != null )
{
originMarginTop = pageLayoutProperties.getMarginTop();
}
if ( pageLayoutProperties.getMarginBottom() != null )
{
originMarginBottom = pageLayoutProperties.getMarginBottom();
}
if ( pageLayoutProperties.getMarginLeft() != null )
{
originMarginLeft = pageLayoutProperties.getMarginLeft();
}
if ( pageLayoutProperties.getMarginRight() != null )
{
originMarginRight = pageLayoutProperties.getMarginRight();
}
super.setMargins( originMarginLeft, originMarginRight, originMarginTop, originMarginBottom );
// orientation
PageOrientation orientation = pageLayoutProperties.getOrientation();
if ( orientation != null )
{
super.setOrientation( orientation );
}
}
}
public Style getLastStyleApplied()
{
return lastStyleApplied;
}
public IStylableContainer getParent()
{
return null;
}
public Element getElement()
{
return null;
}
//
// this amazing and awesome algorithm
// which lay out content in columns on page
// was written by Leszek Piotrowicz
//
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 ODFConverterException( "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 ODFConverterException( e );
}
if ( ColumnText.hasMoreText( res ) )
{
// text does not fit into current column
// split it to a new column
columnBreak();
}
}
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 ODFConverterException( e );
}
}
}
}