* various: merge changes made in gramps20 up until R2_0_10_real tag.

* configure.in: Bump up release number.
* Release: Version 2.0.10 "Holy Hand Grenade of Antioch" released.


svn: r6011
This commit is contained in:
Alex Roitman 2006-02-28 19:54:35 +00:00
parent c4010b28a4
commit 2b96e371e1
58 changed files with 43034 additions and 25057 deletions

View File

@ -1,3 +1,6 @@
2006-02-28 Alex Roitman <shura@gramps-project.org>
* various: merge changes made in gramps20 up until R2_0_10_real tag.
2006-02-25 Don Allingham <don@gramps-project.org>
* src/DisplayTabs.py: repository reference editor
* src/EditRepository.py: repository reference editor
@ -1316,6 +1319,10 @@
2005-12-12 Alex Roitman <shura@gramps-project.org>
* configure.in: bump up the version number.
2006-02-27 Alex Roitman <shura@gramps-project.org>
* configure.in: Bump up release number.
* Release: Version 2.0.10 "Holy Hand Grenade of Antioch" released.
2005-12-11 Don Allingham <don@gramps-project.org>
* Release: Version 2.0.9 "Nobody expects the Spanish inquisition!"
released.

12
NEWS
View File

@ -1,3 +1,15 @@
Version 2.0.10 -- the "Holy Hand Grenade of Antioch" release
* Date handler for Lithuanian language (Arturas Sleinius).
* New Calendar graphical report (Doug Blank).
* Multiple tool fixes.
* GEDCOM import and export improvements.
* Proper rebuilding of secondary indices.
* Open Document Format support in reports (Serge Noiraud, Brian Matherly).
* Multiple report fixes.
* Fix for low-level duplicate records.
* User Manual updates.
* An insane number of bug fixes.
Version 2.0.9 -- the "Nobody expects the Spanish inquisition!" release
* Incremental interface improvements.
* Automated testing added, based on the CLI functionality.

View File

@ -239,6 +239,8 @@ src/data/Makefile
src/data/templates/Makefile
src/po/Makefile
doc/Makefile
doc/man/Makefile
doc/man/fr/Makefile
doc/gramps-manual/Makefile
doc/gramps-manual/C/Makefile
doc/gramps-manual/fr/Makefile

View File

@ -1,13 +1,4 @@
# Process this file with automake to produce Makefile.in
SUBDIRS = gramps-manual
man_IN_FILES = gramps.1.in
man_MANS = $(man_IN_FILES:.1.in=.1)
EXTRA_DIST = $(man_MANS) $(man_IN_FILES) xmldocs.make omf.make
gramps.1: $(top_builddir)/config.status gramps.1.in
cd $(top_builddir) && CONFIG_FILES=doc/$@ $(SHELL) ./config.status
CLEANFILES=$(man_MANS)
SUBDIRS = gramps-manual man
EXTRA_DIST = xmldocs.make omf.make

View File

@ -47,7 +47,7 @@
of Linux to another. On the default GNOME desktop, you'll
find &app; in the
<menuchoice><guimenu>Applications</guimenu><guisubmenu>Other</guisubmenu></menuchoice>
menu. </para>
menu.</para>
</listitem>
</varlistentry>
@ -116,8 +116,7 @@
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="figures/researcher.png" format="PNG"
width="510" depth="369" scale="75"/>
<imagedata fileref="figures/researcher.png" format="PNG"/>
</imageobject>
<textobject>
<phrase>Shows Researcher Information Window. </phrase>
@ -166,8 +165,7 @@
<para>To open a database that you have recently opened, choose the
top selection, select your database from the menu and
click <guibutton>OK</guibutton>. &app; will then ask you to specify
the name of the database you wish to open. </para>
click <guibutton>OK</guibutton>.</para>
<para>To open an existing database you have not recently opened,
choose the middle selection and click

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -101,7 +101,7 @@
immediately applied; this means that clicking
<guibutton>OK</guibutton> in the Person, Family, Source,
Place, Media object, or Event editor immediately records
changes in the database. </para>
changes to the database. </para>
<para>In previous versions, you could &quot;quit without
saving.&quot; This option no longer exists per se; however,
@ -177,7 +177,7 @@
<para>Removal of the Save function and addition of Undo.</para>
</listitem>
<listitem>
<para>Proper window management and removal of most modal windows.</para>
<para>Proper window management.</para>
</listitem>
<listitem>
<para>Support for Tip of the Day.</para>
@ -229,7 +229,7 @@
</listitem>
<listitem>
<para>It is possible to generate reports from the command
line, without launching the interactive GRAMPS
line, without launching an interactive GRAMPS
session.</para>
</listitem>
<listitem>

File diff suppressed because it is too large Load Diff

View File

@ -1485,7 +1485,7 @@
</variablelist>
</sect3>
<sect3 id="cmdplug-id29">
<title>Mémoriser le genre de statistiques ???</title>
<title>Tableau statistique croisé du prénom et du sexe</title>
<variablelist>
<varlistentry>
<term><command>name</command>:</term>

View File

@ -2285,7 +2285,119 @@ directement vers n'importe quelle personne sélectionnée récemment.
</para>
<!-- =============== Usage Sub-subsection ================ -->
<!-- =============== Usage Sub-subsection ================ -->
<sect2 id="subst-values">
<title>Valeurs de substitution</title>
<para>
La plupart des rapports graphiques vous permettent de personnaliser les informations affichées. Les variables de substitution sont représentées par des symboles particuliers. Il existe 2 styles de variables
Leurs différences se trouvent dans la gestion des données vides.
</para>
<para>
Le premier style est une variable précédée par '$'. Si cette variable se rapporte à une chaîne vide alors elle sera remplacée par une chaîne vide. Le second style est une variable précédée par '%'. Si cette variable se rapporte à une chaîne vide alors la ligne contenant la variable sera retirée lors de la sortie.
</para>
<variablelist>
<varlistentry>
<term>$n/%n</term>
<listitem>
<para>
Affiche le nom de l'individu : Prénom Nom
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>$N/%N</term>
<listitem>
<para>
Affiche le nom de l'individu : Nom Prénom
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>$i/%i</term>
<listitem>
<para>
Affiche l'ID GRAMPS associé à l'individu.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>$b/%b</term>
<listitem>
<para>
Affiche la date de naissance de l'individu.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>$B/%B</term>
<listitem>
<para>
Affiche le lieu de naissance de l'individu.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>$d/%d</term>
<listitem>
<para>
Affiche la date de décès de l'individu.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>$D/%D</term>
<listitem>
<para>
Affiche le lieu de décès de l'individu.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>$s/%s</term>
<listitem>
<para>
Affiche le nom du conjoint préféré : Prénom Nom
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>$S/%S</term>
<listitem>
<para>
Affiche le nom du conjoint préféré : Nom Prénom
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>$m/%m</term>
<listitem>
<para>
Affiche la date de marriage de l'individu et de son conjoint préféré.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>$M/%M</term>
<listitem>
<para>
Affiche le lieu du marriage de l'individu et de son conjoint préféré.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="rep-books">
<title>Livres</title>
<para>Il n'y a actuellement qu'une seule édition dans cette catégorie : l'édition Livre. </para>

3
doc/man/.cvsignore Normal file
View File

@ -0,0 +1,3 @@
gramps.1
Makefile.in
Makefile

13
doc/man/Makefile.am Normal file
View File

@ -0,0 +1,13 @@
# Process this file with automake to produce Makefile.in
SUBDIRS = fr
man_IN_FILES = gramps.1.in
man_MANS = $(man_IN_FILES:.1.in=.1)
EXTRA_DIST = $(man_MANS) $(man_IN_FILES)
gramps.1: $(top_builddir)/config.status gramps.1.in
cd $(top_builddir) && CONFIG_FILES=doc/man/$@ $(SHELL) ./config.status
CLEANFILES=$(man_MANS)

3
doc/man/fr/.cvsignore Normal file
View File

@ -0,0 +1,3 @@
gramps.1
Makefile.in
Makefile

13
doc/man/fr/Makefile.am Normal file
View File

@ -0,0 +1,13 @@
# Process this file with automake to produce Makefile.in
man_IN_FILES = gramps.1.in
man_MANS = $(man_IN_FILES:.1.in=.1)
mandir = @mandir@/fr
EXTRA_DIST = $(man_MANS) $(man_IN_FILES)
gramps.1: $(top_builddir)/config.status gramps.1.in
cd $(top_builddir) && CONFIG_FILES=doc/man/fr/$@ $(SHELL) ./config.status
CLEANFILES=$(man_MANS)

214
doc/man/fr/gramps.1.in Normal file
View File

@ -0,0 +1,214 @@
.TH gramps 1 "@VERSION@" "Janvier 2006" "@VERSION@"
.SH NOM
gramps \- GRAMPS est une application de généalogie. GRAMPS est l'acronyme de Genealogical Research and Analysis Management Programming System (Systeme de Programmation pour Recherche, Analyse et Gestion de données généalogiques)
.SH SYNOPSIS
.B gramps
.RB [ \-?|\-\^\-help ]
.RB [ \-\^\-usage ]
.RB [ \-\^\-version ]
.RB [ \-O|\-\^\-open=
.IR FICHIER
.RB [ \-f|\-\^\-format=
.IR FORMAT ]]
.RB [ \-i|\-\^\-import=
.IR FICHIER
.RB [ \-f|\-\^\-format=
.IR FORMAT ]]
.RB [ \-i|\-\^\-import=
.IR ... ]
.RB [ \-o|\-\^\-output=
.IR FICHIER
.RB [ \-f|\-\^\-format=
.IR FORMAT ]]
.RB [ \-a|\-\^\-action=
.IR ACTION ]
.RB [ \-p|\-\^\-options=
.IR OPTIONSTRING ]]
.RB [
.IR FICHIER
.RB ]
.SH DESCRIPTION
.PP
\fIGramps\fP est un programme Libre/OpenSource de généalogie. Il est écrit en python,
et utilise une interface GTK+/GNOME.
Gramps est semblable à d'autres programmes de généalogie tel que \fIFamily Tree Maker (FTM)\fR, \fIPersonal Ancestral
Files\fR, ou le programme GNU Geneweb.
Il peut importer/exporter le format le plus utilisé par les autres logiciels de généalogie : GEDCOM.
.SH OPTIONS
.TP
.BI gramps " FICHIER"
Si \fIFICHIER\fR est désigné (sans autres commandes) alors une session interactive est ouverte. Les autres options sont ignorées. Ce type de lancement permet d'utiliser gramps
pour manipuler des données comme dans un navigateur web. Les formats natifs de gramps sont acceptés, voir ci-dessous.
.br
.TP
.BI \-f,\-\^\-format= " FORMAT"
Le format spécifique du \fIFICHIER\fR est précédé par les options \fB\-O\fR,
\fB\-i\fR, ou
\fB\-o\fR. Si l'option \fB\-f\fR n'est pas donnée pour le \fIFICHIER\fR, alors le format sera celui de l'extension.
.br
Les formats disponibles pour l'ouverture sont \fBgrdb\fR (choisi si \fIFICHIER\fR se termine par
\fB.grdb\fR), \fBgramps\-xml\fR (choisi si \fIFICHIER\fR se termine par
\fB.gramps\fR), et \fBgedcom\fR (choisi si \fIFICHIER\fR se termine par \fB.ged\fR).
.br
Les formats disponibles pour l'importation sont \fBgrdb\fR, \fBgramps\-xml\fR, \fBgedcom\fR,
\fBgramps\-pkg\fR (choisi si \fIFICHIER\fR se termine par \fB.gpkg\fR), et
\fBgeneweb\fR (choisi si \fIFICHIER\fR se termine par \fB.gw\fR).
.br
Les formats disponibles pour l'exportation sont \fBgrdb\fR, \fBgramps\-xml\fR, \fBgedcom\fR,
\fBgramps\-pkg\fR, \fBwft\fR (choisi si \fIFICHIER\fR se termine par \fB.wft\fR),
\fBgeneweb\fR, et \fBiso\fR (jamais deviné, toujours spécifié avec l'option
\fB\-f\fR).
.TP
.BI \-O,\-\^\-open= " FICHIER"
Ouvrir un \fIFICHIER\fR.
Seulement les formats \fBgrdb\fR, \fBgramps\-xml\fR, et \fBgedcom\fR peuvent être ouvert directement. Pour les autres formats, vous devez utiliser l'option d'import,
laquelle ouvrira une base vide et importera les données.
.br
Seulement un fichier peut être ouvert. Si vous utilisez plusieurs sources, vous devez utiliser l'option d'import.
.TP
.BI \-i,\-\^\-import= " FICHIER"
Importer des données depuis un \fIFICHIER\fR.
.br
Quand plus d'un fichier doit être importé, chacun doit être précédé par la commande \fB\-i\fR. Ces fichiers sont importés dans le même ordre,
i.e. \fB\-i\fR \fIFICHIER1\fR \fB\-i\fR \fIFICHIER2\fR
et \fB\-i\fR \fIFICHIER2\fR \fB\-i\fR \fIFICHIER1\fR vont tous les deux produire différents IDs gramps.
.TP
.BI \-o,\-\^\-output= " FICHIER"
Exporter des données dans un \fIFICHIER\fR. Pour le format \fBiso\fR, le \fIFICHIER\fR est le nom du répertoire dans lequel la base de données gramps est écrite.
Pour \fBgrdb\fR, \fBgramps\-xml\fR, \fBgedcom\fR, \fBwft\fR, \fBgramps\-pkg\fR,
et \fBgeneweb\fR, le \fIFICHIER\fR est le nom du fichier de sortie
.br
Quand plus d'un fichier doit être exporté, chacun doit être précédé par la commande \fB\-o\fR. Ces fichiers sont importés dans le même ordre.
.TP
.BI \-a,\-\^\-action= " ACTION"
Accomplir une \fIACTION\fR sur les données importées. C'est effectué à la fin de l'importation. Les actions possibles sont \fBsummary\fR
(Comme le rapport->Affichage->Résumé?), \fBcheck\fR (comme l'outil->Réparation de la base->Vérifier et réparer), et \fBreport\fR (produit un rapport, à besoin
de \fIOPTIONSTRING\fR précédé par la commande \fB\-p\fR.
.br
Ces options de rapport doivent satisfaire ces conditions:
.br
Il ne doit pas y avoir d'espace.
Si certains arguments doivent utiliser des espaces, la chaîne doit être encadrée par des guillemets.
Les options vont par paire nom et valeur.
Une paire est séparée par un signe égal.
Différentes paires sont séparées par une virgule.
.br
La plupart des options sont spécifiques à chaque rapport. Même s'il existe des options communes.
.BI "name=reportname "
.br
Cette option obligatoire, elle détermine quel rapport sera généré. Si le nom du rapport saisi ne correspond à aucun rapport disponible, un message d'erreur sera ajouté.
.BI "show=all"
.br
Cette option produit une liste avec les noms des options disponibles pour un rapport donné.
.BI "show=optionname"
.br
Cette option affiche une description de toutes les fonctionnalités proposées par optionname, aussi bien les types que les valeurs pour une option.
.br
Utiliser les options ci-dessus pour trouver tout sur un rapport choisi.
.LP
Quand plus d'une action doit être effectuée, chacune doit être précédée par la commande \fB\-a\fR. Les actions seront réalisées une à une, dans l'ordre spécifié.
.BI "Operation"
.br
Si le premier argument de la ligne de commande ne commence pas par un tiret (i.e. pas
d'instruction), gramps va essayer d'ouvrir le fichier avec le nom donné par le premier argument et démarrer une session interactive, en ignorant le reste de la ligne de commande.
.LP
Si la commande \fB\-O\fR est notée, alors gramps va essayer le fichier défini et va travailler avec ses données, comme pour les autres paramètres de la ligne de commande.
.LP
Avec ou sans la commande \fB\-O\fR, il peut y avoir plusieurs imports, exports, et actions dans la ligne de commande \fB\-i\fR,
\fB\-o\fR, et \fB\-a\fR.
.LP
L'ordre des options \fB\-i\fR, \fB\-o\fR, ou \fB\-a\fR n'a pas de sens. L'ordre actuel est toujours : imports -> actions -> exports. Mais l'ouverture doit toujours être la première!
.LP
Si aucune option \fB\-O\fR ou \fB\-i\fR n'est donnée, gramps lancera sa propre fenêtre et demarrera avec une base vide, puisqu'il n'y a pas données.
.LP
Si aucune option \fB\-o\fR ou \fB\-a\fR n'est donnée, gramps lancera sa propre fenêtre et démarrera avec la base de données issue de tout les imports. Cette base sera \fBimport_db.grdb\fR sous le répertoire \fB~/.gramps/import\fR.
.LP
Les erreurs rencontrées lors d'import, export, ou action, seront mémorisées en \fIstdout\fR (si elles sont le fait de la manipulation par gramps) ou
en \fIstderr\fR (si elles ne sont pas le fait d'une manipulation). Utilisez les shell de redirection de
\fIstdout\fR et \fIstderr\fR pour sauver les messages et les erreurs dans les fichiers.
.SH EXEMPLES
.TP
Lecture de quatre bases de données dont les formats peuvent être devinés d'après les noms, puis vérification des données:
\fBgramps\fR \fB\-i\fR \fIfile1.ged\fR \fB\-i\fR \fIfile2.tgz\fR \fB\-i\fR \fI~/db3.gramps\fR \fB\-i\fR \fIfile4.wft\fR \fB\-a\fR \fIcheck\fR
.TP
Si vous voulez préciser les formats de fichiers dans l'exemple ci-dessus, complétez les noms de fichiers par les options \fB\-f\fR appropriées:
\fBgramps\fR \fB\-i\fR \fIfile1.ged\fR \fB\-f\fR \fIgedcom\fR \fB\-i\fR \fIfile2.tgz\fR \fB\-f\fR \fIgramps-pkg\fR \fB\-i\fR \fI~/db3.gramps\fR \fB\-f\fR \fIgramps-xml\fR \fB\-i\fR \fIfile4.wft\fR \fB\-f\fR \fIwft\fR \fB\-a\fR \fIcheck\fR
.TP
Pour enregistrer le résultat des lectures, donnez l'option \fB\-o\fR (utiliser \fB\-f\fR si le nom de fichier ne permet pas à gramps de deviner le format):
\fBgramps\fR \fB\-i\fR \fIfile1.ged\fR \fB\-i\fR \fIfile2.tgz\fR \fB\-o\fR \fI~/new-package\fR \fB\-f\fR \fIgramps-pkg\fR
.TP
Pour lire trois ensembles de données puis lancer une session interactive de gramps sur le tout :
\fBgramps\fR \fB\-i\fR \fIfile1.ged\fR \fB\-i\fR \fIfile2.tgz\fR \fB\-i\fR \fI~/db3.gramps\fR
.TP
Enfin, pour lancer une session interactive normale, entrer : \fBgramps\fR
.SH CONCEPTS
GRAMPS est un système basé sur le support de plugin-python, permettant d'importer et d'exporter, la saisie,
générer des rapports, des outils, et afficher des filtres pouvant être ajoutés sans modifier le programme.
.LP
Par ailleurs, gramps permet la génération directe : impression, rapports avec sortie vers d'autres formats, comme \fIOpenOffice.org\fR, \fIAbiWord\fR, HTML,
ou LaTeX pour permettre à l'utilisateur de choisir selon ses besoins
.SH BUGS CONNUS ET LIMITATIONS
.SH FICHIERS
.LP
\fI${PREFIX}/bin/gramps\fP
.br
\fI${PREFIX}/share/gramps\fP
.br
\fI${HOME}/.gramps\fP
.SH AUTEURS
Donald Allingham \fI<don@gramps-project.org>\fR
.br
\fIhttp://gramps.sourceforge.net\fR
.LP
Cette page man a d'abord été écrite par:
.br
Brandon L. Griffith \fI<brandon@debian.org>\fR
.br
pour Debian GNU/Linux système.
.LP
Cette page man est maintenue par:
.br
Alex Roitman \fI<shura@gramps-project.org>\fR
.LP
La traduction française:
.br
Jérôme Rapinat \fI<romjerome@yahoo.fr>\fR
.br
.SH DOCUMENTATION
La documentation-utilisateur est disponible par le navigateur d'aide de GNOME sous la forme du manuel Gramps. Ce manuel est également disponible sous format XML comme \fBgramps-manual.xml\fR sous \fIdoc/gramps-manual/$LANG\fR dans les sources officielles.
.LP
La documentation pour développeur est disponible sur le site \fIhttp://developers.gramps-project.org\fR.

View File

@ -44,8 +44,8 @@ wide by almost all other genealogy software.
.BI gramps " FILE"
When \fIFILE\fR is given (without any flags) then it is
opened and an interactive session is started. The rest of the options
are ignored. This way of launching is suitable for using gramps
as a handler for genealogical data in e.g. web browsers. This invocation
is ignored. This way of launching is suitable for using gramps
as a handler for genealogical data in e.g. web browsers. This invokation
can accept any data format native to gramps, see below.
.br
@ -58,10 +58,9 @@ the format of that file is guessed according to its extension.
.br
Formats
available for opening are \fBgrdb\fR (guessed if \fIFILE\fR ends
with \fB.grdb\fR), \fBgramps\-xml\fR (guessed if \fIFILE\fR ends
with \fB.gramps\fR), and \fBgedcom\fR (guessed if \fIFILE\fR ends
with \fB.ged\fR).
available for opening are \fBgrdb\fR (guessed if \fIFILE\fR ends with
\fB.grdb\fR), \fBgramps\-xml\fR (guessed if \fIFILE\fR ends with
\fB.gramps\fR), and \fBgedcom\fR (guessed if \fIFILE\fR ends with \fB.ged\fR).
.br
Formats
@ -72,7 +71,7 @@ available for import are \fBgrdb\fR, \fBgramps\-xml\fR, \fBgedcom\fR,
Formats available for export are \fBgrdb\fR, \fBgramps\-xml\fR, \fBgedcom\fR,
\fBgramps\-pkg\fR, \fBwft\fR (guessed if \fIFILE\fR ends with \fB.wft\fR),
\fBgeneweb\fR, and \fBiso\fR (never guessed, always specified with
\fBgeneweb\fR, and \fBiso\fR (never guessed, always specify with
\fB\-f\fR option).
.TP
@ -160,8 +159,8 @@ by \fB\-a\fR flag. The actions are performed one by one, in the specified order.
.br
If the first argument on the command line does not start with dash (i.e. no
flag), gramps will attempt to open the file with the name given by the first
argument and start an interactive session, ignoring the rest of the command
line arguments.
argument and start interactive session, ignoring the rest of the command line
arguments.
.LP
If the \fB\-O\fR flag is given, then gramps will try opening
@ -180,8 +179,8 @@ actual order always is: all imports (if any) -> all actions (if any)
.LP
If no \fB\-O\fR or \fB\-i\fR option is given, gramps will launch its main
window and start the usual interactive session with the empty database
anyway, since there is no data to process.
window and start the usual interactive session with the empty database,
since there is no data to process, anyway.
.LP
If no \fB\-o\fR or \fB\-a\fR options are given, gramps will launch its main

View File

@ -3,7 +3,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2003 Donald N. Allingham
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2005 Donald N. Allingham
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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
@ -510,7 +510,7 @@ class ArgHandler:
filename = os.path.normpath(os.path.abspath(filename))
if filename:
try:
g = GrampsDb.XmlWriter(self.parent.db,None,1,1)
g = GrampsDb.XmlWriter(self.parent.db,None,0,1)
ret = g.write(filename)
except:
print "Error exporting %s" % filename

View File

@ -2059,7 +2059,7 @@ class IsLessThanNthGenerationAncestorOfBookmarked(Rule):
name = _('Ancestors of bookmarked people not more '
'than <N> generations away')
category = _('Ancestral filters')
description = _("Matches ancestors of the people on the bookmark list"
description = _("Matches ancestors of the people on the bookmark list "
"not more than N generations away")
def prepare(self,db):

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2004 Donald N. Allingham
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2005 Donald N. Allingham
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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
@ -219,6 +219,7 @@ class MissingMediaDialog:
self.xml = gtk.glade.XML(const.gladeFile,"missmediadialog","gramps")
self.top = self.xml.get_widget('missmediadialog')
self.top.set_icon(ICON)
self.task1 = task1
self.task2 = task2
self.task3 = task3
@ -236,7 +237,15 @@ class MissingMediaDialog:
self.top.show()
if parent:
self.top.set_transient_for(parent)
response = self.top.run()
self.top.connect('delete_event',self.warn)
response = gtk.RESPONSE_DELETE_EVENT
# Need some magic here, because an attempt to close the dialog
# with the X button not only emits the 'delete_event' signal
# but also exits with the RESPONSE_DELETE_EVENT
while response == gtk.RESPONSE_DELETE_EVENT:
response = self.top.run()
if response == 1:
self.task1()
elif response == 2:
@ -248,3 +257,11 @@ class MissingMediaDialog:
else:
self.default_action = 0
self.top.destroy()
def warn(self,obj,obj2):
WarningDialog(
_("Attempt to force closing the dialog"),
_("Please do not force closing this important dialog.\n"
"Instead select one of the available options"),
self.top)
return True

View File

@ -525,7 +525,7 @@ buried_partial_date_place = {
buried_partial_date_no_place = {
RelLib.Person.MALE: [
_("%(male_name)s was buried in %(month_year)s."),
_("He was buried on %(month_year)s."),
_("He was buried in %(month_year)s."),
],
RelLib.Person.FEMALE: [
_("%(female_name)s was buried in %(month_year)s."),
@ -1994,16 +1994,16 @@ def buried_str(database,person,person_name=None,empty_date="",empty_place=""):
'modified_date' : bdate,
}
if bdate and bdate_full:
if bplace: #male, date, place
text = buried_full_date_place[gender][name_index] % values
else: #male, date, no place
text = buried_full_date_no_place[gender][name_index] % values
elif bdate and bdate_mod:
if bdate and bdate_mod:
if bplace: #male, date, place
text = buried_modified_date_place[gender][name_index] % values
else: #male, date, no place
text = buried_modified_date_no_place[gender][name_index] % values
elif bdate and bdate_full:
if bplace: #male, date, place
text = buried_full_date_place[gender][name_index] % values
else: #male, date, no place
text = buried_full_date_no_place[gender][name_index] % values
elif bdate:
if bplace: #male, month_year, place
text = buried_partial_date_place[gender][name_index] % values
@ -2123,8 +2123,11 @@ def old_calc_age(database,person):
months: 2
days: 3
"""
YEARS = 1
MONTHS = 2
DAYS = 3
# This is an old and ugly implementation.
# FIXME: This is an old and ugly implementation.
# It must be changed to use the new age calculator.
age = 0
units = 0
@ -2142,23 +2145,50 @@ def old_calc_age(database,person):
else:
death_year_valid = None
if birth_year_valid and death_year_valid:
age = death.get_year() - birth.get_year()
units = 1 # year
# wihtout at least a year for each event we're clueless
if not (birth_year_valid and death_year_valid):
return (age,units)
# FIXME: The code below uses hard-coded 31 days in a month
# and 12 month in a year. This is incorrect for half the Gregorian
# months and for other calendars.
# FIXME: We need to move to estimate_age !!!
# If born and died in the same year, go to the months
if death.get_year() == birth.get_year():
if birth.get_month_valid() and death.get_month_valid():
# if born and died in the same month, do the days
if birth.get_month() == death.get_month() \
and birth.get_day_valid() and death.get_day_valid():
age = death.get_day() - birth.get_day()
units = DAYS
# if not the same month, just diff the months
else:
age = death.get_month() - birth.get_month()
units = MONTHS
# Born and died in different years
else:
age = death.get_year() - birth.get_year()
units = YEARS
if birth.get_month_valid() and death.get_month_valid():
# Subtract one year if less than a last full year
if birth.get_month() > death.get_month():
age = age - 1
if birth.get_day_valid() and death.get_day_valid():
if birth.get_month() == death.get_month() and birth.get_day() > death.get_day():
age = age - 1
if age == 0:
age = death.get_month() - birth.get_month() # calc age in months
if birth.get_day() > death.get_day():
age = age - 1
units = 2 # month
if age == 0:
age = death.get_day() + 31 - birth.get_day() # calc age in days
units = 3 # day
# If less than a year (but still in different years)
# then calculate month diff modulo 12
if age == 0:
age = 12 + death.get_month() - birth.get_month()
units = MONTHS
# This is the case of birth on Dec 30 and death on Jan 2
# or birth on May 30 and death on June 2
if age == 1 and units == MONTHS \
and birth.get_day_valid() and death.get_day_valid() \
and birth.get_day() > death.get_day():
age = death.get_day() + 31 - birth.get_day()
unit = DAYS
return (age,units)

View File

@ -49,6 +49,7 @@ import GrampsMime
import NameDisplay
import RelLib
import Errors
from QuestionDialog import WarningDialog
#-------------------------------------------------------------------------
#
@ -1144,6 +1145,7 @@ class ProgressMeter:
Specify the title and the current pass header.
"""
self.ptop = gtk.Dialog()
self.ptop.connect('delete_event',self.warn)
self.ptop.set_has_separator(False)
self.ptop.set_title(title)
self.ptop.set_border_width(12)
@ -1193,6 +1195,13 @@ class ProgressMeter:
while gtk.events_pending():
gtk.main_iteration()
def warn(self,obj,obj2):
WarningDialog(
_("Attempt to force closing the dialog"),
_("Please do not force closing this important dialog."),
self.ptop)
return True
def close(self):
"""
Close the progress meter

View File

@ -48,64 +48,97 @@ from DateDisplay import DateDisplay
#-------------------------------------------------------------------------
class DateParserFR(DateParser):
month_to_int = DateParser.month_to_int
# Add common latin, local and historical variants (now only on east france)
month_to_int[u"januaris"] = 1
month_to_int[u"janer"] = 1
month_to_int[u"jenner"] = 1
month_to_int[u"hartmonat"] = 1
month_to_int[u"hartung"] = 1
month_to_int[u"eismond"] = 1
month_to_int[u"bluviose"] = 1
month_to_int[u"februaris"] = 2
month_to_int[u"hornung"] = 2
month_to_int[u"wintermonat"] = 2
month_to_int[u"taumond"] = 2
month_to_int[u"narrenmond"] = 2
month_to_int[u"vendose"] = 2
month_to_int[u"martius"] = 3
month_to_int[u"aprilis"] = 4
month_to_int[u"wiesenmonat"] = 5
month_to_int[u"maius"] = 5
month_to_int[u"junius"] = 6
month_to_int[u"julius"] = 7
month_to_int[u"augustus"] = 8
month_to_int[u"september"] = 9
month_to_int[u"7bre"] = 9
month_to_int[u"7bris"] = 9
month_to_int[u"october"] = 10
month_to_int[u"8bre"] = 10
month_to_int[u"8bris"] = 10
month_to_int[u"nebelmonat"] = 10
month_to_int[u"november"] = 11
month_to_int[u"9bre"] = 11
month_to_int[u"9bris"] = 11
month_to_int[u"december"] = 12
month_to_int[u"10bre"] = 12
month_to_int[u"10bris"] = 12
month_to_int[u"xbre"] = 12
month_to_int[u"xbris"] = 12
modifier_to_int = {
u'avant' : Date.MOD_BEFORE,
u'av.' : Date.MOD_BEFORE,
u'av' : Date.MOD_BEFORE,
u'après' : Date.MOD_AFTER,
u'avant' : Date.MOD_BEFORE,
u'av.' : Date.MOD_BEFORE,
u'av' : Date.MOD_BEFORE,
u'après' : Date.MOD_AFTER,
u'ap.' : Date.MOD_AFTER,
u'ap' : Date.MOD_AFTER,
u'env.' : Date.MOD_ABOUT,
u'env' : Date.MOD_ABOUT,
u'environ': Date.MOD_ABOUT,
u'circa' : Date.MOD_ABOUT,
u'c.' : Date.MOD_ABOUT,
u'ca' : Date.MOD_ABOUT,
u'ca.' : Date.MOD_ABOUT,
u'vers' : Date.MOD_ABOUT,
u'~' : Date.MOD_ABOUT,
}
calendar_to_int = {
u'grégorien' : Date.CAL_GREGORIAN,
u'grégorien' : Date.CAL_GREGORIAN,
u'g' : Date.CAL_GREGORIAN,
u'julien' : Date.CAL_JULIAN,
u'j' : Date.CAL_JULIAN,
u'hébreu' : Date.CAL_HEBREW,
u'hébreu' : Date.CAL_HEBREW,
u'h' : Date.CAL_HEBREW,
u'islamique' : Date.CAL_ISLAMIC,
u'i' : Date.CAL_ISLAMIC,
u'révolutionnaire': Date.CAL_FRENCH,
u'révolutionnaire' : Date.CAL_FRENCH,
u'r' : Date.CAL_FRENCH,
u'perse' : Date.CAL_PERSIAN,
u'p' : Date.CAL_PERSIAN,
}
quality_to_int = {
u'estimated' : Date.QUAL_ESTIMATED,
u'estimer' : Date.QUAL_ESTIMATED,
u'estimée' : Date.QUAL_ESTIMATED,
u'est.' : Date.QUAL_ESTIMATED,
u'est' : Date.QUAL_ESTIMATED,
u'environ' : Date.QUAL_ESTIMATED,
u'env' : Date.QUAL_ESTIMATED,
u'env.' : Date.QUAL_ESTIMATED,
u'calculer' : Date.QUAL_CALCULATED,
u'calculée' : Date.QUAL_CALCULATED,
u'calc.' : Date.QUAL_CALCULATED,
u'calc' : Date.QUAL_CALCULATED,
u'compter' : Date.QUAL_CALCULATED,
u'comptée' : Date.QUAL_CALCULATED,
u'compt' : Date.QUAL_CALCULATED,
u'compt.' : Date.QUAL_CALCULATED,
u'calculated' : Date.QUAL_CALCULATED,
}
def init_strings(self):
DateParser.init_strings(self)
_span_1 = [u'de']
_span_2 = [u'à']
_range_1 = [u'ent.',u'ent',u'entre']
_range_2 = [u'et']
self._span = re.compile("(%s)\s+(?P<start>.+)\s+(%s)\s+(?P<stop>.+)" %
('|'.join(_span_1),'|'.join(_span_2)),
re.IGNORECASE)
self._range = re.compile("(%s)\s+(?P<start>.+)\s+(%s)\s+(?P<stop>.+)" %
('|'.join(_range_1),'|'.join(_range_2)),
re.IGNORECASE)
self._span = re.compile("(de)\s+(?P<start>.+)\s+(à)\s+(?P<stop>.+)",re.IGNORECASE)
self._range = re.compile("(entre|ent|ent.)\s+(?P<start>.+)\s+(et)\s+(?P<stop>.+)",re.IGNORECASE)
self._text2 =re.compile('(\d+)?.?\s+?%s\s*((\d+)(/\d+)?)?' % self._mon_str,
re.IGNORECASE)
self._jtext2 =re.compile('(\d+)?.?\s+?%s\s*((\d+)(/\d+)?)?' % self._mon_str,
re.IGNORECASE)
#-------------------------------------------------------------------------
#
@ -115,19 +148,68 @@ class DateParserFR(DateParser):
class DateDisplayFR(DateDisplay):
calendar = (
"", u" (Julien)", u" (Hébreu)",
"", u" (Julien)", u" (Hébreu)",
u" (Révolutionnaire)", u" (Perse)", u" (Islamique)"
)
_mod_str = ("",u"avant ",u"après ",u"vers ","","","")
_qual_str = ("","estimated ","calculated ")
_qual_str = ("","estimée ","calculée ","")
formats = (
"AAAA-MM-DD (ISO)", "Numérique", "Mois Jour, Année",
"MOI Jour, Année", "Jour Mois, Année", "Jour MOIS Année"
)
def _display_gregorian(self,date_val):
year = self._slash_year(date_val[2],date_val[3])
if self.format == 0:
value = self.display_iso(date_val)
elif self.format == 1:
if date_val[0] == 0 and date_val[1] == 0:
value = str(date_val[2])
else:
value = self._tformat.replace('%m',str(date_val[1]))
value = value.replace('%d',str(date_val[0]))
value = value.replace('%Y',str(date_val[2]))
elif self.format == 2:
# Month Day, Year
if date_val[0] == 0:
if date_val[1] == 0:
value = year
else:
value = "%s %s" % (self._months[date_val[1]],year)
else:
value = "%s %d, %s" % (self._months[date_val[1]],date_val[0],year)
elif self.format == 3:
# MON Day, Year
if date_val[0] == 0:
if date_val[1] == 0:
value = year
else:
value = "%s %s" % (self._MONS[date_val[1]],year)
else:
value = "%s %d, %s" % (self._MONS[date_val[1]],date_val[0],year)
elif self.format == 4:
# Day Month Year
if date_val[0] == 0:
if date_val[1] == 0:
value = year
else:
value = "%s %s" % (self._months[date_val[1]],year)
else:
value = "%d. %s %s" % (date_val[0],self._months[date_val[1]],year)
else:
# Day MON Year
if date_val[0] == 0:
if date_val[1] == 0:
value = year
else:
value = "%s %s" % (self._MONS[date_val[1]],year)
else:
value = "%d. %s %s" % (date_val[0],self._MONS[date_val[1]],year)
return value
def display(self,date):
"""
Returns a text string representing the date.
@ -161,4 +243,4 @@ class DateDisplayFR(DateDisplay):
#
#-------------------------------------------------------------------------
from DateHandler import register_datehandler
register_datehandler(('fr_FR','fr','french'),DateParserFR, DateDisplayFR)
register_datehandler(('fr_FR','fr','french','fr_CA','fr_BE','fr_CH'),DateParserFR,DateDisplayFR)

149
src/dates/Date_lt.py Normal file
View File

@ -0,0 +1,149 @@
# -*- coding: utf-8 -*-
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2004-2005 Donald N. Allingham
#
# 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 2 of the License, or
# (at your option) 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
Lithuanian-specific classes for parsing and displaying dates.
"""
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import re
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import Date
from DateParser import DateParser
from DateDisplay import DateDisplay
#-------------------------------------------------------------------------
#
# Lithuanian parser
#
#-------------------------------------------------------------------------
class DateParserLT(DateParser):
modifier_to_int = {
u'prieš' : Date.MOD_BEFORE,
u'po' : Date.MOD_AFTER,
u'apie' : Date.MOD_ABOUT,
}
calendar_to_int = {
u'Grigaliaus' : Date.CAL_GREGORIAN,
u'g' : Date.CAL_GREGORIAN,
u'Julijaus' : Date.CAL_JULIAN,
u'j' : Date.CAL_JULIAN,
u'Hebrajų' : Date.CAL_HEBREW,
u'h' : Date.CAL_HEBREW,
u'Islamo' : Date.CAL_ISLAMIC,
u'i' : Date.CAL_ISLAMIC,
u'Prancuzų Respublikos': Date.CAL_FRENCH,
u'r' : Date.CAL_FRENCH,
u'Persų' : Date.CAL_PERSIAN,
u'p' : Date.CAL_PERSIAN,
}
quality_to_int = {
u'apytikriai' : Date.QUAL_ESTIMATED,
u'apskaičiuota' : Date.QUAL_CALCULATED,
}
def init_strings(self):
DateParser.init_strings(self)
_span_1 = [u'nuo']
_span_2 = [u'iki']
_range_1 = [u'tarp']
_range_2 = [u'ir']
self._span = re.compile("(%s)\s+(?P<start>.+)\s+(%s)\s+(?P<stop>.+)" %
('|'.join(_span_1),'|'.join(_span_2)),
re.IGNORECASE)
self._range = re.compile("(%s)\s+(?P<start>.+)\s+(%s)\s+(?P<stop>.+)" %
('|'.join(_range_1),'|'.join(_range_2)),
re.IGNORECASE)
#-------------------------------------------------------------------------
#
# Lithuanian displayer
#
#-------------------------------------------------------------------------
class DateDisplayLT(DateDisplay):
calendar = (
"", u" (Julijaus)",
u" (Hebrajų)",
u" (Prancuzų Respublikos)",
u" (Persų)",
u" (Islamo)"
)
_mod_str = ("",u"iki ",
u"po ",
u"apie ","","","")
_qual_str = ("","apytikriai ","apskaičiuota ")
formats = (
"YYYY-MM-DD (ISO)", "Skaitmeninis", "Mėnuo Diena, Metai",
"Mėn DD, YYYY", "Diena Mėnuo Metai", "DD Mėn YYYY"
)
def display(self,date):
"""
Returns a text string representing the date.
"""
mod = date.get_modifier()
cal = date.get_calendar()
qual = date.get_quality()
start = date.get_start_date()
qual_str = self._qual_str[qual]
if mod == Date.MOD_TEXTONLY:
return date.get_text()
elif start == Date.EMPTY:
return ""
elif mod == Date.MOD_SPAN:
d1 = self.display_cal[cal](start)
d2 = self.display_cal[cal](date.get_stop_date())
return "%sс %s %s %s%s" % (qual_str,d1,u'iki',d2,self.calendar[cal])
elif mod == Date.MOD_RANGE:
d1 = self.display_cal[cal](start)
d2 = self.display_cal[cal](date.get_stop_date())
return "%s%s %s %s %s%s" % (qual_str,u'tarp',d1,u'ir',d2,self.calendar[cal])
else:
text = self.display_cal[date.get_calendar()](start)
return "%s%s%s%s" % (qual_str,self._mod_str[mod],text,self.calendar[cal])
#-------------------------------------------------------------------------
#
# Register classes
#
#-------------------------------------------------------------------------
from DateHandler import register_datehandler
register_datehandler(('lt_LT','lt','lithuanian'),DateParserLT, DateDisplayLT)

View File

@ -63,7 +63,7 @@ class DateParserNL(DateParser):
month_to_int[u"januaris"] = 1
month_to_int[u"feber"] = 2
month_to_int[u"februaris"] = 2
month_to_int[u"merz"] = 2
month_to_int[u"merz"] = 3
month_to_int[u"aprilis"] = 4
month_to_int[u"maius"] = 5
month_to_int[u"junius"] = 6

View File

@ -8,6 +8,7 @@ pkgdatadir = $(datadir)/@PACKAGE@/dates
pkgdata_PYTHON = \
Date_de.py\
Date_ru.py\
Date_lt.py\
Date_fr.py\
Date_es.py\
Date_fi.py\

View File

@ -10,6 +10,7 @@ docgen_PYTHON = \
HtmlDoc.py\
KwordDoc.py\
LaTeXDoc.py\
ODFDoc.py\
OpenOfficeDoc.py\
OpenSpreadSheet.py\
PdfDoc.py\

1153
src/docgen/ODFDoc.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -451,13 +451,13 @@ class OpenSpreadSheet(SpreadSheetDoc):
self.f.write(const.progName + ' ' + const.version)
self.f.write('</meta:generator>\n')
self.f.write('<meta:initial-creator>')
self.f.write(name)
self.f.write(self.name)
self.f.write('</meta:initial-creator>\n')
self.f.write('<meta:creation-date>')
self.f.write(self.time)
self.f.write('</meta:creation-date>\n')
self.f.write('<dc:creator>')
self.f.write(name)
self.f.write(self.name)
self.f.write('</dc:creator>\n')
self.f.write('<dc:date>')
self.f.write(self.time)

943
src/plugins/Calendar.py Normal file
View File

@ -0,0 +1,943 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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 2 of the License, or
# (at your option) 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, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
__author__ = "Douglas Blank <Doug.Blank@gmail.com>"
__version__ = "$Revision$"
#------------------------------------------------------------------------
#
# python modules
#
#------------------------------------------------------------------------
from gettext import gettext as _
import datetime, time
from xml.parsers import expat
import const
import os
import locale
#------------------------------------------------------------------------
#
# GRAMPS modules
#
#------------------------------------------------------------------------
import BaseDoc
import Report
import GenericFilter
from ReportUtils import pt2cm
import DateDisplay
import ReportOptions
import RelLib
# _days could be added to DateDisplay:
_codeset = locale.nl_langinfo(locale.CODESET)
# slightly different from _months; this is zero based
_days = (
unicode(locale.nl_langinfo(locale.DAY_1),_codeset),
unicode(locale.nl_langinfo(locale.DAY_2),_codeset),
unicode(locale.nl_langinfo(locale.DAY_3),_codeset),
unicode(locale.nl_langinfo(locale.DAY_4),_codeset),
unicode(locale.nl_langinfo(locale.DAY_5),_codeset),
unicode(locale.nl_langinfo(locale.DAY_6),_codeset),
unicode(locale.nl_langinfo(locale.DAY_7),_codeset),
)
_language, _country = "en", "US"
(_language_country, _encoding) = locale.getlocale()
if _language_country != None and _language_country.count("_") == 1:
(_language, _country) = _language_country.split("_")
#------------------------------------------------------------------------
#
# The one and only GUI, unfortunately. This will be able to be moved to
# Widget once it is created.
#
#------------------------------------------------------------------------
import gtk
#------------------------------------------------------------------------
#
# Support functions
#
#------------------------------------------------------------------------
def easter(year):
"""
Computes the year/month/day of easter. Currently hardcoded in
holidays.xml. Based on work by J.-M. Oudin (1940) and is reprinted in
the "Explanatory Supplement to the Astronomical Almanac", ed. P. K.
Seidelmann (1992).
Note: Ash Wednesday is 46 days before Easter Sunday.
"""
c = year / 100
n = year - 19 * (year / 19)
k = (c - 17) / 25
i = c - c / 4 - (c - k) / 3 + 19 * n + 15
i = i - 30 * (i / 30)
i = i - (i / 28) * (1 - (i / 28) * (29 / (i + 1))
* ((21 - n) / 11))
j = year + year / 4 + i + 2 - c + c / 4
j = j - 7 * (j / 7)
l = i - j
month = 3 + (l + 40) / 44
day = l + 28 - 31 * ( month / 4 )
return "%d/%d/%d" % (year, month, day)
#------------------------------------------------------------------------
#
# Calendar
#
#------------------------------------------------------------------------
class Calendar(Report.Report):
"""
Creates the Calendar object that produces the report.
"""
def __getitem__(self, item):
""" Used to get items from various places. Could be moved up to Report. """
if item in self.doc.style_list:
# font is the only element people refer to in writing reports
# from the style_list:
return self.doc.style_list[item].get_font()
elif item in self.options_class.options_dict:
# otherwise it is a option:
return self.options_class.options_dict[item]
else:
raise AttributeError, ("no widget named '%s'" % item)
def define_graphics_styles(self):
""" Set up the report. Could be moved up to Report. """
for widget in self.options_class.widgets:
if widget.__class__.__name__ == "StyleWidget":
widget.define_graphics_style(self.doc)
def get_short_name(self, person, maiden_name = None):
""" Is there a better, built-in way of getting a short, personal name? """
nickname = person.get_nick_name()
if nickname:
first_name = nickname
else:
first_name = person.get_primary_name().get_first_name()
if first_name:
first_name = first_name.split()[0] # not middle name
if nickname.strip().count(" ") > 0: # HACK: first and last name assumed
family_name = ""
elif maiden_name != None:
family_name = maiden_name
else:
family_name = person.get_primary_name().get_surname()
return ("%s %s" % (first_name, family_name)).strip()
def draw_rectangle(self, style, sx, sy, ex, ey):
""" This should be in BaseDoc """
self.doc.draw_line(style, sx, sy, sx, ey)
self.doc.draw_line(style, sx, sy, ex, sy)
self.doc.draw_line(style, ex, sy, ex, ey)
self.doc.draw_line(style, sx, ey, ex, ey)
### The rest of these all have to deal with calendar specific things
def add_day_item(self, text, year, month, day):
month_dict = self.calendar.get(month, {})
day_list = month_dict.get(day, [])
day_list.append(text)
month_dict[day] = day_list
self.calendar[month] = month_dict
def get_holidays(self, year, country = "US"):
""" Looks in multiple places for holidays.xml files """
locations = [const.pluginsDir,
os.path.expanduser("~/.gramps/plugins")]
holiday_file = 'holidays.xml'
for dir in locations:
holiday_full_path = os.path.join(dir, holiday_file)
if os.path.exists(holiday_full_path):
self.process_holiday_file(holiday_full_path, year, country)
def process_holiday_file(self, filename, year, country):
""" This will process a holiday file """
parser = Xml2Obj()
element = parser.Parse(filename)
calendar = Holidays(element, country)
date = datetime.date(year, 1, 1)
while date.year == year:
holidays = calendar.check_date( date )
for text in holidays:
self.add_day_item(text, date.year, date.month, date.day)
date = date.fromordinal( date.toordinal() + 1)
def write_report(self):
""" The short method that runs through each month and creates a page. """
# initialize the dict to fill:
self.calendar = {}
# get the information, first from holidays:
if self["holidays"]:
self.get_holidays(self["year"], _country) # currently global
# get data from database:
self.collect_data()
# generate the report:
for month in range(1, 13):
self.print_page(month)
def print_page(self, month):
"""
This method actually writes the calendar page.
"""
self.doc.start_page()
width = self.doc.get_usable_width()
height = self.doc.get_usable_height()
header = self.doc.tmargin
self.draw_rectangle("border", 0, 0, width, height)
self.doc.draw_bar("title", 0, 0, width, header)
self.doc.draw_line("border", 0, header, width, header)
year = self["year"]
title = "%s %d" % (DateDisplay.DateDisplay._months[month], year)
font_height = pt2cm(1.25 * self["title"].get_size())
self.doc.center_text("title", title, width/2, font_height + self["offset"]) # 1.0
cell_width = width / 7
cell_height = (height - header)/ 6
current_date = datetime.date(year, month, 1)
spacing = pt2cm(1.25 * self["text"].get_size()) # 158
if current_date.isoweekday() != 7: # start dow here is 7, sunday
current_ord = current_date.toordinal() - current_date.isoweekday()
else:
current_ord = current_date.toordinal()
for day_col in range(7):
self.doc.center_text("daynames", _days[day_col], # global
day_col * cell_width + cell_width/2,
header - font_height/3.0 + self["offset"]) # .35
for week_row in range(6):
something_this_week = 0
for day_col in range(7):
thisday = current_date.fromordinal(current_ord)
if thisday.month == month:
something_this_week = 1
self.draw_rectangle("border", day_col * cell_width,
header + week_row * cell_height,
(day_col + 1) * cell_width,
header + (week_row + 1) * cell_height)
last_edge = (day_col + 1) * cell_width
self.doc.center_text("numbers", str(thisday.day),
day_col * cell_width + cell_width/2,
header + week_row * cell_height + .5 + self["offset"])
list = self.calendar.get(month, {}).get(thisday.day, [])
position = 0.0
for p in list:
lines = p.count("\n") + 1 # lines in the text
position += (lines * spacing)
current = 0
for line in p.split("\n"):
self.doc.write_at("text", line,
day_col * cell_width + .1,
header + (week_row + 1) * cell_height - position + (current * spacing) + self["offset"])
current += 1
current_ord += 1
if not something_this_week:
last_edge = 0
font_height = pt2cm(1.25 * self["text1style"].get_size())
self.doc.center_text("text1style", self["text1"], last_edge + (width - last_edge)/2, height - font_height * 3 + self["offset"]) # - 1.5
self.doc.center_text("text2style", self["text2"], last_edge + (width - last_edge)/2, height - font_height * 2 + self["offset"]) # - 0.78
self.doc.center_text("text3style", self["text3"], last_edge + (width - last_edge)/2, height - font_height * 1 + self["offset"]) # - 0.30
self.doc.end_page()
def collect_data(self):
"""
This method runs through the data, and collects the relevant dates
and text.
"""
filter_num = self.options_class.get_filter_number()
filters = self.options_class.get_report_filters(self.start_person)
filters.extend(GenericFilter.CustomFilters.get_filters())
self.filter = filters[filter_num]
people = self.filter.apply(self.database,
self.database.get_person_handles(sort_handles=False))
for person_handle in people:
person = self.database.get_person_from_handle(person_handle)
birth_handle = person.get_birth_handle()
birth_date = None
if birth_handle:
birth_event = self.database.get_event_from_handle(birth_handle)
birth_date = birth_event.get_date()
if birth_date == "":
birth_date = None
else:
birth_date_obj = birth_event.get_date_object()
death_handle = person.get_death_handle()
death_date = None
if death_handle:
death_event = self.database.get_event_from_handle(death_handle)
death_date = death_event.get_date()
if death_date == "": # BUG: couldn't remove event
death_date = None
else:
death_date_obj = death_event.get_date_object()
if death_date == None:
alive = True # well, until we get probably_alive in here
else:
alive = False
if self["birthdays"] and birth_date != None and ((self["alive"] and alive) or not self["alive"]):
year = birth_date_obj.get_year()
month = birth_date_obj.get_month()
day = birth_date_obj.get_day()
age = self["year"] - year
# add some things to handle maiden name:
father_lastname = None # husband, actually
if self["maiden_name"] == 0: # get husband's last name:
if person.get_gender() == RelLib.Person.FEMALE:
family_list = person.get_family_handle_list()
if len(family_list) > 0:
fhandle = family_list[0] # first is primary
fam = self.database.get_family_from_handle(fhandle)
father_handle = fam.get_father_handle()
mother_handle = fam.get_mother_handle()
if mother_handle == person_handle:
if father_handle:
father = self.database.get_person_from_handle(father_handle)
if father != None:
father_lastname = father.get_primary_name().get_surname()
short_name = self.get_short_name(person, father_lastname)
self.add_day_item("%s, %d" % (short_name, age), year, month, day)
if self["anniversaries"] and ((self["alive"] and alive) or not self["alive"]):
family_list = person.get_family_handle_list()
for fhandle in family_list:
fam = self.database.get_family_from_handle(fhandle)
father_handle = fam.get_father_handle()
mother_handle = fam.get_mother_handle()
if father_handle == person.get_handle():
spouse_handle = mother_handle
else:
continue # with next person if this was the marriage event
if spouse_handle:
spouse = self.database.get_person_from_handle(spouse_handle)
if spouse:
spouse_name = self.get_short_name(spouse)
short_name = self.get_short_name(person)
if self["alive"]:
spouse_death_handle = spouse.get_death_handle()
if spouse_death_handle != None:
# there is a death event, maybe empty though
spouse_death_event = self.database.get_event_from_handle(spouse_death_handle)
if spouse_death_event != None:
spouse_death_date = spouse_death_event.get_date()
if spouse_death_date != "": # BUG: couldn't remove event
continue
for event_handle in fam.get_event_list():
event = self.database.get_event_from_handle(event_handle)
event_obj = event.get_date_object()
year = event_obj.get_year()
month = event_obj.get_month()
day = event_obj.get_day()
years = self["year"] - year
text = _("%(spouse)s and\n %(person)s, %(nyears)d") % {
'spouse' : spouse_name,
'person' : short_name,
'nyears' : years,
}
self.add_day_item(text, year, month, day)
###################################################################################
# These classes are a suggested of how to rework the graphics out of reports. It also
# makes these items abstractions, which makes it easy to change the report
# infrastructure without having everyone rewrite their reports each time.
#
# This builds on the current document code, so no changes are needed.
###################################################################################
class Widget:
""" A Widget virtual base class. This contains no graphics specifics. """
commonDefaults = {
"wtype" : None,
"name" : None,
"label" : None,
"help" : None,
"wtype" : None,
"valid_text" : None,
"frame" : None,
"value" : None,
}
defaults = {}
def __init__(self, option_object, **args):
self.option_object = option_object
self.setup(args)
self.register()
def __getitem__(self, key):
if key in self.settings:
return self.settings[key]
else:
raise AttributeError, ("no widget attribute named '%s'" % key)
def __setitem__(self, key, value):
self.settings[key] = value
def setup(self, args = {}):
# start with the base defaults common to all:
self.settings = self.commonDefaults.copy()
# now add those from the subclass:
self.settings.update(self.defaults)
# ad finally, those from the user:
self.settings.update(args)
def register(self):
className = self.__class__.__name__
if className == "FilterWidget":
self.option_object.enable_dict['filter'] = 0
elif className == "StyleWidget":
self.option_object[self["name"]] = self["value"]
else:
self.option_object[self["name"]] = self["value"]
self.option_object.options_help[self["name"]] = (
self["wtype"], self["help"], self["valid_text"])
def add_gui(self, dialog): pass
def update(self): pass
class SpinWidget(Widget):
""" A spinner number selector widget for GTK. """
defaults = {
"wtype" : "=num",
"help" : "Numeric option",
"valid_text": "Any number",
}
def add_gui(self, dialog):
keyword = self["name"]
obj = self.option_object.__dict__
obj[keyword] = gtk.SpinButton()
obj[keyword].set_digits(0)
obj[keyword].set_increments(1,2)
obj[keyword].set_range(0,2100)
obj[keyword].set_numeric(True)
obj[keyword].set_value(self.option_object[keyword])
if self["frame"] != None:
dialog.add_frame_option(self["frame"], self["label"], obj[keyword])
else:
dialog.add_option(self["label"], obj[keyword])
def update(self):
dict = self.option_object.__dict__
keyword = self["name"]
self.option_object[keyword] = dict[keyword].get_value_as_int()
self[keyword] = dict[keyword].get_value_as_int()
class CheckWidget(Widget):
""" A check box widget for GTK. """
defaults = {
"wtype" : "=0/1",
"help" : "Yes/No option",
"valid_text": "1 for yes, 0 for no",
}
def add_gui(self, dialog):
keyword = self["name"]
obj = self.option_object.__dict__
obj[keyword] = gtk.CheckButton(self["label"])
obj[keyword].set_active(self.option_object[keyword])
if self["frame"] != None:
dialog.add_frame_option(self["frame"], "", obj[keyword])
else:
dialog.add_option("", obj[keyword])
def update(self):
dict = self.option_object.__dict__
keyword = self["name"]
self.option_object[keyword] = int(dict[keyword].get_active())
self[keyword] = int(dict[keyword].get_active())
class EntryWidget(Widget):
""" A text widget for GTK. """
defaults = {
"wtype" : "=str",
"help" : "String option",
"valid_text": "Any textual data",
}
def add_gui(self, dialog):
keyword = self["name"]
obj = self.option_object.__dict__
obj[keyword] = gtk.Entry()
obj[keyword].set_text(self.option_object[keyword])
if self["frame"] != None:
dialog.add_frame_option(self["frame"], self["label"], obj[keyword])
else:
dialog.add_option(self["label"], obj[keyword])
def update(self):
dict = self.option_object.__dict__
keyword = self["name"]
self.option_object[keyword] = unicode(dict[keyword].get_text())
self[keyword] = unicode(dict[keyword].get_text())
class NumberWidget(EntryWidget):
""" A number widget for GTK. """
defaults = {
"wtype" : "=num",
"help" : "Numeric option",
"valid_text": "Any number",
}
def add_gui(self, dialog):
keyword = self["name"]
obj = self.option_object.__dict__
obj[keyword] = gtk.Entry()
obj[keyword].set_text(str(self.option_object[keyword]))
if self["frame"] != None:
dialog.add_frame_option(self["frame"], self["label"], obj[keyword])
else:
dialog.add_option(self["label"], obj[keyword])
def update(self):
dict = self.option_object.__dict__
keyword = self["name"]
self.option_object[keyword] = float(dict[keyword].get_text())
self[keyword] = float(dict[keyword].get_text())
class StyleWidget(Widget):
defaults = {
"size" : 8,
"bold" : 0,
"italics" : 0,
"type_face" : BaseDoc.FONT_SERIF,
"fill_color": None,
}
def make_default_style(self, default_style):
f = BaseDoc.FontStyle()
f.set_size(self["size"])
f.set_italic(self["italics"])
f.set_bold(self["bold"])
f.set_type_face(self["type_face"])
p = BaseDoc.ParagraphStyle()
p.set_font(f)
p.set_description(self["label"])
default_style.add_style(self["name"],p)
def define_graphics_style(self, document):
g = BaseDoc.GraphicsStyle()
g.set_paragraph_style(self["name"])
if self["fill_color"]:
g.set_fill_color(self["fill_color"])
# FIXME: add all other graphics items (color, etc) here
document.add_draw_style(self["name"],g)
class FilterWidget(Widget):
"""
A filter widget. This doesn't have the GTK code here, but should.
This class takes names of the filters and does everything for you.
"all filters" - all of them
"everyone" - all people in table
"descendents" - direct descendents
"descendent familes" - direct descendents and their familes
"ancestors" - all ancestors of person
"common ancestors" - all common ancestors
"calendar attribute" - experimental filter for tagging people
"""
def get_filters(self, person):
"""Set up the list of possible content filters."""
if person:
name = person.get_primary_name().get_name()
gramps_id = person.get_gramps_id()
else:
name = 'PERSON'
gramps_id = ''
retval = []
for filter in self["filters"]:
if filter in ["everyone", "all filters"]:
f = GenericFilter.GenericFilter()
f.set_name(_("Entire Database"))
f.add_rule(GenericFilter.Everyone([]))
retval.append(f)
if filter in ["descendants", "all filters"]:
f = GenericFilter.GenericFilter()
f.set_name(_("Descendants of %s") % name)
f.add_rule(GenericFilter.IsDescendantOf([gramps_id,1]))
retval.append(f)
if filter in ["descendant families", "all filters"]:
f = GenericFilter.GenericFilter()
f.set_name(_("Descendant Families of %s") % name)
f.add_rule(GenericFilter.IsDescendantFamilyOf([gramps_id]))
retval.append(f)
if filter in ["ancestors", "all filters"]:
f = GenericFilter.GenericFilter()
f.set_name(_("Ancestors of %s") % name)
f.add_rule(GenericFilter.IsAncestorOf([gramps_id,1]))
retval.append(f)
if filter in ["common ancestors", "all filters"]:
f = GenericFilter.GenericFilter()
f.set_name(_("People with common ancestor with %s") % name)
f.add_rule(GenericFilter.HasCommonAncestorWith([gramps_id]))
retval.append(f)
if filter in ["calendar attribute", "all filters"]:
f = GenericFilter.ParamFilter()
f.set_name(_("People with a Calendar attribute"))
f.add_rule(GenericFilter.HasTextMatchingSubstringOf(['Calendar',0,0]))
retval.append(f)
return retval
# -----------------------------------------------------------------
# The following could all be moved to the parent class, if you wanted
# to adopt this report reworking. Even if you didn't want to use them
# it would be ok to put there, because self.widgets would be empty.
# -----------------------------------------------------------------
class NewReportOptions(ReportOptions.ReportOptions):
"""
Defines options and provides code to handling the interface.
This is free of any graphics specifics.
"""
def __getitem__(self, keyword):
""" This could be moved up to ReportOptions """
if keyword in self.options_dict:
return self.options_dict[keyword]
else:
raise AttributeError, ("no widget named '%s'" % keyword)
def __setitem__(self, keyword, value):
""" This could be moved up to ReportOptions """
self.options_dict[keyword] = value
def add_user_options(self,dialog):
for widget in self.widgets:
widget.add_gui(dialog)
def parse_user_options(self,dialog):
for widget in self.widgets:
widget.update()
def get_report_filters(self,person):
for widget in self.widgets:
if widget.__class__.__name__ == "FilterWidget":
return widget.get_filters(person)
def make_default_style(self,default_style):
for widget in self.widgets:
if widget.__class__.__name__ == "StyleWidget":
widget.make_default_style(default_style)
class CalendarOptions(NewReportOptions):
def enable_options(self):
self.enable_dict = {}
self.widgets = [
FilterWidget(self, label = _("Filter"),
name = "filter",
filters = ["all filters"]),
EntryWidget(self, label = _("Text 1"),
name = "text1",
value = "My Calendar",
help = "Large text area",
valid_text = "Any text",
frame = _("Text Options")
),
EntryWidget(self, label = _("Text 2"),
name = "text2",
value = "Produced with GRAMPS",
help = "Medium size text",
valid_text = "Any text",
frame = _("Text Options")
),
EntryWidget(self, label = _("Text 3"),
name = "text3",
value = "http://gramps-project.org/",
help = "Small text area",
valid_text = "Any text",
frame = _("Text Options")
),
SpinWidget(self, label = _("Year of calendar"),
name = "year",
value = time.localtime()[0], # the current year
help = "Year of calendar",
valid_text = "Any year",
),
CheckWidget(self, label = _("Use maiden names"),
name = "maiden_name",
value = 1,
help = "Use married women's maiden name.",
valid_text = "Select to use married women's maiden name.",
),
CheckWidget(self, label = _("Only include living people"),
name = "alive",
value = 1,
help = "Include only living people",
valid_text = "Select to only include living people",
),
CheckWidget(self, label = _("Include birthdays"),
name = "birthdays",
value = 1,
help = "Include birthdays",
valid_text = "Select to include birthdays",
),
CheckWidget(self, label = _("Include anniversaries"),
name = "anniversaries",
value = 1,
help = "Include anniversaries",
valid_text = "Select to include anniversaries",
),
CheckWidget(self, label = _("Include holidays"),
name = "holidays",
value = 1,
help = "Include holidays",
valid_text = "Select to include holidays",
),
NumberWidget(self, label = "Offset",
name = "offset",
value = -0.5,
help = "Distance to move text on page",
valid_text = "Any number",
frame = "Text Options"
),
StyleWidget(self, label = _('Title text and background color.'),
name = "title",
size = 20,
italics = 1,
bold = 1,
fill_color = (0xEA,0xEA,0xEA),
type_face = BaseDoc.FONT_SERIF,
),
StyleWidget(self, label = _('Border lines of calendar boxes.'),
name = "border",
),
StyleWidget(self, label = _('Calendar day numbers.'),
name = "numbers",
size = 13,
bold = 1,
type_face = BaseDoc.FONT_SERIF,
),
StyleWidget(self, label = _('Daily text display.'),
name = "text",
size = 9,
type_face = BaseDoc.FONT_SERIF,
),
StyleWidget(self, label = _('Days of the week text.'),
name = "daynames",
size = 12,
italics = 1,
bold = 1,
type_face = BaseDoc.FONT_SERIF,
),
StyleWidget(self, label = _('Text at bottom, line 1.'),
name = "text1style",
size = 12,
type_face = BaseDoc.FONT_SERIF,
),
StyleWidget(self, label = _('Text at bottom, line 2.'),
name = "text2style",
size = 12,
type_face = BaseDoc.FONT_SERIF,
),
StyleWidget(self, label = _('Text at bottom, line 3.'),
name = "text3style",
size = 9,
type_face = BaseDoc.FONT_SERIF,
),
]
class Element:
""" A parsed XML element """
def __init__(self,name,attributes):
'Element constructor'
# The element's tag name
self.name = name
# The element's attribute dictionary
self.attributes = attributes
# The element's cdata
self.cdata = ''
# The element's child element list (sequence)
self.children = []
def AddChild(self,element):
'Add a reference to a child element'
self.children.append(element)
def getAttribute(self,key):
'Get an attribute value'
return self.attributes.get(key)
def getData(self):
'Get the cdata'
return self.cdata
def getElements(self,name=''):
'Get a list of child elements'
#If no tag name is specified, return the all children
if not name:
return self.children
else:
# else return only those children with a matching tag name
elements = []
for element in self.children:
if element.name == name:
elements.append(element)
return elements
def toString(self, level=0):
retval = " " * level
retval += "<%s" % self.name
for attribute in self.attributes:
retval += " %s=\"%s\"" % (attribute, self.attributes[attribute])
c = ""
for child in self.children:
c += child.toString(level+1)
if c == "":
retval += "/>\n"
else:
retval += ">\n" + c + ("</%s>\n" % self.name)
return retval
class Xml2Obj:
""" XML to Object """
def __init__(self):
self.root = None
self.nodeStack = []
def StartElement(self,name,attributes):
'SAX start element even handler'
# Instantiate an Element object
element = Element(name.encode(),attributes)
# Push element onto the stack and make it a child of parent
if len(self.nodeStack) > 0:
parent = self.nodeStack[-1]
parent.AddChild(element)
else:
self.root = element
self.nodeStack.append(element)
def EndElement(self,name):
'SAX end element event handler'
self.nodeStack = self.nodeStack[:-1]
def CharacterData(self,data):
'SAX character data event handler'
if data.strip():
data = data.encode()
element = self.nodeStack[-1]
element.cdata += data
return
def Parse(self,filename):
# Create a SAX parser
Parser = expat.ParserCreate()
# SAX event handlers
Parser.StartElementHandler = self.StartElement
Parser.EndElementHandler = self.EndElement
Parser.CharacterDataHandler = self.CharacterData
# Parse the XML File
ParserStatus = Parser.Parse(open(filename,'r').read(), 1)
return self.root
class Holidays:
""" Class used to read XML holidays to add to calendar. """
def __init__(self, elements, country="US"):
self.debug = 0
self.elements = elements
self.country = country
self.dates = []
self.initialize()
def set_country(self, country):
self.country = country
self.dates = []
self.initialize()
def initialize(self):
# parse the date objects
for country_set in self.elements.children:
if country_set.name == "country" and country_set.attributes["name"] == self.country:
for date in country_set.children:
if date.name == "date":
data = {"value" : "",
"name" : "",
"offset": "",
"type": "",
"if": "",
} # defaults
for attr in date.attributes:
data[attr] = date.attributes[attr]
self.dates.append(data)
def get_daynames(self, y, m, dayname):
if self.debug: print "%s's in %d %d..." % (dayname, m, y)
retval = [0]
dow = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'].index(dayname)
for d in range(1, 32):
try:
date = datetime.date(y, m, d)
except ValueError:
continue
if date.weekday() == dow:
retval.append( d )
if self.debug: print "dow=", dow, "days=", retval
return retval
def check_date(self, date):
retval = []
for rule in self.dates:
if self.debug: print "Checking ", rule["name"], "..."
offset = 0
if rule["offset"] != "":
if rule["offset"].isdigit():
offset = int(rule["offset"])
elif rule["offset"][0] in ["-","+"] and rule["offset"][1:].isdigit():
offset = int(rule["offset"])
else:
# must be a dayname
offset = rule["offset"]
if rule["value"].count("/") == 3: # year/num/day/month, "3rd wednesday in april"
y, num, dayname, mon = rule["value"].split("/")
if y == "*":
y = date.year
else:
y = int(y)
if mon.isdigit():
m = int(mon)
elif mon == "*":
m = date.month
else:
m = ['jan', 'feb', 'mar', 'apr', 'may', 'jun',
'jul', 'aug', 'sep', 'oct', 'nov', 'dec'].index(mon) + 1
dates_of_dayname = self.get_daynames(y, m, dayname)
if self.debug: print "num =", num
d = dates_of_dayname[int(num)]
elif rule["value"].count("/") == 2: # year/month/day
y, m, d = rule["value"].split("/")
if y == "*":
y = date.year
else:
y = int(y)
if m == "*":
m = date.month
else:
m = int(m)
if d == "*":
d = date.day
else:
d = int(d)
ndate = datetime.date(y, m, d)
if self.debug: print ndate, offset, type(offset)
if type(offset) == int:
if offset != 0:
ndate = ndate.fromordinal(ndate.toordinal() + offset)
elif type(offset) in [type(u''), str]:
dir = 1
if offset[0] == "-":
dir = -1
offset = offset[1:]
if offset in ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']:
# next tuesday you come to, including this one
dow = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'].index(offset)
ord = ndate.toordinal()
while ndate.fromordinal(ord).weekday() != dow:
ord += dir
ndate = ndate.fromordinal(ord)
if self.debug: print "ndate:", ndate, "date:", date
if ndate == date:
if rule["if"] != "":
if not eval(rule["if"]):
continue
retval.append(rule["name"])
return retval
#------------------------------------------------------------------------
#
# Register this plugin
#
#------------------------------------------------------------------------
from PluginMgr import register_report
register_report(
name = 'calendar',
category = Report.CATEGORY_DRAW,
report_class = Calendar,
options_class = CalendarOptions,
modes = Report.MODE_GUI | Report.MODE_BKI | Report.MODE_CLI,
translated_name = _("Calendar"),
status = _("Experimental"),
author_name = "Douglas S. Blank",
author_email = "Doug.Blank@gmail.com",
description = _("Produces a graphical calendar"),
)

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2005 Donald N. Allingham
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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
@ -80,10 +80,11 @@ class ChangeTypes(Tool.Tool):
AutoComp.fill_combo(self.auto1,const.personalEvents)
AutoComp.fill_combo(self.auto2,const.personalEvents)
self.auto1.child.set_text(
self.options.handler.options_dict['fromtype'])
self.auto2.child.set_text(
self.options.handler.options_dict['totype'])
# Need to display localized event names
self.auto1.child.set_text(const.display_event(
self.options.handler.options_dict['fromtype']))
self.auto2.child.set_text(const.display_event(
self.options.handler.options_dict['totype']))
self.title = _('Change Event Types')
self.window = self.glade.get_widget('top')
@ -103,6 +104,7 @@ class ChangeTypes(Tool.Tool):
def run_tool(self,cli=False):
# Run tool and return results
# These are English names, no conversion needed
fromtype = self.options.handler.options_dict['fromtype']
totype = self.options.handler.options_dict['totype']
@ -162,10 +164,11 @@ class ChangeTypes(Tool.Tool):
self.window.present()
def on_apply_clicked(self,obj):
self.options.handler.options_dict['fromtype'] = unicode(
self.auto1.child.get_text())
self.options.handler.options_dict['totype'] = unicode(
self.auto2.child.get_text())
# Need to store English names for later comparison
self.options.handler.options_dict['fromtype'] = const.save_event(
unicode(self.auto1.child.get_text()))
self.options.handler.options_dict['totype'] = const.save_event(
unicode(self.auto2.child.get_text()))
modified,msg = self.run_tool(cli=False)
OkDialog(_('Change types'),msg,self.parent.topWindow)

View File

@ -51,6 +51,79 @@ import const
import Tool
from QuestionDialog import OkDialog, MissingMediaDialog
#-------------------------------------------------------------------------
#
# Low Level repair
#
#-------------------------------------------------------------------------
def low_level(db):
"""
This is a low-level repair routine.
It is fixing DB inconsistencies such as duplicates.
Returns a (status,name) tuple.
The boolean status indicates the success of the procedure.
The name indicates the problematic table (empty if status is True).
"""
for the_map in [('Person',db.person_map),
('Family',db.family_map),
('Event',db.event_map),
('Place',db.place_map),
('Source',db.source_map),
('Media',db.media_map)]:
print "Low-level repair: table: %s" % the_map[0]
if _table_low_level(db,the_map[1]):
print "Done."
else:
print "Low-level repair: Problem with table: %s" % the_map[0]
return (False,the_map[0])
return (True,'')
def _table_low_level(db,table):
"""
Low level repair for a given db table.
"""
handle_list = table.keys()
dup_handles = sets.Set(
[ handle for handle in handle_list if handle_list.count(handle) > 1 ]
)
if not dup_handles:
print " No dupes found for this table"
return True
import GrampsBSDDB
table_cursor = GrampsBSDDB.GrampsBSDDBDupCursor(table)
for handle in dup_handles:
print " Duplicates found for handle: %s" % handle
try:
ret = table_cursor.set(handle)
except:
print " Failed setting initial cursor."
return False
for count in range(handle_list.count(handle)-1):
try:
table_cursor.delete()
print " Succesfully deleted dupe #%d" % (count+1)
except:
print " Failed deleting dupe."
return False
try:
ret = table_cursor.next_dup()
except:
print " Failed moving the cursor."
return False
table_cursor.close()
table.sync()
return True
#-------------------------------------------------------------------------
#
# runTool
@ -68,6 +141,12 @@ class Check(Tool.Tool):
# TODO: split plugin in a check and repair part to support
# checking of a read only database
return
# The low-level repair is bypassing the transaction mechanism.
# As such, we run it before starting the transaction.
# We only do this for the BSDDB backend.
if db.__class__.__name__ == 'GrampsBSDDB':
low_level(db)
trans = db.transaction_begin("",batch=True)
db.disable_signals()
@ -136,10 +215,8 @@ class CheckIntegrity:
self.progress.set_pass(_('Looking for duplicate spouses'),
self.db.get_number_of_people())
cursor = self.db.get_person_cursor()
data = cursor.first()
while data:
(handle,value) = data
for handle in self.db.person_map.keys():
value = self.db.person_map[handle]
p = RelLib.Person(value)
splist = p.get_family_handle_list()
if len(splist) != len(sets.Set(splist)):
@ -150,27 +227,21 @@ class CheckIntegrity:
self.duplicate_links.append((handle,value))
p.set_family_handle_list(new_list)
self.db.commit_person(p,self.trans)
data = cursor.next()
self.progress.step()
cursor.close()
def fix_encoding(self):
self.progress.set_pass(_('Looking for character encoding errors'),
self.db.get_number_of_media_objects())
cursor = self.db.get_media_cursor()
value = cursor.first()
while value:
(handle,data) = value
for handle in self.db.media_map.keys():
data = self.db.media_map[handle]
if type(data[2]) != unicode or type(data[4]) != unicode:
obj = self.db.get_object_from_handle(handle)
obj.path = Utils.fix_encoding( obj.path)
obj.desc = Utils.fix_encoding( obj.desc)
self.db.commit_media_object(obj,self.trans)
self.progress.step()
value = cursor.next()
cursor.close()
def check_for_broken_family_links(self):
# Check persons referenced by the family objects
@ -558,11 +629,9 @@ class CheckIntegrity:
self.progress.set_pass(_('Looking for source reference problems'),
total)
cursor = self.db.get_person_cursor()
data = cursor.first()
while data:
for handle in self.db.person_map.keys():
self.progress.step()
handle,info = data
info = self.db.person_map[handle]
person = RelLib.Person()
person.unserialize(info)
handle_list = person.get_referenced_handles_recursively()
@ -575,14 +644,10 @@ class CheckIntegrity:
new_bad_handles = [handle for handle in bad_handles if handle
not in self.invalid_source_references]
self.invalid_source_references += new_bad_handles
data = cursor.next()
cursor.close()
cursor = self.db.get_family_cursor()
data = cursor.first()
while data:
for handle in self.db.family_map.keys():
self.progress.step()
handle,info = data
info = self.db.family_map[handle]
family = RelLib.Family()
family.unserialize(info)
handle_list = family.get_referenced_handles_recursively()
@ -595,14 +660,10 @@ class CheckIntegrity:
new_bad_handles = [handle for handle in bad_handles if handle
not in self.invalid_source_references]
self.invalid_source_references += new_bad_handles
data = cursor.next()
cursor.close()
cursor = self.db.get_place_cursor()
data = cursor.first()
while data:
for handle in self.db.place_map.keys():
self.progress.step()
handle,info = data
info = self.db.place_map[handle]
place = RelLib.Place()
place.unserialize(info)
handle_list = place.get_referenced_handles_recursively()
@ -611,18 +672,14 @@ class CheckIntegrity:
item[1] not in known_handles ]
if bad_handles:
place.remove_source_references(bad_handles)
self.db.commit_family(place,self.trans)
self.db.commit_place(place,self.trans)
new_bad_handles = [handle for handle in bad_handles if handle
not in self.invalid_source_references]
self.invalid_source_references += new_bad_handles
data = cursor.next()
cursor.close()
cursor = self.db.get_source_cursor()
data = cursor.first()
while data:
for handle in known_handles:
self.progress.step()
handle,info = data
info = self.db.source_map[handle]
source = RelLib.Source()
source.unserialize(info)
handle_list = source.get_referenced_handles_recursively()
@ -635,14 +692,10 @@ class CheckIntegrity:
new_bad_handles = [handle for handle in bad_handles if handle
not in self.invalid_source_references]
self.invalid_source_references += new_bad_handles
data = cursor.next()
cursor.close()
cursor = self.db.get_media_cursor()
data = cursor.first()
while data:
for handle in self.db.media_map.keys():
self.progress.step()
handle,info = data
info = self.db.media_map[handle]
obj = RelLib.MediaObject()
obj.unserialize(info)
handle_list = obj.get_referenced_handles_recursively()
@ -655,14 +708,10 @@ class CheckIntegrity:
new_bad_handles = [handle for handle in bad_handles if handle
not in self.invalid_source_references]
self.invalid_source_references += new_bad_handles
data = cursor.next()
cursor.close()
cursor = self.db.get_event_cursor()
data = cursor.first()
while data:
for handle in self.db.event_map.keys():
self.progress.step()
handle,info = data
info = self.db.event_map[handle]
event = RelLib.Event()
event.unserialize(info)
handle_list = event.get_referenced_handles_recursively()
@ -675,8 +724,6 @@ class CheckIntegrity:
new_bad_handles = [handle for handle in bad_handles if handle
not in self.invalid_source_references]
self.invalid_source_references += new_bad_handles
data = cursor.next()
cursor.close()
def build_report(self,cl=0):
self.progress.close()

View File

@ -112,13 +112,15 @@ class DescendantReport(Report.Report):
if birth:
bplace_handle = birth.get_place_handle()
if bplace_handle:
birth_place = self.database.get_place_from_handle(bplace_handle).get_title()
birth_place = self.database.get_place_from_handle(
bplace_handle).get_title()
death_place = ""
if death:
dplace_handle = death.get_place_handle()
if dplace_handle:
death_place = self.database.get_place_from_handle(dplace_handle).get_title()
death_place = self.database.get_place_from_handle(
dplace_handle).get_title()
if birth_year_valid:
if birth_place:
@ -163,7 +165,6 @@ class DescendantReport(Report.Report):
if level >= self.max_generations:
return
childlist = []
for family_handle in person.get_family_handle_list():
family = self.database.get_family_from_handle(family_handle)
@ -176,10 +177,9 @@ class DescendantReport(Report.Report):
self.dump_dates(spouse)
self.doc.end_paragraph()
for child_handle in family.get_child_handle_list():
childlist.append(child_handle)
childlist = family.get_child_handle_list()[:]
childlist.sort(self.by_birthdate)
for child_handle in childlist:
child = self.database.get_person_from_handle(child_handle)
self.dump(level+1,child)
@ -230,7 +230,8 @@ class DescendantOptions(ReportOptions.ReportOptions):
p.set_bottom_margin(ReportUtils.pt2cm(f.get_size()*0.125))
p.set_first_indent(-0.5)
p.set_left_margin(min(10.0,float(i-0.5)))
p.set_description(_("The style used for the level %d display.") % i)
p.set_description(_("The style used for the "
"level %d display.") % i)
default_style.add_style("DR-Level%d" % i,p)
p = BaseDoc.ParagraphStyle()
@ -238,7 +239,8 @@ class DescendantOptions(ReportOptions.ReportOptions):
p.set_top_margin(ReportUtils.pt2cm(f.get_size()*0.125))
p.set_bottom_margin(ReportUtils.pt2cm(f.get_size()*0.125))
p.set_left_margin(min(10.0,float(i-0.5)))
p.set_description(_("The style used for the spouse level %d display.") % i)
p.set_description(_("The style used for the "
"spouse level %d display.") % i)
default_style.add_style("DR-Spouse%d" % i,p)
#------------------------------------------------------------------------

View File

@ -2,7 +2,7 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2002 Bruce J. DeGrasse
# Copyright (C) 2000-2005 Donald N. Allingham
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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
@ -235,8 +235,9 @@ class DetAncestorReport(Report.Report):
self.endnotes(self.database.get_event_from_handle(birth_handle))
first = 0
age,units = self.calc_age(person)
text = ReportUtils.died_str(self.database,person,first,
self.EMPTY_DATE,self.EMPTY_PLACE)
self.EMPTY_DATE,self.EMPTY_PLACE,age,units)
if text:
self.doc.write_text(text)
death_handle = person.get_birth_handle()
@ -503,25 +504,29 @@ class DetAncestorReport(Report.Report):
self.doc.start_paragraph('DAR-Endnotes',"%d." % key)
self.doc.write_text(base.get_title())
for item in [ base.get_author(), base.get_publication_info(),
base.get_abbreviation(),
_dd.display(srcref.get_date_object()),]:
if item:
self.doc.write_text('; %s' % item)
item = srcref.get_text()
if item:
self.doc.write_text('; ')
self.doc.write_text(_('Text:'))
self.doc.write_text(' ')
self.doc.write_text(item)
item = srcref.get_note()
if item:
self.doc.write_text('; ')
self.doc.write_text(_('Comments:'))
self.doc.write_text(' ')
self.doc.write_text(item)
# Disable writing reference details, because only the details
# the first reference to this source will appear.
# FIXME: need to properly change self.endnotes() to put
# this feature back correclty.
## for item in [ base.get_author(), base.get_publication_info(),
## base.get_abbreviation(),
## _dd.display(srcref.get_date_object()),]:
## if item:
## self.doc.write_text('; %s' % item)
##
## item = srcref.get_text()
## if item:
## self.doc.write_text('; ')
## self.doc.write_text(_('Text:'))
## self.doc.write_text(' ')
## self.doc.write_text(item)
##
## item = srcref.get_note()
## if item:
## self.doc.write_text('; ')
## self.doc.write_text(_('Comments:'))
## self.doc.write_text(' ')
## self.doc.write_text(item)
self.doc.write_text('.')
self.doc.end_paragraph()
@ -551,9 +556,9 @@ class DetAncestorReport(Report.Report):
self.sref_map[self.sref_index] = ref
msg.write("%d" % self.sref_index)
msg.write('</super>')
str = msg.getvalue()
the_str = msg.getvalue()
msg.close()
return str
return the_str
#------------------------------------------------------------------------
#

View File

@ -2,7 +2,7 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2002 Bruce J. DeGrasse
# Copyright (C) 2000-2005 Donald N. Allingham
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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
@ -88,6 +88,7 @@ class DetDescendantReport(Report.Report):
firstName - Whether to use first names instead of pronouns.
fullDate - Whether to use full dates instead of just year.
listChildren - Whether to list children.
includeMates - Whether to include information about spouses
includeNotes - Whether to include notes.
blankPlace - Whether to replace missing Places with ___________.
blankDate - Whether to replace missing Dates with ___________.
@ -116,6 +117,7 @@ class DetDescendantReport(Report.Report):
self.includeNames = options_class.handler.options_dict['incnames']
self.includeEvents = options_class.handler.options_dict['incevents']
self.includeSources= options_class.handler.options_dict['incsources']
self.includeMates = options_class.handler.options_dict['incmates']
self.gen_handles = {}
self.prev_gen_handles= {}
@ -261,9 +263,10 @@ class DetDescendantReport(Report.Report):
if birth_handle:
self.endnotes(self.database.get_event_from_handle(birth_handle))
first = 0
age,units = self.calc_age(person)
text = ReportUtils.died_str(self.database,person,first,
self.EMPTY_DATE,self.EMPTY_PLACE)
self.EMPTY_DATE,self.EMPTY_PLACE,age,units)
if text:
self.doc.write_text(text)
death_handle = person.get_birth_handle()
@ -283,7 +286,7 @@ class DetDescendantReport(Report.Report):
self.write_marriage(person)
self.doc.end_paragraph()
if key == 1:
if self.includeMates:
self.write_mate(person)
if person.get_note() != "" and self.includeNotes:
@ -528,24 +531,28 @@ class DetDescendantReport(Report.Report):
self.doc.start_paragraph('DDR-Endnotes',"%d." % key)
self.doc.write_text(base.get_title())
for item in [ base.get_author(), base.get_publication_info(), base.get_abbreviation(),
_dd.display(srcref.get_date_object()),]:
if item:
self.doc.write_text('; %s' % item)
item = srcref.get_text()
if item:
self.doc.write_text('; ')
self.doc.write_text(_('Text:'))
self.doc.write_text(' ')
self.doc.write_text(item)
item = srcref.get_note()
if item:
self.doc.write_text('; ')
self.doc.write_text(_('Comments:'))
self.doc.write_text(' ')
self.doc.write_text(item)
# Disable writing reference details, because only the details
# the first reference to this source will appear.
# FIXME: need to properly change self.endnotes() to put
# this feature back correclty.
## for item in [ base.get_author(), base.get_publication_info(), base.get_abbreviation(),
## _dd.display(srcref.get_date_object()),]:
## if item:
## self.doc.write_text('; %s' % item)
##
## item = srcref.get_text()
## if item:
## self.doc.write_text('; ')
## self.doc.write_text(_('Text:'))
## self.doc.write_text(' ')
## self.doc.write_text(item)
##
## item = srcref.get_note()
## if item:
## self.doc.write_text('; ')
## self.doc.write_text(_('Comments:'))
## self.doc.write_text(' ')
## self.doc.write_text(item)
self.doc.write_text('.')
self.doc.end_paragraph()
@ -610,6 +617,7 @@ class DetDescendantOptions(ReportOptions.ReportOptions):
'incnames' : 0,
'incevents' : 0,
'incsources' : 0,
'incmates' : 1,
}
self.options_help = {
'fulldates' : ("=0/1","Whether to use full dates instead of just year.",
@ -651,6 +659,9 @@ class DetDescendantOptions(ReportOptions.ReportOptions):
'incsources' : ("=0/1","Whether to include source references.",
["Do not include sources","Include sources"],
True),
'incmates' : ("=0/1","Whether to include detailed spouse information.",
["Do not include spouse info","Include spouse info"],
True),
}
def enable_options(self):
@ -820,6 +831,10 @@ class DetDescendantOptions(ReportOptions.ReportOptions):
self.include_sources_option = gtk.CheckButton(_("Include sources"))
self.include_sources_option.set_active(self.options_dict['incsources'])
# Print Spouses
self.include_spouses_option = gtk.CheckButton(_("Include spouses"))
self.include_spouses_option.set_active(self.options_dict['incmates'])
# Add new options. The first argument is the tab name for grouping options.
# if you want to put everyting in the generic "Options" category, use
# self.add_option(text,widget) instead of self.add_frame_option(category,text,widget)
@ -834,6 +849,7 @@ class DetDescendantOptions(ReportOptions.ReportOptions):
dialog.add_frame_option(_('Include'),'',self.include_names_option)
dialog.add_frame_option(_('Include'),'',self.include_events_option)
dialog.add_frame_option(_('Include'),'',self.include_sources_option)
dialog.add_frame_option(_('Include'),'',self.include_spouses_option)
dialog.add_frame_option(_('Missing information'),'',self.place_option)
dialog.add_frame_option(_('Missing information'),'',self.date_option)
@ -854,6 +870,7 @@ class DetDescendantOptions(ReportOptions.ReportOptions):
self.options_dict['incnames'] = int(self.include_names_option.get_active())
self.options_dict['incevents'] = int(self.include_events_option.get_active())
self.options_dict['incsources'] = int(self.include_sources_option.get_active())
self.options_dict['incmates'] = int(self.include_spouses_option.get_active())
#------------------------------------------------------------------------
#

View File

@ -312,8 +312,9 @@ class DisplayChart:
titles = []
index = 0
for v in self.event_titles:
titles.append((v,index,150))
for event_name in self.event_titles:
# Need to display localized event names
titles.append((const.display_event(event_name),index,150))
index = index + 1
self.list = ListModel.ListModel(self.eventlist,titles)
@ -436,10 +437,12 @@ class DisplayChart:
pstyle = BaseDoc.PaperStyle("junk",10,10)
doc = OpenSpreadSheet.OpenSpreadSheet(pstyle,BaseDoc.PAPER_PORTRAIT)
doc.creator(self.db.get_researcher().get_name())
spreadsheet = TableReport(name,doc)
spreadsheet.initialize(len(self.event_titles))
spreadsheet.write_table_head(self.event_titles)
spreadsheet.write_table_head([const.display_event(event_name)
for event_name in self.event_titles])
index = 0
for top in self.row_data:

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2005 Donald N. Allingham
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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
@ -72,7 +72,7 @@ class FamilyGroup(Report.Report):
"""
Report.Report.__init__(self,database,person,options_class)
self.family = None
self.family_handle = None
spouse_id = options_class.handler.options_dict['spouse_id']
if spouse_id:
@ -86,9 +86,18 @@ class FamilyGroup(Report.Report):
this_spouse = database.get_person_from_handle(this_spouse_handle)
this_spouse_id = this_spouse.get_gramps_id()
if spouse_id == this_spouse_id:
self.family = family
self.family_handle = family_handle
break
self.recursive = options_class.handler.options_dict['recursive']
self.missingInfo = options_class.handler.options_dict['missinginfo']
self.generations = options_class.handler.options_dict['generations']
self.incParEvents = options_class.handler.options_dict['incParEvents']
self.incParAddr = options_class.handler.options_dict['incParAddr']
self.incParNotes = options_class.handler.options_dict['incParNotes']
self.incParNames = options_class.handler.options_dict['incParNames']
self.incRelDates = options_class.handler.options_dict['incRelDates']
def define_table_styles(self):
"""
Define the table styles used by the report.
@ -152,18 +161,58 @@ class FamilyGroup(Report.Report):
table.set_column_width(3,40)
self.doc.add_table_style('FGR-ChildTable',table)
def dump_parent_event(self,name,event):
place = ""
date = ""
if event:
date = event.get_date()
place_handle = event.get_place_handle()
if place_handle:
place = self.database.get_place_from_handle(place_handle).get_title()
self.doc.start_row()
self.doc.start_cell("FGR-TextContents")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(name)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell("FGR-TextContents")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(date)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell("FGR-TextContentsEnd")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(place)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
def dump_parent_line(self,name,text):
self.doc.start_row()
self.doc.start_cell("FGR-TextContents")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(name)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell("FGR-TextContentsEnd",2)
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(text)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
def dump_parent(self,person_handle):
if not person_handle:
return
person = self.database.get_person_from_handle(person_handle)
if person.get_gender() == RelLib.Person.MALE:
the_id = _("Husband")
else:
the_id = _("Wife")
self.doc.start_table(the_id,'FGR-ParentTable')
self.doc.start_row()
self.doc.start_cell('FGR-ParentHead',3)
@ -173,62 +222,20 @@ class FamilyGroup(Report.Report):
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
birth_handle = person.get_birth_handle()
bdate = ""
bplace = ""
birth = None
if birth_handle:
birth = self.database.get_event_from_handle(birth_handle)
bdate = DateHandler.get_date(birth)
bplace_handle = birth.get_place_handle()
if bplace_handle:
bplace = self.database.get_place_from_handle(bplace_handle).get_title()
if birth or self.missingInfo:
self.dump_parent_event(_("Birth"),birth)
death_handle = person.get_death_handle()
ddate = ""
dplace = ""
death = None
if death_handle:
death = self.database.get_event_from_handle(death_handle)
ddate = DateHandler.get_date(death)
dplace_handle = death.get_place_handle()
if dplace_handle:
dplace = self.database.get_place_from_handle(dplace_handle).get_title()
self.doc.start_row()
self.doc.start_cell("FGR-TextContents")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(_("Birth"))
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell("FGR-TextContents")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(bdate)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell("FGR-TextContentsEnd")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(bplace)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
self.doc.start_row()
self.doc.start_cell("FGR-TextContents")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(_("Death"))
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell("FGR-TextContents")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(ddate)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell("FGR-TextContentsEnd")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(dplace)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
if death or self.missingInfo:
self.dump_parent_event(_("Death"),death)
family_handle = person.get_main_parents_family_handle()
father_name = ""
@ -237,36 +244,81 @@ class FamilyGroup(Report.Report):
family = self.database.get_family_from_handle(family_handle)
father_handle = family.get_father_handle()
if father_handle:
father_name = self.database.get_person_from_handle(father_handle).get_primary_name().get_regular_name()
father = self.database.get_person_from_handle(father_handle)
father_name = father.get_primary_name().get_regular_name()
if self.incRelDates:
birth_handle = father.get_birth_handle()
birth = " "
if birth_handle:
birth = self.database.get_event_from_handle(birth_handle).get_date()
death_handle = father.get_death_handle()
death = " "
if death_handle:
death = self.database.get_event_from_handle(death_handle).get_date()
if birth_handle or death_handle:
father_name = "%s (%s - %s)" % (father_name,birth,death)
mother_handle = family.get_mother_handle()
if mother_handle:
mother_name = self.database.get_person_from_handle(mother_handle).get_primary_name().get_regular_name()
mother = self.database.get_person_from_handle(mother_handle)
mother_name = mother.get_primary_name().get_regular_name()
if self.incRelDates:
birth_handle = mother.get_birth_handle()
birth = " "
if birth_handle:
birth = self.database.get_event_from_handle(birth_handle).get_date()
death_handle = mother.get_death_handle()
death = " "
if death_handle:
death = self.database.get_event_from_handle(death_handle).get_date()
if birth_handle or death_handle:
mother_name = "%s (%s - %s)" % (mother_name,birth,death)
self.doc.start_row()
self.doc.start_cell("FGR-TextContents")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(_("Father"))
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell("FGR-TextContentsEnd",2)
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(father_name)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
if self.missingInfo or father_name != "":
self.dump_parent_line(_("Father"),father_name)
self.doc.start_row()
self.doc.start_cell("FGR-TextContents")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(_("Mother"))
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell("FGR-TextContentsEnd",2)
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(mother_name)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
if self.missingInfo or mother_name != "":
self.dump_parent_line(_("Mother"),mother_name)
if self.incParEvents:
for event_handle in person.get_event_list():
event = self.database.get_event_from_handle(event_handle)
evtName = event.get_name()
if (evtName != "Death") and (evtName != "Birth"):
self.dump_parent_event(_(evtName),event)
if self.incParAddr:
addrlist = person.get_address_list()[:]
for addr in addrlist:
location = "%s %s %s %s" % (addr.get_street(),addr.get_city(),
addr.get_state(),addr.get_country())
date = addr.get_date()
self.doc.start_row()
self.doc.start_cell("FGR-TextContents")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(_("Address"))
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell("FGR-TextContents")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(date)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell("FGR-TextContentsEnd")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(location)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
if self.incParNotes and (person.get_note() != ""):
self.dump_parent_line(_("Notes"),person.get_note())
if self.incParNames:
for alt_name in person.get_alternate_names():
type = const.NameTypesMap.find_value(alt_name.get_type())
name = alt_name.get_regular_name()
self.dump_parent_line(type,name)
self.doc.end_table()
@ -304,22 +356,6 @@ class FamilyGroup(Report.Report):
def dump_child(self,index,person_handle):
person = self.database.get_person_from_handle(person_handle)
self.doc.start_row()
self.doc.start_cell('FGR-TextChild1')
self.doc.start_paragraph('FGR-ChildText')
if person.get_gender() == RelLib.Person.MALE:
self.doc.write_text("%dM" % index)
else:
self.doc.write_text("%dF" % index)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell('FGR-ChildName',3)
self.doc.start_paragraph('FGR-ChildText')
self.doc.write_text(person.get_primary_name().get_regular_name())
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
families = len(person.get_family_handle_list())
birth_handle = person.get_birth_handle()
if birth_handle:
@ -331,14 +367,55 @@ class FamilyGroup(Report.Report):
death = self.database.get_event_from_handle(death_handle)
else:
death = None
self.dump_child_event('FGR-TextChild1',_('Birth'),birth)
if families == 0:
self.dump_child_event('FGR-TextChild2',_('Death'),death)
else:
self.dump_child_event('FGR-TextChild1',_('Death'),death)
index = 1
spouse_count = 0;
for family_handle in person.get_family_handle_list():
family = self.database.get_family_from_handle(family_handle)
spouse_id = None
if person_handle == family.get_father_handle():
spouse_id = family.get_mother_handle()
else:
spouse_id = family.get_father_handle()
if spouse_id:
spouse_count = spouse_count + 1
self.doc.start_row()
if spouse_count != 0 or self.missingInfo or death != None or birth != None:
self.doc.start_cell('FGR-TextChild1')
else:
self.doc.start_cell('FGR-TextChild2')
self.doc.start_paragraph('FGR-ChildText')
if person.get_gender() == RelLib.Person.MALE:
self.doc.write_text("%dM" % index)
elif person.get_gender() == RelLib.Person.FEMALE:
self.doc.write_text("%dF" % index)
else:
self.doc.write_text("%dU" % index)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell('FGR-ChildName',3)
self.doc.start_paragraph('FGR-ChildText')
self.doc.write_text(person.get_primary_name().get_regular_name())
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
if self.missingInfo or birth != None:
if spouse_count != 0 or self.missingInfo or death != None:
self.dump_child_event('FGR-TextChild1',_('Birth'),birth)
else:
self.dump_child_event('FGR-TextChild2',_('Birth'),birth)
if self.missingInfo or death != None:
if spouse_count == 0:
self.dump_child_event('FGR-TextChild2',_('Death'),death)
else:
self.dump_child_event('FGR-TextChild1',_('Death'),death)
index = 0
for family_handle in person.get_family_handle_list():
index = index + 1
family = self.database.get_family_from_handle(family_handle)
for event_handle in family.get_event_list():
if event_handle:
@ -349,63 +426,98 @@ class FamilyGroup(Report.Report):
else:
m = None
spouse_id = None
if person_handle == family.get_father_handle():
spouse_id = family.get_mother_handle()
else:
spouse_id = family.get_father_handle()
self.doc.start_row()
self.doc.start_cell('FGR-TextChild1')
self.doc.start_paragraph('FGR-Normal')
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell('FGR-TextContents')
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(_("Spouse"))
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell('FGR-TextContentsEnd',2)
self.doc.start_paragraph('FGR-Normal')
if spouse_id:
spouse = self.database.get_person_from_handle(spouse_id)
self.doc.write_text(spouse.get_primary_name().get_regular_name())
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
if index == families:
self.dump_child_event('FGR-TextChild2',_("Married"),m)
else:
self.dump_child_event('FGR-TextChild1',_("Married"),m)
def write_report(self):
self.doc.start_paragraph('FGR-Title')
self.doc.write_text(_("Family Group Report"))
self.doc.end_paragraph()
if self.family:
self.dump_parent(self.family.get_father_handle())
self.doc.start_paragraph("FGR-blank")
self.doc.end_paragraph()
self.dump_parent(self.family.get_mother_handle())
length = len(self.family.get_child_handle_list())
if length > 0:
self.doc.start_paragraph("FGR-blank")
self.doc.end_paragraph()
self.doc.start_table('FGR-Children','FGR-ChildTable')
self.doc.start_row()
self.doc.start_cell('FGR-ParentHead',4)
self.doc.start_paragraph('FGR-ParentName')
self.doc.write_text(_("Children"))
self.doc.start_cell('FGR-TextChild1')
self.doc.start_paragraph('FGR-Normal')
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell('FGR-TextContents')
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(_("Spouse"))
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell('FGR-TextContentsEnd',2)
self.doc.start_paragraph('FGR-Normal')
if spouse_id:
spouse = self.database.get_person_from_handle(spouse_id)
spouse_name = spouse.get_primary_name().get_regular_name()
if self.incRelDates:
birth_handle = spouse.get_birth_handle()
birth = " "
if birth_handle:
birth = self.database.get_event_from_handle(birth_handle).get_date()
death_handle = spouse.get_death_handle()
death = " "
if death_handle:
death = self.database.get_event_from_handle(death_handle).get_date()
if birth_handle or death_handle:
spouse_name = "%s (%s - %s)" % (spouse_name,birth,death)
self.doc.write_text(spouse_name)
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
index = 1
for child_handle in self.family.get_child_handle_list():
self.dump_child(index,child_handle)
index = index + 1
self.doc.end_table()
if m:
if index == families:
self.dump_child_event('FGR-TextChild2',_("Married"),m)
else:
self.dump_child_event('FGR-TextChild1',_("Married"),m)
def dump_family(self,family_handle,generation):
self.doc.start_paragraph('FGR-Title')
if self.recursive and self.generations:
self.doc.write_text(_("Family Group Report - Generation %d") % generation)
else:
self.doc.write_text(_("Family Group Report") )
self.doc.end_paragraph()
family = self.database.get_family_from_handle(family_handle)
self.dump_parent(family.get_father_handle())
self.doc.start_paragraph("FGR-blank")
self.doc.end_paragraph()
self.dump_parent(family.get_mother_handle())
length = len(family.get_child_handle_list())
if length > 0:
self.doc.start_paragraph("FGR-blank")
self.doc.end_paragraph()
self.doc.start_table('FGR-Children','FGR-ChildTable')
self.doc.start_row()
self.doc.start_cell('FGR-ParentHead',4)
self.doc.start_paragraph('FGR-ParentName')
self.doc.write_text(_("Children"))
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.end_row()
index = 1
for child_handle in family.get_child_handle_list():
self.dump_child(index,child_handle)
index = index + 1
self.doc.end_table()
if self.recursive:
for child_handle in family.get_child_handle_list():
child = self.database.get_person_from_handle(child_handle)
for child_family_handle in child.get_family_handle_list():
if child_family_handle != family_handle:
self.doc.page_break()
self.dump_family(child_family_handle,(generation+1))
def write_report(self):
if self.family_handle:
self.dump_family(self.family_handle,1)
else:
self.doc.start_paragraph('FGR-Title')
self.doc.write_text(_("Family Group Report"))
self.doc.end_paragraph()
#------------------------------------------------------------------------
#
@ -425,6 +537,14 @@ class FamilyGroupOptions(ReportOptions.ReportOptions):
# Options specific for this report
self.options_dict = {
'spouse_id' : '',
'recursive' : 0,
'missinginfo' : 1,
'generations' : 1,
'incParEvents' : 0,
'incParAddr' : 0,
'incParNotes' : 0,
'incParNames' : 0,
'incRelDates' : 0,
}
self.options_help = {
@ -433,6 +553,37 @@ class FamilyGroupOptions(ReportOptions.ReportOptions):
#[item[0] for item in self.get_spouses(None,None)],
#False
),
'recursive' : ("=0/1","Create reports for all decendants of this family.",
["Do not create reports for decendants","Create reports for decendants"],
False),
'missinginfo' : ("=0/1","Whether to include fields for missing information.",
["Do not include missing info","Include missing info"],
True),
'generations' : ("=0/1","Whether to include the generation on each report (recursive only).",
["Do not include the generation","Include the generation"],
True),
'incParEvents' : ("=0/1","Whether to include events for parents.",
["Do not include parental events","Include parental events"],
True),
'incParAddr' : ("=0/1","Whether to include addresses for parents.",
["Do not include parental addresses","Include parental addresses"],
True),
'incParNotes' : ("=0/1","Whether to include notes for parents.",
["Do not include parental notes","Include parental notes"],
True),
'incParNames' : ("=0/1","Whether to include alternate names for parents.",
["Do not include parental names","Include parental names"],
True),
'incRelDates' : ("=0/1","Whether to include dates for relatives.",
["Do not include dates of relatives","Include dates of relatives"],
True),
}
def get_spouses(self,database,person):
@ -477,8 +628,48 @@ class FamilyGroupOptions(ReportOptions.ReportOptions):
spouse_index = index
index = index + 1
self.spouse_menu.set_active(spouse_index)
# Recursive
self.recursive_option = gtk.CheckButton()
self.recursive_option.set_active(self.options_dict['recursive'])
# Missing Info
self.missing_info_option = gtk.CheckButton(_("Print fields for missing information"))
self.missing_info_option.set_active(self.options_dict['missinginfo'])
# Generations
self.include_generations_option = gtk.CheckButton(_("Generation numbers (recursive only)"))
self.include_generations_option.set_active(self.options_dict['generations'])
# Parental Events
self.include_par_events_option = gtk.CheckButton(_("Parent Events"))
self.include_par_events_option.set_active(self.options_dict['incParEvents'])
# Parental Addresses
self.include_par_addr_option = gtk.CheckButton(_("Parent Addresses"))
self.include_par_addr_option.set_active(self.options_dict['incParAddr'])
# Parental Notes
self.include_par_notes_option = gtk.CheckButton(_("Parent Notes"))
self.include_par_notes_option.set_active(self.options_dict['incParNotes'])
# Parental Names
self.include_par_names_option = gtk.CheckButton(_("Alternate Parent Names"))
self.include_par_names_option.set_active(self.options_dict['incParNames'])
# Relatives Dates
self.include_rel_dates_option = gtk.CheckButton(_("Dates of Relatives (father, mother, spouse)"))
self.include_rel_dates_option.set_active(self.options_dict['incRelDates'])
dialog.add_option(_("Spouse"),self.spouse_menu)
dialog.add_option(_("Recursive"),self.recursive_option)
dialog.add_frame_option(_('Include'),'',self.include_generations_option)
dialog.add_frame_option(_('Include'),'',self.include_par_events_option)
dialog.add_frame_option(_('Include'),'',self.include_par_addr_option)
dialog.add_frame_option(_('Include'),'',self.include_par_notes_option)
dialog.add_frame_option(_('Include'),'',self.include_par_names_option)
dialog.add_frame_option(_('Include'),'',self.include_rel_dates_option)
dialog.add_frame_option(_('Missing Information'),'',self.missing_info_option)
def parse_user_options(self,dialog):
"""
@ -488,6 +679,15 @@ class FamilyGroupOptions(ReportOptions.ReportOptions):
spouse_index = self.spouse_menu.get_active()
if spouses:
self.options_dict['spouse_id'] = spouses[spouse_index][0]
self.options_dict['recursive'] = int(self.recursive_option.get_active())
self.options_dict['missinginfo'] = int(self.missing_info_option.get_active())
self.options_dict['generations'] = int(self.include_generations_option.get_active())
self.options_dict['incParEvents'] = int(self.include_par_events_option.get_active())
self.options_dict['incParAddr'] = int(self.include_par_addr_option.get_active())
self.options_dict['incParNotes'] = int(self.include_par_notes_option.get_active())
self.options_dict['incParNames'] = int(self.include_par_names_option.get_active())
self.options_dict['incRelDates'] = int(self.include_rel_dates_option.get_active())
def make_default_style(self,default_style):
"""Make default output style for the Family Group Report."""

View File

@ -307,7 +307,8 @@ class GraphViz:
label = label + '\\n(%s - %s)' % (birth, death)
self.f.write('p%s [shape=box, ' % the_id)
if self.includeurl:
self.f.write('URL="%s.html", ' % the_id)
h = person.get_handle()
self.f.write('URL="ppl/%s/%s/%s.html", ' % (h[0],h[1],h))
if self.colorize != 'outline':
if self.colorize == 'filled':
style = 'style=filled, fillcolor'

View File

@ -112,7 +112,10 @@ class GeneWebParser:
self.lineno += 1
line = self.f.readline()
if line:
line = unicode( line.strip())
try:
line = unicode(line.strip())
except UnicodeDecodeError:
line = unicode(line.strip(),'iso-8859-1')
else:
line = None
return line
@ -258,8 +261,6 @@ class GeneWebParser:
else:
(idx,child) = self.parse_person(fields,1,RelLib.Person.UNKNOWN,father_surname)
print child.get_gender(),":",fields[1], child.get_primary_name().get_name()
if child:
self.current_family.add_child_handle(child.get_handle())
self.db.commit_family(self.current_family,self.trans)
@ -302,7 +303,7 @@ class GeneWebParser:
def read_notes_lines(self,line,fields):
(idx,person) = self.parse_person(fields,1,None,None)
note_txt = ""
while 1:
while True:
line = self.get_next_line()
if line == None:
break
@ -402,16 +403,18 @@ class GeneWebParser:
if not father_surname:
if not idx < len(fields):
print "Missing surname of person in line %d!" % self.lineno
return (idx,None)
surname = self.decode(fields[idx])
surname =""
else:
surname = self.decode(fields[idx])
idx = idx + 1
else:
surname = father_surname
if not idx < len(fields):
print "Missing firstname of person in line %d!" % self.lineno
return (idx,None)
firstname = self.decode(fields[idx])
firstname = ""
else:
firstname = self.decode(fields[idx])
idx = idx + 1
if idx < len(fields) and father_surname:
noSurnameRe = re.compile("^[({\[~><?0-9#].*$")

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2003-2005 Donald N. Allingham
# Copyright (C) 2003-2006 Donald N. Allingham
#
# 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
@ -31,6 +31,7 @@ Show uncollected objects in a window.
#------------------------------------------------------------------------
import os
from gettext import gettext as _
from bsddb.db import DBError
#------------------------------------------------------------------------
#
@ -114,10 +115,15 @@ class Leak(Tool.Tool):
mylist = []
if len(gc.garbage):
for each in gc.garbage:
mylist.append(str(each))
self.ebuf.set_text(_("Uncollected objects:\n\n") + '\n\n'.join(mylist))
try:
mylist.append(str(each))
except DBError:
mylist.append('db.DB instance at %s' % id(each))
self.ebuf.set_text(_("Uncollected objects:\n\n")
+ '\n\n'.join(mylist))
else:
self.ebuf.set_text(_("No uncollected objects\n") + str(gc.get_debug()))
self.ebuf.set_text(_("No uncollected objects\n")
+ str(gc.get_debug()))
def apply_clicked(self,obj):
self.display()

View File

@ -112,12 +112,12 @@ _character_sets = [
]
_cc = [
'<a rel="license" href="http://creativecommons.org/licenses/by/2.5/"><img alt="Creative Commons License" src="#PATH#images/somerights20.gif" /></a>',
'<a rel="license" href="http://creativecommons.org/licenses/by-nd/2.5/"><img alt="Creative Commons License" src="#PATH#images/somerights20.gif" /></a>',
'<a rel="license" href="http://creativecommons.org/licenses/by-sa/2.5/"><img alt="Creative Commons License" src="#PATH#images/somerights20.gif" /></a>',
'<a rel="license" href="http://creativecommons.org/licenses/by-nc/2.5/"><img alt="Creative Commons License" src="#PATH#images/somerights20.gif" /></a>',
'<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/2.5/"><img alt="Creative Commons License" src="#PATH#images/somerights20.gif" /></a>',
'<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.5/"><img alt="Creative Commons License" src="#PATH#images/somerights20.gif" /></a>',
'<a rel="license" href="http://creativecommons.org/licenses/by/2.5/"><img alt="Creative Commons License - By attribution" title="Creative Commons License - By attribution" src="#PATH#images/somerights20.gif" /></a>',
'<a rel="license" href="http://creativecommons.org/licenses/by-nd/2.5/"><img alt="Creative Commons License - By attribution, No derivations" title="Creative Commons License - By attribution, No derivations" src="#PATH#images/somerights20.gif" /></a>',
'<a rel="license" href="http://creativecommons.org/licenses/by-sa/2.5/"><img alt="Creative Commons License - By attribution, Share-alike" title="Creative Commons License - By attribution, Share-alike" src="#PATH#images/somerights20.gif" /></a>',
'<a rel="license" href="http://creativecommons.org/licenses/by-nc/2.5/"><img alt="Creative Commons License - By attribution, Non-commercial" title="Creative Commons License - By attribution, Non-commercial" src="#PATH#images/somerights20.gif" /></a>',
'<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/2.5/"><img alt="Creative Commons License - By attribution, Non-commercial, No derivations" title="Creative Commons License - By attribution, Non-commercial, No derivations" src="#PATH#images/somerights20.gif" /></a>',
'<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.5/"><img alt="Creative Commons License - By attribution, Non-commerical, Share-alike" title="Creative Commons License - By attribution, Non-commerical, Share-alike" src="#PATH#images/somerights20.gif" /></a>',
]
@ -1665,6 +1665,14 @@ class IndividualPage(BasePage):
of.write('</td>\n</tr>\n')
# Gender
nick = self.person.get_nick_name()
if nick:
of.write('<tr><td class="field">%s</td>\n' % _('Nickname'))
of.write('<td class="data">%s</td>\n' % nick)
of.write('</tr>\n')
# Gender
of.write('<tr><td class="field">%s</td>\n' % _('Gender'))
gender = self.gender_map[self.person.gender]
@ -2100,7 +2108,7 @@ class WebReport(Report.Report):
# Copy the Creative Commons icon if the a Creative Commons
# license is requested
if 1 < self.copyright < 7:
if 0 < self.copyright < 7:
from_path = os.path.join(const.dataDir,"somerights20.gif")
to_path = os.path.join("images","somerights20.gif")
self.store_file(archive,self.target_path,from_path,to_path)
@ -2837,7 +2845,7 @@ def nameof(person,private):
if person.private and private:
return _("Private")
else:
return _nd.display(person)
return _nd.display_with_nick(person)
def name_nameof(name,private):
if name.private and private:

View File

@ -66,8 +66,10 @@ prefix_list = [
_title_re = re.compile(r"^([A-Za-z][A-Za-z]+\.)\s+(.*)$")
_nick_re = re.compile(r"(.+)\s*[(\"](.*)[)\"]")
_fn_prefix_re = re.compile("(.*)\s+(%s)\s*$" % '|'.join(prefix_list),re.IGNORECASE)
_sn_prefix_re = re.compile("^\s*(%s)\s+(.*)" % '|'.join(prefix_list),re.IGNORECASE)
_fn_prefix_re = re.compile("(.*)\s+(%s)\s*$" % '|'.join(prefix_list),
re.IGNORECASE)
_sn_prefix_re = re.compile("^\s*(%s)\s+(.*)" % '|'.join(prefix_list),
re.IGNORECASE)
#-------------------------------------------------------------------------
#
@ -111,19 +113,22 @@ class PatchNames(Tool.Tool):
first = name.get_first_name()
sname = name.get_surname()
match = _title_re.match(first)
if name.get_title():
current_title = [name.get_title()]
old_title = [name.get_title()]
else:
current_title = []
old_title = []
new_title = []
match = _title_re.match(first)
while match:
groups = match.groups()
first = groups[1]
current_title.append(groups[0])
new_title.append(groups[0])
match = _title_re.match(first)
if current_title:
self.title_list.append((key," ".join(current_title),first))
if new_title:
self.title_list.append((key," ".join(old_title+new_title),
first))
continue
match = _nick_re.match(first)
@ -131,15 +136,24 @@ class PatchNames(Tool.Tool):
groups = match.groups()
self.nick_list.append((key,groups[0],groups[1]))
continue
old_prefix = name.get_surname_prefix()
match = _fn_prefix_re.match(first)
if match:
groups = match.groups()
self.prefix1_list.append((key,groups[0],groups[1]))
self.prefix1_list.append((key,groups[0],
" ".join([groups[1],old_prefix]))
)
continue
match = _sn_prefix_re.match(sname)
if match:
groups = match.groups()
self.prefix2_list.append((key,groups[1],groups[0]))
self.prefix2_list.append((key,groups[1],
" ".join([old_prefix,groups[0]]))
)
self.progress.step()
if self.nick_list or self.title_list or self.prefix1_list or self.prefix2_list:
@ -217,38 +231,38 @@ class PatchNames(Tool.Tool):
self.nick_hash[id] = handle
self.progress.step()
for (id,title,nick) in self.title_list:
for (id,title,name) in self.title_list:
p = self.db.get_person_from_handle(id)
gid = p.get_gramps_id()
handle = self.model.append()
self.model.set_value(handle,0,1)
self.model.set_value(handle,1,gid)
self.model.set_value(handle,2,_('Title'))
self.model.set_value(handle,3,nick)
self.model.set_value(handle,3,title)
self.model.set_value(handle,4,p.get_primary_name().get_name())
self.title_hash[id] = handle
self.progress.step()
for (id,prefix,fname) in self.prefix1_list:
for (id,fname,prefix) in self.prefix1_list:
p = self.db.get_person_from_handle(id)
gid = p.get_gramps_id()
handle = self.model.append()
self.model.set_value(handle,0,1)
self.model.set_value(handle,1,gid)
self.model.set_value(handle,2,_('Prefix'))
self.model.set_value(handle,3,fname)
self.model.set_value(handle,3,prefix)
self.model.set_value(handle,4,p.get_primary_name().get_name())
self.prefix1_hash[id] = handle
self.progress.step()
for (id,prefix,fname) in self.prefix2_list:
for (id,sname,prefix) in self.prefix2_list:
p = self.db.get_person_from_handle(id)
gid = p.get_gramps_id()
handle = self.model.append()
self.model.set_value(handle,0,1)
self.model.set_value(handle,1,gid)
self.model.set_value(handle,2,_('Prefix'))
self.model.set_value(handle,3,fname)
self.model.set_value(handle,3,prefix)
self.model.set_value(handle,4,p.get_primary_name().get_name())
self.prefix2_hash[id] = handle
self.progress.step()

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2005 Donald N. Allingham
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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
@ -55,44 +55,51 @@ import TarFile
#-------------------------------------------------------------------------
def impData(database, name,cb=None,cl=0):
# Create tempdir, if it does not exist, then check for writability
tmpdir_path = os.path.expanduser("~/.gramps/tmp" )
# THE TEMP DIR is named as the filname.gpkg.media and is created
# in the same dir as the database that we are importing into.
db_path = os.path.dirname(database.get_save_path())
media_dir = "%s.media" % os.path.basename(name)
tmpdir_path = os.path.join(db_path,media_dir)
if not os.path.isdir(tmpdir_path):
try:
os.mkdir(tmpdir_path,0700)
except:
ErrorDialog( _("Could not create temporary directory %s") %
tmpdir_path )
tmpdir_path )
return
elif not os.access(tmpdir_path,os.W_OK):
ErrorDialog( _("Temporary directory %s is not writable") % tmpdir_path )
ErrorDialog(_("Temporary directory %s is not writable") % tmpdir_path)
return
else: # tempdir exists and writable -- clean it up if not empty
files = os.listdir(tmpdir_path) ;
for filename in files:
os.remove( os.path.join(tmpdir_path,filename) )
os.remove(os.path.join(tmpdir_path,filename))
try:
t = TarFile.ReadTarFile(name,tmpdir_path)
t.extract()
t.close()
except:
ErrorDialog(_("Error extracting into %s") % tmpdir_path )
ErrorDialog(_("Error extracting into %s") % tmpdir_path)
return
dbname = os.path.join(tmpdir_path,const.xmlFile)
imp_db_name = os.path.join(tmpdir_path,const.xmlFile)
try:
ReadXML.importData(database,dbname,cb)
ReadXML.importData(database,imp_db_name,cb)
except:
import DisplayTrace
DisplayTrace.DisplayTrace()
# Clean up tempdir after ourselves
files = os.listdir(tmpdir_path)
for filename in files:
os.remove(os.path.join(tmpdir_path,filename))
# THIS HAS BEEN CHANGED, because now we want to keep images
# stay after the import is over. Just delete the XML file.
os.remove(imp_db_name)
os.rmdir(tmpdir_path)
## files = os.listdir(tmpdir_path)
## for filename in files:
## os.remove(os.path.join(tmpdir_path,filename))
## os.rmdir(tmpdir_path)
#------------------------------------------------------------------------
#

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2005 Donald N. Allingham
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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
@ -65,16 +65,13 @@ class Rebuild(Tool.Tool):
# checking of a read only database
return
total = db.get_number_of_people() + \
db.get_number_of_families() + \
db.get_number_of_places() + \
db.get_number_of_sources() + \
db.get_number_of_media_objects()
db.disable_signals()
if parent:
progress = Utils.ProgressMeter(
_('Rebuilding Secondary Indices'))
# Six indices to rebuild, and the first step is removing
# old ones
total = 7
progress.set_pass('',total)
db.rebuild_secondary(progress.step)
progress.close()

119
src/plugins/holidays.xml Normal file
View File

@ -0,0 +1,119 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<calendar>
<country name="US">
<date name="New Year's Day" value="*/1/1" type="national" />
<date name="Independence Day" value="*/7/4" type="national" />
<date name="Veterans Day" value="*/11/11" type="national" />
<date name="Christmas" value="*/12/25" type="national" />
<date name="Labor Day" value="*/1/mon/sep" type="national" />
<date name="Thanksgiving" value="*/4/thu/nov" type="national" />
<date name="Inauguration Day" value="*/1/20" if="(y - 1980) % 4 == 0" type="national" />
<date name="Groundhog Day" value="*/2/2" type="secular" />
<date name="Lincoln's Birthday" value="*/2/12" type="secular" />
<date name="Valentine's Day" value="*/2/14" type="secular" />
<date name="Presidents' Day" value="*/3/mon/feb" type="secular" />
<date name="Washington's Birthday" value="*/2/22" type="secular" />
<date name="St. Patrick's Day" value="*/3/17" type="secular" />
<date name="April Fools's Day" value="*/4/1" type="secular" />
<date name="Earth Day" value="*/4/22" type="secular" />
<date name="Assistants' Day" value="*/-1/sat/apr" offset="-3" type="secular" />
<date name="Arbor Day" value="*/-1/fri/apr" type="secular" />
<date name="Mothers' Day" value="*/2/sun/may" type="secular" />
<date name="Fathers' Day" value="*/3/sun/jun" type="secular" />
<date name="Parents' Day" value="*/4/sun/jul" type="secular" />
<date name="Grandparents' Day" value="*/1/mon/sep" offset="6" type="secular" />
<date name="Columbus Day" value="*/2/mon/oct" type="secular" />
<date name="United Nations Day" value="*/10/24" type="secular" />
<date name="Halloween" value="*/10/31" type="secular" />
<date name="ML Kings's Birthday" value="*/3/mon/jan" type="secular" />
<date name="Armed Forces Day" value="*/3/sat/may" type="secular" />
<date name="Memorial Day" value="*/-1/mon/may" type="secular" />
<date name="Flag Day" value="*/6/14" type="secular" />
<date name="Election Day" value="*/11/2" offset="tue" type="secular" />
<date name="Daylight Savings begins" value="*/1/sun/apr" type="informational" />
<date name="Income Taxes due" value="*/4/15" type="national"
if="date.weekday().__cmp__(4)-1" />
<date name="Income Taxes due" value="*/4/16" type="national"
if="date.weekday() == 0" />
<date name="Income Taxes due" value="*/4/17" type="national"
if="date.weekday() == 0" />
<date name="Daylight Savings ends" value="*/-1/sun/oct" type="informational" />
<date name="Easter" type="religious" value="1980/4/6" />
<date name="Easter" type="religious" value="1981/4/19" />
<date name="Easter" type="religious" value="1982/4/11" />
<date name="Easter" type="religious" value="1983/4/3" />
<date name="Easter" type="religious" value="1984/4/22" />
<date name="Easter" type="religious" value="1985/4/7" />
<date name="Easter" type="religious" value="1986/3/30" />
<date name="Easter" type="religious" value="1987/4/19" />
<date name="Easter" type="religious" value="1988/4/3" />
<date name="Easter" type="religious" value="1989/3/26" />
<date name="Easter" type="religious" value="1990/4/15" />
<date name="Easter" type="religious" value="1991/3/31" />
<date name="Easter" type="religious" value="1992/4/19" />
<date name="Easter" type="religious" value="1993/4/11" />
<date name="Easter" type="religious" value="1994/4/3" />
<date name="Easter" type="religious" value="1995/4/16" />
<date name="Easter" type="religious" value="1996/4/7" />
<date name="Easter" type="religious" value="1997/3/30" />
<date name="Easter" type="religious" value="1998/4/12" />
<date name="Easter" type="religious" value="1999/4/4" />
<date name="Easter" type="religious" value="2000/4/23" />
<date name="Easter" type="religious" value="2001/4/15" />
<date name="Easter" type="religious" value="2002/3/31" />
<date name="Easter" type="religious" value="2003/4/20" />
<date name="Easter" type="religious" value="2004/4/11" />
<date name="Easter" type="religious" value="2005/3/27" />
<date name="Easter" type="religious" value="2006/4/16" />
<date name="Easter" type="religious" value="2007/4/8" />
<date name="Easter" type="religious" value="2008/3/23" />
<date name="Easter" type="religious" value="2009/4/12" />
<date name="Easter" type="religious" value="2010/4/4" />
<date name="Easter" type="religious" value="2011/4/24" />
<date name="Easter" type="religious" value="2012/4/8" />
<date name="Easter" type="religious" value="2013/3/31" />
<date name="Easter" type="religious" value="2014/4/20" />
<date name="Easter" type="religious" value="2015/4/5" />
<date name="Easter" type="religious" value="2016/3/27" />
<date name="Easter" type="religious" value="2017/4/16" />
<date name="Easter" type="religious" value="2018/4/1" />
<date name="Easter" type="religious" value="2019/4/21" />
<date name="Easter" type="religious" value="2020/4/12" />
<date name="Easter" type="religious" value="2021/4/4" />
<date name="Easter" type="religious" value="2022/4/17" />
<date name="Easter" type="religious" value="2023/4/9" />
<date name="Easter" type="religious" value="2024/3/31" />
<date name="Passover" value="2005/4/24" type="religious" />
<date name="Passover" value="2006/4/13" type="religious" />
<date name="Passover" value="2007/4/03" type="religious" />
<date name="Passover" value="2008/4/20" type="religious" />
<date name="Passover" value="2009/4/09" type="religious" />
<date name="Passover" value="2010/3/30" type="religious" />
<date name="Passover" value="2011/4/19" type="religious" />
<date name="Yom Kippur" value="2005/10/13" type="religious" />
<date name="Yom Kippur" value="2006/10/02" type="religious" />
<date name="Yom Kippur" value="2007/9/27" type="religious" />
<date name="Yom Kippur" value="2008/10/09" type="religious" />
<date name="Yom Kippur" value="2009/9/28" type="religious" />
<date name="Yom Kippur" value="2010/9/18" type="religious" />
<date name="Hanukkah begins" value="2004/10/07" type="religious" />
<date name="Hanukkah begins" value="2005/10/26" type="religious" />
<date name="Hanukkah begins" value="2006/10/15" type="religious" />
<date name="Hanukkah begins" value="2007/10/05" type="religious" />
<date name="Hanukkah begins" value="2008/10/22" type="religious" />
<date name="Hanukkah begins" value="2009/10/12" type="religious" />
<date name="Hanukkah begins" value="2010/10/22" type="religious" />
<date name="Ramadan begins" value="2006/9/24" type="religious" />
<date name="Ramadan begins" value="2007/9/13" type="religious" />
<date name="Ramadan begins" value="2008/9/2" type="religious" />
<date name="Kwanzaa begins" value="*/12/26" type="religious" />
<date name="Cinco de Mayo" value="*/5/5" type="secular" />
</country>
<country name="CN">
<date name="Chinese New Year" value="2006/1/29" type="national" />
</country>
<country name="FI">
<date name="Chinese New Year" value="2006/1/29" type="national" />
<date name="Card Night" value="*/-1/thu/*" type="personal" />
</country>
</calendar>

View File

@ -20,7 +20,4 @@ uninstall-local:
SUFFIXES = .po .mo
.po.mo:
$(MSGCONV) --to-code=UTF-8 $< -o temp.po
$(MSGFMT) temp.po -o $@
rm temp.po
$(MSGCONV) --to-code=UTF-8 $< | $(MSGFMT) - -o $@

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

11192
src/po/lt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

10381
src/po/nl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,7 @@ OPTS="-i $EXAMPLE_XML"
GRPH_FMT="sxw ps pdf svg"
TEXT_FMT="sxw pdf kwd abw rtf txt html tex"
GRPH_REP="ancestor_chart2 descend_chart2 fan_chart statistics_chart timeline"
GRPH_REP="ancestor_chart2 descend_chart2 fan_chart statistics_chart timeline calendar"
TEXT_REP="ancestor_report ancestors_report descend_report det_ancestor_report det_descendant_report family_group"
# Single run with all graphical reports in all formats