/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.modules.output.pageable.plaintext.driver;
import org.pentaho.reporting.engine.classic.core.style.StyleSheet;
import org.pentaho.reporting.engine.classic.core.style.TextStyleKeys;
import java.awt.print.Paper;
import java.io.IOException;
/**
* The plain text page is used to buffer a complete page and to write the buffered data when the page is closed.
*
* @author Thomas Morgner
*/
public class PlainTextPage {
/**
* the page buffer is used to store all TextDataChunks.
*/
private PlaintextDataChunk[][] pageBuffer;
/**
* The command-set that is used to finally print the content.
*/
private PrinterDriver driver;
/**
* The width of the page in characters.
*/
private int width;
/**
* the height of the page in lines.
*/
private int height;
private Paper paper;
private String defaultEncoding;
/**
* Creates a new PlainTextPage with the given dimensions and the specified PrinterCommandSet.
*
* @param driver
* the command-set for printing and formatting the text.
*/
public PlainTextPage( final Paper pageFormat, final PrinterDriver driver, final String defaultEncoding ) {
if ( driver == null ) {
throw new NullPointerException( "PrinterCommandSet must be defined." );
}
if ( pageFormat == null ) {
throw new NullPointerException( "PageFormat must be defined." );
}
if ( defaultEncoding == null ) {
throw new NullPointerException( "DefaultEncoding must be defined." );
}
final float characterWidthInPoint = ( 72.0f / driver.getCharactersPerInch() );
final float characterHeightInPoint = ( 72.0f / driver.getLinesPerInch() );
final int currentPageHeight =
PlainTextPage.correctedDivisionFloor( pageFormat.getImageableHeight(), characterHeightInPoint );
final int currentPageWidth =
PlainTextPage.correctedDivisionFloor( pageFormat.getImageableWidth(), characterWidthInPoint );
// Log.debug("Created page with " + currentPageWidth + ", " + currentPageHeight);
pageBuffer = new PlaintextDataChunk[currentPageWidth][currentPageHeight];
width = currentPageWidth;
height = currentPageHeight;
paper = pageFormat;
this.driver = driver;
this.defaultEncoding = defaultEncoding;
}
/**
* Fixes some floating point errors when calculating positions.
*
* @param c
* the divisor
* @param d
* the dividend
* @return the corrected division result.
*/
public static int correctedDivisionFloor( double c, double d ) {
c = Math.round( c * 100.0f );
d = Math.round( d * 100.0f );
return (int) Math.floor( c / d );
}
/**
* Returns the page width in characters.
*
* @return the page width.
*/
public int getWidth() {
return width;
}
/**
* Returns the page height in lines.
*
* @return the page height.
*/
public int getHeight() {
return height;
}
/**
* Adds a new text chunk to this PlainTextPage. A chunk consists of a single line of text.
*
* @param x
* the column of the first character of the text
* @param y
* the row where to print the text
* @param w
* the number of characters to print.
* @param text
* the text that should be printed.
* @param format
* the font definition used to format the text.
*/
public void addTextChunk( final int x, final int y, final int w, final String text, final StyleSheet format ) {
if ( text.length() == 0 ) {
return;
}
if ( x < 0 ) {
throw new IllegalArgumentException( "X < 0: " + x );
}
if ( y < 0 ) {
throw new IllegalArgumentException( "y < 0: " + y );
}
if ( w < 0 ) {
throw new IllegalArgumentException( "w < 0 " + w );
}
if ( x + w > width ) {
throw new IllegalArgumentException( "X+W [" + ( x + w ) + "] > bufferWidth [" + width + ']' );
}
if ( y >= height ) {
throw new IllegalArgumentException( "Y > bufferHeight: " + text + " y=" + y + " h=" + height );
}
final String font = (String) format.getStyleProperty( TextStyleKeys.FONT );
final boolean bold = format.getBooleanStyleProperty( TextStyleKeys.BOLD );
final boolean italic = format.getBooleanStyleProperty( TextStyleKeys.ITALIC );
final boolean underline = format.getBooleanStyleProperty( TextStyleKeys.UNDERLINED );
final boolean strikethrough = format.getBooleanStyleProperty( TextStyleKeys.STRIKETHROUGH );
final PlaintextDataChunk chunk =
new PlaintextDataChunk( text, font, bold, italic, underline, strikethrough, x, y, w );
// TODO: Why are we storing a chunk 'x' number of times where 'x' the width of the chunk
for ( int i = 0; i < w; i++ ) {
if ( pageBuffer[x + i][y] == null ) {
pageBuffer[x + i][y] = chunk;
}
}
}
/**
* returns the chunk stored at the given position or null, if no chunk was stored there.
*
* @param x
* the column
* @param y
* the line
* @return the text chunk or null.
*/
private PlaintextDataChunk getChunk( final int x, final int y ) {
return pageBuffer[x][y];
}
/**
* Writes the contents of the page using the printer command set.
*
* @throws java.io.IOException
* if an I/O error occured while writing the page.
*/
public void writePage() throws IOException {
driver.startPage( paper, defaultEncoding );
for ( int y = 0; y < height; y++ ) {
driver.startLine();
int emptyChunkCount = 0;
boolean overflow = false;
for ( int x = 0; x < width; x++ ) {
final PlaintextDataChunk chunk = getChunk( x, y );
if ( chunk == null ) {
emptyChunkCount += 1;
} else if ( chunk.getX() == x ) {
if ( emptyChunkCount != 0 ) {
driver.printEmptyChunk( emptyChunkCount );
emptyChunkCount = 0;
}
// Log.debug ("Print Chunk At " + x);
driver.printChunk( chunk );
x += ( chunk.getWidth() - 1 );
// we reached the end of the line ...
if ( x == ( width - 1 ) ) {
overflow = true;
}
}
}
// end the page on the last line. Note: overflow is ignored when ending page or line.
if ( y == ( height - 1 ) ) {
driver.endPage( overflow );
} else {
driver.endLine( overflow );
}
}
driver.flush();
}
}