org.fossa.rolp.util.PdfStreamSource.java Source code

Java tutorial

Introduction

Here is the source code for org.fossa.rolp.util.PdfStreamSource.java

Source

/**
 * Copyright (c) 2013, 2014 Frank Kaddereit, Anne Lachnitt, http://www.fossa.de/
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package org.fossa.rolp.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collection;

import org.fossa.rolp.data.leb.LebData;
import org.fossa.rolp.data.leb.LebFacheinschaetzungData;
import org.fossa.vaadin.FossaApplication;

import com.itextpdf.text.Anchor;
import com.itextpdf.text.Chapter;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Section;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import com.vaadin.terminal.StreamResource.StreamSource;

public class PdfStreamSource implements StreamSource {

    private static final long serialVersionUID = -3132301652943616825L;

    private static final Integer DUMMY_LINE_MAX = 99;
    private static final Integer HURENKIND_MAX = 99;

    private static final float FIXED_LEADING_TEXT = 1;
    private static final float SCHUSTERJUNGEN_DISTANCE_FACTOR_FOR_FONTSIZE = 3.2f;
    private static final float HURENKIND_DISTANCE_FACTOR_FOR_FONTSIZE = 3.2f;

    private static Font lernentwicklungsberichtUeberschriftFont;
    private static Font standardTextFont;
    private static Font standardTextBoldFont;
    private static Font headerFont;
    private static Font footerFont;
    private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    private LebData lebData;
    private Document document;
    private float zeilenabstandsfaktor;
    private Font fusszeilenFont;
    private Integer bottomMargin = 100;
    private Integer topMargin = 150;
    private LebCreator lebCreator;
    private Integer sectionCount = 0;

    public PdfStreamSource(FossaApplication app, LebData lebData, LebCreator lebCreator)
            throws DocumentException, IOException, PdfFormatierungsException {
        this.lebData = lebData;
        this.lebCreator = lebCreator;
        BaseFont fontNormal = BaseFont.createFont(
                app.getContext().getBaseDirectory() + Config.getRelativeNormalFontPath(), BaseFont.CP1252,
                BaseFont.EMBEDDED);
        BaseFont fontBold = BaseFont.createFont(
                app.getContext().getBaseDirectory() + Config.getRelativeBoldFontPath(), BaseFont.CP1252,
                BaseFont.EMBEDDED);
        BaseFont fontThin = BaseFont.createFont(
                app.getContext().getBaseDirectory() + Config.getRelativeThinFontPath(), BaseFont.CP1252,
                BaseFont.EMBEDDED);

        lernentwicklungsberichtUeberschriftFont = new Font(fontThin, 22, Font.NORMAL);
        standardTextFont = new Font(fontNormal, KlassenstufenUtils.getLebFontSize(lebData.getKlassenname()),
                Font.NORMAL);
        standardTextBoldFont = new Font(fontBold, KlassenstufenUtils.getLebFontSize(lebData.getKlassenname()),
                Font.NORMAL);
        headerFont = new Font(fontNormal, 12, Font.NORMAL);
        footerFont = new Font(fontNormal, 10, Font.NORMAL);
        fusszeilenFont = new Font(fontNormal, 8, Font.NORMAL);
        zeilenabstandsfaktor = KlassenstufenUtils.getLebZeilenabstandAsFactor(lebData.getKlassenname());
        document = null;
        try {
            document = new Document(PageSize.A4, 100, 90, topMargin, bottomMargin);
            PdfWriter writer = PdfWriter.getInstance(document, outputStream);
            LebPageHelper event = new LebPageHelper(lebData,
                    Image.getInstance(app.getContext().getBaseDirectory() + Config.getRelativeLogoPath()),
                    fusszeilenFont);
            writer.setPageEvent(event);
            document.open();
            addContent(writer);
            addFooter(lebData, writer);
        } finally {
            if (document != null) {
                document.close();
            }
        }
    }

    private void addFooter(LebData lebData, PdfWriter writer) throws DocumentException, PdfFormatierungsException {
        int footerMargin = 0;
        if (lebData.getSchulhalbjahr().isErstesHalbjahr()) {
            footerMargin = bottomMargin + 85;
        } else {
            footerMargin = bottomMargin + 170;
        }
        alertLonelyFooter(writer, footerMargin);
        while (writer.getVerticalPosition(false) > (footerMargin + 20)) {
            document.add(Chunk.NEWLINE);
        }
        float footerBegin = writer.getVerticalPosition(false);
        Paragraph footerTopParagraph = new Paragraph();
        footerTopParagraph.setLeading(1, 0.4f);
        footerTopParagraph.add(Chunk.NEWLINE);
        footerTopParagraph.add(Chunk.NEWLINE);

        Paragraph footerBottompParagraph = new Paragraph();
        footerBottompParagraph.setLeading(1, 0.4f);

        if (lebData.getSchulhalbjahr().isErstesHalbjahr()) {
            footerTopParagraph
                    .add(PdfFormatHelper.buildFooterHalbjahrDatumLine(lebData.getDatumString(), footerFont));
            footerTopParagraph.add(PdfFormatHelper.buildFooterHalbjahrDatumKlassenleiterLine(footerFont));
        } else {
            footerTopParagraph.add(
                    PdfFormatHelper.buildFooterVersetzungsvermerkLine(lebData.getVersetzungsvermerk(), footerFont));
            footerTopParagraph.add(Chunk.NEWLINE);
            footerTopParagraph.add(PdfFormatHelper.buildFooterDatumLine(lebData.getDatumString(), footerFont));
            document.add(footerTopParagraph);
            while (writer.getVerticalPosition(false) > (footerBegin - 82)) {
                document.add(Chunk.NEWLINE);
            }
            footerBottompParagraph.add(PdfFormatHelper.buildFooterDienstsiegelLine(footerFont));
            footerBottompParagraph.add(Chunk.NEWLINE);
            footerBottompParagraph.add(PdfFormatHelper.buildFooterUnterschriftenLine(footerFont));
        }
        footerBottompParagraph.add(Chunk.NEWLINE);
        footerBottompParagraph.add(Chunk.NEWLINE);
        footerBottompParagraph.add(Chunk.NEWLINE);
        footerBottompParagraph.add(PdfFormatHelper.buildFooterKenntnisLine(footerFont));
        document.add(footerBottompParagraph);
    }

    private void addContent(PdfWriter writer) throws DocumentException, PdfFormatierungsException {
        Anchor anchor = new Anchor("Lernentwicklungsbericht", lernentwicklungsberichtUeberschriftFont);
        Chapter chapterLEB = new Chapter(new Paragraph(anchor), 1);
        chapterLEB.setNumberDepth(0);
        Paragraph paragraphHeader = new Paragraph();
        paragraphHeader.setLeading(FIXED_LEADING_TEXT, 1);
        sectionCount += 1;
        Section headerSection = chapterLEB.addSection(paragraphHeader);
        headerSection.setNumberDepth(0);

        paragraphHeader.add(Chunk.NEWLINE);
        paragraphHeader.add(PdfFormatHelper.buildHeaderNameLine(lebData.getSchuelername(), headerFont));
        paragraphHeader.add(Chunk.NEWLINE);
        paragraphHeader.add(PdfFormatHelper.buildHeaderKlassendatenLine(lebData, headerFont));
        headerSection.add(Chunk.NEWLINE);
        headerSection.add(Chunk.NEWLINE);
        document.add(chapterLEB);
        insertDummyLineIfNecessary(writer);

        addKlassenbrief(chapterLEB, writer);
        addIndividuelleEinschaetzung(chapterLEB, writer);
        addFacheinschaetzungen(chapterLEB, writer);
    }

    private void addFacheinschaetzungen(Chapter chapterLEB, PdfWriter writer)
            throws DocumentException, PdfFormatierungsException {
        for (LebFacheinschaetzungData facheinschaetzungsdaten : lebData.getFacheinschaetzungsdaten()) {
            sectionCount += 1;
            breakHurenkind(writer);
            breakSchusterjunge(writer);
            Paragraph paragraphFacheinschaetzung = new Paragraph();
            Section facheinschaetzungsTextSection = chapterLEB.addSection(paragraphFacheinschaetzung);
            facheinschaetzungsTextSection.setNumberDepth(0);
            Collection<String> fachbezeichnungen = facheinschaetzungsdaten.getFachbezeichnungen();
            fachbezeichnungen.add(facheinschaetzungsdaten.getFachname());

            String facheinschaetzung = facheinschaetzungsdaten.getFacheinschaetzung();

            Integer firstIndex = null;
            String boldedWord = "";
            for (String fachbezeichnung : fachbezeichnungen) {
                int index = facheinschaetzung.toLowerCase().indexOf(fachbezeichnung.toLowerCase());
                if (index != -1 && (firstIndex == null || firstIndex > index)) {
                    firstIndex = index;
                    boldedWord = fachbezeichnung;
                }
            }
            Paragraph facheinschaetzungParapgraph = new Paragraph();
            facheinschaetzungParapgraph.setAlignment(Element.ALIGN_JUSTIFIED);
            facheinschaetzungParapgraph.setLeading(FIXED_LEADING_TEXT, zeilenabstandsfaktor);
            if (firstIndex == null) {
                facheinschaetzungParapgraph.add(new Phrase(
                        facheinschaetzungsdaten.getFacheinschaetzung().replace('\t', '\0'), standardTextFont));
            } else {
                String beforeBoldWord = facheinschaetzung.substring(0, firstIndex);
                facheinschaetzungParapgraph.add(new Phrase(beforeBoldWord.replace('\t', '\0'), standardTextFont));

                String boldWord = facheinschaetzung.substring(firstIndex, firstIndex + boldedWord.length());
                facheinschaetzungParapgraph.add(new Phrase(boldWord, standardTextBoldFont));

                String afterBoldWord = facheinschaetzung.substring(firstIndex + boldedWord.length());
                facheinschaetzungParapgraph.add(new Phrase(afterBoldWord.replace('\t', '\0'), standardTextFont));
            }
            facheinschaetzungParapgraph.setFont(standardTextFont);
            facheinschaetzungsTextSection.add(facheinschaetzungParapgraph);
            Paragraph unterschriftParagraph = new Paragraph();
            document.add(facheinschaetzungsTextSection);
            Section facheinschaetzungsUnterschriftSection = chapterLEB.addSection(unterschriftParagraph);
            facheinschaetzungsUnterschriftSection.setNumberDepth(0);
            unterschriftParagraph.add(
                    new Phrase(facheinschaetzungsdaten.getUnterschrift().replace('\t', '\0'), standardTextFont));
            unterschriftParagraph.setAlignment(Element.ALIGN_RIGHT);
            unterschriftParagraph.add(Chunk.NEWLINE);
            unterschriftParagraph.add(Chunk.NEWLINE);
            document.add(facheinschaetzungsUnterschriftSection);
            alertHurenkind(writer);
            insertDummyLineIfNecessary(writer);
        }
    }

    private void addIndividuelleEinschaetzung(Chapter chapterLEB, PdfWriter writer)
            throws DocumentException, PdfFormatierungsException {
        if (!lebData.getIndividuelleEinschaetzung().isEmpty()) {
            sectionCount += 1;
            breakHurenkind(writer);
            breakSchusterjunge(writer);
            Paragraph paragraphIndividuelleEinschaetzung = new Paragraph();
            Section individuelleEinschaetzungsTextSection = chapterLEB
                    .addSection(paragraphIndividuelleEinschaetzung);
            individuelleEinschaetzungsTextSection.setNumberDepth(0);
            Paragraph schuelereinschaetzungParapgraph = new Paragraph(
                    lebData.getIndividuelleEinschaetzung().replace('\t', '\0'), standardTextFont);
            schuelereinschaetzungParapgraph.setAlignment(Element.ALIGN_JUSTIFIED);
            schuelereinschaetzungParapgraph.setLeading(FIXED_LEADING_TEXT, zeilenabstandsfaktor);
            individuelleEinschaetzungsTextSection.add(schuelereinschaetzungParapgraph);
            document.add(individuelleEinschaetzungsTextSection);
            document.add(getKlassenlehrerunterschrift(chapterLEB));
            alertHurenkind(writer);
            insertDummyLineIfNecessary(writer);
        }
    }

    private void addKlassenbrief(Chapter chapterLEB, PdfWriter writer)
            throws DocumentException, PdfFormatierungsException {
        if (!lebData.getKlassenbrief().isEmpty()) {
            sectionCount += 1;
            breakSchusterjunge(writer);
            Paragraph paragraphKlassenbrief = new Paragraph();
            Section klassenbriefSection = chapterLEB.addSection(paragraphKlassenbrief);
            klassenbriefSection.setNumberDepth(0);
            Paragraph klasseneinschaetzungParapgraph = new Paragraph(lebData.getKlassenbrief().replace('\t', '\0'),
                    standardTextFont);
            klasseneinschaetzungParapgraph.setAlignment(Element.ALIGN_JUSTIFIED);
            klasseneinschaetzungParapgraph.setLeading(FIXED_LEADING_TEXT, zeilenabstandsfaktor);
            klasseneinschaetzungParapgraph.add(Chunk.NEWLINE);
            if (lebData.getIndividuelleEinschaetzung().isEmpty()) {
                klassenbriefSection.add(klasseneinschaetzungParapgraph);
                document.add(klassenbriefSection);
                document.add(getKlassenlehrerunterschrift(chapterLEB));
            } else {
                klasseneinschaetzungParapgraph.add(Chunk.NEWLINE);
                klassenbriefSection.add(klasseneinschaetzungParapgraph);
                document.add(klassenbriefSection);
            }
            alertLonelyHeader(writer);
            insertDummyLineIfNecessary(writer);
        }
    }

    private Section getKlassenlehrerunterschrift(Section chapterLEB) {
        Paragraph unterschriftParagraph = new Paragraph();
        Section klassenbriefUnterschriftSection = chapterLEB.addSection(unterschriftParagraph);
        klassenbriefUnterschriftSection.setNumberDepth(0);
        unterschriftParagraph
                .add(new Phrase(lebData.getKlassenlehrerUnterschrift().replace('\t', '\0'), standardTextFont));
        unterschriftParagraph.setAlignment(Element.ALIGN_RIGHT);
        unterschriftParagraph.add(Chunk.NEWLINE);
        unterschriftParagraph.add(Chunk.NEWLINE);
        return klassenbriefUnterschriftSection;
    }

    private void breakHurenkind(PdfWriter writer) {
        if (lebCreator.getHurenkinderMarker().containsKey(sectionCount)) {
            document.newPage();
        }
    }

    private void breakSchusterjunge(PdfWriter writer) {
        if (writer.getVerticalPosition(false) < getSchusterjungenCriticalDistance()) {
            document.newPage();
        }
    }

    private void alertHurenkind(PdfWriter writer) throws PdfFormatierungsException {
        if (writer.getVerticalPosition(false) > getHurenkindCriticalDistance()
                && lebCreator.getHurenkindCount() < HURENKIND_MAX) {
            lebCreator.getHurenkinderMarker().put(sectionCount, true);
            throw new PdfFormatierungsException(PdfFormatierungsException.TYPE_HURENKIND);
        }
    }

    private void alertLonelyHeader(PdfWriter writer) throws PdfFormatierungsException {
        if (writer.getVerticalPosition(false) > getHurenkindCriticalDistance()
                && lebCreator.getHurenkindCount() < HURENKIND_MAX) {
            throw new PdfFormatierungsException(PdfFormatierungsException.TYPE_LONELY_HEADER_OR_FOOTER);
        }
    }

    private void alertLonelyFooter(PdfWriter writer, float footerMargin) throws PdfFormatierungsException {
        if ((writer.getVerticalPosition(false) < footerMargin
                || writer.getVerticalPosition(false) > getHurenkindCriticalDistance())
                && lebCreator.getDummyLineCount() < DUMMY_LINE_MAX) {
            throw new PdfFormatierungsException(PdfFormatierungsException.TYPE_LONELY_HEADER_OR_FOOTER);
        }
    }

    private void insertDummyLineIfNecessary(PdfWriter writer) throws DocumentException {
        int countNewLines = 0;
        while (countNewLines < lebCreator.getDummyLineCount()) {
            countNewLines += 1;
            if (writer.getVerticalPosition(false) < getSchusterjungenCriticalDistance()) {
                break;
            }
            document.add(Chunk.NEWLINE);
        }
    }

    private float getSchusterjungenCriticalDistance() {
        return (standardTextFont.getSize() * zeilenabstandsfaktor * SCHUSTERJUNGEN_DISTANCE_FACTOR_FOR_FONTSIZE)
                + bottomMargin;
    }

    private float getHurenkindCriticalDistance() {
        return 840 - (standardTextFont.getSize() * zeilenabstandsfaktor * HURENKIND_DISTANCE_FACTOR_FOR_FONTSIZE)
                - topMargin;
    }

    @Override
    public ByteArrayInputStream getStream() {
        return new ByteArrayInputStream(outputStream.toByteArray());
    }

    public ByteArrayOutputStream getByteArrayOutputStream() {
        return outputStream;
    }

}