Package de.chris_soft.fyllgen

Source Code of de.chris_soft.fyllgen.GUI

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

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;
import de.chris_soft.fyllgen.data.AtomData;
import de.chris_soft.fyllgen.data.Family;
import de.chris_soft.fyllgen.data.LastOpenedFamilyFile;
import de.chris_soft.fyllgen.data.Person;
import de.chris_soft.fyllgen.data.Relationship;
import de.chris_soft.fyllgen.data.RelationshipParentChild;
import de.chris_soft.fyllgen.data.RelationshipPartners;
import de.chris_soft.fyllgen.export.ExportService;
import de.chris_soft.fyllgen.utilities.SwtConsts;
import de.chris_soft.fyllgen.utilities.SwtUtilities;
import de.chris_soft.fyllgen.widget.FamilyComposite;
import de.chris_soft.fyllgen.widget.ShellMenu;
import de.chris_soft.fyllgen.widget.listener.CurrentPersonChangeEvent;
import de.chris_soft.fyllgen.widget.listener.CurrentPersonChangeListener;
import de.chris_soft.fyllgen.widget.listener.CurrentPersonChanger;
import de.chris_soft.fyllgen.widget.listener.RelationshipChangeListener;
import de.chris_soft.fyllgen.widget.listener.RelationshipChanger;
import de.chris_soft.fyllgen.widget.person.PersonChangeButton;
import de.chris_soft.fyllgen.widget.person.PersonDateField;
import de.chris_soft.fyllgen.widget.person.PersonOption;
import de.chris_soft.fyllgen.widget.person.PersonRelationCombo;
import de.chris_soft.fyllgen.widget.person.PersonText;
import de.chris_soft.fyllgen.widget.person.PersonTextAreaComposite;
import de.chris_soft.fyllgen.widget.person.PersonTextarea;
import de.chris_soft.fyllgen.widget.relationship.RelationshipDateField;
import de.chris_soft.fyllgen.widget.relationship.RelationshipOption;
import de.chris_soft.fyllgen.widget.relationship.RelationshipText;

/**
* Aufbau des Hauptfensters des Programmes.
* @author Christian Packenius, Juni 2008.
*/
public class GUI implements DisposeListener, MouseWheelListener, SwtConsts, PaintListener, CurrentPersonChangeListener,
    SelectionListener, MouseListener {
  /**
   * Hauptfenster.
   */
  public final Shell shell;

  /**
   * Das Icon f�r die Shell.
   */
  public final Image shellIcon;

  /**
   * Im oberen Teil des Fensters nun die Familienverh�ltnisse darstellen.
   */
  private FamilyComposite familyComposite;

  /**
   * TabFolder, in dem Personen-Daten sowie deren Beziehungen liegen.
   */
  private TabFolder tabFolder;

  /**
   * Erstes Control im ersten Tab.
   */
  private Control firstControl;

  /**
   * Das Composite, in dem das Familien-Composite eingebettet liegt und gescrollt werden kann.
   */
  private ScrolledComposite scrollerFamilyComposite;

  /**
   * Das Composite, in dem das TabFolder eingebettet liegt.
   */
  private Composite inputFieldsComposite;

  /**
   * Textbox f�r das Logging - aktuell noch nicht aktiv.
   */
  private Text textLogging;

  /**
   * Canvas f�r Images.
   */
  private Canvas canvasImage;

  /**
   * H�he des Composites, das den kompletten unteren Bereich umfasst.
   */
  private int inputFieldsCompositeHeight = -1;

  /**
   * Composite-Objekt, in dem die Statuszeile liegt.
   */
  private Composite compositeStatusLine;

  /**
   * Label in der Statuszeile.
   */
  private Label labelStatusLine;

  /**
   * ID des Tabs f�r die Daten zur aktuellen Person.
   */
  public static final int TAB_PERSON_DATA = 0;

  /**
   * ID des Tabs f�r die Daten zu den Partnerschaften.
   */
  public static final int TAB_PARENTS = 1;

  /**
   * ID des Tabs f�r die Daten zu den Kindern.
   */
  public static final int TAB_CHILDREN = 2;

  /**
   * ID des Tabs f�r die Daten zu den Partnern.
   */
  public static final int TAB_PARTNER = 3;

  /**
   * ID des Tabs f�r die Notizen zur Person.
   */
  public static final int TAB_NOTES = 4;

  /**
   * ID des Tabs f�r die Quellenangaben.
   */
  public static final int TAB_SOURCES = 5;

  /**
   * Einzige Instanz der Klasse.
   */
  public static final GUI instance = new GUI();

  /**
   * Konstruktor.
   */
  private GUI() {
    // Icon f�r die Shell erzeugen.
    shellIcon = createShellIcon();

    // Hauptfenster aufbauen.
    shell = new Shell(display, SWT.SHELL_TRIM);
    setShellTitle();
    shell.setImage(shellIcon);
    shell.addDisposeListener(this);

    // Location und Size der Shell ermitteln und setzen.
    setShellBounds();

    // Layout f�r das Hauptfenster.
    FormLayout layout = new FormLayout();
    layout.marginHeight = 2;
    layout.marginWidth = 2;
    shell.setLayout(layout);

    // Den oberen Bereich dominiert das Family-Composite, wo die einzelnen
    // Familienmitglieder dargestellt werden.
    scrollerFamilyComposite = new ScrolledComposite(shell, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
    scrollerFamilyComposite.getVerticalBar().setIncrement(10);
    scrollerFamilyComposite.getVerticalBar().setPageIncrement(100);
    scrollerFamilyComposite.getHorizontalBar().setIncrement(10);
    scrollerFamilyComposite.getHorizontalBar().setPageIncrement(100);
    familyComposite = new FamilyComposite(scrollerFamilyComposite);
    scrollerFamilyComposite.setContent(familyComposite);
    scrollerFamilyComposite.setExpandVertical(true);
    scrollerFamilyComposite.setExpandHorizontal(true);

    // Mausrad soll innerhalb der Shell wirken.
    shell.addMouseWheelListener(this);

    // Ganz unten ist dann eine Statuszeile.
    compositeStatusLine = new Composite(shell, 0);
    FormData fdsl = new FormData();
    fdsl.bottom = new FormAttachment(100, 0);
    fdsl.right = new FormAttachment(100, 0);
    fdsl.left = new FormAttachment(0, 0);
    compositeStatusLine.setLayoutData(fdsl);
    GridLayout glsl = new GridLayout(1, false);
    glsl.horizontalSpacing = 0;
    glsl.verticalSpacing = 0;
    glsl.marginHeight = 0;
    glsl.marginWidth = 0;
    compositeStatusLine.setLayout(glsl);
    labelStatusLine = new Label(compositeStatusLine, SWT.BORDER);
    labelStatusLine.setText("");
    GridData gdsl = new GridData(SWT.FILL, SWT.BOTTOM, true, false);
    labelStatusLine.setLayoutData(gdsl);

    // Der untere Bereich ist f�r die Eingabefelder (vor allem das TabFolder)
    // zust�ndig. Dieses "inputFieldsComposite" enth�lt den unteren Bereich
    // komplett.
    FormLayout ifcLayout = new FormLayout();
    ifcLayout.marginHeight = ifcLayout.marginWidth = 0;
    inputFieldsComposite = new Composite(shell, 0);
    inputFieldsComposite.setLayout(ifcLayout);

    // Darstellung der Images.
    canvasImage = new Canvas(inputFieldsComposite, SWT.V_SCROLL);
    canvasImage.addPaintListener(this);
    canvasImage.addMouseListener(this);
    ScrollBar vBar = canvasImage.getVerticalBar();
    vBar.addSelectionListener(this);
    int vBarWidth = vBar.getSize().x;
    FormData fd = new FormData();
    fd.top = new FormAttachment(0, 0);
    fd.bottom = new FormAttachment(100, 0);
    fd.right = new FormAttachment(100, 0);
    fd.left = new FormAttachment(100, -97 - vBarWidth);
    canvasImage.setLayoutData(fd);
    Family.instance.addCurrentPersonChangeListener(this);

    // Erzeugt das TabFolder mit s�mtlichen Inhalten.
    createTabFolder();

    // Men� erzeugen.
    new ShellMenu(shell);

    // Haupt-Widgets in Beziehung zueinander setzen (f�r das Layout).
    setLayoutWhenPersonDataVisible();
  }

  /**
   * Erzeugt das TabFolder mit s�mtlichen Inhalten.
   */
  private void createTabFolder() {
    FormData fd;
    // Unten ein TabFolder-Composite erzeugen.
    tabFolder = new TabFolder(inputFieldsComposite, 0);
    fd = new FormData();
    fd.top = new FormAttachment(0, 0);
    fd.bottom = new FormAttachment(100, 0);
    fd.left = new FormAttachment(0, 0);
    fd.right = new FormAttachment(canvasImage, -5);
    tabFolder.setLayoutData(fd);

    // Im hier erzeugten Composite werden die elementaren Daten zur aktuellen
    // Person dargestellt.
    Composite comp;
    Family family = Family.instance;

    comp = createTabItemComposite("Personendaten");
    createTabItemWidgets(Person.atomData, comp, null, family);

    comp = createTabItemComposite("Eltern");
    createTabItemWidgets(RelationshipParentChild.atomDataParent, comp, Relationship.PARENTS, family);

    comp = createTabItemComposite("Kinder");
    createTabItemWidgets(RelationshipParentChild.atomDataChild, comp, Relationship.CHILDREN, family);

    comp = createTabItemComposite("Partner");
    createTabItemWidgets(RelationshipPartners.atomDataPartner, comp, Relationship.PARTNERS, family);

    comp = createTabItemComposite("Notizen");
    createTabItemWidgets(Person.atomDataNotes, comp, null, family);

    comp = createTabItemComposite("Quellen");
    createTabItemWidgets(Person.atomDataSources, comp, null, family);

    // Logging-Tab erst einmal nicht anzeigen.
    if (System.currentTimeMillis() == 0) {
      createLoggingTab(createTabItemComposite("Log"));
    }

    // Personendaten nach vorne holen.
    tabFolder.setSelection(TAB_PERSON_DATA);
  }

  /**
   * Setzt das Layout so, dass der untere Teil mit den Personendaten sichtbar ist.
   */
  private void setLayoutWhenPersonDataVisible() {
    // Im unteren Teil so klein wie m�glich das TabFolder mit den Personendaten.
    FormData fd = new FormData();
    if (inputFieldsCompositeHeight > 0) {
      fd.top = new FormAttachment(100, -inputFieldsCompositeHeight - compositeStatusLine.getSize().y);
    }
    fd.bottom = new FormAttachment(compositeStatusLine, 0, SWT.TOP);
    fd.left = new FormAttachment(0, 0);
    fd.right = new FormAttachment(100, 0);
    inputFieldsComposite.setLayoutData(fd);
    inputFieldsComposite.setVisible(true);

    // Der gesamte Rest dar�ber f�r das Family-Composite.
    fd = new FormData();
    fd.top = new FormAttachment(0, 0);
    fd.bottom = new FormAttachment(inputFieldsComposite, -5, SWT.TOP);
    fd.left = new FormAttachment(0, 0);
    fd.right = new FormAttachment(100, 0);
    scrollerFamilyComposite.setLayoutData(fd);

    shell.setFullScreen(false);

    shell.layout();
  }

  /**
   * Setzt das Layout so, dass der untere Teil mit den Personendaten unsichtbar ist.
   */
  private void setLayoutWhenPersonDataInvisible() {
    // Personendaten unsichtbar schalten.
    inputFieldsComposite.setVisible(false);
    // compositeStatusLine.setVisible(false);

    // Das Family-Composite belegt nun den gesamten Fensterplatz.
    FormData fd = new FormData();
    fd.top = new FormAttachment(0, 0);
    fd.bottom = new FormAttachment(compositeStatusLine, 0, SWT.TOP);
    fd.left = new FormAttachment(0, 0);
    fd.right = new FormAttachment(100, 0);
    scrollerFamilyComposite.setLayoutData(fd);

    shell.setFullScreen(true);

    shell.layout();
  }

  /**
   * Setzt den Titel des Fensters.
   */
  public void setShellTitle() {
    final String sChangeMarker = Family.instance.getChanged() ? "* " : "";
    String lastOpenedFamilyFile = LastOpenedFamilyFile.getLastOpenedFamilyFile();
    final String title;
    if (lastOpenedFamilyFile != null) {
      File file = new File(lastOpenedFamilyFile);
      final String shortFilename = file.getName();
      int count1 = Family.instance.getPersonsCount();
      final String counts0 = "  [" + count1 + " Personen";
      final String counts1 =
        Statics.mergeFamily == null ? "]" : ", " + Statics.mergeFamily.getPersonsCount() + " noch zu verkn�pfen]";
      final String counts = counts0 + counts1;
      title = Statics.producer + "  --  " + sChangeMarker + shortFilename + counts;
    }
    else {
      title = Statics.producer;
    }
    Display.getDefault().syncExec(new Runnable() {
      public void run() {
        shell.setText(title);
      }
    });
  }

  /**
   * Erzeugt ein TabItem mit einem darin liegenden Composite-Widget und setzt auch direkt das richtige Layout.
   */
  private Composite createTabItemComposite(String title) {
    // Rahmen-Composite erzeugen.
    Composite comp = new Composite(tabFolder, 0);

    // Grid-Layout verwenden.
    GridLayout gridLayout = new GridLayout();
    gridLayout.numColumns = 2;
    comp.setLayout(gridLayout);

    // Erzeugt das TabItem, in dem die Daten dargestellt werden sollen.
    TabItem tabItem = new TabItem(tabFolder, SWT.NONE);
    tabItem.setText(title);
    tabItem.setControl(comp);

    // Erzeugtes Composite-Objekt wieder zur�ck geben.
    return comp;
  }

  /**
   * Setzt das Hauptfenster an die richtige Stelle und setzt dessen Gr��e. Maximiert es auch eventuell.
   */
  private void setShellBounds() {
    // Eventuell schon vorher eingelesene Daten ermitteln.
    int shellX = 0;
    int shellY = 0;
    int shellWidth = 800;
    int shellHeight = 600;
    boolean shellMaximized = true;
    try {
      FileInputStream in = new FileInputStream("shell.properties");
      Properties prop = new Properties();
      prop.load(in);
      shellX = Integer.parseInt(getProperty(prop, "shell-x", "0"));
      shellY = Integer.parseInt(getProperty(prop, "shell-y", "0"));
      shellWidth = Integer.parseInt(getProperty(prop, "shell-width", "800"));
      shellHeight = Integer.parseInt(getProperty(prop, "shell-height", "600"));
      shellMaximized = getProperty(prop, "shell-maximized", "true").equals("true");
      in.close();
    } catch (IOException e) {
      // Default-Werte verwenden (wurden vorher festgelegt).
    }

    // Gr��e der Shell festlegen.
    shell.setSize(shellWidth, shellHeight);
    shell.setLocation(shellX, shellY);
    shell.setMaximized(shellMaximized);
  }

  /**
   * Holt ein Property-Objekt. Wenn nicht angegeben, den Default-Wert zur�ckgeben.
   */
  private String getProperty(Properties prop, String key, String defaultValue) {
    String val = prop.getProperty(key);
    if (val == null) {
      return defaultValue;
    }
    return val;
  }

  /**
   * Erzeugt das Icon f�r das Hauptfenster.
   * @return Image f�r das Hauptfenster.
   */
  private Image createShellIcon() {
    Image image = null;
    try {
      image = new Image(display, getClass().getResourceAsStream("icons/icon64.ico"));
    } catch (Exception exc) {
      try {
        FileInputStream in = new FileInputStream("icons/icon64.ico");
        image = new Image(display, in);
        in.close();
      } catch (Exception exc2) {
        image = new Image(display, 64, 64);
        GC gc = new GC(image);
        gc.setBackground(COLOR_BLACK);
        gc.setForeground(COLOR_BLACK);
        gc.fillRectangle(1, 1, 24, 16);
        gc.fillRectangle(1, 46, 24, 16);
        gc.fillRectangle(30, 24, 24, 16);
        gc.dispose();
      }
    }

    return image;
  }

  /**
   * Erzeugt die Widgets, in denen die elementaren Daten zur Person oder Relation angezeigt werden.
   * @param atomData Array aufzulistender Daten.
   * @param parentComposite Composite, in das die Datenfelder eingestellt werden sollen.
   * @param relationshipType Relationship-Typ oder null, falls Personendaten.
   * @param currentPersonChanger Changer, der Bescheid gibt, wenn sich die aktuelle Person �ndert.
   * @return Erstes Widget im Composite.
   */
  public Control createTabItemWidgets(AtomData[] atomData, Composite parentComposite, String relationshipType,
      CurrentPersonChanger currentPersonChanger) {
    Properties[] viewData = new Properties[0];
    Control firstControl = null;
    PersonRelationCombo relationshipChanger = null;
    for (AtomData atom : atomData) {
      // In einem speziellen Fall wird das Label nicht erzeugt, weil auch das
      // "personencombo"-Objekt nicht erzeugt wird.
      if (relationshipChanger == null || !atom.type.equals("personcombo")) {
        boolean atTop = atom.type.equals("textarea");
        createGridLabelTopLeft(parentComposite, atom.title, atTop);
      }

      // Einzeiliges Textfeld als Eingabe.
      if (atom.type.equals("text")) {
        GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
        if (relationshipType == null) {
          CurrentPersonChangeListener cpcl = new PersonText(parentComposite, atom.name, viewData);
          cpcl.getControl().setLayoutData(gd);
          cpcl.setCurrentPersonChanger(currentPersonChanger);
          if (this.firstControl == null) {
            this.firstControl = cpcl.getControl();
          }
          if (firstControl == null) {
            firstControl = cpcl.getControl();
          }
        }
        else {
          RelationshipChangeListener rcl = new RelationshipText(parentComposite, atom.name, viewData);
          rcl.getControl().setLayoutData(gd);
          rcl.setRelationshipChanger(relationshipChanger);
        }
      }

      // Mehrzeiliges Textfeld, in der Regel das einzige auf diesem Reiter.
      else if (atom.type.equals("textarea")) {
        PersonTextarea textarea = new PersonTextarea(parentComposite, atom.name, viewData);
        GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        textarea.getControl().setLayoutData(gd);
        textarea.setCurrentPersonChanger(currentPersonChanger);
      }

      // Datumsfelder.
      else if (atom.type.equals("date")) {
        if (relationshipType == null) {
          CurrentPersonChangeListener cpcl = new PersonDateField(parentComposite, atom.name, viewData);
          cpcl.setCurrentPersonChanger(currentPersonChanger);
        }
        else {
          RelationshipChangeListener rcl = new RelationshipDateField(parentComposite, atom.name, viewData);
          rcl.setRelationshipChanger(relationshipChanger);
        }
      }

      // Optionen zur Auswahl.
      else if (atom.type.equals("option")) {
        if (relationshipType == null) {
          CurrentPersonChangeListener cpcl =
            new PersonOption(parentComposite, atom.name, atom.keys, atom.values, "?", viewData);
          cpcl.setCurrentPersonChanger(currentPersonChanger);
        }
        else {
          RelationshipChangeListener rcl =
            new RelationshipOption(parentComposite, atom.name, atom.keys, atom.values, "?", viewData);
          rcl.setRelationshipChanger(relationshipChanger);
        }
      }

      // Personen-ComboBox.
      else if (atom.type.equals("personcombo")) {
        if (relationshipChanger == null) {
          // Ein Composite erzeugen, in dem die ComboBox und ein Button zum
          // Wechsel liegen.
          Composite c2 = new Composite(parentComposite, 0);
          GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
          c2.setLayoutData(gd);
          GridLayout gl = new GridLayout();
          gl.numColumns = 2;
          gl.marginHeight = gl.marginWidth = 0;
          c2.setLayout(gl);

          // ComboBox im inneren Composite erzeugen.
          PersonRelationCombo personRelationCombo = new PersonRelationCombo(c2, relationshipType);
          CurrentPersonChangeListener cpcl = personRelationCombo;
          gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
          cpcl.getControl().setLayoutData(gd);
          cpcl.setCurrentPersonChanger(currentPersonChanger);

          // ComboBox als Personenbeziehungsbox merken.
          relationshipChanger = (PersonRelationCombo) cpcl;

          // Schlie�lich noch der Button zum Personen-Wechsel.
          PersonChangeButton personChangeButton = new PersonChangeButton(c2);
          personChangeButton.setCurrentPersonChanger(personRelationCombo);
        }
      }

      // Mehr gibt's bislang nicht!
      else {
        throw new RuntimeException("Programmfehler - atom.type.equals(" + atom.type + ")!");
      }
    }

    return firstControl;
  }

  /**
   * Erzeugt die Widgets, in denen die elementaren Daten zur Person oder Relation angezeigt werden.
   * @param atomData Array aufzulistender Daten.
   * @param parentComposite Composite, in das die Datenfelder eingestellt werden sollen.
   * @param relationshipType Relationship-Typ oder null, falls Personendaten.
   * @param currentPersonChanger Changer, der Bescheid gibt, wenn sich die aktuelle Person �ndert.
   * @param relationshipChanger Changer, der Bescheid gibt, wenn sich die aktuelle Beziehung �ndert.
   * @param viewData Array mit Daten, die zus�tzlich einfach nur angezeigt werden.
   * @return Erstes Widget im Composite.
   */
  public Control createAtomWidgets(AtomData[] atomData, Composite parentComposite, String relationshipType,
      CurrentPersonChanger currentPersonChanger, RelationshipChanger relationshipChanger, Properties[] viewData) {
    viewData = viewData == null ? new Properties[0] : viewData;
    Control firstControl = null;
    for (AtomData atom : atomData) {
      // In einem speziellen Fall wird das Label nicht erzeugt, weil auch das
      // "personencombo"-Objekt nicht erzeugt wird.
      if (relationshipChanger == null || !atom.type.equals("personcombo")) {
        boolean atTop = atom.type.equals("textarea");
        createGridLabelTopLeft(parentComposite, atom.title, atTop);
      }

      // Einzeiliges Textfeld als Eingabe.
      if (atom.type.equals("text")) {
        GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
        if (relationshipType == null) {
          CurrentPersonChangeListener cpcl = new PersonText(parentComposite, atom.name, viewData);
          cpcl.getControl().setLayoutData(gd);
          cpcl.setCurrentPersonChanger(currentPersonChanger);
          if (this.firstControl == null) {
            this.firstControl = cpcl.getControl();
          }
          if (firstControl == null) {
            firstControl = cpcl.getControl();
          }
        }
        else {
          RelationshipChangeListener rcl = new RelationshipText(parentComposite, atom.name, viewData);
          rcl.getControl().setLayoutData(gd);
          rcl.setRelationshipChanger(relationshipChanger);
        }
      }

      // Mehrzeiliges Textfeld, in der Regel das einzige auf diesem Reiter.
      else if (atom.type.equals("textarea")) {
        PersonTextarea textarea = new PersonTextarea(parentComposite, atom.name, viewData);
        GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        textarea.getControl().setLayoutData(gd);
        textarea.setCurrentPersonChanger(currentPersonChanger);
      }

      // Datumsfelder.
      else if (atom.type.equals("date")) {
        if (relationshipType == null) {
          CurrentPersonChangeListener cpcl = new PersonDateField(parentComposite, atom.name, viewData);
          cpcl.setCurrentPersonChanger(currentPersonChanger);
        }
        else {
          RelationshipChangeListener rcl = new RelationshipDateField(parentComposite, atom.name, viewData);
          rcl.setRelationshipChanger(relationshipChanger);
        }
      }

      // Optionen zur Auswahl.
      else if (atom.type.equals("option")) {
        if (relationshipType == null) {
          CurrentPersonChangeListener cpcl =
            new PersonOption(parentComposite, atom.name, atom.keys, atom.values, "?", viewData);
          cpcl.setCurrentPersonChanger(currentPersonChanger);
        }
        else {
          RelationshipChangeListener rcl =
            new RelationshipOption(parentComposite, atom.name, atom.keys, atom.values, "?", viewData);
          rcl.setRelationshipChanger(relationshipChanger);
        }
      }

      // Personen-ComboBox.
      else if (atom.type.equals("personcombo")) {
        if (relationshipChanger == null) {
          // Ein Composite erzeugen, in dem die ComboBox und ein Button zum
          // Wechsel liegen.
          Composite c2 = new Composite(parentComposite, 0);
          GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
          c2.setLayoutData(gd);
          GridLayout gl = new GridLayout();
          gl.numColumns = 2;
          gl.marginHeight = gl.marginWidth = 0;
          c2.setLayout(gl);

          // ComboBox im inneren Composite erzeugen.
          PersonRelationCombo personRelationCombo = new PersonRelationCombo(c2, relationshipType);
          CurrentPersonChangeListener cpcl = personRelationCombo;
          gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
          cpcl.getControl().setLayoutData(gd);
          cpcl.setCurrentPersonChanger(currentPersonChanger);

          // ComboBox als Personenbeziehungsbox merken (f�r weitere zu
          // erstellendes Controls).
          relationshipChanger = (PersonRelationCombo) cpcl;

          // Schlie�lich noch der Button zum Personen-Wechsel.
          PersonChangeButton personChangeButton = new PersonChangeButton(c2);
          personChangeButton.setCurrentPersonChanger(personRelationCombo);
        }
      }

      // Mehr gibt's bislang nicht!
      else {
        throw new RuntimeException("Programmfehler - atom.type.equals(" + atom.type + ")!");
      }
    }

    return firstControl;
  }

  /**
   * Erzeugt ein Label, dessen Text links oben im Grid angezeigt wird.
   */
  private void createGridLabelTopLeft(Composite parentComposite, String labelTitle, boolean atTop) {
    Label label = new Label(parentComposite, 0);
    label.setText(labelTitle);
    GridData gdl = new GridData();
    gdl.horizontalAlignment = SWT.LEFT;
    gdl.verticalAlignment = atTop ? SWT.TOP : SWT.CENTER;
    label.setLayoutData(gdl);
  }

  /**
   * Erzeugt ein eigenes Tab f�r das programminterne Logging.
   */
  private void createLoggingTab(Composite parentComp) {
    createGridLabelTopLeft(parentComp, "Protokoll: ", true);

    PersonTextAreaComposite comp = new PersonTextAreaComposite(parentComp, 0);
    comp.setLayout(new FormLayout());
    GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
    comp.setLayoutData(gd);

    textLogging = new Text(comp, SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL);
    textLogging.setText("");
    textLogging.setEditable(false);
    textLogging.setEnabled(true);
    FormData fd = new FormData();
    fd.top = new FormAttachment(0, 0);
    fd.left = new FormAttachment(0, 0);
    fd.right = new FormAttachment(100, 0);
    fd.bottom = new FormAttachment(100, 0);
    textLogging.setLayoutData(fd);
  }

  /**
   * Im oberen Teil des Fensters Personen darstellen.
   * @param mainPerson In der Mitte darzustellende Hauptperson.
   */
  public void showPersons(Person mainPerson) {
    familyComposite.setMainPerson(mainPerson);
  }

  /**
   * Setzt den Focus auf das erste Widget der Personendaten.
   */
  public void setFocusToFirstWidget() {
    tabFolder.setSelection(TAB_PERSON_DATA);
    if (firstControl != null) {
      firstControl.forceFocus();
    }
  }

  /**
   * Setzt einen bestimmten Tab aktiv.
   * @param tabID ID des Tabs im TabFolder.
   */
  public void selectTab(int tabID) {
    tabFolder.setSelection(tabID);
  }

  /**
   * �ndert das TabFolder: Wenn es eingeblendet ist, dann wird es ausgeblendet oder umgekehrt.
   */
  public void changePersonDataVisibility() {
    tabFolder.setVisible(!tabFolder.getVisible());
    if (tabFolder.getVisible()) {
      setLayoutWhenPersonDataVisible();
    }
    else {
      setLayoutWhenPersonDataInvisible();
    }
  }

  /**
   * Das Hauptfenster wird geschlossen.
   * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
   */
  public void widgetDisposed(DisposeEvent e) {
    if (e.widget == shell) {
      // Alles ausf�hren, das noch auszuf�hren ist.
      ExportService.shutdown();

      // Daten speichern.
      try {
        Family.instance.writePersons(LastOpenedFamilyFile.getLastOpenedFamilyFile());
      } catch (IOException e1) {
        // Wohl nicht mehr zu �ndern.
      }

      Family.saveMergeData();

      // Fenster-Bounds speichern.
      Rectangle rect = shell.getBounds();
      Properties prop = new Properties();
      prop.setProperty("shell-x", Integer.toString(rect.x));
      prop.setProperty("shell-y", Integer.toString(rect.y));
      prop.setProperty("shell-width", Integer.toString(rect.width));
      prop.setProperty("shell-height", Integer.toString(rect.height));
      prop.setProperty("shell-maximized", shell.getMaximized() ? "true" : "false");
      try {
        FileOutputStream out = new FileOutputStream("shell.properties");
        prop.store(out, null);
        out.close();
      } catch (IOException e1) {
        // Dann halt nicht.
      }
    }
  }

  /**
   * Das Mausrad wurde bewegt. Nun das Familienobjekt entsprechend hoch/runter scrollen lassen.
   * @see org.eclipse.swt.events.MouseWheelListener#mouseScrolled(org.eclipse.swt.events.MouseEvent)
   */
  public void mouseScrolled(MouseEvent e) {
    if (e.widget == canvasImage) {
      System.out.println("image");
    }
    if (e.widget == shell) {
      System.out.println("sonstwas");
    }
    Point origin = scrollerFamilyComposite.getOrigin();
    origin.y -= e.count * 25;
    scrollerFamilyComposite.setOrigin(origin);
  }

  /**
   * Ermittelt das aktuell verwendete FamilyComposite (Hinweis: �ndert sich in der Regel nie, aber wer wei�...).
   * @return FamilyComposite-Objekt.
   */
  public FamilyComposite getFamilyComposite() {
    return familyComposite;
  }

  /**
   * Ermittelt die Liste der aktuell angezeigten Personen.
   * @return Liste der aktuell angezeigten Personen.
   */
  public List<Person> getCurrentViewedPersonList() {
    return familyComposite.getCurrentViewedPersonList();
  }

  /**
   * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent)
   */
  public void paintControl(PaintEvent e) {
    if (e.widget == canvasImage) {
      ScrollBar vBar = canvasImage.getVerticalBar();
      int scrollY = vBar.getSelection();
      Person person = Family.instance.getCurrentPerson();
      if (person != null) {
        List<File> imList = person.getImageList();
        for (int i = 0; i < imList.size(); i++) {
          try {
            File imagePath1 = imList.get(i);
            FileInputStream in = new FileInputStream(imagePath1);
            Image image = new Image(SwtConsts.display, new ImageData(in));
            in.close();
            int destY = (128 + 5) * i - scrollY;
            e.gc.drawImage(image, 0, 0, image.getBounds().width, image.getBounds().height, 0, destY, 97, 128);
          } catch (IOException exception) {
            // Dann wird halt kein Image angezeigt - ist nicht weiter tragisch!
          }
        }
      }
    }
  }

  /**
   * @see de.chris_soft.fyllgen.widget.listener.CurrentPersonChangeListener#currentPersonChanged(de.chris_soft.fyllgen.widget.listener.CurrentPersonChangeEvent)
   */
  public void currentPersonChanged(CurrentPersonChangeEvent event) {
    if (canvasImage != null && event.person != null) {
      int imageCount = event.person.getImageList().size();
      int fullSize = imageCount * (128 + 5) - 5;
      ScrollBar vBar = canvasImage.getVerticalBar();
      int areaHeight = canvasImage.getClientArea().height;
      if (fullSize <= areaHeight) {
        vBar.setEnabled(false);
      }
      else {
        vBar.setValues(0, 0, fullSize, areaHeight, 10, areaHeight);
        vBar.setEnabled(true);
      }
      canvasImage.redraw();
    }
  }

  /**
   * @see de.chris_soft.fyllgen.widget.listener.CurrentPersonChangeListener#setCurrentPersonChanger(de.chris_soft.fyllgen.widget.listener.CurrentPersonChanger)
   */
  public void setCurrentPersonChanger(CurrentPersonChanger currentPersonChanger) {
    // Ungenutzt.
  }

  /**
   * @see de.chris_soft.fyllgen.widget.listener.CurrentPersonChangeListener#getControl()
   */
  public Control getControl() {
    return null;
  }

  /**
   * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
   */
  public void widgetSelected(SelectionEvent e) {
    canvasImage.redraw();
  }

  /**
   * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
   */
  public void widgetDefaultSelected(SelectionEvent e) {
    widgetSelected(e);
  }

  /**
   * Speichert die H�he des Composites, in dem alle Familiendaten angezeigt werden (kompletter unterer Bereich).
   */
  void saveInputFieldsCompositeHeight() {
    inputFieldsCompositeHeight = GUI.instance.inputFieldsComposite.getSize().y;
    setLayoutWhenPersonDataVisible();
  }

  /**
   * Beim Doppelklick auf ein Image soll dieses (nach Nachfrage) gel�scht werden.
   * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
   */
  public void mouseDoubleClick(MouseEvent e) {
    if (e.widget == canvasImage) {
      int y = e.y + canvasImage.getVerticalBar().getSelection();
      int id = y / (128 + 5);
      int re = y % (128 + 5);
      Person person = Family.instance.getCurrentPerson();
      if (person != null) {
        List<File> images = person.getImageList();
        int imageCount = images.size() + 1;
        if (id < imageCount && re < 128) {
          String quest = "Soll dieses Bild wirklich gel�scht werden?";
          if (SwtUtilities.askYesNo(GUI.instance.shell, quest, "L�schanfrage")) {
            person.deleteImage(images.get(id));
            Family.instance.review();
          }
        }
      }
    }
  }

  /**
   * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
   */
  public void mouseDown(MouseEvent e) {
    // Ignorieren.
  }

  /**
   * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
   */
  public void mouseUp(MouseEvent e) {
    // Ignorieren.
  }

  /**
   * Setzt einen Text in die Statuszeile.
   * @param text Neuer Text f�r die Statuszeile.
   */
  public void setStatusLineText(String text) {
    if (!labelStatusLine.isDisposed()) {
      labelStatusLine.setText(text);
    }
  }
}
TOP

Related Classes of de.chris_soft.fyllgen.GUI

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.