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