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

net.sf.nervalreports.generators.PDFLine Maven / Gradle / Ivy

Go to download

This is the PDF generator package of NervalReports (a lightweight report creation library), used to generate a report directly to a .pdf file.

There is a newer version: 1.2
Show newest version
/** This file is part of nervalreports.
 *
 * nervalreports is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * nervalreports 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.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with nervalreports.  If not, see . */
package net.sf.nervalreports.generators;

import java.io.IOException;
import java.util.ArrayList;

import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;

import net.sf.nervalreports.core.ReportColor;
import net.sf.nervalreports.core.ReportTextAlignment;
import net.sf.nervalreports.generators.PDFTextSentence.PDFTextSentenceType;

/** A line of sentences construction info for {@link PDFReportGenerator}.  
 * @author farrer */
/* default */ class PDFLine {
	
	/** Each sentence in the line */
	private final ArrayList sentences;
	
	/** If need to recalculate the width or not. */
	private boolean widthChange;
	
	/** Current calculated width.  */
	private float width;
	
	/** Line's X alignment. */
	private final ReportTextAlignment textAlignment;
	
	/** Needed height for the line  */
	private int neededHeight;
	
	/** If recalculation of correction factor is needed. */
	private boolean mustCalculateCorrectionFactor;
	
	/** Maximum width for the line (including spanned cells). */
	private final float maxWidth;
	
	/** Maximum correction factor from line sentences. */
	private final float[] correctionFactor = new float[2];
	
	/** If line have a current page sentence. */
	private boolean haveCurrentPageSentence;
	/** If line have a total pages sentence. */
	private boolean haveTotalPagesSentence;
	
	/** Default constructor.
	 * @param textAligment {@link #textAlignment}
	 * @param maxWidth {@link #maxWidth} */
	PDFLine(ReportTextAlignment textAligment, float maxWidth) {
		sentences = new ArrayList();
		widthChange = false;
		width = 0.0f;
		neededHeight = 0;
		correctionFactor[0] = 0.0f;
		correctionFactor[1] = 0.0f;
		mustCalculateCorrectionFactor = false;
		this.textAlignment = textAligment;
		this.maxWidth = maxWidth;
		haveCurrentPageSentence = false;
		haveTotalPagesSentence = false;
	}
	
	/** @return width needed for the line */
	float getWidth() {
		if (widthChange) {
			/* Recalculate the width */
			width = 0.0f;
			for (PDFSentence sentence : sentences) {
				width += sentence.getWidth();
			}
			widthChange = false;
		}
		
		return width;
	}
	
	/** Add text to the last sentence, when already known they are compatible.
	 * @param text text to append
	 * @param widthForText width of the text we are adding (as with a final space).  */
	void addToLastSentence(String text, float widthForText) {
		PDFSentence sentence = this.sentences.get(this.sentences.size() - 1);
		if (!(sentence instanceof PDFTextSentence)) {
			throw new IllegalStateException("Last sentence must be a textual one.");
		}
		PDFTextSentence textSentence = (PDFTextSentence) this.sentences.get(this.sentences.size() - 1);
		textSentence.addText(text, widthForText);
	}
	
	/** Add a text to the last sentence (if they are compatible), or append it as a new one.
	 * @param type type of the textual sentence to add or append.
	 * @param sentence to add.
	 * @param color color to use.
	 * @param font to use
	 * @param fontSize size of the font to use.
	 * @param width width of the text we are adding (as with a final space).
	 * @throws IOException in error retrieving font bounding box.  */
	void addToOrAppendToNewSentence(PDFTextSentenceType type, String text, ReportColor color, 
			PDType1Font font, int fontSize, float width) throws IOException {
		
		boolean created = false;
		
		if (PDFTextSentenceType.CURRENT_PAGE.equals(type)) {
			haveCurrentPageSentence = true;
		} else if(PDFTextSentenceType.PAGE_COUNT.equals(type)) {
			haveTotalPagesSentence = true;
		}
		
		/* Define the needed height according to the biggest font */
		if ((fontSize) > neededHeight) {
			neededHeight = fontSize;
		}
		
		if (this.sentences.size() > 0) {
			/* Must check compatibility */
			PDFSentence sentence = this.sentences.get(this.sentences.size() - 1);
			if (sentence instanceof PDFTextSentence) {
				PDFTextSentence lastSentence = (PDFTextSentence) sentence;
				if (lastSentence.isCompatibleWith(type, color, font, fontSize)) {
					/* Compatible. Add and done. */
					lastSentence.addText(text, width);
					created = true;
				}
			}
		}
		
		if (!created) {
			/* Must create a new one. */
			this.sentences.add(new PDFTextSentence(type, text, color, font, fontSize, width));
		}
		this.widthChange = true;
		this.mustCalculateCorrectionFactor = true;
	}
	
	/** Add an image to the line as a sentence. 
	 * @param image image to be used as sentence.
	 * @param width desired width to render the image at the sentence.
	 * @param height desired height to render the image at the sentence. */
	void addSentenceImage(PDImageXObject image, float width, float height) {
		this.sentences.add(new PDFImageSentence(image, width, height));
		this.widthChange = true;
		this.mustCalculateCorrectionFactor = true;
		if (height > neededHeight) {
			neededHeight = (int) Math.ceil(height);
		}
	}
	
	/** @return {@link #neededHeight}. */
	int getNeededHeight() {
		return this.neededHeight;
	}
	
	/** @return {@link #sentences}. */
	ArrayList getSentences() {
		return this.sentences;
	}
	
	/** @return {@link #correctionFactor}.
	 * @see PDFTextSentence#getYCorrectionFactor() */
	float[] getYCorrectionFactor() {
		if (mustCalculateCorrectionFactor) {
			/* Define maximum correction factor from sentences. */
			correctionFactor[0] = 0.0f;
			correctionFactor[1] = 0.0f;
			for (PDFSentence sentence : sentences) {
				if (sentence instanceof PDFTextSentence) {
					/* Check if the sentence correction factor is greater current one. */
					float[] sentenceCorrectionFactor = ((PDFTextSentence) sentence).getYCorrectionFactor();
					for (int i = 0; i < 2; i++) {
						if (sentenceCorrectionFactor[i] > correctionFactor[i]) {
							correctionFactor[i] = sentenceCorrectionFactor[i];
						}
					}
				} else if (sentence instanceof PDFImageSentence) {
					/* "upper" correction factor should be equal to the image size (if not greater). */
					if (sentence.getHeight() > correctionFactor[1]) {
						correctionFactor[1] = sentence.getHeight();
					}
				}
			}
			mustCalculateCorrectionFactor = false;
		}
		
		return correctionFactor;
	}
	
	/** @return {@link #textAlignment}. */
	ReportTextAlignment getTextAlignment() {
		return textAlignment;
	}
	
	/** @return {@link #maxWidth}. */
	float getMaxWidth() {
		return maxWidth;
	}
	
	/** @return {@link #haveCurrentPageSentence}. */
	boolean haveCurrentPageSentence() {
		return haveCurrentPageSentence;
	}
	
	/** @return {@link #haveTotalPagesSentence}. */
	boolean haveTotalPagesSentence() {
		return haveTotalPagesSentence;
	}
	
	/** @return needed width for newText using sentence style. */
	private float calculateTextWidth(PDFTextSentence textSentence, String newText) throws Exception {
		PDType1Font font = textSentence.getFont();
		int fontSize = textSentence.getFontSize();
		return (font.getStringWidth(newText) / 1000) * fontSize;
	}
	
	/** Set current and total page at sentences (usually called for headers and footers).
* Note: Check if {@link #haveTotalPagesSentence()} before calling this method. * @param currentPage current page number. */ void setPageReferences(int currentPage, int totalPages) throws Exception { /* Generate the texts */ String currentPageText = String.valueOf(currentPage); String totalPagesText = String.valueOf(totalPages); String textToReplace; /* Do replaces at each needed sentence. */ for (PDFSentence sentence : sentences) { textToReplace = null; if (sentence instanceof PDFTextSentence) { PDFTextSentence textSentence = (PDFTextSentence) sentence; if (PDFTextSentenceType.CURRENT_PAGE.equals(textSentence.getType())) { textToReplace = currentPageText; } else if (PDFTextSentenceType.PAGE_COUNT.equals(textSentence.getType())) { textToReplace = totalPagesText; } if (textToReplace != null) { float previousWidth = textSentence.getWidth(); /* Calculate new width. */ float textWidth = calculateTextWidth(textSentence, textToReplace); /* Replace the text. */ textSentence.replaceText(textToReplace, textWidth); /* And redefine line width */ width -= (textWidth - previousWidth); } } } } /** Set current page at sentences (usually called for headers and footers).
* Note: Check if {@link #haveCurrentPageSentence()} before calling this method. * @param currentPage current page number. */ void setCurrentPage(int currentPage) throws Exception { String currentPageText = String.valueOf(currentPage); for (PDFSentence sentence : sentences) { if (sentence instanceof PDFTextSentence) { PDFTextSentence textSentence = (PDFTextSentence) sentence; if (PDFTextSentenceType.CURRENT_PAGE.equals(textSentence.getType())) { float previousWidth = textSentence.getWidth(); /* Calculate new width. */ float textWidth = calculateTextWidth(textSentence, currentPageText); /* Replace the text. */ textSentence.replaceText(currentPageText, textWidth); /* And redefine line width */ width -= (textWidth - previousWidth); } } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy