/**
* FyLLGen - A Java based tool for collecting and distributing family data
*
* Copyright (C) 2007-2011 Christian Packenius
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.chris_soft.fyllgen.export;
import java.awt.Graphics2D;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.itextpdf.text.Anchor;
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.ElementTags;
import com.itextpdf.text.Font;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.Image;
import com.itextpdf.text.Meta;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import de.chris_soft.fyllgen.Statics;
import de.chris_soft.fyllgen.data.OptionData;
import de.chris_soft.fyllgen.data.Person;
import de.chris_soft.fyllgen.data.Relationship;
import de.chris_soft.fyllgen.data.RelationshipPartners;
import de.chris_soft.fyllgen.utilities.FamilyUtilities;
import de.chris_soft.fyllgen.utilities.PersonListSort;
/**
* Export the instance data into a PDF file.
* @author Christian Packenius, 20100630.
*/
public class PdfExporter extends DataExporter {
/**
* Anhang A - �berschrift.
*/
private static final String ANHANG_A_PERSONEN_SORTIERT_NACH_GEBURTSJAHR = "Personen, sortiert nach Geburtsjahr";
/**
* Anhang B - �berschrift.
*/
private static final String ANHANG_B_VERSTORBENE_PERSONEN_SORTIERT_NACH_ALTER =
"Verstorbene Personen, sortiert nach Alter";
/**
* Anhang C - �berschrift.
*/
private static final String ANHANG_C_PERSONEN_SORTIERT_NACH_GEBURTSTAG_OHNE_JAHR =
"Personen, sortiert nach Geburtstag (ohne Jahr)";
/**
* Anhang D - �berschrift.
*/
private static final String ANHANG_D_BILDER = "Portraits";
/**
* Font for title on first page of the document.
*/
private final Font fontHelvetica36Bold = FontFactory.getFont(FontFactory.HELVETICA, 36, Font.BOLD);
/**
* Font for title on first page of the document.
*/
private final Font fontHelvetica24Bold = FontFactory.getFont(FontFactory.HELVETICA, 24, Font.BOLD);
/**
* Font for title on first page of the document.
*/
private final Font fontHelvetica24BoldItalic = FontFactory
.getFont(FontFactory.HELVETICA, 24, Font.BOLD | Font.ITALIC);
/**
* Font for title in appendix.
*/
private final Font fontHelvetica18BoldItalic = FontFactory
.getFont(FontFactory.HELVETICA, 18, Font.BOLD | Font.ITALIC);
/**
* Font for appendix number.
*/
private final Font fontHelvetica18Bold = FontFactory.getFont(FontFactory.HELVETICA, 18, Font.BOLD);
/**
* Font for title of simple data in a single line.
*/
private final Font fontHelvetica12Bold = FontFactory.getFont(FontFactory.HELVETICA, 12, Font.BOLD);
/**
* Font of simple text.
*/
private final Font fontHelvetica12 = FontFactory.getFont(FontFactory.HELVETICA, 12);
/**
* Font of italic text.
*/
private final Font fontHelvetica12Italic = FontFactory.getFont(FontFactory.HELVETICA, 12, Font.ITALIC);
/**
* Font for links [1].
*/
private Font fontTimes12ItalicBlue = FontFactory.getFont(FontFactory.TIMES, 12, Font.ITALIC, new BaseColor(32, 32,
192));
/**
* Font for links [2].
*/
private final Font fontTimes12Blue = FontFactory.getFont(FontFactory.TIMES, 12, Font.NORMAL, new BaseColor(32, 32,
192));
/**
* Font for links [2].
*/
private final Font fontTimes10Italic = FontFactory.getFont(FontFactory.TIMES, 10, Font.ITALIC);
/**
* Font for page title with full name of the person.
*/
private final Font fontCourier14Bold = FontFactory.getFont(FontFactory.COURIER, 14, Font.BOLD);
/**
* List of persons to export.
*/
private List<Person> persons;
/**
* Liste der obigen Personen, die w�hrend des Exports in ihrer Reihenfolge nicht ver�ndert wird.
*/
private final List<Person> personsSorted = new ArrayList<Person>();
/**
* PDF-Dokument, das erzeugt wird.
*/
private Document document;
/**
* Der PDF-Writer.
*/
private PdfWriter writer;
/**
* Erste Person in der Liste und damit die Person, deren Stammbuch hier aufgebaut wird.
*/
private Person person0;
/**
* Name der Hauptperson.
*/
private String person0Name;
/**
* Laufende Nummer des Dokumentes.
*/
private long documentNumber;
/**
* Hinweis auf die jeweils n�chste Person, die mich einen Schritt weiter Richtung Hauptperson bringt.
*/
private Map<Person, Person> nextPersons;
/**
* Liste aller Bilder, f�r den Anhang D.
*/
private final List<Image> listImages_D = new ArrayList<Image>();
/**
* Liste aller Person obiger Bilder, f�r den Anhang D.
*/
private final List<Person> listPersons_D = new ArrayList<Person>();
/**
* Menge aller Personen, deren Images angezeigt werden d�rfen. Eventuell werden auch andere Daten unterdr�ckt, wenn die Person
* nicht in dieser Menge enthalten ist.
*/
private Set<Person> imagingPersonsList = new HashSet<Person>();
/**
* @see de.chris_soft.fyllgen.export.DataExporter#export(java.util.List, java.io.OutputStream)
*/
@Override
public long export(List<Person> persons, OutputStream out) throws DocumentException, IOException {
if (createPrintVersion) {
fontTimes12ItalicBlue = FontFactory.getFont(FontFactory.TIMES, 12, Font.ITALIC);
}
else {
fontTimes12ItalicBlue = FontFactory.getFont(FontFactory.TIMES, 12, Font.ITALIC, new BaseColor(32, 32, 192));
}
// Ein paar Listen f�llen / leeren.
this.persons = persons;
listImages_D.clear();
listPersons_D.clear();
personsSorted.clear();
imagingPersonsList.clear();
personsSorted.addAll(persons);
person0 = persons.get(0);
person0Name = person0.getValue(Person.NAME);
documentNumber = DataExporter.createExportedFilesEntry(persons, this);
// Liste von Personenlinks erzeugen.
nextPersons = FamilyUtilities.createNextPersonsMap(person0, persons);
// Liste der Bilder erzeugen.
createImagingList();
SimpleDateFormat dayForm = new SimpleDateFormat("dd.");
SimpleDateFormat timeForm = new SimpleDateFormat("HH.mm");
String day = dayForm.format(new Date());
String date = day + " " + Statics.currentMonth + " " + Statics.currentYear;
String time = timeForm.format(new Date());
String datetime = "am " + date + " um " + time + " Uhr";
document = new Document();
writer = PdfWriter.getInstance(document, out);
addMetaData();
document.open();
addTitlePages(datetime);
addPersonPages();
addAppendixPages();
document.close();
return documentNumber;
}
/**
* Erzeugt eine Liste von Personen, deren Images mit angezeigt werden sollen. Bei allen anderen Personen werden keine Images
* angezeigt.
*/
private void createImagingList() {
imagingPersonsList.clear();
imagingPersonsList.add(person0);
// 3-stufig alle direkten Verwandten �bernehmen.
for (int i = 0; i < 4; i++) {
ArrayList<Person> list = new ArrayList<Person>();
list.addAll(imagingPersonsList);
for (Person pp : list) {
imagingPersonsList.addAll(Statics.getList(pp.getPartner()));
// In der letzten Iteration nur noch die Partner �bernehmen.
if (i < 3) {
imagingPersonsList.addAll(Statics.getList(pp.getParents()));
imagingPersonsList.addAll(Statics.getList(pp.getChildren()));
imagingPersonsList.addAll(Statics.getList(pp.getSiblings()));
}
}
}
// Nun s�mtliche Kinder- und Elterngenerationen mit hinzunehmen (und deren
// Partner).
ArrayList<Person> list1 = new ArrayList<Person>();
list1.addAll(imagingPersonsList);
ArrayList<Person> list2 = new ArrayList<Person>();
list2.addAll(imagingPersonsList);
for (int i = 0; i < list1.size(); i++) {
for (Person pp : list1.get(i).getParents()) {
if (!list1.contains(pp)) {
list1.add(pp);
imagingPersonsList.add(pp);
}
}
for (Person pp : list1.get(i).getPartner()) {
if (!list1.contains(pp)) {
list1.add(pp);
imagingPersonsList.add(pp);
}
}
}
for (int i = 0; i < list2.size(); i++) {
for (Person pp : list2.get(i).getChildren()) {
if (!list2.contains(pp)) {
list2.add(pp);
imagingPersonsList.add(pp);
}
}
for (Person pp : list2.get(i).getPartner()) {
if (!list2.contains(pp)) {
list2.add(pp);
imagingPersonsList.add(pp);
}
}
}
// Alle Personen einf�gen, die entweder seit mindestens 40 Jahren tot sind.
for (Person pp : persons) {
if (!imagingPersonsList.contains(pp)) {
// Todestag plus 40 Jahre.
try {
String sDeathday = pp.getValueView(Person.DEATHDAY);
final int deathyear;
if (sDeathday.endsWith("?")) {
deathyear = pp.getBirthYear(true) + OptionData.instance.getInt(OptionData.MAX_PERSON_AGE);
}
else {
int ik = sDeathday.lastIndexOf('.');
deathyear = Integer.parseInt(sDeathday.substring(ik + 1));
}
if (Statics.currentYear >= deathyear + 40) {
imagingPersonsList.add(pp);
}
} catch (NumberFormatException nfe) {
// Okay, Person nicht im Detail anzeigen.
}
}
}
}
// /**
// * Erzeugt eine Map, in der je Person diejenige Person steht, die "mich" der
// Hauptperson (der ersten in der Liste) n�her
// * bringt.
// */
// private void createNextPersonsMap() {
// nextPersons = new HashMap<Person, Person>();
// nextPersons.put(person0, person0);
// while (nextPersons.size() < persons.size()) {
// boolean bSet = false;
// Person[] keyPersons = nextPersons.keySet().toArray(new Person[0]);
// for (Person person : keyPersons) {
// List<Person> hpl = new ArrayList<Person>();
// hpl.addAll(Arrays.asList(person.getChildren()));
// hpl.addAll(Arrays.asList(person.getParents()));
// hpl.addAll(Arrays.asList(person.getPartner()));
// for (Person hp : hpl) {
// if (nextPersons.get(hp) == null) {
// nextPersons.put(hp, person);
// bSet = true;
// }
// }
// }
//
// // Darf zwar nicht vorkommen, aber man wei� ja nie...
// if (!bSet) {
// break;
// }
// }
// }
/**
* F�gt der Seite ein paar Metadaten hinzu.
*/
private void addMetaData() throws DocumentException {
document.addCreator(Statics.producer);
document.addCreationDate();
document.add(new Meta(ElementTags.PRODUCER, Statics.producer));
String title =
"Familienstammbuch der Familie " + person0Name + " (" + Statics.shortProducer + " #" + documentNumber + ")";
document.addSubject(title);
document.addTitle(title);
document.addKeywords("Personen, Verwandtschaft, Genealogie, Familie, Stammbaum, " + Statics.producer);
}
/**
* Add one or more pages before the person data pages.
* @param datetime
* @throws DocumentException
* @throws IOException
*/
private void addTitlePages(String datetime) throws DocumentException, IOException {
sign();
// Die ersten Seiten sind mehr oder minder fix.
addFirstPage(person0);
addSecondPage(datetime);
addThirdPage(person0);
}
/**
* Erste Seite "Familienstammbaum der Familie XYZ".
*/
private void addFirstPage(Person person) throws DocumentException {
Paragraph paragraph = new Paragraph();
paragraph.setAlignment(Element.ALIGN_CENTER);
paragraph.add(new Chunk("\r\n\r\n\r\n\r\n\r\n\r\nFamilienstammbaum", fontHelvetica36Bold));
document.add(paragraph);
paragraph = new Paragraph();
paragraph.setAlignment(Element.ALIGN_CENTER);
paragraph.add(new Chunk("\r\n\r\n\r\n\r\nder Familie ", fontHelvetica24Bold));
paragraph.setAlignment(Element.ALIGN_CENTER);
paragraph.add(new Chunk("\r\n\r\n\r\n\r\n", fontHelvetica24BoldItalic));
// paragraph.add(new Chunk(person.getValue(Person.NAME),
// secondTitleFontItalic));
Chunk chunk = new Chunk(person.getValue(Person.NAME), fontHelvetica24BoldItalic);
Anchor anchor = new Anchor(chunk);
anchor.setReference("#p-" + person.getXREFID());
paragraph.add(anchor);
document.add(paragraph);
}
/**
* Zweite Seite: Belehrung.
*/
private void addSecondPage(String datetime) throws DocumentException {
Paragraph paragraph;
newPage();
paragraph = new Paragraph();
paragraph.setFont(fontHelvetica12Italic);
paragraph.setAlignment(Element.ALIGN_CENTER);
paragraph.add(new Chunk("\r\n\r\n\r\n\r\n\r\n\r\nDiese PDF-Datei wurde\r\n"));
paragraph.add(new Chunk(datetime));
paragraph.add(new Chunk("\r\nvom Programm\r\n"));
paragraph.add(new Chunk(Statics.producer));
paragraph.add(new Chunk("\r\nf�r\r\n"));
paragraph.add(new Chunk(person0Name));
paragraph.add(new Chunk("\r\nerzeugt.\r\n\r\n"));
paragraph.add(new Chunk(" Sie darf nur f�r private Zwecke "));
paragraph.add(new Chunk("verwendet werden. Um die Wahrung der Privatsph�re "));
paragraph.add(new Chunk("aller in dieser Datei genannten Personen sicher zu stellen, "));
paragraph.add(new Chunk("ist eine Weitergabe oder Ver�ffentlichung dieser Datei (auch in Ausz�gen, "));
paragraph.add(new Chunk("als Druck oder in anderer Form) nur an "));
paragraph.add(new Chunk("innerhalb dieses Dokumentes genannte Personen erlaubt. "));
paragraph.add(new Chunk("Eine Ausnahme von diesem Verbot ist nur gegeben, "));
paragraph.add(new Chunk("wenn alle in diesem Dokument genannten noch lebenden Personen "));
paragraph.add(new Chunk("ihre schriftliche Zustimmung zur Weitergabe oder Ver�ffentlichung gegeben haben. "));
paragraph.add(new Chunk("(Entsprechendes gilt f�r die Weitergabe oder Ver�ffentlichung "));
paragraph.add(new Chunk("eines Auszuges dieses Dokumentes.) "));
paragraph.add(new Chunk("\r\n\r\n"));
paragraph.add(new Chunk("F�r die Richtigkeit der hier gemachten Angaben wird keinerlei Gew�hr �bernommen. "));
String eMail = OptionData.instance.getString(OptionData.EXPORT_MAIL);
if (eMail != null && eMail.trim().length() > 0) {
paragraph.add(new Chunk("Sollten Sie Fehler erkennen oder Erg�nzungen zu den gemachten Angaben haben, "));
paragraph.add(new Chunk("senden Sie diese bitte an die folgende E-Mailadresse:\r\n\r\n"));
Anchor iref = new Anchor(new Chunk(eMail, fontTimes12ItalicBlue));
iref.setReference("mailto:" + eMail);
paragraph.add(iref);
paragraph.add(new Chunk("\r\n\r\nSie werden darauf hin eine aktualisierte Version dieser PDF-Datei "));
paragraph.add(new Chunk("per E-Mail erhalten."));
paragraph.add(new Chunk("\r\n\r\nVielen Dank!"));
}
paragraph.add(new Chunk("\r\n\r\nDie von " + Statics.shortProducer
+ " erzeugten PDF-Dateien werden durchgehend nummeriert.", fontHelvetica12));
paragraph.add(new Chunk("\r\nDiese Datei besitzt die laufende Nummer " + documentNumber + ".", fontHelvetica12));
document.add(paragraph);
}
/**
* Dritte Seite: Links auf die Anh�nge und so.
*/
private void addThirdPage(Person person) throws DocumentException {
newPage();
Paragraph paragraph;
paragraph = new Paragraph();
paragraph.setFont(fontHelvetica12);
paragraph.add(new Chunk("\r\n\r\nIn dieser Datei stehen die Stammdaten von insgesamt "));
paragraph.add(new Chunk(persons.size() + " Personen, "));
paragraph.add(new Chunk("die erste aufgelistete Person ist "));
Chunk chunk = new Chunk(person.getValue(Person.NAME), fontHelvetica12Italic);
Anchor anchor = new Anchor(chunk);
anchor.setReference("#p-" + person.getXREFID());
paragraph.add(anchor);
paragraph.add(new Chunk(". Alle weiteren Personen sind �ber ihre 'verwandtschaftliche N�he' sortiert. "));
paragraph.add(new Chunk("Soweit dies m�glich ist, l�sst sich innerhalb dieser Dateien navigieren."));
document.add(paragraph);
paragraph = new Paragraph();
paragraph.setFont(fontHelvetica12Italic);
paragraph.add(new Chunk("\r\n\r\nAnh�nge:\r\n\r\n", fontHelvetica12Bold));
anchor = new Anchor(new Chunk("Anhang A: " + ANHANG_A_PERSONEN_SORTIERT_NACH_GEBURTSJAHR));
anchor.setReference("#anhang-a");
paragraph.add(anchor);
paragraph.add(new Chunk("\r\n"));
anchor = new Anchor(new Chunk("Anhang B: " + ANHANG_B_VERSTORBENE_PERSONEN_SORTIERT_NACH_ALTER));
anchor.setReference("#anhang-b");
paragraph.add(anchor);
paragraph.add(new Chunk("\r\n"));
anchor = new Anchor(new Chunk("Anhang C: " + ANHANG_C_PERSONEN_SORTIERT_NACH_GEBURTSTAG_OHNE_JAHR));
anchor.setReference("#anhang-c");
paragraph.add(anchor);
paragraph.add(new Chunk("\r\n"));
anchor = new Anchor(new Chunk("Anhang D: " + ANHANG_D_BILDER));
anchor.setReference("#anhang-d");
paragraph.add(anchor);
document.add(paragraph);
}
/**
* Adds all pages for the single persons.
*/
private void addPersonPages() throws DocumentException {
for (Person person : persons) {
newPage();
fillPersonPage(person);
}
}
/**
* Fill a person page with all person data.
*/
private void fillPersonPage(Person person) throws DocumentException {
addPageTitle(person);
addImages(person);
addPersonData(person);
addAllPersonLists(person);
showConnectionToMainPerson(person);
}
/**
* Falls f�r diese Person Bilder hinterlegt sind, werden diese mit angezeigt.
*/
private void addImages(Person person) throws DocumentException {
if (imagingPersonsList.contains(person)) {
boolean first = true;
for (File imageFile : person.getImageList()) {
first = addImage(first, imageFile, person);
}
if (!first) {
Paragraph paragraph = new Paragraph();
document.add(paragraph);
}
}
else {
Paragraph paragraph = new Paragraph();
paragraph.add(new Chunk("(Bilder und weitere Daten wurden eventuell unterdr�ckt.)", fontTimes10Italic));
document.add(paragraph);
}
}
/**
* Setzt eine Bilddatei auf die Seite.
*/
private boolean addImage(boolean first, File imageFile, Person person) throws BadElementException, DocumentException {
try {
Image image = Image.getInstance("images/" + imageFile.getName());
image.setBorderWidth(5);
if (first) {
Paragraph paragraph = new Paragraph();
paragraph.add(new Chunk("\r\n"));
document.add(paragraph);
first = false;
}
Chunk imageChunk = new Chunk(image, 0, 0, true);
Anchor imageAnchor = new Anchor(imageChunk);
imageAnchor.setReference("#anhang-d-" + listImages_D.size());
// imageAnchor.setReference("#i-" + person.getXREFID());
listImages_D.add(image);
listPersons_D.add(person);
document.add(imageAnchor);
document.add(new Phrase(" "));
} catch (MalformedURLException exception) {
// Dann halt kein Image einbinden.
System.err.println("Image " + imageFile.getAbsolutePath() + " konnte nicht in das PDF eingebunden werden:");
exception.printStackTrace();
} catch (IOException exception) {
// Dann halt kein Image einbinden.
System.err.println("Image " + imageFile.getAbsolutePath() + " konnte nicht in das PDF eingebunden werden:");
exception.printStackTrace();
}
return first;
}
/**
* Zeigt die Verbindung zur "Hauptperson" dieser PDF-Datei.
*/
private void showConnectionToMainPerson(Person person) throws DocumentException {
// Not for the first person!
if (person == person0) {
return;
}
// Eigenen Paragraph f�r die Verbindung zur Hauptperson erzeugen.
Paragraph paragraph = new Paragraph();
paragraph.add(new Chunk("\r\nVerbindung zu " + person0Name + ":\r\n"));
while (person != person0) {
Person currPerson = person;
Person nextPerson = nextPersons.get(person);
// Das hier passiert nur, wenn der Packenius/Vietor-Filter eingeschaltet
// ist!
if (nextPerson == null) {
break;
}
int count = 0;
String s = "";
// Richtung Vorfahren.
if (nextPerson.isChildOf(currPerson)) {
while (currPerson != person0 && nextPerson.isChildOf(currPerson)) {
currPerson = nextPerson;
nextPerson = nextPersons.get(currPerson);
count++;
}
if (count == 1) {
if (person.isFemale()) {
s += "Mutter";
}
else if (person.isMale()) {
s += "Vater";
}
else {
s += "Elternteil";
}
}
else {
for (int i = 2; i < count; i++) {
s += "Ur-";
}
if (person.isFemale()) {
s += "Gro�mutter";
}
else if (person.isMale()) {
s += "Gro�vater";
}
else {
s += "Gro�elter";
}
}
}
// Richtung Nachkommen.
else if (nextPerson.isParentOf(currPerson)) {
while (currPerson != person0 && nextPerson.isParentOf(currPerson)) {
currPerson = nextPerson;
nextPerson = nextPersons.get(currPerson);
count++;
}
if (count == 1) {
if (person.isFemale()) {
s += "Tochter";
}
else if (person.isMale()) {
s += "Sohn";
}
else {
s += "Kind";
}
}
else {
for (int i = 2; i < count; i++) {
s += "Ur-";
}
s += "Enkel";
}
}
// Partner.
else {
currPerson = nextPerson;
Relationship relship = person.getRelationship(currPerson);
if (person.isFemale()) {
if (relship.getType().equals(RelationshipPartners.MARRIAGE)) {
s = "Gattin";
}
else {
s = "Partnerin";
}
}
else if (person.isMale()) {
if (relship.getType().equals(RelationshipPartners.MARRIAGE)) {
s = "Gatte";
}
else {
s = "Partner";
}
}
else {
s = "Partner/in";
}
}
Chunk chunk = new Chunk(" " + person.getValueView(Person.NAME), fontTimes12Blue);
Anchor anchor = new Anchor(chunk);
anchor.setReference("#p-" + person.getXREFID());
paragraph.add(anchor);
paragraph.add(new Chunk(" ist " + s + " von "));
chunk = new Chunk(currPerson.getValueView(Person.NAME), fontTimes12Blue);
anchor = new Anchor(chunk);
anchor.setReference("#p-" + currPerson.getXREFID());
paragraph.add(anchor);
paragraph.add(new Chunk(".\r\n"));
person = currPerson;
}
document.add(paragraph);
}
/**
* Just show the full person name at the top of the page.
*/
private void addPageTitle(Person person) throws DocumentException {
String fullname = person.getValueView(Person.NAME);
if (createPrintVersion) {
fullname += " [" + (personsSorted.indexOf(person) + 1) + "]";
}
Paragraph pdfParagraph = new Paragraph();
Chunk fullnameChunk = new Chunk(fullname, fontCourier14Bold);
Anchor zref = new Anchor(fullnameChunk);
zref.setName("p-" + person.getXREFID());
pdfParagraph.add(zref);
document.add(pdfParagraph);
}
/**
* Adds relevant and given person data.
*/
private void addPersonData(Person person) throws DocumentException {
// Einzelne Daten werden unterdr�ckt, falls Person nicht "nahe genug".
boolean viewPersonDetails = imagingPersonsList.contains(person);
// Read person data.
String birthday = person.getValueView(Person.BIRTHDAY);
String deathday = person.getValueView(Person.DEATHDAY);
birthday = birthday == "?.?.?" ? "" : birthday;
deathday = deathday == "?.?.?" ? "" : deathday;
String birthplace = person.getValueView(Person.BIRTHPLACE);
String deathplace = person.getValueView(Person.DEATHPLACE);
// Create data paragraph.
if (birthday.length() + deathday.length() + birthplace.length() + deathplace.length() > 0) {
Paragraph paragraph = new Paragraph();
// paragraph.add(new Chunk("\r\n"));
PdfPTable table = createKeyValuePdfTable();
addSingleDataLine(table, "Geburtstag", birthday, true, Statics.niceShortDate(birthday));
if (viewPersonDetails) {
addSingleDataLine(table, "Geboren in", birthplace, false, null);
}
addSingleDataLine(table, "Todestag", deathday, false, Statics.niceShortDate(deathday));
if (viewPersonDetails) {
addSingleDataLine(table, "Gestorben in", deathplace, false, null);
}
paragraph.add(table);
document.add(paragraph);
}
// Add additional data.
String job = person.getValueView(Person.JOB).trim();
if (viewPersonDetails) {
if (job.length() > 0) {
Paragraph paragraph = new Paragraph();
// paragraph.add(new Chunk("\r\n"));
PdfPTable table = createKeyValuePdfTable();
addSingleDataLine(table, "Beruf", job, false, null);
paragraph.add(table);
document.add(paragraph);
}
}
}
/**
* Erzeugt f�r die PDF-Datei eine Tabelle mit zwei Spalten.
*/
private PdfPTable createKeyValuePdfTable() throws DocumentException {
PdfPTable table = new PdfPTable(new float[] {1f, 2f});
table.setWidthPercentage(100);
table.getDefaultCell().setPaddingLeft(0);
table.getDefaultCell().setBorderWidth(0);
table.setHorizontalAlignment(Element.ALIGN_LEFT);
table.setWidths(new int[] {16, 100 - 16});
table.addCell(new Phrase(" "));
table.addCell(new Phrase(" "));
return table;
}
/**
* Adds a single data line, if the data is not empty.
*/
private void addSingleDataLine(PdfPTable table, String title, String data, boolean withDateLinks, String niceData) {
if (data != null && data.trim().length() > 0) {
Phrase phrase = new Phrase(title + ": ", fontHelvetica12Bold);
table.addCell(phrase);
Phrase phrase2 = new Phrase();
if (withDateLinks) {
createTableCellWithDateLinks(data, niceData, phrase2);
}
else {
phrase = new Phrase(niceData == null ? data : niceData);
phrase2.add(phrase);
}
table.addCell(phrase2);
}
}
/**
* Create a table cell with a date as data.
*/
private void createTableCellWithDateLinks(String data, String niceDate, Phrase phrase2) {
Phrase phrase;
int ndSpace1 = niceDate.indexOf(' ');
int ndSpace2 = ndSpace1 < 0 ? -1 : niceDate.indexOf(' ', ndSpace1 + 1);
String dayMonth = data.substring(0, data.lastIndexOf('.'));
String year = data.substring(data.lastIndexOf('.') + 1);
if (!dayMonth.contains("?")) {
Anchor anchor = new Anchor(new Phrase(niceDate.substring(0, ndSpace2 < 0 ? niceDate.length() : ndSpace2)));
anchor.setReference("#dm-" + dayMonth);
phrase2.add(anchor);
}
else {
phrase =
new Phrase(year.contains("?") ? niceDate : niceDate.substring(0, Math.max(0, Math.max(ndSpace1, ndSpace2))));
phrase2.add(phrase);
}
phrase = new Phrase(" ");
phrase2.add(phrase);
if (!year.contains("?")) {
Anchor anchor = new Anchor(new Phrase(year));
anchor.setReference("#y-" + year);
phrase2.add(anchor);
}
else {
phrase = new Phrase(year);
phrase2.add(phrase);
}
}
/**
* Adds multiple person lists to the document.
*/
private void addAllPersonLists(Person person) throws DocumentException {
addPersonList(person, person.getParents(), Relationship.PARENTS);
addPersonList(person, person.getChildren(), Relationship.CHILDREN);
addPersonList(person, person.getPartner(), Relationship.PARTNERS);
addPersonList(person, person.getSiblings(), Relationship.SIBLINGS);
}
/**
* Adds a list of persons with the same header to the document.
*/
private void addPersonList(Person currPerson, Person[] personList, String relationType) throws DocumentException {
String personListHeader = getHeaderForPersonList(personList, relationType);
String[] additionalTextList = new String[personList.length];
sortPersonList(personList, relationType, additionalTextList, currPerson);
if (personList.length > 0) {
// Create pdf header of the person list.
Paragraph paragraph = new Paragraph();
paragraph.add(new Chunk("\r\n", fontHelvetica12));
paragraph.add(new Chunk(personListHeader, fontHelvetica12));
document.add(paragraph);
// Person list.
for (int i = 0; i < personList.length; i++) {
Person person = personList[i];
// Name extension.
String nameExt = getNameExtension(currPerson, person);
paragraph = new Paragraph();
// Name of the person.
String fullPersonName = person.getValue(Person.NAME) + nameExt;
if (createPrintVersion) {
fullPersonName += " [" + (personsSorted.indexOf(person) + 1) + "]";
}
if (persons.contains(person)) {
Chunk chunk = new Chunk(fullPersonName, fontTimes12ItalicBlue);
Anchor iref = new Anchor(chunk);
iref.setReference("#p-" + person.getXREFID());
paragraph.add(iref);
}
else {
Chunk chunk = new Chunk(fullPersonName, fontHelvetica12);
paragraph.add(chunk);
}
// Extra text.
if (additionalTextList[i] != null && additionalTextList[i].trim().length() > 0) {
Chunk chunk = new Chunk(" " + additionalTextList[i].trim(), fontHelvetica12);
paragraph.add(chunk);
}
paragraph.setIndentationLeft(8);
document.add(paragraph);
}
}
}
/**
* Sort the list of the person (by anything) and create additional text for it.
* @param currPerson
*/
private void sortPersonList(Person[] personList, String relationType, String[] additionalTextList, Person currPerson) {
// Order persons by birthday and add birthday text.
if (relationType.equals(Relationship.CHILDREN) || relationType.equals(Relationship.SIBLINGS)
|| relationType.equals(Relationship.PARENTS)) {
List<Person> personList2 = Arrays.asList(personList);
PersonListSort.sortByBirthday(personList2);
for (int i = 0; i < personList.length; i++) {
Person p0 = personList2.get(i);
personList[i] = p0;
}
}
// Order partners by marriage date.
else if (relationType.equals(Relationship.PARTNERS)) {
List<Person> personList2 = Arrays.asList(personList);
PersonListSort.sortByMarriageDate(personList2, currPerson);
for (int i = 0; i < personList.length; i++) {
Person p0 = personList2.get(i);
personList[i] = p0;
Relationship relship = currPerson.getRelationship(p0);
String relType = relship.getType();
String marriageDate = relship.getValue(RelationshipPartners.STARTDATE);
String marriageEnd = relship.getValue(RelationshipPartners.ENDDATE);
if (relType.equals(RelationshipPartners.MARRIAGE)) {
String divorceExtraText = "";
if (i < personList.length - 1) { // Nicht die letzte Person.
Relationship relship2 = currPerson.getRelationship(personList2.get(i + 1));
String marriageDate2 = relship2.getValue(RelationshipPartners.STARTDATE);
long lP0DeathDate = Statics.getMinYYYYMMDDlong(p0.getValueView(Person.DEATHDAY));
if (Statics.getMinYYYYMMDDlong(marriageDate2) > lP0DeathDate && lP0DeathDate > 9999) {
divorceExtraText = ", verwittwet";
}
}
if (marriageDate != null) {
if (marriageEnd == null) {
additionalTextList[i] =
" (verheiratet seit " + Statics.niceShortDate(marriageDate) + divorceExtraText + ")";
}
else {
additionalTextList[i] =
" (verheiratet vom " + Statics.niceShortDate(marriageDate) + " bis "
+ Statics.niceShortDate(marriageEnd) + ")";
}
}
else if (marriageEnd != null) {
additionalTextList[i] = " (verheiratet bis " + Statics.niceShortDate(marriageEnd) + ")";
}
else {
additionalTextList[i] = " (verheiratet)";
}
}
if (relType.equals(RelationshipPartners.DIVORCE)) {
if (marriageDate != null) {
if (marriageEnd == null) {
additionalTextList[i] = " (geheiratet am " + Statics.niceShortDate(marriageDate) + ", Ehe geschieden)";
}
else {
additionalTextList[i] =
" (verheiratet vom " + Statics.niceShortDate(marriageDate) + " bis "
+ Statics.niceShortDate(marriageEnd) + ", geschieden)";
}
}
else if (marriageEnd != null) {
additionalTextList[i] = " (verheiratet bis " + Statics.niceShortDate(marriageEnd) + ", geschieden)";
}
else {
additionalTextList[i] = " (geschieden)";
}
}
}
}
}
/**
* Get extension for name.<br>
* http://www.fileformat.info/info/unicode/char/26ad/index.htm<br>
* http://de.wikipedia.org/wiki/Genealogische_Zeichen
*/
private String getNameExtension(Person person1, Person person2) {
String nameExt = "";
Relationship relship = person1.getRelationship(person2);
if (relship != null) {
String type = relship.getValue(Relationship.TYPE, "option");
if (type != null) {
boolean isMarriage = type.equals(RelationshipPartners.MARRIAGE);
if (isMarriage) {
// Funktioniert leider nicht... :-(
// nameExt = " (\u26AD)";
}
}
}
return nameExt;
}
/**
* Add appendix pages with person list by first letter or some statistics.
*/
private void addAppendixPages() throws DocumentException {
addAppendix_A_PersonsListedByBirthday();
addAppendix_B_PersonsListedByAge();
addAppendix_C_PersonsListedByBirthdayDayMonth();
addAppendix_D_Images();
}
/**
* List the persons by birthday.
*/
private void addAppendix_A_PersonsListedByBirthday() throws DocumentException {
newPage();
PersonListSort.sortByBirthday(persons);
Paragraph paragraph = new Paragraph();
Chunk chunk = new Chunk("Anhang A\r\n", fontHelvetica18Bold);
Anchor anchor = new Anchor(chunk);
anchor.setName("anhang-a");
paragraph.add(anchor);
document.add(paragraph);
paragraph = new Paragraph();
chunk = new Chunk("\r\n" + ANHANG_A_PERSONEN_SORTIERT_NACH_GEBURTSJAHR + "\r\n", fontHelvetica18BoldItalic);
paragraph.add(chunk);
document.add(paragraph);
int lastYear = Integer.MIN_VALUE + 2;
for (Person person : persons) {
int currentBirthYear = person.getBirthYear(false);
if (lastYear != currentBirthYear) {
paragraph = new Paragraph();
lastYear = currentBirthYear;
String header = lastYear == Integer.MIN_VALUE ? "ohne Angabe" : Integer.toString(lastYear);
chunk = new Chunk("\r\n" + header + "\r\n", fontHelvetica12Bold);
anchor = new Anchor(chunk);
anchor.setName("y-" + lastYear);
paragraph.add(anchor);
document.add(paragraph);
}
paragraph = new Paragraph();
String fullname = person.getValue(Person.NAME);
if (createPrintVersion) {
fullname += " [" + (personsSorted.indexOf(person) + 1) + "]";
}
chunk = new Chunk(fullname, fontTimes12ItalicBlue);
anchor = new Anchor(chunk);
anchor.setReference("#p-" + person.getXREFID());
paragraph.add(anchor);
document.add(paragraph);
}
}
/**
* List the oldest person first.
*/
private void addAppendix_B_PersonsListedByAge() throws DocumentException {
newPage();
PersonListSort.sortByAge(persons);
Paragraph paragraph = new Paragraph();
Chunk chunk = new Chunk("Anhang B\r\n", fontHelvetica18Bold);
Anchor anchor = new Anchor(chunk);
anchor.setName("anhang-b");
paragraph.add(anchor);
document.add(paragraph);
paragraph = new Paragraph();
chunk = new Chunk("\r\n" + ANHANG_B_VERSTORBENE_PERSONEN_SORTIERT_NACH_ALTER + "\r\n", fontHelvetica18BoldItalic);
paragraph.add(chunk);
document.add(paragraph);
long lastAge = Integer.MIN_VALUE;
for (Person person : persons) {
String birthday = person.getValueView(Person.BIRTHDAY);
long b = Statics.getYYYYMMDDlong(birthday);
String deathday = person.getValueView(Person.DEATHDAY);
long d = Statics.getYYYYMMDDlong(deathday);
if (b >= 0 && d >= 0) {
long currAge = (d - b) / 10000;
if (currAge != lastAge) {
paragraph = new Paragraph();
lastAge = currAge;
String header = "Alter: " + lastAge + " Jahre";
chunk = new Chunk("\r\n" + header + "\r\n", fontHelvetica12Bold);
paragraph.add(chunk);
document.add(paragraph);
}
paragraph = new Paragraph();
String fullname = person.getValue(Person.NAME);
if (createPrintVersion) {
fullname += " [" + (personsSorted.indexOf(person) + 1) + "]";
}
chunk = new Chunk(fullname, fontTimes12ItalicBlue);
anchor = new Anchor(chunk);
anchor.setReference("#p-" + person.getXREFID());
paragraph.add(anchor);
paragraph.add(new Chunk(" (" + person.getShortDate() + ")"));
document.add(paragraph);
}
}
}
/**
* List the persons by birthday day and month.
*/
private void addAppendix_C_PersonsListedByBirthdayDayMonth() throws DocumentException {
newPage();
PersonListSort.sortByBirthdayDayMonth(persons);
Paragraph paragraph = new Paragraph();
Chunk chunk = new Chunk("Anhang C\r\n", fontHelvetica18Bold);
Anchor anchor = new Anchor(chunk);
anchor.setName("anhang-c");
paragraph.add(anchor);
document.add(paragraph);
paragraph = new Paragraph();
chunk =
new Chunk("\r\n" + ANHANG_C_PERSONEN_SORTIERT_NACH_GEBURTSTAG_OHNE_JAHR + "\r\n", fontHelvetica18BoldItalic);
paragraph.add(chunk);
document.add(paragraph);
int lastDay = Integer.MIN_VALUE + 2;
int lastMonth = Integer.MIN_VALUE + 2;
for (Person person : persons) {
String birthday = person.getValue(Person.BIRTHDAY);
int currDay = person.getBirthDay();
int currMonth = person.getBirthMonth();
int currYear = person.getBirthYear(false);
if (currDay > 0 && currMonth > 0) {
if (lastDay != currDay || lastMonth != currMonth) {
paragraph = new Paragraph();
lastDay = currDay;
lastMonth = currMonth;
String header = lastDay + ". " + Statics.months[lastMonth - 1];
chunk = new Chunk("\r\n" + header + "\r\n", fontHelvetica12Bold);
anchor = new Anchor(chunk);
anchor.setName("dm-" + birthday.substring(0, birthday.lastIndexOf('.')));
paragraph.add(anchor);
document.add(paragraph);
}
paragraph = new Paragraph();
String fullname = person.getValue(Person.NAME);
if (createPrintVersion) {
fullname += " [" + (personsSorted.indexOf(person) + 1) + "]";
}
chunk = new Chunk(fullname, fontTimes12ItalicBlue);
anchor = new Anchor(chunk);
anchor.setReference("#p-" + person.getXREFID());
paragraph.add(anchor);
paragraph.add(new Chunk(" ("));
anchor = new Anchor(new Chunk(Integer.toString(currYear)));
anchor.setReference("#y-" + currYear);
paragraph.add(anchor);
paragraph.add(new Chunk(")"));
document.add(paragraph);
}
}
}
/**
* List all portraits of persons.
*/
private void addAppendix_D_Images() throws DocumentException {
newPage();
Paragraph paragraph = new Paragraph();
Chunk chunk = new Chunk("Anhang D\r\n", fontHelvetica18Bold);
Anchor anchor = new Anchor(chunk);
anchor.setName("anhang-d");
paragraph.add(anchor);
document.add(paragraph);
paragraph = new Paragraph();
chunk = new Chunk("\r\n" + ANHANG_D_BILDER + "\r\n", fontHelvetica18BoldItalic);
paragraph.add(chunk);
document.add(paragraph);
if (!listImages_D.isEmpty()) {
for (int i = 0; i < listImages_D.size(); i++) {
if (i % 25 == 0) {
if (i > 0) {
newPage();
}
paragraph = new Paragraph();
paragraph.add(new Chunk("\r\n"));
document.add(paragraph);
}
Image image = listImages_D.get(i);
Person person = listPersons_D.get(i);
image.setBorderWidth(5);
// Image anzeigen - dient gleichzeitig als Link und als Anchor.
Chunk imageChunk = new Chunk(image, 0, 0, true);
Anchor imageAnchor = new Anchor(imageChunk);
imageAnchor.setName("anhang-d-" + i);
imageAnchor.setReference("#p-" + person.getXREFID());
document.add(imageAnchor);
// Etwas Platz zum n�chsten Image lassen.
document.add(new Phrase(" "));
}
document.add(new Paragraph());
}
}
/**
* Create a new page.
*/
private void newPage() {
document.newPage();
sign();
}
/**
* Sign the current page at the bottom left.
*/
private void sign() {
// Ist ausgeschaltet, weil nicht alle Seiten signiert werden...
if (System.currentTimeMillis() > 1) {
return;
}
PdfContentByte cb = writer.getDirectContent();
Rectangle pagesize = document.getPageSize();
float w = pagesize.getWidth();
float h = pagesize.getHeight();
Graphics2D g2 = cb.createGraphics(w, h);
g2.setFont(new java.awt.Font("Arial", 0, 6));
g2.setColor(new java.awt.Color(96, 96, 96));
String produced =
"(produced by " + Statics.shortProducer + " " + Statics.currentYear + ", #" + documentNumber + ", " + person0Name
+ ")";
g2.drawString(produced, 20, h - 20);
g2.dispose();
}
/**
* @see de.chris_soft.fyllgen.export.DataExporter#getFileExtension()
*/
@Override
public String getFileExtension() {
return "pdf";
}
/**
* @see de.chris_soft.fyllgen.export.DataExporter#getLongTitle()
*/
@Override
public String getLongTitle() {
return "PDF (Portable Document Format)";
}
/**
* @see de.chris_soft.fyllgen.export.DataExporter#getShortTitle()
*/
@Override
public String getShortTitle() {
return "PDF";
}
}