
net.sf.nervalreports.generators.PDFLine Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pdf-generator Show documentation
Show all versions of pdf-generator Show documentation
This is the PDF generator package of NervalReports (a lightweight report creation library),
used to generate a report directly to a .pdf file.
/** 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