* 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

@ -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

View File

@ -25,7 +25,7 @@
<title>Main Window</title>
<para>
When you open a database (either existing or brand new), the
When you open a database (either existing or new), the
following window is displayed:
</para>
@ -38,14 +38,6 @@
<imageobject>
<imagedata fileref="figures/mainwin.png" format="PNG" width="500" depth="352" scale="70"/>
</imageobject>
<textobject>
<phrase>
Shows GRAMPS main window. Contains titlebar, menubar,
toolbar, sidebar, display area, statusbar, progressbar, and
scrollbars. Menubar contains File, Edit, View, Go, Bookmarks,
Reports, Tools, Settings, and Help menus.
</phrase>
</textobject>
</mediaobject>
</screenshot>
</figure>
@ -53,7 +45,7 @@
<!-- ==== End of Figure ==== -->
<para>
The &app; window contains the following elements:
The main &app; window contains the following elements:
</para>
<variablelist>
@ -63,8 +55,8 @@
<listitem>
<para>
The menubar is located at the very top of the window (right
below the window title) and provides access to all features
of &app; through its menus.
below the window title) and provides access to all the features
of &app;.
</para>
</listitem>
</varlistentry>
@ -73,37 +65,40 @@
<term>Toolbar</term>
<listitem>
<para>
The toolbar is located immediately below the menubar. The
toolbar provides access to the most frequently used
functions of &app;. The appearance of the toolbar can be
adjusted in the <guilabel>Preferences</guilabel> dialog.
The toolbar is located right below the menubar. It gives you
access to the most frequently used
functions of &app;. You can set options that control how it
appears by going to
<menuchoice><guimenu>Edit</guimenu><guisubmenu>Preferences</guisubmenu></menuchoice>. You can also hide it entirely by going to <menuchoice><guimenu>View</guimenu><guisubmenu>Toolbar</guisubmenu></menuchoice>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Progressbar</term>
<term>Progress Bar</term>
<listitem>
<para>
The progressbar is located in the lower left corner of the
The Progress Bar is located in the lower left corner of the
&app; window. It displays the progress of time consuming
operations, such as opening and saving large data bases,
importing and exporting to other formats, generating web
sites, etc.
sites, etc. When you are not doing these types of operations,
the Progress Bar is blank.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Statusbar</term>
<term>Status Bar</term>
<listitem>
<para>
The statusbar is located to the right of the progressbar, on
the very bottom of the &app; window. It displays
The Status Bar is located to the right of the Progress Bar,
on the very bottom of the &app; window. It displays
information about current &app; activity and contextual
information about the menu items. The behavior of the
statusbar can be adjusted in
<guilabel>Preferences</guilabel> dialog.
information about the selected items. The behavior of the
Status Bar can be adjusted in the Preferences dialog, which
can be found by selecting
<menuchoice><guimenu>Edit</guimenu><guisubmenu>Preferences</guisubmenu></menuchoice>.
</para>
</listitem>
</varlistentry>
@ -113,17 +108,8 @@
<listitem>
<para>
The largest area in the center of the &app; window is the
display area. It shows certain aspects of genealogical
information, depending on the currently selected View. The
following six Views are available in &app;:
<itemizedlist>
<listitem><para>People View</para></listitem>
<listitem><para>Family View</para></listitem>
<listitem><para>Pedigree View</para></listitem>
<listitem><para>Sources View</para></listitem>
<listitem><para>Places View</para></listitem>
<listitem><para>Media View</para></listitem>
</itemizedlist>
display area. What it displays depends on the currently
selected View. We'll discuss Views in detail below.
</para>
</listitem>
</varlistentry>
@ -133,38 +119,44 @@
<sect1 id="gramps-views">
<title>Views</title>
<para>
Views are the various ways to display different aspects of
genealogical information. It is best to split the relevant
information display into smaller categories, uniform in context
and modality; since it is very broad and non-uniform in both
context and modality. Each View represents such a split and
displays a certain portion of overall available
information. Before reviewing the detailed description of
available Views, you will be guided through the ways of
switching between the Views.
</para>
<para>Genealogical information is very broad and can be extremely
detailed. Displaying it poses a challenge that GRAMPS takes on by
dividing and organizing the information into a series of
Views. Each View displays a portion of the total information,
selected according to a particular category. This will become
clearer as we explore the six different Views, listed
below:</para>
<itemizedlist>
<listitem><para>People View</para></listitem>
<listitem><para>Family View</para></listitem>
<listitem><para>Pedigree View</para></listitem>
<listitem><para>Sources View</para></listitem>
<listitem><para>Places View</para></listitem>
<listitem><para>Media View</para></listitem>
</itemizedlist>
<para>Before we launch into a description of each View,
let's first explain how to switch between Views.</para>
<!-- ================ Main Window Sub-subsection -->
<sect2 id="view-modes">
<title>Switching Views and Viewing Modes</title>
<para>
Depending on the state of the <menuchoice>
<guimenu>View</guimenu><guimenuitem>Sidebar</guimenuitem>
</menuchoice> menu item, the View could be switched either in
the sidebar or in the notebook tabs in the top part of the
window.
</para>
<variablelist>
<varlistentry>
<term>
To switch the View while in a Sidebar mode,
click on the desired sidebar icon.
</term>
<listitem>
<para>As mentioned above there are six different Views. In
addition, there are two different Viewing Modes. You can tell at
a glance which Viewing Mode you are in: If you see icons listed
vertically in a sidebar at the left of the window, you are in
the Sidebar Viewing Mode. If instead you see a series of
&quot;notebook tabs&quot; (labeled People, Family, Pedigree, Sources,
Places, Media) that run horizontally across the window, then you
are in the Tabbed Viewing Mode. You can switch from one Viewing
Mode to another by selecting <menuchoice><guimenu>View</guimenu><guimenuitem>Sidebar</guimenuitem></menuchoice> from the Sidebar menu item.</para>
<para>If you're in the Sidebar Viewing Mode, you can select the View
you want by clicking one of the sidebar icons.</para>
<!-- ==== Figure: Sidebar Mode ==== -->
<figure id="side-nofilt-fig">
@ -183,15 +175,8 @@
<!-- ==== End of Figure ==== -->
</listitem>
</varlistentry>
<varlistentry>
<term>
To switch the View while in a Tabbed mode,
click on the desired notebook tab.
</term>
<listitem>
<para>If you're in the Tabbed Viewing Mode, you can select the
View you want by clicking the corresponding notebook tab.</para>
<!-- ==== Figure: Tabbed Notebook Mode ==== -->
@ -209,16 +194,6 @@
</screenshot>
</figure>
<!-- ==== End of Figure ==== -->
</listitem>
</varlistentry>
</variablelist>
<para>
To switch between sidebar and tabbed viewing modes, choose
<menuchoice> <guimenu>View</guimenu>
<guimenuitem>Sidebar</guimenuitem> </menuchoice> from the
&app; menu.
</para>
</sect2>
@ -227,59 +202,47 @@
<sect2 id="people-view">
<title>People View</title>
<para>
When &app; first opens a database, the View is set to the
When &app; first opens a database, it displays the
People View (<xref linkend="side-nofilt-fig"/> and <xref
linkend="noside-nofilt-fig"/>). The People View lists
individuals whose data is stored in the database.
linkend="noside-nofilt-fig"/>). This view lists
all the people stored in the database.
</para>
<para>
The individuals are arranged in a tree-like structure,
according to their family names. Every family name is a node
of the tree. Clicking the arrow on the left of the node will
toggle its expansion state. When expanded, the node's content
is listed in the window. When collapsed, the content is
rolled up and not visible. All the data is still
intact. It is just not being displayed.
You'll note that people are grouped according to their family
names. To the left of each family name is an arrow. Clicking it
once will reveal the entire list of people sharing that
name. Clicking the arrow again will &quot;roll up&quot; the
list and show only the family name.
</para>
<para>
The People View, in its default state, displays people's
By default, the People View, displays the following columns:
<guilabel>Names</guilabel>, &app; <guilabel>ID</guilabel>
numbers, <guilabel>Gender</guilabel>, and their
<guilabel>Birth</guilabel> and <guilabel>Death
dates</guilabel>. The list can be ordered by any field.
dates</guilabel>. You can add or remove columns to and from
the display by calling up the <guilabel>Column
Editor</guilabel> dialog
(<menuchoice><guimenu>Edit</guimenu><guimenuitem>Column
Editor</guimenuitem></menuchoice>) and checking or unchecking
the boxes listed. You can also change the position of a column
in People View by clicking and dragging it to a new position
in the Editor. Once you have made the changes you want, click
<guibutton>OK</guibutton> to exit the Editor and see your
changes in the People View.
</para>
<tip id="columns-tip">
<title>Order list by selected column</title>
<note id="columns-tip">
<title>Column Editor</title>
<para>
To order list by the Birth date, click on the
<guilabel>Birth date</guilabel> column heading. To order
list in reverse (descending) order, click one more time on
the desired column heading.
The Column Editor is available in all Views and works the
same way in each.
</para>
</tip>
</note>
<para>
The columns of the view may be added, removed, or reordered in
a <guilabel>Column Editor Dialog</guilabel>, see <xref
linkend="column-editor-fig"/>. Only checked columns will be
shown in the view. To change their order, drag any column to
its desired location inside the editor. Clicking
<guibutton>OK</guibutton> will reflect the changes in the
People View. To invoke <guilabel>Column Editor
Dialog</guilabel>, choose
<menuchoice><guimenu>Edit</guimenu><guimenuitem>Column
Editor</guimenuitem></menuchoice>.
</para>
<tip id="columns-tip2">
<title>Other Views</title>
<para>
The <guilabel>Column Editor</guilabel> is available and
works in the same way for all list views, not only People
View.
</para>
</tip>
<!-- ==== Figure: Enabled Filter ==== -->
@ -288,7 +251,7 @@
<screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="figures/column-editor.png" format="PNG" width="444" depth="437" scale="75"/>
<imagedata fileref="figures/column-editor.png" format="PNG" width="444" depth="437"/>
</imageobject>
<textobject>
<phrase>Shows column editor dialog. </phrase>
@ -301,14 +264,16 @@
<sect3 id="filters">
<title>Filters</title>
<para>
Genealogical databases may contain huge numbers of people.
Since the long lists are hard for humans to manage, &app;
provides a convenient way to limit the scope of browsing by
using the filter. To save screen space, filter controls may
be hidden, depending on the state of <menuchoice>
<guimenu>View</guimenu> <guimenuitem>Filter</guimenuitem>
</menuchoice> menu item.
Genealogical databases can contain information on many people,
families, places, and objects. It's therefore possible for a
View to contain a long list of data that's difficult to
work with. &app; gives you a means for controlling this
condition by allowing you to filter a list to a more
manageable size.
</para>
<!-- ==== Figure: Enabled Filter ==== -->
@ -330,20 +295,42 @@
<!-- ==== End of Figure ==== -->
<para>
When &app; opens a database, the filter is set to the
trivial filter called <guilabel>All people</guilabel>,
i.e. no filtering is in effect. To choose a filter, use the
pop-up <guilabel>Filter</guilabel> menu above the people's
list. Once the filter is chosen, click the
<guibutton>Apply</guibutton> button in the upper right
corner of the window. The filtering will take effect upon
clicking the <guibutton>Apply</guibutton> button.
When &app; opens a database, no filtering is in effect. In
People View, for example, all people in the database are
listed by default. To filter the list, go to <menuchoice>
<guimenu>View</guimenu> <guimenuitem>Filter</guimenuitem>
</menuchoice>. This will place a new menu just above the list
of People. Click on the double arrows of this menu to get a
pop-up list of all the criteria by which you can filter the
People listed. Choose a filter (for example, &quot;Males&quot;
or &quot;People with children&quot;) and click
<guibutton>Apply</guibutton>.
</para>
<note id="filter-note">
<title>Displaying the filter</title>
<para>
To reduce screen clutter, the filter menu is hidden by
default. To display it, go to the <menuchoice>
<guimenu>View</guimenu> <guimenuitem>Filter</guimenuitem>
</menuchoice> menu. Please understand that even if the
filter menu is not displayed, filtering may still be in
effect. (Thus, we say that filtering is persistent.) If you
are unsure if your list is filtered, bring up the filter
menu (by going to <menuchoice> <guimenu>View</guimenu>
<guimenuitem>Filter</guimenuitem> </menuchoice>) and check
if any filtering is set.
</para>
</note>
<tip id="filt-tip">
<title>Example filter use</title>
<para>
To show males only, choose <guilabel>Males</guilabel>
To show males only, choose the <guilabel>Males</guilabel>
filter, then click the <guibutton>Apply</guibutton>
button. To cancel any filtering, set the filter to
<guilabel>Entire Database</guilabel> and then click the
@ -351,27 +338,6 @@
</para>
</tip>
<note id="filt-note">
<title>Filtering is persistent</title>
<para>
Even if the filter controls are not displayed
(<menuchoice> <guimenu>View</guimenu>
<guimenuitem>Filter</guimenuitem> </menuchoice> menu
item is unchecked), the filtering might still be in
place. In other words, the visibility of the filter
controls is not related to the actual filtering imposed
on the list.
</para>
<para>
This may be a cause of confusion, when you enable the
filtering and then remove the controls from the
display. If in doubt, enable the display of filter
controls by checking <menuchoice>
<guimenu>View</guimenu>
<guimenuitem>Filter</guimenuitem> </menuchoice> menu
item and check what kind of filtering is currently set.
</para>
</note>
</sect3>
</sect2>
@ -380,12 +346,9 @@
<sect2 id="family-view">
<title>Family View</title>
<para>
Family View displays the family information of a currently
selected (or Active) person. Specifically, this view shows
the relationships (e.g. marriages, partnerships, etc.) of the
active person, his/her parents (or step parents, or
guardians, etc), and his/her children (could be step
children, adopted children, etc.).
The Family View displays the family information of a
selected person that we call the Active person. Specifically,
it shows his or her closest relationships.
</para>
<!-- ==== Figure: Family View ==== -->
@ -407,80 +370,135 @@
<!-- ==== End of Figure ==== -->
<para>
The Active person's data is in the list box in the upper
left corner of the window. Directly below it, another box
lists the Spouse's data, for each relationship of Active
person (can be more than one). The double-arrow button to
the right of the Active person list box allows you to
exchange the currently selected spouse (Current spouse) with
the Active person. Double-clicking on the Active person
allows the editing of Active person's data. Double-clicking
on the Current spouse allows you to edit their relationship
information. Shift-clicking on the Current spouse allows the
editing of the Current spouse's data.
The Family View displays the following series of list boxes:
</para>
<variablelist>
<varlistentry>
<term>Active person</term>
<listitem>
<para>
To add a new relationship, use one of the two upper buttons
to the right of the spouse box. Click the top one to add a
new person to a database and to the new relationship. Click
the middle one to add a person already existing in the
database to the new relationship. To remove Current spouse,
click the lowest button (<guibutton>-</guibutton>) to the
right of the spouse box. Note that removing a spouse from
the relationship does not remove the person from the
database. Most of these functions are also available by
right-clicking into the spouse box and selecting an
appropriate item from the context menu.
Shows birth and death data for the individual you have
selected. Double-click inside the box to edit the Active
person's information. Click on the double arrow to the
right and the currently selected Spouse will become the
new Active person.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Relationship</term>
<listitem>
<para>
The parents of both the Active person and the Current spouse
are listed in the corresponding list boxes in the right-hand
part of the window (Active person's parents on top, Current
spouse parents on the bottom). Both list boxes have a set of
three buttons on their right side. The
<guibutton>+</guibutton> and <guibutton>-</guibutton>
buttons allow you to add and remove parents of the Active
person and the Current spouse, respectively. Clicking the
right arrow button makes the family in the corresponding
list box an active family. That is, it makes the selected
Father the Active person, and the selected Mother the
Current spouse. Most of these functions are also available
by right-clicking into the parent box and selecting an
appropriate item from the context menu.
Displays birth and death data for the Active person's
Spouse(s).
</para>
<note id="spouse-info">
<title>Terminology</title>
<para>
The bottom list box displays children of the Active person
and the Current Spouse. The Children's list can be ordered
by the Birth date in the usual way of clicking on the
<guilabel>Birth date</guilabel> column header. In addition
to the <guilabel>Name</guilabel>, <guilabel>ID</guilabel>,
<guilabel>Gender</guilabel>, and <guilabel>Birth
date</guilabel> columns, the list includes a
<guilabel>Status</guilabel> column. The pair of status words
reflect the relationship between the child and his
Father/Mother (such as Birth, Adoption,
etc.). <guilabel>Column Editor Dialog</guilabel> can be used
to change column arrangement. Four buttons are available on
the right side of the children list box. The top (left
arrow) button makes the selected child the Active
person. The next two buttons add a new child to the family:
the upper one adds a new person to the database and to the
family, the lower one just adds a person existing in the
database to the family. Finally, the lowest
<guibutton>-</guibutton> button removes the selected child
from the family. Note that removing a child from the family
does not remove the person from the database. Most of these
functions are also available by right-clicking into the
children box and selecting an appropriate item from the
context menu.
In the Family View, we use the term &quot;spouse&quot;
for sake of simplicity. However, please note that
&quot;spouse&quot; may in fact be a domestic partner, a
partner in a civil union, etc.
</para>
</note>
<para>
Double-click a Spouse to edit his or her
relationship to the Active person. Shift-click (that is,
hold down the Shift key while you click) a Spouse to edit
his or her personal information. Click the icon to the
top right of the Relationship box to add a new person to
the database and to create a relationship between this
person and the Active person. Click the middle icon to
create a relationship between the Active person and
another person already stored in the database. Click the
minus (-) button to remove the relationship between the
currently selected Spouse and the Active person. (Note
that this does not remove the Spouse from the database.)
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Active person's parents</term>
<listitem>
<para>
Click the <guibutton>+</guibutton> or
<guibutton>-</guibutton> buttons to add or remove parents
of the Active person. Click the right arrow button to make
the Father the new Active person and the Mother the new
Spouse.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Spouse's parents</term>
<listitem>
<para>
This list box functions the same as that of the Active
person's parents.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Children</term>
<listitem>
<para>
Displays the children of the Active person and the
currently selected Spouse. The list can be ordered however
you want by clicking on a column heading.
</para><para>
Note that in addition to columns for Name, ID, Gender,
Birth Date, and Death Date, there is a column labeled
Status.1 This column reflects the relationship between the
child and his parents (Birth, Adoption, etc.).
</para><para>
As with the other list boxes, the Children list box has
some associated buttons. Click the left arrow button to
make the selected Child the Active person. Click the next
button down to add a new person to the database and to
make this person a Child of the Active person. Click the
next button down to select a person from the database and
to make this person a Child of the Active person. Click
the lowest button to remove the selected Child from the
Family (note that this does not remove the Child from the
database).
</para>
<note id="right-click-menu">
<title>Right Click Menu</title>
<para>
Most of the functions described above can also be executed
by right-clicking your mouse.
</para>
</note>
</listitem>
</varlistentry>
</variablelist>
<para>
The layout of the Family View can be switched from the
left-to-right arrangement (shown above) to the top-to-bottom
arrangement (shown below). This can be done in the
<guilabel>Display</guilabel> section of the
<guilabel>Preferences</guilabel> dialog. The top-to-bottom
view has the same functionality as the left-to-right view.
&quot;left-to-right&quot; arrangement shown in <xref linkend="family-fig"/> to the
&quot;top-to-bottom&quot; arrangement shown in <xref linkend="family-alt-fig"/>. This is
done by going to
<menuchoice><guimenu>Edit</guimenu><guimenuitem>Preferences</guimenuitem></menuchoice>
and selecting the <guilabel>Display</guilabel> section of
the dialog that appears.
</para>
<!-- ==== Figure: Family View ==== -->
@ -507,6 +525,19 @@
<sect2 id="pedigree-view">
<title>Pedigree View</title>
<para>
The Pedigree View displays a family tree of the Active
person's ancestors. The Pedigree View shows up to five
generations, depending on the size of the window. Each person is
indicated by a box labeled with his or her name. Two lines
branch from each box. The top one shows the person's father
and the bottom one the mother. Solid lines represent birth
relations, while dashed lines represent non-birth relations
such as adoption, step-parenthood, guardianship, etc.
</para>
<!-- ==== Figure: Pedigree View ==== -->
<figure id="pedigree-fig">
@ -527,26 +558,11 @@
<para>
The Pedigree View helps to visualize the place of the Active
person in the tree of his/her ancestors. The Pedigree View
shows four generations, going back in time from the Active
person <guilabel>1</guilabel> to his/her parents
<guilabel>2</guilabel>, to grandparents
<guilabel>3</guilabel>, to great-grandparents
<guilabel>4</guilabel>. Each person is denoted by a box
bearing the person's name. The two lines that converge on
the box represent ties with the person's Father (top line)
and mother (bottom line). Solid lines represent birth
relations, while dashed lines represent non-birth relations
(such as adoption, step-parenthood, guardianship, etc.).
When the mouse moves over the white box, it expands to
display the corresponding person's dates of birth and
death. When the mouse is placed over the family line, the
line becomes highlighted to indicate an active link:
double-clicking on the line makes the corresponding ancestor
the Active person. The display in that case is re-adjusted
to show four generations, starting from the newly selected
Active person.
If you move your mouse over a box, it expands to show birth
and death dates. If you move your mouse over a line, the line
gets highlighted, indicating an active link. Double-click the
line to make the corresponding ancestor the Active
person.
</para>
@ -570,19 +586,22 @@
<para>
The left-hand side of the window shows the left arrow
button. Upon clicking, the button expands to the menu
listing the children of the Active person. Selecting the
menu item makes the corresponding child the Active
person. The appearance of the children's names in the menu
serves to differentiate the "dead ends" of the tree from the
continuing branches as follows. The children who have
children appear in the menu in the boldface and italic
typeset, while the children without children ("dead ends")
appear in a regular font. If the Active person has a single
child, no menu will be displayed (since there is no choice)
and the child will become the Active person upon clicking
the arrow button.
To the left of the Active person is a left arrow button. If
the Active person has children, clicking this button expands a
list of the Active person's children. Selecting one of the
children makes that child the pctive Person.
</para><para>
The appearance of the children's names in the menu
differentiates the &quot;dead ends&quot; of the tree from the
continuing branches. Children who have children themselves
appear in the menu in the boldface and italic type, while
children without children (&quot;dead ends&quot;) appear in a
regular font. If the Active person has only one child, no menu
will be displayed (since there is only one choice) and the
child will become the Active person when the arrow button is
clicked.
</para><para>
@ -590,8 +609,7 @@
buttons. When the top button is clicked, the Father of the
Active person becomes the Active person. Clicking the bottom
button makes the Mother of the Active person the Active
person. Again, the display is re-adjusted to show four
generations, starting from the newly selected Active person.
person.
</para>
@ -616,15 +634,15 @@
<para>
Right-clicking on any person's box in the Pedigree View will
bring up the context menu. Among other useful items, the
context menu has submenus listing
bring up the &quot;context menu&quot;. Among other useful
items, the context menu has sub-menus listing
<guilabel>Spouses</guilabel>, <guilabel>Siblings</guilabel>,
<guilabel>Children</guilabel>, and
<guilabel>Parents</guilabel> of that person. Insensitive
(grayed out) sub-menus indicate the absence of the data in
the appropriate category. Similarly to the children menu
above, children's and parents' menus distinguish continuing
lines from dead ends.
<guilabel>Parents</guilabel> of that
person. &quot;Greyed-out&quot; sub-menus indicate the absence
of the data in the appropriate category. Similarly to the
children menu above, Childrens' and Parents' menus distinguish
continuing lines from dead ends.
</para>
@ -649,36 +667,57 @@
<para>
An additional advanced scheme of labeling generations exists
in Pedigree View. It becomes available by setting the anchor
on some active person. If the anchor is set, the generations
are labeled as follows. The anchor person (and his/her
generation) is labeled as <guilabel>0</guilabel>. The
ancestor generations are numbered with positive integers
Pedigree View gives you an additional, advanced way of
labeling generations. This feature becomes available by
setting the &quot;anchor&quot; on a selected person. If the
anchor is set, the generations are labeled as follows:
</para>
<itemizedlist>
<listitem>
<para>
The Anchor Person (and his/her generation) is labeled as
<guilabel>0</guilabel>.
</para>
</listitem>
<listitem>
<para>
The ancestor generations are numbered with positive integers
(<guilabel>1</guilabel>,<guilabel>2</guilabel>,
<guilabel>3</guilabel>, etc.) while the descendant
generations are numbered with negative integers
<guilabel>3</guilabel>,etc.).
</para>
</listitem>
<listitem>
<para>
The descendant generations are numbered with negative integers
(<guilabel>-1</guilabel>,<guilabel>-2</guilabel>,
<guilabel>-3</guilabel>, etc.). In all cases, the number
represents the number of generations between the labeled
generation and the anchor person. In this mode, you can
travel along the extensive pedigree line and see the number
of generations counting from the anchor person.
<guilabel>-3</guilabel>, etc.).
</para>
</listitem>
<listitem>
<para>
In all cases, the number represents the number of
generations between the labeled generation and the anchor
person. In this mode, you can travel along the extensive
pedigree line and see the number of generations removed
from the Anchor Person.
</para>
</listitem>
</itemizedlist>
</para><para>
<para>
To set the anchor, select the <guilabel>Set
anchor</guilabel> menu item from the right-click context
menu, when the desired person is the Active person in the
Pedigree View. The labels will change immediately, and the
name of the anchor person will appear at the lower left
corner of the display area. The set anchor person will stay
in effect until either the anchor is removed (by selecting
the <guilabel>Remove anchor</guilabel> item from the context
menu), or until the active person chosen is unrelated to the
anchor person. The latter move can be made using extensive
navigation tools available in &app;, see <xref
linkend="gramps-nav"/> for the detailed reference.
To set the anchor, select the person you want as the Active
person (recall that you can do so in the Pedigree View by
clicking the line that leads to the person from his or her
child). Then, while in Pedigree View, right click anywhere in
the main window. A context menu will appear. Select
<guilabel>Set anchor</guilabel> and you will see the Active
person indicated as the anchor in the lower left corner.
This newly established Anchor Person will remain in effect
until you right-click again and select <guilabel>Remove
anchor</guilabel> from the context menu or until a new Active
person is chosen who is unrelated to the Anchor Person.
</para>
@ -688,6 +727,29 @@
<sect2 id="sources-view">
<title>Sources View</title>
<para>
Sources View lists the sources of certain information stored
in the database. These can include various documents (birth,
death, and marriage certificates, etc.), books, films,
journals, private diaries, - nearly anything that can
provide genealogical evidence. GRAMPS gives you the option
to provide a source for each event you record (births,
deaths, marriages, etc.). The Source View lists the
<guilabel>Title</guilabel>, <guilabel>ID</guilabel>, and
<guilabel>Author</guilabel> of the source, as well as any
<guilabel>Publication</guilabel> information that may be
associated with it.
</para><para>
The list of Sources can be sorted in the usual manner, by
clicking on a column heading. Clicking once sorts in
ascending order, clicking again sorts in descending
order. The <guilabel>Column Editor</guilabel> dialog can be
used to add, remove and rearrange the displayed columns.
</para>
<!-- ==== Figure: Sources View ==== -->
@ -706,29 +768,30 @@
</figure>
<!-- ==== End of Figure ==== -->
<para>
The Sources View lists the sources of information stored in
the database. This can include various documents (birth,
death, and marriage certificates, etc.), books, films,
journals, private diaries; virtually anything that can
be classified as a source of information. The sources can be
used as a reference for any event stored in the
database. The Source View lists the
<guilabel>Title</guilabel>, <guilabel>ID</guilabel>, and the
<guilabel>Author</guilabel> of the source. Any column can be
used for sorting the list. The usual rules apply: one click
for ascending order, another click for descending order.
<guilabel>Column Editor Dialog</guilabel> may be used to
rearrange the displayed columns.
</para>
</sect2>
<!-- ================ Main Window Sub-subsection -->
<sect2 id="places-view">
<title>Places View</title>
<para>
The Places View lists the geographical places in which the
events of the database took place. These could be places of
birth, death, and marriages of people, as well as their
home, employment, education addresses, or any other
conceivable reference to the geographical location. The
Places View lists the places' <guilabel>Name</guilabel>,
<guilabel>ID</guilabel>, <guilabel>Church Parish</guilabel>,
<guilabel>City</guilabel>, <guilabel>County</guilabel>,
<guilabel>State</guilabel>, and
<guilabel>Country</guilabel>. All of these columns can be
used for sorting by the usual sorting rules. The
<guilabel>Column Editor</guilabel> dialog may be used to
add, remove and rearrange the displayed columns.
</para>
<!-- ==== Figure: Places View ==== -->
@ -747,22 +810,6 @@
</figure>
<!-- ==== End of Figure ==== -->
<para>
The Places View lists the geographical places in which the
events of the database took place. These could be places of
birth, death, and marriages of people, as well as their
home, employment, education addresses, or any other
conceivable reference to the geographical location. The
Places View lists the places' <guilabel>Name</guilabel>,
<guilabel>ID</guilabel>, <guilabel>Church Parish</guilabel>,
<guilabel>City</guilabel>, <guilabel>County</guilabel>,
<guilabel>State</guilabel>, and
<guilabel>Country</guilabel>. All of these columns can be
used for sorting by the usual sorting rules.
<guilabel>Column Editor Dialog</guilabel> may be used to
rearrange the displayed columns.
</para>
</sect2>
<!-- ================ Main Window Sub-subsection -->
@ -797,14 +844,13 @@
images, audio files, animation files, etc. The list box on
the bottom lists the <guilabel>Name</guilabel>,
<guilabel>ID</guilabel>, <guilabel>Type</guilabel>, and
<guilabel>Path</guilabel> of the Media Object.
<guilabel>Column Editor Dialog</guilabel> may be used to
<guilabel>Path</guilabel> of the Media Object. The
<guilabel>Column Editor</guilabel> dialog may be used to
rearrange the displayed columns, which obey usual sorting
rules. The top part of the GRAMPS window shows a preview (if
available) and information about the Media Object.
</para>
</sect2>
</sect1>
</chapter>

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

@ -2286,6 +2286,118 @@ directement vers n'importe quelle personne sélectionnée récemment.
<!-- =============== 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

@ -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)
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 less than a year (but still in different years)
# then calculate month diff modulo 12
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
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,6 +48,44 @@ 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,
@ -57,9 +95,13 @@ class DateParserFR(DateParser):
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 = {
@ -78,33 +120,24 @@ class DateParserFR(DateParser):
}
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)),
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._range = re.compile("(%s)\s+(?P<start>.+)\s+(%s)\s+(?P<stop>.+)" %
('|'.join(_range_1),'|'.join(_range_2)),
self._jtext2 =re.compile('(\d+)?.?\s+?%s\s*((\d+)(/\d+)?)?' % self._mon_str,
re.IGNORECASE)
#-------------------------------------------------------------------------
@ -121,13 +154,62 @@ class DateDisplayFR(DateDisplay):
_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
@ -69,6 +142,12 @@ class Check(Tool.Tool):
# 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()
checker = CheckIntegrity(db,parent,trans)
@ -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= {}
@ -262,8 +264,9 @@ class DetDescendantReport(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()
@ -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,6 +161,46 @@ 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:
@ -175,60 +224,18 @@ class FamilyGroup(Report.Report):
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)
if self.missingInfo or father_name != "":
self.dump_parent_line(_("Father"),father_name)
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(_("Father"))
self.doc.write_text(_("Address"))
self.doc.end_paragraph()
self.doc.end_cell()
self.doc.start_cell("FGR-TextContentsEnd",2)
self.doc.start_cell("FGR-TextContents")
self.doc.start_paragraph('FGR-Normal')
self.doc.write_text(father_name)
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()
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.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
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)
if families == 0:
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 = 1
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,10 +426,13 @@ 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()
if spouse_id:
self.doc.start_row()
self.doc.start_cell('FGR-TextChild1')
self.doc.start_paragraph('FGR-Normal')
@ -367,29 +447,45 @@ class FamilyGroup(Report.Report):
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())
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()
if m:
if index == families:
self.dump_child_event('FGR-TextChild2',_("Married"),m)
else:
self.dump_child_event('FGR-TextChild1',_("Married"),m)
def write_report(self):
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()
if self.family:
self.dump_parent(self.family.get_father_handle())
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(self.family.get_mother_handle())
self.dump_parent(family.get_mother_handle())
length = len(self.family.get_child_handle_list())
length = len(family.get_child_handle_list())
if length > 0:
self.doc.start_paragraph("FGR-blank")
self.doc.end_paragraph()
@ -402,11 +498,27 @@ class FamilyGroup(Report.Report):
self.doc.end_cell()
self.doc.end_row()
index = 1
for child_handle in self.family.get_child_handle_list():
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):
@ -478,7 +629,47 @@ class FamilyGroupOptions(ReportOptions.ReportOptions):
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):
"""
@ -489,6 +680,15 @@ class FamilyGroupOptions(ReportOptions.ReportOptions):
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."""
para = BaseDoc.ParagraphStyle()

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:
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,7 +403,8 @@ 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 =""
else:
surname = self.decode(fields[idx])
idx = idx + 1
else:
@ -410,7 +412,8 @@ class GeneWebParser:
if not idx < len(fields):
print "Missing firstname of person in line %d!" % self.lineno
return (idx,None)
firstname = ""
else:
firstname = self.decode(fields[idx])
idx = idx + 1
if idx < len(fields) and father_surname:

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:
try:
mylist.append(str(each))
self.ebuf.set_text(_("Uncollected objects:\n\n") + '\n\n'.join(mylist))
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,7 +55,11 @@ 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)
@ -79,20 +83,23 @@ def impData(database, name,cb=None,cl=0):
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

11190
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