## Schreiben von Reporten

Diese Seite erläutert Fragestellungen zum Schreiben eigener GenJ-Reporte:

1. Grundlagen
2. Eigenschaften und Mehrsprachigkeit
3. Optionen
4. weiteren Java-Code laden
5. Datenabfrage (Teil 1): Methoden von Objekten verwenden
6. Datenabfrage (Teil 2): Kennzeichen und Eigenschaften verwenden

## Grundlagen

Ein GenJ-Report ist ein Java-Typ, der den abstrakten Typ genj.report.Report erweitert. Das Schreiben eigener Funktionalität beginnt mit der Definition einer Klasse in einer Quelldatei und dem Ablegen dieser Datei im Report-Unterverzeichnis (der Name muss mit Report* beginnen).

Angenommen wir wollen einen Test-Report namens "Test" schreiben. Erstellen Sie zunächst in ./reports eine Text-Datei mit dem Namen ReportTest.java. Dann Übersetzen Sie die Datei durch Aufruf des compile-Skripts im selben Verzeichnis. Dieses Skript startet javac - den Java-Compiler. Als Ergebnis erhalten wir eine Datei namens ReportTest.class, die GenJ laden und ausführen kann nachdem sie in der Report-Ansicht ausgewählt wurde.

Sehen wir uns das Muster ReportTest.java an. Es enthält eine public class-Definition, die den Report-Vereinbarungen entspricht (extends Report). Teil dieser Vereinbarung ist die Implementierung von public void start(Object context) - dem Einstiegspunkt des Reports. Wir können alle von der Oberklasse Report bereitgestellten Methoden verwenden - hier benutzen wir deren println-Methode - println() füllt ein Widget mit Text, den der Benutzer bei Ausführung des Reports sieht.

      import genj.gedcom.*;
      import genj.report.*;

      import genj.report.Report;

      public class ReportTest extends Report {

        /**
         * die Haupt-Methode ("main")
         */
        public void start(Object context) {
          println("Hallo Welt!");
        }

      }

Nun wollen wir den Report mit Namen, einigen grundlegenden Informationen und der Angabe des Autors in die Report-Ansicht integrieren. Um dies zu erreichen erstellen wir im selben Verzeichnis die Datei ReportTest.properties und füllen sie mit den notwendigen Informationen wie beispielsweise:

      # Datei: ReportTest.properties
      # Dies sind die Text-Bausteine für ReportTest
      name   = Ein einfacher Test
      info   = Dies ist ein Test-Report, um das Schreiben von GenJ-Reporten zu erlernen
      author = Carsten Müssig

Nun wird der Report vernüftig angezeigt, jedoch sollte er etwas in start() tun, um für einige Benutzer interessant zu sein. Per Definition können Reporte nur auf einem Gedcom-Kontext ausgeführt werden - dies bedeutet, dass das Argument von start() eine Instanz des Java-Typs Gedcom sein muss. Also nehmen wir an, dass context instanceof Gedcom. Ein einfacher Anwungsfall könnte die Ausgabe der Personenzahl im übergebenen Gedcom-Objekt sein. Wir erreichen dies durch eine Änderung der oben angegebenen start-Methode:

        public void start(Object context) {
          // wir wissen, dass context per Definition eine Instanz von Gedcom ist
          Gedcom gedcom = (Gedcom)context;
          // Anzahl der Personen berechnen
          int count = gedcom.getEntities(Gedcom.INDI).size()
          // ... Ausgabe
          println("Gedcom "+gedcom.getName()+" umfasst "+count+" Personen");
        }

Die API für genj.report.Report und genj.gedcom.Gedcom enthält eine Reihe von Methoden zum Zugriff und zur Anzeige der enhaltenen Informationen (siehe GenJ-Javadocs für mehr).

## Eigenschaften und Mehrsprachigkeit

Um Mehrsprachigkeit zu unterstützen sollte Ihr Report nicht direkt Zeichenketten ausgeben. Stattdessen sollte eine properties-Datei verwendet werden, um die auszugebenden Zeichenketten festzulegen und die Strings aus der Datei angezeigt werden. In dieser Variante kann der Inhalt der properties-Datei in andere Sprachen übersetzt werden. Machen Sie z. B. nicht folgendes: `println("Geburtsdatum ist");`
Tun Sie dieses:

        println(i18n("BirthDateIs"));

und erstellen Sie einen entsprechenden Eintrag in der properties-Datei:

        BirthDateIs = Geburtsdatum ist

## Optionen

Jeder Report hat eine Options-Anzeige, die Sie auf einfache Art und Weise durch Anlegen von public-Variablen in der Report-Klasse und Einträgen in der properties-Datei nutzen können. Nehmen wir an Ihr Report erzeugt standardmäßig Text, kann aber auch HTML erstellen und das Ausgabeformat soll durch den Benutzer festgelegt werden. Beginnen wir mit dem Anlegen einer neuen public-Variablen in der Report-Klasse:

        public boolean generateHTML = true ;

und fügen jetzt den Text zur properties-Datei hinzu:

        generateHTML = Soll die Ausgabe in HTML erstellt werden?

Laden Sie den Report und werden Sie einen Blick auf die Optionen, um das Ergebnis zu sehen.

Verwenden sie folgende public-Variablen, um ein PullDown-Menü mit einigen Auswahlmöglichkeiten zu erstellen:

        public int outputFormat = 0;
        public static String[] outputFormats = { "Soundex", "Metahphone", "Double Metaphone", "NYSIIS", "Phonex" };

und ergäzen Sie dies in der properties-Datei:

        outputFormat=Output format
        outputFormat.de=Ausgabe-Format

Es gibt einige komplexere Optionen. Bitte sehen Sie sich dazu ReportEvent.java an.

## weiteren Java-Code laden

Der Java-Code im report-Verzeichnis ist mit dem rcompile-Skript übersetzt und wird in GenJ geladen. Wenn Sie also andere Klassen in Ihrem Report verwenden wollen kopieren Sie die Java-Dateien in Ihren Report, damit sie geladen werden.

Wenn Sie beispielsweise die Klasse DMSoundex verwenden wollen legen Sie die DMSoundex.java-Datei in das Report-Verzeichnis und starten Sie rcompile. Nun ist die Datei zwar verfügbar, erscheint aber nicht als ein Report, da sie nicht von genj.report.Report abgeleitet ist.

## Datenabfrage (Teil 1): Methoden von Objekten verwenden

Die Java-Objekte, die Informationen aus einer GEDCOM-Datei speichern, besitzen Methoden, um auf Namen, Zeitangaben, Kinder und Eltern zuzugreifen (aber nicht so viele, wie Sie vielleicht erwarten). Nachfolgend einige Beispiele:

        //Methoden der Klasse Indi (Personen)
        //Diese Liste ist nicht vollständig!  Für den Einstieg jedoch genug.
        String getBirthAsString()   // Hinweis: dies ist ein Geburtsdatum (kein Objekt)
        String getDeathAsString()   // Hinweis: dies ist ein Todesdatum (kein Objekt)
        String getName()
        String getFirstName()
        String getLastName()
        Fam getFamc()               // ermittelt die Familie, in der diese Person Kind ist
        Indi getFather()
        Indi getMother
        Indi[] getChildren()
        //Methoden der Klasse Fam (Familien)
        //Diese Liste ist nicht vollständig!  Für den Einstieg jedoch genug.
        Indi getChild(int which)
        Indi[] getChildren()
        Indi getHusband()
        Indi getWife()

Sie sollten sich auch die Klasse PropertyDate und die Methoden, die solche Objekte aus anderen Klassen zurückliefern, ansehen.

## Datenabfrage (Teil 2): Kennzeichen und Eigenschaften verwenden

Die meisten Daten in einer GEDCOM-Datein sind über Kennzeichen verfügbar. Um beispielsweise die Einbürgerungs-Informationen einer Person zu erhalten ist nicht `indi.getNaturalization()` aufzurufen, sondern: this:

    PropertyEvent naturalization = (PropertyEvent)indi.getProperty(new TagPath("INDI:NATU")) ;

Oder Sie können andere spezifische Daten mit Aufrufen wie:

    PropertyDate prop = (PropertyDate)indi.getProperty(new TagPath("INDI:NATU:DATE"));
    String dateOfNaturalization = prop.getValue() ;

ermitteln. An Notizen zu kommen ist etwas aufwendiger. Sofern eine Notiz vorhanden ist gibt folgender Code die Notiz zu einem Ereignis als String zurück. Der Aufruf sieht wie folgt aus:

       // Anwendungsbeispiel:
       PropertyEvent immigration = (PropertyEvent)indi.getProperty(new TagPath("INDI:IMMI")) ;
       String note = getNote(immigration) ;
       if (note==null) note = i18n("noNote") ;
       println(note) ;

       // aufgerufener Code:

       private String getNote(PropertyEvent e) {
           if (e==null) return null ;
           MultiLineProperty prop = checkNote(e.getProperty("NOTE")) ;
           if (prop==null) return null ;
           return prop.getLinesValue()  ;
       }

      /**
       * Checks for a NOTE property and if applicable
       * return the MultiLineProperty for accessing its value
       */
      MultiLineProperty checkNote(Property prop) {
           if (prop==null) return null ;

        // has to be 'NOTE'
       if (!prop.getTag().equals("NOTE"))
         return null;

        // see if prop is a reference to a Note
        if (prop instanceof PropertyNote) {
          // .. jump to the referenced target
          prop = ((PropertyNote)prop).getTarget();
        }

        // see if we have a multiline property containing
        // the note text now
        if (prop instanceof MultiLineProperty )
          return (MultiLineProperty)prop;

        // no candidate
        return null;
      }

Die Verwendung von Kennzeichnungspfaden setzt Kenntnisse über GEDCOM-konforme Abkürzungen, die eine Länge von vier Buchstaben haben, voraus. Hier zwei Verweise mit weiteren Informationen:
http://www.math.clemson.edu/~rsimms/genealogy/ll/gedcom55.pdf
http://www.gendex.com/gedcom55/55gcappa.htm

Nachfolgend die am häufigsten verwendeten Kennzeichnungen:
oberste Ebene: INDI (Person), FAM (Familie)
Ereignisse: BIRT (Geburt), DEAT (Tod), IMMI (Immigration),NATU (Einbürgerung), BAPT (Taufe)
weitere: CHIL (Kind), FAMC (Kind in Familie), HUSB (Ehemann), WIFE (Ehefrau)
Bestandteile: ADDR (Addresse), DATE (Datum), NOTE (Notiz), PLAC (Ort)

Die "Editier-Ansicht" zeigt genau welche Kennzeichnungen Daten zu welchen Instanzen haben und ist eine gute Möglichkeit, um die Daten und die Struktur von GEDCOM zu verstehen.

Sehen Sie sich den Quellcode des Event-Reports an, um besser zu verstehen wie Kennzeichnungen verwendet werden. Weiterhin können Sie eine GEDCOM-Datei einsehen, um nachzuschauen welche Kennzeichnungen von anderen Kennzeichnungen umgeben sind.