Package de.chris_soft.fyllgen.data

Source Code of de.chris_soft.fyllgen.data.Family

/**
* 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.data;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import de.chris_soft.fyllgen.GUI;
import de.chris_soft.fyllgen.Statics;
import de.chris_soft.fyllgen.export.ExportService;
import de.chris_soft.fyllgen.utilities.IOTools;
import de.chris_soft.fyllgen.utilities.PersonListSort;
import de.chris_soft.fyllgen.utilities.StatusProvider;
import de.chris_soft.fyllgen.utilities.SwtUtilities;
import de.chris_soft.fyllgen.utilities.ZipWritingEntryListener;
import de.chris_soft.fyllgen.widget.FamilyComposite;
import de.chris_soft.fyllgen.widget.FamilyModel;
import de.chris_soft.fyllgen.widget.FamilyModelStandard;
import de.chris_soft.fyllgen.widget.StatusLine;
import de.chris_soft.fyllgen.widget.listener.CurrentPersonChangeEvent;
import de.chris_soft.fyllgen.widget.listener.CurrentPersonChangeListener;
import de.chris_soft.fyllgen.widget.listener.CurrentPersonChanger;

/**
* Methoden rund um die Personendaten.
* @author Christian Packenius, Juni 2008.
*/
public class Family implements CurrentPersonChanger, ZipWritingEntryListener, StatusProvider {
  /**
   * Die Person, die aktuell angezeigt wird.
   */
  private Person currentPerson = null;

  /**
   * Liste aller Personen.
   */
  final List<Person> persons = new ArrayList<Person>();

  /**
   * Z�hlt die Anzahl der Speicherungen mit.
   */
  private int saveIndex;

  /**
   * Liste aller Listener, die �ber einen Wechsel der aktuellen Person
   * informiert werden wollen.
   */
  private final List<CurrentPersonChangeListener> vCurrentPersonChangeListener = new ArrayList<CurrentPersonChangeListener>();

  /**
   * Zeigt an, ob die Familiendaten ge�ndert wurden (true) oder inzwischen
   * (wieder) gespeichert sind (false).
   */
  private boolean bDataChanged;

  /**
   * Wird auf <i>true</i> gesetzt, wenn das automatische Mailing mittendrin
   * durch den Anwender unterbrochen wurde.
   */
  boolean cancelAutomaticMailing;

  /**
   * Map, in der eine Imagedatei einer Person zugeordnet ist.
   */
  final Map<File, Person> imagePersonMap = new HashMap<File, Person>();

  /**
   * K�mmert sich um alles rund um die aktuell dargestellte Person.
   */
  public static final Family instance = new Family();

  /**
   * Das IO-Tool f�r die Familie.
   */
  public final FamilyLoader loader = new FamilyLoader(this);

  static {
    // Genau diese Familie soll auch in der Statusleiste f�r Updates sorgen (das
    // gilt f�r alle anderen nicht (z.B. die Merge-Familie)!).
    StatusLine.addStatusProvider(instance);
  }

  /**
   * Setzt die neu anzuzeigende Person.
   * @param person Aktuelle Person, also jene, deren Daten im unteren Bereich
   *          angezeigt werden und die hier mit gr�nem Rahmen gekennzeichnet
   *          wird.
   * @param askForViewChange (0) Kein Wechsel der Ansicht, (1) evtl. nach
   *          Wechsel fragen, (2) unbedingt wechseln falls notwendig.
   */
  public void setCurrentPerson(Person person, int askForViewChange) {
    // Erstmal pr�fen, ob wir eventuell das Modell anpassen m�ssen.
    FamilyComposite familyComposite = GUI.instance.getFamilyComposite();
    FamilyModel familyModel = familyComposite.getFamilyModel();
    if (askForViewChange > 0 && !(familyModel instanceof FamilyModelStandard)) {
      String quest = "Wollen Sie in die Standardansicht wechseln?";
      if (askForViewChange == 2 || SwtUtilities.askYesNo(GUI.instance.shell, quest, "Ansichtenwechsel?")) {
        familyComposite.setFamilyModel(new FamilyModelStandard(familyComposite));
      }
    }

    currentPerson = person;
    sendCurrentPersonChangeListenerEvent(new CurrentPersonChangeEvent(person));

    // Alle Daten zur Person anzeigen.
    refreshPerson();

    // Auf den Namen gehen.
    GUI.instance.setFocusToFirstWidget();
  }

  /**
   * Zeigt alles nochmal an. Sinnvoll bei �nderungen der Optionen oder so.
   */
  public void review() {
    setCurrentPerson(getCurrentPerson(), 0);
  }

  /**
   * Ermittelt die Person, die gerade bearbeitet wird.
   * @return Aktuell zur Bearbeitung anstehende Person.
   */
  public Person getCurrentPerson() {
    if (persons.contains(currentPerson)) {
      return currentPerson;
    }
    if (persons.size() > 0) {
      return persons.get(0);
    }
    return null;
  }

  /**
   * Person(en) auf der Oberfl�che aktualisieren.
   */
  private void refreshPerson() {
    // Anzeige der Daten der aktuellen Person.
    GUI.instance.showPersons(currentPerson);
  }

  /**
   * Liest alle Personen aus der Datei in das Programm ein.
   * @param filename Name der einzulesenden Datei.
   * @throws IOException
   */
  public void readPersons(String filename) throws IOException {
    if (filename == null) {
      throw new IOException("Konnte keine Familiendatei finden!");
    }
    LastOpenedFamilyFile.setLastOpenedFamilyFile(filename);

    loader.load(filename);

    // Neue Datei wurde frisch ge�ffnet, ist also noch unver�ndert.
    setChanged(false);

    // Suchen, wer angezeigt werden soll.
    Person person2show = null;
    String xrefid = OptionData.instance.getString(OptionData.LAST_PERSONS_XREFID);
    if (xrefid != null) {
      person2show = getPersonFromXREFID(xrefid);
    }
    if (person2show == null) {
      person2show = getPersonByName("Christian PACKENIUS");
      if (person2show == null) {
        person2show = getFirstPerson();
      }
    }
    setCurrentPerson(person2show, 2);

    // Falls eine Person schon l�nger keine E-Mail mehr erhalten hat, hier
    // nachfragen, ob dies geschehen soll.
    // Aber in einem eigenen Thread!
    if (this == instance) {
      // Nicht f�r Merge-Files!
      ExportService.askForAutomaticMailing();
    }
  }

  /**
   * Sucht nach der Person, die den angegebenen String im Namen hat.
   * @param namepart
   * @return Gesuchte Person oder null, falls nicht gefunden.
   */
  private Person getPersonByName(String namepart) {
    namepart = namepart.toLowerCase();
    for (Person person : persons) {
      if (person.getValueView(Person.NAME).toLowerCase().indexOf(namepart) >= 0) {
        return person;
      }
    }
    return null;
  }

  /**
   * Geht zur ersten Person in der Liste.
   */
  public void showFirstPerson() {
    setCurrentPerson(getFirstPerson(), 2);
  }

  /**
   * Schreibt alle Personen aus dem Programm in die Datei.
   * @param filename
   * @throws IOException
   */
  public void writePersons(String filename) throws IOException {
    save(filename);

    setChanged(false);
  }

  /**
   * Speichert die Daten unter dem genannten Dateinamen ab. Dies hat keinerlei
   * Einfluss auf das Changed-Flag!
   * @param filename Dateiname zur Speicherung.
   * @throws IOException
   */
  public void save(String filename) throws IOException {
    if (filename.toLowerCase().endsWith(".fgf")) {
      filename = filename.substring(0, filename.length() - 4) + ".zip";
    }
    if (!filename.toLowerCase().endsWith(".zip")) {
      filename += ".zip";
    }

    writeToZip(filename);
  }

  /**
   * Erzeugt eine ZIP-datei mit allen Familiendaten (.fgf-Datei und Images).
   */
  private void writeToZip(String filename) {
    IOTools zip = new IOTools();
    List<File> files = new ArrayList<File>();
    List<String> names = new ArrayList<String>();

    files.add(null);
    names.add("family.fgf");
    files.add(null);
    names.add(Statics.OPTIONS_PROPERTIES);

    List<File> images = getAllImages();
    new File("images").mkdir();
    for (File image : images) {
      files.add(image);
      names.add("images/" + image.getName());
    }

    // Noch als ZIP-Datei wegschreiben.
    try {
      zip.writeZipFile(filename, files, names, this);
    }
    catch (IOException exception) {
      exception.printStackTrace();
      SwtUtilities.sayError(GUI.instance.shell, "Fehler beim Schreiben der ZIP-Datei mit den Familiendaten!");
    }
  }

  /**
   * Schreibt die Familiendaten als *.fgf-Stream in die ZIP-Datei.
   * @see de.chris_soft.fyllgen.utilities.ZipWritingEntryListener#fillOutputStreamForZipEntry(java.lang.String,
   *      java.io.OutputStream)
   */
  public void fillOutputStreamForZipEntry(String entryName, OutputStream outStream) throws IOException {
    if (entryName.endsWith(".fgf")) {
      saveIndex++;
      PrintStream out = new PrintStream(outStream);

      // Personen wegschreiben.
      for (Person person : persons) {
        out.println("person");
        person.writeData(out);
        Person[] children = person.getChildren();
        for (Person child : children) {
          int c = persons.indexOf(child);
          out.println("child");
          out.println(c);
          Relationship relship = person.getChildrenRelationship(child);
          relship.writeData(out, saveIndex);
        }
        Person[] partners = person.getPartner();
        for (Person partner : partners) {
          int c = persons.indexOf(partner);
          out.println("partner");
          out.println(c);
          Relationship relship = person.getPartnersRelationship(partner);
          relship.writeData(out, saveIndex);
        }
      }
      out.flush();
    }
    else if (entryName.equals(Statics.OPTIONS_PROPERTIES)) {
      OptionData.instance.saveOptions(outStream);
      outStream.flush();
    }
    else {
      SwtUtilities.sayError(GUI.instance.shell, "Programmfehler #5776: " + entryName);
    }
  }

  /**
   * L�scht s�mtliche Dateien zur Familie. Wird am Programmende aufgerufen,
   * nachdem die Daten ohnehin in der ZIP-Datei verschwunden sind.
   */
  public void deleteUnzippedFiles() {
    String filename = LastOpenedFamilyFile.getLastOpenedFamilyFile();
    if (filename.toLowerCase().endsWith(".zip")) {
      filename = filename.substring(0, filename.length() - 4) + ".fgf";
    }
    List<File> files = new ArrayList<File>();
    files.add(new File(filename));
    files.addAll(getAllImages());
    for (File file : files) {
      file.delete();
    }
    new File("images").delete();
  }

  /**
   * Ermittelt eine Liste s�mtlicher Bilder zu Personen.
   * @return Liste aller Bilddateien.
   */
  public List<File> getAllImages() {
    List<File> files = new ArrayList<File>();
    for (File file : imagePersonMap.keySet()) {
      if (!files.contains(file)) {
        files.add(file);
      }
    }
    return files;
  }

  /**
   * Ermittelt die erste Person in der Liste der Personen.
   * @return Erste Person in der Liste.
   */
  public Person getFirstPerson() {
    // Falls es keine Person gibt, eine leere erzeugen.
    if (persons.size() == 0) {
      createFirstDummyPerson();
    }

    // Diese Person zur�ck geben.
    return persons.get(0);
  }

  /**
   * Legt eine erste Person f�r die Familiendatei an.
   */
  private void createFirstDummyPerson() {
    Person person = new Person();
    person.setValue(Person.NAME, "unbekannt");
    persons.add(person);
  }

  /**
   * F�gt der Liste der Personen eine weitere Person hinzu.
   * @param person
   */
  public void addNewPerson(Person person) {
    if (!persons.contains(person)) {
      persons.add(person);
      setChanged(true);
    }
  }

  /**
   * Erzeugt ein Array mit allen vorhandenen Personen.
   * @return Array aller Personen.
   */
  public Person[] getPersonsArray() {
    return persons.toArray(new Person[persons.size()]);
  }

  /**
   * Creates an array of all persons which are related to the current person.
   * @param useSpecialFilterRule User special "Vietor" rule to not export the
   *          Packenius data.
   * @return Person array.
   */
  public Person[] getCurrentPersonsFamilyArray(boolean useSpecialFilterRule) {
    Person p0 = getCurrentPerson();
    return getAnyPersonsFamilyArray(useSpecialFilterRule, p0);
  }

  /**
   * Creates an array of all persons which are related to the given person.
   * @param useSpecialFilterRule User special "Vietor" rule to not export the
   *          Packenius data.
   * @param p0 Person to start with.
   * @return Person array.
   */
  public Person[] getAnyPersonsFamilyArray(boolean useSpecialFilterRule, Person p0) {
    List<Person> list = new ArrayList<Person>();
    list.add(p0);
    // Die spezielle Filter-Regel wird hier genau dann gesetzt, wenn (a)
    // Christian noch nicht entdeckt wurde und (b) Simone
    // aktuell verarbeitet wird. Allerdings wird sie in diesem Fall auch nur bei
    // der Bearbeitung von Christian verwendet.
    boolean vietorPackeniusFilterFound = false;
    boolean chrisFound = false;
    for (int i = 0; i < list.size(); i++) {
      Person person = list.get(i);
      boolean sissiHere = person.getValue(Person.NAME).equals("Simone KNIPPRATH");
      boolean chrisHere = person.getValue(Person.NAME).equals("Christian PACKENIUS");

      // i > 0, weil Simone auch die volle Liste erhalten soll.
      if (sissiHere && !chrisFound && i > 0) {
        vietorPackeniusFilterFound = useSpecialFilterRule;
      }
      boolean doNotGoOn = chrisHere && vietorPackeniusFilterFound;
      if (!doNotGoOn) {
        for (Relationship relship : person.getAllRelationships()) {
          Person relshipPerson = relship.getOtherPerson(person);
          chrisFound = relshipPerson.getValue(Person.NAME).equals("Christian PACKENIUS");
          if (!list.contains(relshipPerson)) {
            list.add(relshipPerson);
          }
        }
      }
    }

    return list.toArray(new Person[list.size()]);
  }

  /**
   * Entfernt die aktuelle Person und zeigt wieder die erste an.
   */
  public void removeCurrentPerson() {
    Person curr = getCurrentPerson();

    Person nextCurrent = removePerson(curr);

    if (nextCurrent == null) {
      showFirstPerson();
    }
    else {
      setCurrentPerson(nextCurrent, 1);
    }
  }

  /**
   * Entfernt die angegebene Person und zeigt eine andere an.
   * @param person2remove Zu l�schende Person.
   * @return Irgendeine Person, die eine Beziehung zur gel�schten Person hatte.
   */
  public Person removePerson(Person person2remove) {
    Person nextCurrent = null;
    for (Person person : person2remove.getChildren()) {
      if (nextCurrent == null) {
        nextCurrent = person;
      }
      person.removePerson(person2remove);
    }
    for (Person person : person2remove.getParents()) {
      if (nextCurrent == null) {
        nextCurrent = person;
      }
      person.removePerson(person2remove);
    }
    for (Person person : person2remove.getPartner()) {
      if (nextCurrent == null) {
        nextCurrent = person;
      }
      person.removePerson(person2remove);
    }
    persons.remove(person2remove);
    setChanged(true);
    if (nextCurrent == null) {
      if (persons.size() > 0) {
        nextCurrent = persons.get(0);
      }
    }
    return nextCurrent;
  }

  /**
   * F�gt einen weiteren Listener hinzu, der informiert werden m�chte, sobald
   * sich die aktuelle Person �ndern.
   * @param listener
   */
  public void addCurrentPersonChangeListener(CurrentPersonChangeListener listener) {
    // Den neuen Listener merken und ihm die aktuelle Person anzeigen.
    vCurrentPersonChangeListener.add(listener);
    listener.currentPersonChanged(new CurrentPersonChangeEvent(currentPerson));
  }

  /**
   * Entfernt den angegebenen Listener wieder.
   * @param listener
   */
  public void removeCurrentPersonChangeListener(CurrentPersonChangeListener listener) {
    vCurrentPersonChangeListener.remove(listener);
  }

  /**
   * Den Event an alle Listener senden, dass sich die aktuelle Person ge�ndert
   * hat.
   * @param event
   */
  private void sendCurrentPersonChangeListenerEvent(CurrentPersonChangeEvent event) {
    for (CurrentPersonChangeListener listener : vCurrentPersonChangeListener) {
      listener.currentPersonChanged(event);
    }
  }

  /**
   * Zeigt die �nderung oder Speicherung der Familiendaten an.
   * @param b true: Es wurden Daten ge�ndert. false: Die Daten wurden
   *          gespeichert.
   */
  public void setChanged(boolean b) {
    if (b != bDataChanged) {
      bDataChanged = b;
    }
    if (GUI.instance != null) {
      GUI.instance.setShellTitle();
    }
  }

  /**
   * Ermittelt, ob die Daten der Familie ungespeichert und ge�ndert sind.
   * @return true/false.
   */
  public boolean getChanged() {
    return bDataChanged;
  }

  /**
   * Ermittelt eine Person anhand ihrer XREF-ID.
   * @param xrefid
   * @return Person oder null.
   */
  public Person getPersonFromXREFID(String xrefid) {
    for (Person person : persons) {
      if (person.getValueView(Person.XREFID).equals(xrefid)) {
        return person;
      }
    }
    return null;
  }

  /**
   * Ermittelt die x-te Person in der Liste.
   * @param index
   * @return Person.
   */
  public Person getPersonFromIndex(int index) {
    return persons.get(index);
  }

  /**
   * Sortiert die Personen der Familie.
   */
  public void sortPersons() {
    PersonListSort.sort(persons);
  }

  /**
   * L�scht rekursiv alle Personen, die fertig ge-merge-d wurden und zus�tzlich
   * keine Verbindungen mehr zu nicht verarbeiteten Personen haben.
   * @param list Leere Liste zu �bergeben. Sie enth�lt anschlie�end die
   *          gepr�ften Personen.
   * @param person Zu pr�fende Person.
   */
  public void removeFinishedMergePersons(List<Person> list, Person person) {
    // Ist diese Person schon erledigt und noch nicht hier gepr�ft?
    if (person.isFinishedMerge() && !list.contains(person)) {
      list.add(person);
      Relationship[] relships = person.getAllRelationships();
      boolean bDeletePerson = relships.length == 0;
      for (Relationship relship : relships) {
        Person p2 = relship.getOtherPerson(person);
        if (p2.isFinishedMerge()) {
          // Beziehung darf doch nicht gel�scht werden, sie muss ja noch
          // verglichen werden.
          // person.removeRelationship(relship);
          removeFinishedMergePersons(list, person);
        }
      }

      // Wenn diese Person nun keine Verbindung mehr zu einer nicht
      // abgeschlossenen Person hat, sie einfach l�schen.
      if (bDeletePerson) {
        removePerson(person);

        // Wenn die gesamte zu mergende Familie leer ist, sie wieder l�schen.
        if (persons.size() == 0) {
          Statics.mergeFamily = null;
        }

        GUI.instance.setShellTitle();
      }
    }
  }

  /**
   * Ermittelt den Index einer Person in der Familie. Nicht zu verwechseln mit
   * der XREFID!
   * @param person Person, deren Index gesucht wird.
   * @return Index oder -1, falls Person nicht Teil dieser Familie.
   */
  public int getPersonIndex(Person person) {
    return persons.indexOf(person);
  }

  /**
   * Entfernt eine Beziehung zwischen zwei Personen.
   * @param mergeRelationship
   */
  public void removeRelationship(Relationship mergeRelationship) {
    mergeRelationship.partner1.removeRelationship(mergeRelationship);
    setChanged(true);
  }

  /**
   * Gibt die Anzahl der Personen innerhalb der Familie zur�ck.
   * @return Anzahl der Personen.
   */
  public int getPersonsCount() {
    return persons.size();
  }

  /**
   * Speichert die Daten zur MERGE-Family.
   */
  public static void saveMergeData() {
    // Die Familiendatei abspeichern oder l�schen, falls leer.
    try {
      if (Statics.mergeFamily != null) {
        Statics.mergeFamily.writePersons(Statics.FAMILY2MERGE_ZIP);
      }
      else {
        new File(Statics.FAMILY2MERGE_ZIP).delete();
      }
    }
    catch (IOException e1) {
      // Wohl nicht mehr zu �ndern.
    }
  }

  /**
   * Vermerkt, dass ein Bild einer Person zugeordnet ist.
   * @param image Bild-Datei.
   * @param person Person, zu der dieses Bild geh�rt.
   */
  public void addImage(File image, Person person) {
    imagePersonMap.put(image, person);
  }

  /**
   * Ermittelt zu einem Image-File die dazugeh�rige Person.
   * @param file Image-File.
   * @return Person bzw. null.
   */
  public Person getPersonByImage(File file) {
    return imagePersonMap.get(file);
  }

  /**
   * @see de.chris_soft.fyllgen.utilities.StatusProvider#getStatus()
   */
  public String[] getStatus() {
    String statusPersonCount = persons.size() + " Personen";
    String statusImageCount = imagePersonMap.size() + " Portraitfotos";
    return new String[] { statusPersonCount, statusImageCount };
  }

  /**
   * Liefert eine Liste aller Personen zur�ck.
   * @return Personenliste.
   */
  public List<Person> getPersonsList() {
    List<Person> list = new ArrayList<Person>();
    list.addAll(persons);
    return list;
  }
}
TOP

Related Classes of de.chris_soft.fyllgen.data.Family

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.