Compare commits

..

56 Commits

Author SHA1 Message Date
de4a0766e7 Update
svn: r4788
2005-06-05 05:19:16 +00:00
078cafc0c8 * src/DateHandler.py: handle generic "en", "fr" cases as a fallback
if the unknown "yy_XX" code is passed. Try yy if yy_XX fails.
* src/dates/Date_*.py: add a default xx case


svn: r4783
2005-06-04 19:08:38 +00:00
c5b68976e1 * src/DateHandler.py: add more English locales
* src/dates/Date_fi.py: fix estimated/calculated, handle span
properly
* src/dates/Makefile.am: remove Date_fi for 2.0.2


svn: r4782
2005-06-04 04:06:47 +00:00
d9edb0bd9c - update translation from template.pot
- translate everything except for a few dozen tips


svn: r4779
2005-06-03 22:01:49 +00:00
c99cd60e81 * src/po/es.po: Translation update for version 2.0.2.
svn: r4778
2005-06-03 21:07:17 +00:00
e4a677f57d * src/plugins/FamilyGroup.py (parse_user_options): Only select
spouse if there is any.


svn: r4777
2005-06-03 20:23:44 +00:00
7d8f3c7dfb * src/EditPlace.py, src/EditSource.py: Detect new objects by
handle.
* src/const.py.in (save_frel): Return English strings.


svn: r4776
2005-06-03 19:29:43 +00:00
bda1ace41f empty place check fixed
svn: r4775
2005-06-03 16:03:45 +00:00
493be971c2 * src/EditPlace.py, src/EditSource.py: Detect new objects by handle.
svn: r4774
2005-06-03 15:36:24 +00:00
aa1fb05e26 * src/ImageSelect (__init__,on_switch_page): Call
display_references using idle_add; (display_references): set
cursor when done.


svn: r4772
2005-06-03 14:09:47 +00:00
7115f24e54 * src/EditPlace (__init__,on_switch_page): Call
display_references using idle_add; (display_references): set
cursor when done.


svn: r4771
2005-06-03 13:44:55 +00:00
97900a087d * src/Utils.py (bold_label,unbold_label,temp_label): optionally
set cursor.
* src/EditSource.py (__init__,on_switch_page): Call
display_references using idle_add; (display_references): set
cursor when done.


svn: r4770
2005-06-03 13:39:36 +00:00
cd8579654a Updated with new template file. Controlled a few strings.
svn: r4769
2005-06-03 12:25:43 +00:00
b614f650d0 Translation fixes for 2.0.2
svn: r4768
2005-06-03 10:16:14 +00:00
6eb7599b68 Translation update for 2.0.2
svn: r4766
2005-06-03 09:32:28 +00:00
2110e52171 added Date_fi.py
svn: r4762
2005-06-02 22:10:28 +00:00
5dd1e197d1 * NEWS: Update.
svn: r4761
2005-06-02 21:23:28 +00:00
e97199cba3 * src/po/ru.po: Update for 2.0.2.
svn: r4760
2005-06-02 21:05:08 +00:00
bb2e2fd1cc Filter problem fixes
svn: r4759
2005-06-02 20:31:39 +00:00
aceb486b79 * src/ReadGedcom.py (get_next): Use single space to split the line
into level, tag, and the field contents; strip extra white space
off the tag name.


svn: r4758
2005-06-02 20:06:37 +00:00
85fa8c09ea * src/Utils.py (probably_alive): If no year is given it now treats people as dead when they have a death event instead of counting them as alive in the curent year when they died in the current year.
svn: r4752
2005-06-01 20:36:23 +00:00
f283347987 * src/po/de.po: Updated translation from Anton Huber
svn: r4751
2005-06-01 19:25:28 +00:00
2e7ad59d01 * src/PeopleModel.py: Improve rebuid times by using database cursor,
caching sort names, and replacing loops with map/lamba
* src/PeopleView.py: prevent goto_active_person reentrancy, use get_selected_objects
instead of selected_foreach, combine row_changed and set_dnd_target into the same
callback, rebuild only affected surname on person-update if pissible


svn: r4750
2005-06-01 18:02:53 +00:00
31650baf2c * src/plugins/Makefile.am: Don't ship NavWebPage yet.
* src/po/template.po: Update for 2.0.2.


svn: r4749
2005-06-01 15:09:55 +00:00
bfa94869bc * src/plugins/Checkpoint.py: add support for custom command
svn: r4747
2005-06-01 03:45:40 +00:00
447191f427 * src/DbPrompter.py: Properly return False if opening a file failed
svn: r4740
2005-05-31 15:30:42 +00:00
fdda045607 * src/po/de.po: Updated translation from Anton Huber
svn: r4739
2005-05-31 13:53:01 +00:00
5ce490e3fa * src/plugins/Checkpoint.py: Start of a checkpoint tool
svn: r4738
2005-05-31 03:21:10 +00:00
d77174143d * src/ArgHandler.py (handle_args) Exit if opening a file failed
* src/Errors.py: New exception type "FileVersionError"
* src/GrampsDbBase.py (version_supported): New method
* src/GrampsBSDDB.py (version_supported): New method
* src/gramps_main.py (read_file) catch FileVersionError; (post_load): only load if version_supported()
* src/ReadGrdb.py (importData): only load if version_supported()


svn: r4734
2005-05-30 15:19:04 +00:00
ebfbdce49b * src/DbPrompter.py: fix handling of spaces when creating a new
file - use open instead of "touch"


svn: r4733
2005-05-30 15:16:12 +00:00
1fc782a60e * src/po/sv.po: Typo (closes 1211150).
svn: r4732
2005-05-30 15:00:57 +00:00
01e6dedae9 * src/gramps_main.py (read_file): Optimize exception handling of load_database errors.
* src/ArgHandler.py (auto_save_load): Return actual status of read_file instead of always 1. This will now open the select database dialog on autoload errors.


svn: r4730
2005-05-28 19:29:29 +00:00
0cb7d90257 * configure.in: Bump up the version number after 2.0.1.
svn: r4728
2005-05-28 15:55:21 +00:00
1ab9c7c6d8 Update
svn: r4727
2005-05-28 15:54:48 +00:00
d120265624 * src/gramps_main.py (change_active_person): Dont change to the current active person again.
* src/FamilyView.py (drag_data_received): Allow reordering of childs when they were not correctly ordered before.


svn: r4725
2005-05-28 06:21:37 +00:00
811014e1c2 Translation fixes for 2.0.1
svn: r4711
2005-05-27 17:30:42 +00:00
d15f8ffe07 Translation fixes for 2.0.1
svn: r4706
2005-05-27 13:49:50 +00:00
e177fe4030 * src/PeopleView.py: back port anti-flicker code from HEAD
* src/dates/Date_de.py: use "etwa" instead of "circa"


svn: r4699
2005-05-27 02:47:01 +00:00
175ee0f498 * src/DateDisplay.py: don't mark date formats as translatable
svn: r4698
2005-05-26 22:31:04 +00:00
63dbb12bfa Updated all the fuzzy strings to translate correct. Still need to wash them.
The tips are not translated


svn: r4692
2005-05-26 16:08:58 +00:00
2fa9ffc7fe * src/DateDisplay.py: properly encode french republican dates as unicode
svn: r4682
2005-05-26 00:12:34 +00:00
745585d93c * src/EditSource.py (DelSrcQuery.query_response), src/EditPlace.py (DeletePlaceQuery.query_response), src/ImageSelect.py (DeleteMediaQuery.query_response): Block signals while removing the references of the to be deleted object to get much more speed.
* src/plugins/TestcaseGenerator.py: Add place, media and source references.
* src/SourceView.py (button_press): Handle case of no selection.


svn: r4681
2005-05-25 21:09:51 +00:00
27e22a5b21 * src/NameDisplay.py (sorted): Use sorted name, not display name flag.
* src/Sort.py (by_sorted_name): Add method.
* src/WebPage (dump_index): Proper sorting, for both last name
sections and the names within each section.


svn: r4679
2005-05-25 18:51:10 +00:00
b444385631 * src/WriteGedcom.py (write_person): Typo.
svn: r4677
2005-05-25 17:20:47 +00:00
6dd80f4955 Fixed obvius errors in the strings up to 301. Need washing.
svn: r4675
2005-05-25 15:19:38 +00:00
0b8985216c Translated the few untranslated strings that did not have anyting to do with the tips.
svn: r4674
2005-05-25 14:55:58 +00:00
e3431e1d98 2005-05-25 Richard Taylor <rjt-gramps@thegrindstone.me.uk>
* src/plugins/ScratchPad.py: disabled search because it does not do
	  what the user expects.

2005-05-25  Richard Taylor <rjt-gramps@thegrindstone.me.uk>
	* src/plugins/ScratchPad.py: rename on_scratch_pad_delete_event for consistency
        * src/plugins/scratchpad.glade: add on_scratch_pad_delete_event to fix bug
	  when window is close using the window manager close button.


svn: r4673
2005-05-25 13:31:18 +00:00
59fb9bbb64 Update
svn: r4664
2005-05-24 02:49:53 +00:00
e09a5741b7 * src/MergePeople.py: clean up and refactoring of code.
svn: r4663
2005-05-24 02:45:48 +00:00
db9b15a18c * src/po/ru.po: More tranlsated tips.
svn: r4662
2005-05-23 23:54:26 +00:00
9273ca6886 Exit on DBError for now
svn: r4661
2005-05-23 21:25:16 +00:00
1e81e32965 Catch db.DBError
svn: r4660
2005-05-23 21:08:29 +00:00
32b8401167 translation updates, remove Finnish Date parser for now
svn: r4659
2005-05-23 20:55:25 +00:00
59d4cfa35e Added additional BSDDB exception case
svn: r4658
2005-05-23 20:31:56 +00:00
3ed52a7ed6 Translation update for 2.0.1
svn: r4657
2005-05-23 18:49:52 +00:00
a109d25c0b * src/MergePeople.py: merge improvements, merge data not merged before.
svn: r4656
2005-05-23 04:08:41 +00:00
55 changed files with 13086 additions and 11947 deletions

@ -1,3 +1,191 @@
2005-06-04 Don Allingham <don@gramps-project.org>
* src/DateHandler.py: handle generic "en", "fr" cases as a fallback
if the unknown "yy_XX" code is passed. Try yy if yy_XX fails.
* src/dates/Date_*.py: add a default xx case
* Release: Version 2.0.2 "Little fermented curd will do the trick"
released.
2005-06-03 Don Allingham <don@gramps-project.org>
* src/DateHandler.py: add more English locales
* src/dates/Date_fi.py: fix estimated/calculated, handle span
properly
* src/dates/Makefile.am: remove Date_fi for 2.0.2
2005-06-04 Eero Tamminen <eerot@sf>
* src/po/fi.po: Updated translation to 2.0.2 template.pot.
Everything except for a few dozen tips is translated.
2005-06-03 Julio Sanchez <jsanchez@users.sourceforge.net>
* src/po/es.po: Translation update for version 2.0.2.
2005-06-03 Don Allingham <don@gramps-project.org>
* src/EditPerson.py: Don't add empty strings to pdmap
* src/AutoComp.py: don't add empty strings to completion
2005-06-03 Alexander Roitman <shura@gramps-project.org>
* src/Utils.py (bold_label,unbold_label,temp_label): optionally
set cursor.
* src/EditSource.py (__init__,on_switch_page): Call
display_references using idle_add; (display_references): set
cursor when done.
* src/EditPlace (__init__,on_switch_page): Call
display_references using idle_add; (display_references): set
cursor when done.
* src/ImageSelect (__init__,on_switch_page): Call
display_references using idle_add; (display_references): set
cursor when done.
* src/EditPlace.py, src/EditSource.py: Detect new objects by
handle.
* src/const.py.in (save_frel): Return English strings.
* src/plugins/FamilyGroup.py (parse_user_options): Only select
spouse if there is any.
2005-06-03 Jens Arvidsson <jya@sverige.nu>
* src/po/sv.po: Minor fixes found via pochkpyvar.pl.
2005-06-03 Jens Arvidsson <jya@sverige.nu>
* src/po/sv.po: Translation update for version 2.0.2.
2005-06-02 Don Allingham <don@gramps-project.org>
* src/dates/Date_fi.py: Finnish date parser
* src/dates/Makefile.am: added Date_fi.py
* src/ChooseParents.py: fixed all_males filtering problem, display
all people when a person is blocked by the likely filter
2005-06-02 Alex Roitman <shura@gramps-project.org>
* src/ReadGedcom.py (get_next): Use single space to split the line
into level, tag, and the field contents; strip extra white space
off the tag name.
* src/po/ru.po: Update for 2.0.2.
* NEWS: Update.
2005-06-01 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/Utils.py (probably_alive): If no year is given it now treats
people as dead when they have a death event instead of counting them
as alive in the curent year when they died in the current year.
2005-06-01 Anton Huber <anton_huber@gmx.de>
* src/po/de.po: Updated translation
2005-06-01 Don Allingham <don@gramps-project.org>
* src/PeopleModel.py: Improve rebuid times by using database cursor,
caching sort names, and replacing loops with map/lamba
* src/PeopleView.py: prevent goto_active_person reentrancy, use get_selected_objects
instead of selected_foreach, combine row_changed and set_dnd_target into the same
callback, rebuild only affected surname on person-update if pissible
2005-06-01 Alex Roitman <shura@gramps-project.org>
* src/plugins/Makefile.am: Don't ship NavWebPage yet.
* src/po/template.po: Update for 2.0.2.
2005-05-31 Don Allingham <don@gramps-project.org>
* src/plugins/Checkpoint.py: add support for custom command
2005-05-30 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/DbPrompter.py: Properly return False if opening a file failed
2005-05-31 Anton Huber <anton_huber@gmx.de>
* src/po/de.po: Updated translation
2005-05-30 Don Allingham <don@gramps-project.org>
* src/plugins/Checkpoint.py: Start of a checkpoint tool
2005-05-30 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/ArgHandler.py (handle_args) Exit if opening a file failed
* src/Errors.py: New exception type "FileVersionError"
* src/GrampsDbBase.py (version_supported): New method
* src/GrampsBSDDB.py (version_supported): New method
* src/gramps_main.py (read_file) catch FileVersionError;
(post_load): only load if version_supported()
* src/ReadGrdb.py (importData): only load if version_supported()
2005-05-30 Matt Brubeck <mbrubeck@cs.hmc.edu>
* src/DbPrompter.py: fix handling of spaces when creating a new
file - use open instead of "touch"
2005-05-30 Alex Roitman <shura@gramps-project.org>
* src/po/sv.po: Typo (closes 1211150).
2005-05-28 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/gramps_main.py (read_file): Optimize exception handling of
load_database errors.
* src/ArgHandler.py (auto_save_load): Return actual status of
read_file instead of always 1. This will now open the select database
dialog on autoload errors.
2005-05-28 Alex Roitman <shura@gramps-project.org>
* configure.in: Bump up the version number after 2.0.1.
2005-05-28 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/gramps_main.py (change_active_person): Dont change to the
current active person again.
* src/FamilyView.py (drag_data_received): Allow reordering of childs
when they were not correctly ordered before.
2005-05-23 Jens Arvidsson <jya@sverige.nu>
* src/po/sv.po: A few fixes to the Swedish translation.
2005-05-26 Don Allingham <don@gramps-project.org>
* src/PeopleView.py: back port anti-flicker code from HEAD
* src/dates/Date_de.py: use "etwa" instead of "circa"
* src/DateDisplay.py: don't mark date formats as translatable
2005-05-25 Don Allingham <don@gramps-project.org>
* src/DateDisplay.py: properly encode french republican dates as unicode
2005-05-26 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/EditSource.py (DelSrcQuery.query_response),
src/EditPlace.py (DeletePlaceQuery.query_response),
src/ImageSelect.py (DeleteMediaQuery.query_response): Block
signals while removing the references of the to be deleted
object to get much more speed.
* src/plugins/TestcaseGenerator.py: Add place, media and source
references.
* src/SourceView.py (button_press): Handle case of no selection.
2005-05-25 Alex Roitman <shura@gramps-project.org>
* src/WriteGedcom.py (write_person): Typo.
* src/NameDisplay.py (sorted): Use sorted name, not display name flag.
* src/Sort.py (by_sorted_name): Add method.
* src/WebPage (dump_index): Proper sorting, for both last name
sections and the names within each section.
2005-05-25 Richard Taylor <rjt-gramps@thegrindstone.me.uk>
* src/plugins/ScratchPad.py: disabled search because it does not do
what the user expects.
2005-05-25 Richard Taylor <rjt-gramps@thegrindstone.me.uk>
* src/plugins/ScratchPad.py: rename on_scratch_pad_delete_event for consistency
* src/plugins/scratchpad.glade: add on_scratch_pad_delete_event to fix bug
when window is close using the window manager close button.
2005-05-23 Don Allingham <don@gramps-project.org>
* src/MergePeople.py: clean up and refactoring of code.
* Release: Version 2.0.1 "None shall pass" released.
2005-05-23 Alex Roitman <shura@gramps-project.org>
* src/po/ru.po: More tranlsated tips.
2005-05-23 Eero Tamminen <eerot@sf>
* src/po/fi.po: Translate all fuzzy strings. Tips are still to be
translated
* src/plugins/StatisticsChart.py: Fix a typo in one string
(I actually changed the string, but now it should actually be
understandable i.e. something people can localize)
* src/dates/Makefile.am, src/dates/Date_fi.py: Remove Finnish date
parser. Unfortunately I don't have time either to fix DateParser.py
regexps matches to be position independent or write the required
(almost) duplicate code to Date_fi.py directly
2005-05-23 Jens Arvidsson <jya@sverige.nu>
* src/po/sv.po: Translation update for version 2.0.1.
2005-05-22 Don Allingham <don@gramps-project.org>
* src/MergePeople.py: merge improvements, merge data not merged before.
2005-05-22 Alex Roitman <shura@gramps-project.org>
* src/ImageSelect.py (item_event): Do nothing if nothing is selected.
* src/EditSource.py (button_press): Return if no data.

@ -1,3 +1,8 @@
Version 2.0.2 -- the "Little fermented curd will do the trick" release
* Updated German translation (Anton Huber).
* Usability improvements for large databases.
* Bug fixes
Version 2.0.1 -- the "None shall pass" release
* Example database function is back.
* Entering incestuous relations is possible (with the warning).

@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script.
dnl May need to run automake && aclocal first
AC_PREREQ(2.57)
AC_INIT(gramps, 2.0.1, gramps-bugs@lists.sourceforge.net)
AC_INIT(gramps, 2.0.2, gramps-bugs@lists.sourceforge.net)
AC_CONFIG_SRCDIR(src/gramps.py)
AM_INIT_AUTOMAKE(1.6.3)
RELEASE=0.CVS$(head -c 10 ${srcdir}/ChangeLog | tr -d '-')

@ -102,6 +102,7 @@
2 DATE BET. 1794 - 1796
2 PLAC Tommarp, Kristianstad Lan, Sweden
1 DEAT
2 DATE deceased
2 PLAC Sweden
1 REFN 366
1 FAMS @F03@

@ -228,20 +228,17 @@ class ArgHandler:
import GrampsBSDDB
self.parent.db.close()
self.parent.db = GrampsBSDDB.GrampsBSDDB()
self.parent.read_file(filename)
return 1
return self.parent.read_file(filename)
elif filetype == const.app_gramps_xml:
import GrampsXMLDB
self.parent.db.close()
self.parent.db = GrampsXMLDB.GrampsXMLDB()
self.parent.read_file(filename)
return 1
return self.parent.read_file(filename)
elif filetype == const.app_gedcom:
import GrampsGEDDB
self.parent.db.close()
self.parent.db = GrampsGEDDB.GrampsGEDDB()
self.parent.read_file(filename)
return 1
return self.parent.read_file(filename)
else:
return 0
@ -307,6 +304,8 @@ class ArgHandler:
# Add the file to the recent items
RecentFiles.recent_files(filename,filetype)
self.parent.build_recent_menu()
else:
os._exit(1)
return
if self.open:

@ -32,7 +32,8 @@ def fill_combo(combo,data_list):
store = gtk.ListStore(gobject.TYPE_STRING)
for data in data_list:
store.append(row=[data])
if data:
store.append(row=[data])
combo.set_model(store)
combo.set_text_column(0)
@ -45,7 +46,8 @@ def fill_combo(combo,data_list):
def fill_entry(entry,data_list):
store = gtk.ListStore(gobject.TYPE_STRING)
for data in data_list:
store.append(row=[data])
if data:
store.append(row=[data])
completion = gtk.EntryCompletion()
completion.set_model(store)
@ -56,7 +58,8 @@ def fill_entry(entry,data_list):
def fill_option_text(combobox,data):
store = gtk.ListStore(str)
for item in data:
store.append(row=[item])
if item:
store.append(row=[item])
combobox.set_model(store)
combobox.set_active(0)

@ -93,7 +93,7 @@ class ChooseParents:
db.connect('person-add', self.redraw)
db.connect('person-update', self.redraw)
db.connect('person-delete', self.redraw)
db.connect('person-rebuild', self.redraw2)
db.connect('person-rebuild', self.redraw)
# set default filters
self.all_males_filter = GenericFilter.GenericFilter()
@ -286,14 +286,6 @@ class ChooseParents:
def redraw(self,handle_list):
self.redrawf()
self.redrawm()
# self.father_model.rebuild_data()
# self.mother_model.rebuild_data()
def redraw2(self):
self.redrawf()
self.redrawm()
# self.father_model.rebuild_data()
# self.mother_model.rebuild_data()
def redrawf(self):
"""Redraws the potential father list"""
@ -326,7 +318,7 @@ class ChooseParents:
def showallf_toggled(self,obj):
if self.father_filter == self.likely_males_filter:
self.father_filter = self.all_females_filter
self.father_filter = self.all_males_filter
else:
self.father_filter = self.likely_males_filter
self.redrawf()
@ -529,11 +521,13 @@ class ChooseParents:
self.father_selection.select_path(path)
self.father_list.scroll_to_cell(path,None,1,0.5,0)
except KeyError:
WarningDialog(_("Added person is not visible"),
_("The person you added is currently "
"not visible due to the chosen filter. "
"This may occur if you did not specify "
"a birth date."))
self.father_filter = self.all_males_filter
self.showallf_toggled(None)
path = self.father_model.on_get_path(handle)
top_path = self.father_model.on_get_path(name)
self.father_list.expand_row(top_path,0)
self.father_selection.select_path(path)
self.father_list.scroll_to_cell(path,None,1,0.5,0)
else:
try:
path = self.mother_model.on_get_path(handle)
@ -542,11 +536,13 @@ class ChooseParents:
self.mother_selection.select_path(path)
self.mother_list.scroll_to_cell(path,None,1,0.5,0)
except:
WarningDialog(_("Added person is not visible"),
_("The person you added is currently "
"not visible due to the chosen filter. "
"This may occur if you did not specify "
"a birth date."))
self.mother_filter = self.all_females_filter
self.showallm_toggled(None)
path = self.mother_model.on_get_path(handle)
top_path = self.mother_model.on_get_path(name)
self.mother_list.expand_row(top_path,0)
self.mother_selection.select_path(path)
self.mother_list.scroll_to_cell(path,None,1,0.5,0)
def add_parent_clicked(self,obj):
"""Called with the Add New Person button is pressed. Calls the QuickAdd

@ -83,11 +83,20 @@ class DateDisplay:
)
_french = (
'', u'Vend\xc3\xa9miaire', 'Brumaire',
'Frimaire', u'Niv\xc3\xb4se', u'Pluvi\xc3\xb4se',
u'Vent\xc3\xb4se', 'Germinal', u'Flor\xc3\xa9al',
'Prairial', 'Messidor', 'Thermidor',
'Fructidor', 'Extra'
'',
unicode("Vend<EFBFBD>miaire",'latin-1'),
'Brumaire',
'Frimaire',
unicode("Niv<EFBFBD>se",'latin-1'),
unicode("Pluvi<EFBFBD>se",'latin-1'),
unicode("Vent<EFBFBD>se",'latin-1'),
'Germinal',
unicode("Flor<EFBFBD>al",'latin-1'),
'Prairial',
'Messidor',
'Thermidor',
'Fructidor',
'Extra'
)
_persian = (
@ -271,9 +280,9 @@ class DateDisplay:
if date_val[1] == 0:
return year
else:
return "%s %d" % (month_list[date_val[1]],year)
return u"%s %d" % (month_list[date_val[1]],year)
else:
return "%s %d, %s" % (month_list[date_val[1]],date_val[0],year)
return u"%s %d, %s" % (month_list[date_val[1]],date_val[0],year)
def _display_french(self,date_val):
return self._display_calendar(date_val,self._french)
@ -293,8 +302,8 @@ class DateDisplayEn(DateDisplay):
"""
formats = (
_("YYYY-MM-DD (ISO)"), _("Numerical"), _("Month Day, Year"),
_("MON DAY, YEAR"), _("Day Month Year"), _("DAY MON YEAR")
"YYYY-MM-DD (ISO)", "Numerical", "Month Day, Year",
"MON DAY, YEAR", "Day Month Year", "DAY MON YEAR"
)
def __init__(self,format=None):

@ -46,24 +46,18 @@ import DateDisplay
#
#-------------------------------------------------------------------------
_lang = locale.getlocale(locale.LC_TIME)[0]
if _lang:
_lang_short = _lang.split('_')[0]
else:
_lang_short = "C"
_lang_to_parser = {
'C' : DateParser.DateParser,
'en_US' : DateParser.DateParser,
'en_GB' : DateParser.DateParser,
'en_AU' : DateParser.DateParser,
'en_CA' : DateParser.DateParser,
'en_SE' : DateParser.DateParser,
'en' : DateParser.DateParser,
}
_lang_to_display = {
'C' : DateDisplay.DateDisplayEn,
'en_US' : DateDisplay.DateDisplayEn,
'en_GB' : DateDisplay.DateDisplayEn,
'en_AU' : DateDisplay.DateDisplayEn,
'en_CA' : DateDisplay.DateDisplayEn,
'en_SE' : DateDisplay.DateDisplayEn,
'en' : DateDisplay.DateDisplayEn,
'zh_CN' : DateDisplay.DateDisplay,
'zh_TW' : DateDisplay.DateDisplay,
@ -123,7 +117,10 @@ load_plugins(datesDir)
#-------------------------------------------------------------------------
try:
parser = _lang_to_parser[_lang]()
if _lang_to_parser.has_key(_lang):
parser = _lang_to_parser[_lang]
else:
parser = _lang_to_parser[_lang_short]
except:
print "Date parser for",_lang,"not available, using default"
parser = _lang_to_parser["C"]()
@ -138,7 +135,11 @@ except:
val = 0
try:
displayer = _lang_to_display[_lang](val)
if _lang_to_display.has_key(_lang):
displayer = _lang_to_display[_lang](val)
else:
displayer = _lang_to_display[_lang_short](val)
except:
print "Date displayer for",_lang,"not available, using default"
displayer = _lang_to_display["C"](val)

@ -257,9 +257,9 @@ class DateParser:
re.IGNORECASE)
self._qual = re.compile("%s\s+(.+)" % self._qual_str,
re.IGNORECASE)
self._span = re.compile("(from)\s+(.+)\s+(to)\s+(.+)",
self._span = re.compile("(from)\s+(?P<start>.+)\s+to\s+(?P<stop>.+)",
re.IGNORECASE)
self._range = re.compile("(bet|bet.|between)\s+(.+)\s+(and)\s+(.+)",
self._range = re.compile("(bet|bet.|between)\s+(?P<start>.+)\s+and\s+(?P<stop>.+)",
re.IGNORECASE)
self._modifier = re.compile('%s\s+(.*)' % self._mod_str,
re.IGNORECASE)
@ -452,10 +452,9 @@ class DateParser:
"""
match = self._span.match(text)
if match:
grps = match.groups()
text_parser = self.parser[cal]
start = self._parse_subdate(grps[1],text_parser)
stop = self._parse_subdate(grps[3],text_parser)
start = self._parse_subdate(match.group('start'),text_parser)
stop = self._parse_subdate(match.group('stop'),text_parser)
date.set(qual,Date.MOD_SPAN,cal,start + stop)
return 1
return 0
@ -468,10 +467,9 @@ class DateParser:
"""
match = self._range.match(text)
if match:
grps = match.groups()
text_parser = self.parser[cal]
start = self._parse_subdate(grps[1],text_parser)
stop = self._parse_subdate(grps[3],text_parser)
start = self._parse_subdate(match.group('start'),text_parser)
stop = self._parse_subdate(match.group('stop'),text_parser)
date.set(qual,Date.MOD_RANGE,cal,start + stop)
return 1
return 0

@ -193,17 +193,19 @@ class ExistingDbPrompter:
filetype = get_mime_type(filename)
(the_path,the_file) = os.path.split(filename)
choose.destroy()
try:
if open_native(self.parent,filename,filetype):
return True
except db.DBInvalidArgError, msg:
QuestionDialog.ErrorDialog(
_("Could not open file: %s") % filename, msg[1])
return False
except:
import DisplayTrace
DisplayTrace.DisplayTrace()
return False
if filetype in [const.app_gramps,const.app_gramps_xml,
const.app_gedcom]:
try:
return open_native(self.parent,filename,filetype)
except db.DBInvalidArgError, msg:
QuestionDialog.ErrorDialog(
_("Could not open file: %s") % filename, msg[1])
return False
except:
import DisplayTrace
DisplayTrace.DisplayTrace()
return False
# The above native formats did not work, so we need to
# look up the importer for this format
@ -472,7 +474,8 @@ class NewSaveasDbPrompter:
continue
filetype = type_selector.get_value()
if filetype == 'auto':
os.system('touch %s' % filename)
new_file = open(filename, "w")
new_file.close()
filetype = get_mime_type(filename)
(the_path,the_file) = os.path.split(filename)
choose.destroy()
@ -531,17 +534,14 @@ def open_native(parent,filename,filetype):
while gtk.events_pending():
gtk.main_iteration()
parent.read_file(filename,update_msg)
success = parent.read_file(filename,update_msg)
msg_top.destroy()
success = True
elif filetype == const.app_gramps_xml:
parent.db = GrampsXMLDB.GrampsXMLDB()
parent.read_file(filename)
success = True
success = parent.read_file(filename)
elif filetype == const.app_gedcom:
parent.db = GrampsGEDDB.GrampsGEDDB()
parent.read_file(filename)
success = True
success = parent.read_file(filename)
if success:
# Add the file to the recent items

@ -537,7 +537,8 @@ class EditPerson:
cursor = self.db.get_place_cursor()
data = cursor.next()
while data:
self.pdmap[data[1][2]] = data[0]
if data[1][2]:
self.pdmap[data[1][2]] = data[0]
data = cursor.next()
cursor.close()
@ -620,7 +621,7 @@ class EditPerson:
self.close_child_windows()
self.remove_itself_from_winsmenu()
self.window.destroy()
def add_itself_to_winsmenu(self):
self.parent.child_windows[self.orig_handle] = self
win_menu_label = self.name_display.display(self.person)

@ -61,21 +61,22 @@ class EditPlace:
def __init__(self,parent,place,parent_window=None):
self.parent = parent
if place.get_handle():
if place and place.get_handle():
if self.parent.child_windows.has_key(place.get_handle()):
self.parent.child_windows[place.get_handle()].present(None)
return
else:
self.win_key = place.get_handle()
self.ref_not_loaded = 1
else:
self.win_key = self
self.ref_not_loaded = 0
self.name_display = NameDisplay.displayer.display
self.place = place
self.db = parent.db
self.child_windows = {}
self.path = parent.db.get_save_path()
self.not_loaded = 1
self.ref_not_loaded = 1
self.lists_changed = 0
if place:
self.srcreflist = place.get_source_references()
@ -237,12 +238,15 @@ class EditPlace:
self.redraw_url_list()
self.redraw_location_list()
self.display_references()
if parent_window:
self.top.set_transient_for(parent_window)
self.add_itself_to_menu()
self.top_window.get_widget('ok').set_sensitive(not self.db.readonly)
self.top.show()
if self.ref_not_loaded:
Utils.temp_label(self.refs_label,self.top)
gobject.idle_add(self.display_references)
self.ref_not_loaded = 0
def on_delete_event(self,obj,b):
self.glry.close()
@ -407,7 +411,8 @@ class EditPlace:
self.glry.load_images()
elif page == 6 and self.ref_not_loaded:
self.ref_not_loaded = 0
self.display_references()
Utils.temp_label(self.refs_label,self.top)
gobject.idle_add(self.display_references)
text = unicode(self.note_buffer.get_text(self.note_buffer.get_start_iter(),
self.note_buffer.get_end_iter(),False))
if text:
@ -544,9 +549,9 @@ class EditPlace:
self.refinfo.get_buffer().set_text(msg)
if any:
Utils.bold_label(self.refs_label)
self.ref_not_loaded = 0
Utils.bold_label(self.refs_label,self.top)
else:
Utils.unbold_label(self.refs_label,self.top)
#-------------------------------------------------------------------------
#
@ -577,9 +582,9 @@ class DeletePlaceQuery:
def query_response(self):
trans = self.db.transaction_begin()
self.db.disable_signals()
place_handle = self.place.get_handle()
self.db.remove_place(place_handle,trans)
for handle in self.db.get_person_handles(sort_handles=False):
person = self.db.get_person_from_handle(handle)
@ -599,5 +604,7 @@ class DeletePlaceQuery:
event.remove_handle_references('Place',place_handle)
self.db.commit_event(event,trans)
self.db.enable_signals()
self.db.remove_place(place_handle,trans)
self.db.transaction_commit(trans,
_("Delete Place (%s)") % self.place.get_title())

@ -32,6 +32,7 @@ from gettext import gettext as _
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gobject
import gtk.glade
import gnome
@ -60,6 +61,10 @@ class EditSource:
self.source = source
else:
self.source = RelLib.Source()
if self.source.get_handle():
self.ref_not_loaded = 1
else:
self.ref_not_loaded = 0
self.db = db
self.parent = parent
self.name_display = NameDisplay.displayer.display
@ -74,7 +79,6 @@ class EditSource:
self.child_windows = {}
self.path = db.get_save_path()
self.not_loaded = 1
self.ref_not_loaded = 1
self.lists_changed = 0
self.gallery_ok = 0
mode = not self.db.readonly
@ -180,11 +184,14 @@ class EditSource:
self.top_window.get_widget('ok').set_sensitive(not self.db.readonly)
self.display_references()
if parent_window:
self.top.set_transient_for(parent_window)
self.add_itself_to_menu()
self.top.show()
if self.ref_not_loaded:
self.ref_not_loaded = 0
Utils.temp_label(self.refs_label,self.top)
gobject.idle_add(self.display_references)
self.data_sel = self.datalist.get_selection()
def on_add_data_clicked(self,widget):
@ -343,9 +350,9 @@ class EditSource:
self.model.add([_("Media"),gramps_id,name],(5,handle))
if any:
Utils.bold_label(self.refs_label)
Utils.bold_label(self.refs_label,self.top)
else:
Utils.unbold_label(self.refs_label)
Utils.unbold_label(self.refs_label,self.top)
self.ref_not_loaded = 0
@ -403,7 +410,8 @@ class EditSource:
self.gallery.load_images()
elif page == 3 and self.ref_not_loaded:
self.ref_not_loaded = 0
self.display_references()
Utils.temp_label(self.refs_label,self.top)
gobject.idle_add(self.display_references)
text = unicode(self.notes_buffer.get_text(self.notes_buffer.get_start_iter(),
self.notes_buffer.get_end_iter(),False))
if text:
@ -420,6 +428,7 @@ class DelSrcQuery:
def query_response(self):
trans = self.db.transaction_begin()
self.db.disable_signals()
(person_list,family_list,event_list,
place_list,source_list,media_list) = self.the_lists
@ -456,6 +465,7 @@ class DelSrcQuery:
media.remove_source_references(src_handle_list)
self.db.commit_media_object(media,trans)
self.db.enable_signals()
self.db.remove_source(self.source.get_handle(),trans)
self.db.transaction_commit(
trans,_("Delete Source (%s)") % self.source.get_title())

@ -90,3 +90,15 @@ class GConfSchemaError(Exception):
def __str__(self):
return self.value
class FileVersionError(Exception):
"""
Error used to report that a file could not be read because
it is written in an unsupported version of the file format.
"""
def __init__(self,value):
Exception.__init__(self)
self.value = value
def __str__(self):
return self.value

@ -790,6 +790,7 @@ class FamilyView:
self.parent.db.commit_family(family,trans)
self.parent.db.commit_person(person,trans)
# TODO: Add child ordered by birth day
family.add_child_handle(new_person.get_handle())
new_person.add_parent_family_handle(family.get_handle(),
RelLib.Person.CHILD_REL_BIRTH,
@ -1467,11 +1468,15 @@ class FamilyView:
src = spath[0]
child_list = self.family.get_child_handle_list()
# Check if the children were in order before the attempt to reorder
was_ordered = self.birth_dates_in_order(child_list)
obj = child_list[src]
child_list.remove(obj)
child_list.insert(row,obj)
if self.birth_dates_in_order(child_list) == 0:
# abort if a valid order was attempt to destroy
if was_ordered and self.birth_dates_in_order(child_list) == False:
WarningDialog(_("Attempt to Reorder Children Failed"),
_("Children must be ordered by their birth dates."))
return

@ -111,6 +111,9 @@ class GrampsBSDDB(GrampsDbBase):
def get_media_cursor(self):
return GrampsBSDDBCursor(self.media_map)
def version_supported(self):
return self.metadata.get('version',0) <= _DBVERSION
def need_upgrade(self):
return not self.readonly and self.metadata.get('version',0) < _DBVERSION
@ -407,6 +410,7 @@ class GrampsBSDDB(GrampsDbBase):
"Sponsored", "Foster", "Unknown", "Other", ]
version = self.metadata.get('version',0)
if version < 2:
self.upgrade_2(child_rel_notrans)
if version < 3:

@ -191,6 +191,10 @@ class GrampsDbBase(GrampsDBCallback.GrampsDBCallback):
self.place2title = {}
self.name_group = {}
def version_supported(self):
""" Returns True when the file has a supported version"""
return True
def need_upgrade(self):
return False

@ -892,14 +892,16 @@ class GlobalMediaProperties:
self.win_key = self
self.child_windows = {}
self.obj = obj
self.alist = self.obj.get_attribute_list()[:]
self.lists_changed = 0
self.db = db
self.refs = 0
if obj:
self.date_object = Date.Date(self.obj.get_date_object())
self.alist = self.obj.get_attribute_list()[:]
self.refs = 0
else:
self.date_object = Date.Date()
self.alist = []
self.refs = 1
self.path = self.db.get_save_path()
self.change_dialog = gtk.glade.XML(const.imageselFile,
@ -1012,11 +1014,13 @@ class GlobalMediaProperties:
self.change_dialog.get_widget(name).set_sensitive(mode)
self.redraw_attr_list()
self.display_refs()
if parent_window:
self.window.set_transient_for(parent_window)
self.add_itself_to_menu()
self.window.show()
if not self.refs:
Utils.temp_label(self.refs_label,self.window)
gobject.idle_add(self.display_refs)
def on_delete_event(self,obj,b):
self.close_child_windows()
@ -1090,8 +1094,6 @@ class GlobalMediaProperties:
return
def display_refs(self):
if self.refs == 1:
return
self.refs = 1
(person_list,family_list,event_list,place_list,source_list
@ -1135,13 +1137,14 @@ class GlobalMediaProperties:
self.refmodel.add([_("Source"),gramps_id,name])
if any:
Utils.bold_label(self.refs_label)
Utils.bold_label(self.refs_label,self.window)
else:
Utils.unbold_label(self.refs_label)
Utils.unbold_label(self.refs_label,self.window)
def on_notebook_switch_page(self,obj,junk,page):
if page == 3:
self.display_refs()
if page == 3 and not self.refs:
Utils.temp_label(self.refs_label,self.window)
gobject.idle_add(self.display_refs)
t = self.notes.get_buffer()
text = unicode(t.get_text(t.get_start_iter(),t.get_end_iter(),False))
if text:
@ -1243,6 +1246,7 @@ class DeleteMediaQuery:
def query_response(self):
trans = self.db.transaction_begin()
self.db.disable_signals()
(person_list,family_list,event_list,
place_list,source_list) = self.the_lists
@ -1282,6 +1286,7 @@ class DeleteMediaQuery:
source.set_media_list(new_list)
self.db.commit_source(source,trans)
self.db.enable_signals()
self.db.remove_object(self.media_handle,trans)
self.db.transaction_commit(trans,_("Remove Media Object"))

@ -291,17 +291,64 @@ class MergePeople:
for h,m1,m2 in person.get_parent_family_handle_list():
print " - parent family %s" % h
def merge(self):
"""
Perform the actual merge. A new person is created to store the
merged data. First, the person information is merged. This is a
very straight forward process. Second, the families associated
with the merged people must be modified to handle the family
information. This process can be tricky.
Finally, the merged person is delete from the database and the
entire transaction is committed.
"""
self.debug_person(self.p1, "P1")
self.debug_person(self.p2, "P2")
new = RelLib.Person()
trans = self.db.transaction_begin()
self.merge_person_information(new,trans)
self.merge_family_information(new,trans)
self.db.commit_person(new,trans)
self.debug_person(new, "NEW")
self.db.remove_person(self.old_handle,trans)
self.db.transaction_commit(trans,"Merge Person")
def merge_person_information(self,new,trans):
"""
Merging the person's individual information is pretty simple. The
person 'new' is a new, empty person. The data is loaded in this
new person. The idea is that all information that can possibly be
preserved is preserved.
"""
self.old_handle = self.p2.get_handle()
self.new_handle = self.p1.get_handle()
# Choose the handle from the target person. Since this is internal
# only information, no user visible information is lost.
new.set_handle(self.new_handle)
# The gender is chosen from the primary person. This is one case
# where data may be lost if you merge the data from two people of
# opposite genders.
new.set_gender(self.p1.get_gender())
# copy the GRAMPS Ids
self.merge_gramps_ids(new)
# copy names
self.merge_names(new)
# copy the birth event
self.merge_birth(new,trans)
# copy the death event
self.merge_death(new,trans)
# merge the event lists
self.merge_event_lists(new)
# copy attributes
new.set_attribute_list(self.p1.get_attribute_list() +
self.p2.get_attribute_list())
@ -325,80 +372,346 @@ class MergePeople:
for photo in self.p2.get_media_list():
new.add_media_reference(photo)
# note
note1 = self.p1.get_note_object()
note2 = self.p2.get_note_object()
new.set_note_object(self.merge_notes(note1,note2))
def merge(self):
def merge_gramps_ids(self,new):
"""
Merges the GRAMPS IDs. The new GRAMPS ID is taken from
destination person. The GRAMPS ID of the other person is added
to the merged person as an attribute.
"""
# copy of GRAMPS ID as an attribute
attr = RelLib.Attribute()
attr.set_type('Merged GRAMPS ID')
attr.set_value(self.p2.get_gramps_id())
new.add_attribute(attr)
self.debug_person(self.p1, "P1")
self.debug_person(self.p2, "P2")
new = RelLib.Person()
trans = self.db.transaction_begin()
# store GRAMPS ID of the destination person
new.set_gramps_id(self.p1.get_gramps_id())
self.merge_person_information(new,trans)
self.merge_family_information(new,trans)
self.db.commit_person(new,trans)
self.debug_person(new, "NEW")
self.db.remove_person(self.old_handle,trans)
self.db.transaction_commit(trans,"Merge Person")
def merge_names(self, new):
"""
Merges the names of the two people into the destination. The
primary name of the destination person is kept as the primary
name.
def convert_child_ids(self, family_id, id1, id2, trans):
new_list = []
change = False
family = self.db.get_family_from_handle(family_id)
The other person's name is stored as an alternate name if it is
not entirely identical to the destination person's primary name.
for child_id in family.get_child_handle_list():
if child_id == id2:
if id1 not in new_list:
new_list.append(id1)
change = True
elif child_id not in new_list:
new_list.append(child_id)
#if change:
family.set_child_handle_list(new_list)
self.db.commit_family(family,trans)
In the current implementation, If only one person has a
nickname, it is assigned as the merged person's nickname. If
both people have nicknames, then the nickname of the second
person is lost.
Remaining alternate names are then added to the merged
person's alternate names.
"""
p1_name = self.p1.get_primary_name()
p2_name = self.p2.get_primary_name()
new.set_primary_name(self.p1.get_primary_name())
if not p2_name.is_equal(p1_name):
new.add_alternate_name(p2_name)
if self.p1.get_nick_name() == "":
new.set_nick_name(self.p2.get_nick_name())
else:
new.set_nick_name(self.p1.get_nick_name())
for name in self.p1.get_alternate_names():
new.add_alternate_name(name)
for name in self.p2.get_alternate_names():
new.add_alternate_name(name)
def merge_birth(self, new,trans):
"""
Merges the birth events of the two people. If the primary
person does not have a birth event, then the birth event from
the secodnary person is selected. If the primary person has
a birth date, then the merged person gets the primary person's
birth event, and the secondary person's birth event is added
as a 'Alternate Birth' event.
"""
handle1 = self.p1.get_birth_handle()
handle2 = self.p2.get_birth_handle()
if handle1:
new.set_birth_handle(handle1)
if handle2:
event = self.db.get_event_from_handle(handle2)
event.set_name('Alternate Birth')
self.db.add_event(event,trans)
new.add_event_handle(event.get_handle())
elif not handle1 and handle2:
new.set_birth_handle(handle2)
def merge_death(self, new, trans):
"""
Merges the death events of the two people. If the primary
person does not have a death event, then the death event from
the secodnary person is selected. If the primary person has
a death date, then the merged person gets the primary person's
death event, and the secondary person's death event is added
as a 'Alternate Death' event.
"""
handle1 = self.p1.get_death_handle()
handle2 = self.p2.get_death_handle()
if handle1:
new.set_death_handle(handle1)
if handle2:
event = self.db.get_event_from_handle(handle2)
event.set_handle(Utils.create_id())
event.set_name('Alternate Death')
new.add_event_handle(event.get_handle())
self.db.add_event(event,trans)
elif not handle1 and handle2:
new.set_death_handle(handle2)
def merge_event_lists(self, new):
"""
Merges the events from the two people into the destination
person. Duplicates are not transferred.
"""
data_list = new.get_event_list()
for handle in self.p1.get_event_list():
if handle not in data_list:
data_list.append(handle)
for handle in self.p2.get_event_list():
if handle not in data_list:
data_list.append(handle)
new.set_event_list(data_list)
def merge_family_information(self, new, trans):
"""
Merge the parent families and the relationship families of the
selected people.
"""
self.merge_parents(new, trans)
self.merge_relationships(new, trans)
def merge_parents(self, new, trans):
f1_list = self.p1.get_parent_family_handle_list()
f2_list = self.p2.get_parent_family_handle_list()
"""
Merging the parent list is not too difficult. We grab the
parent list of the destination person. We then loop through
the parent list of the secondary person, adding to the parent
list any parents that are not already there. This eliminates
any duplicates.
parent_list = f1_list
Once this has been completed, we loop through each family,
converting any child handles referring to the secondary person
to the destination person.
"""
parent_list = self.p1.get_parent_family_handle_list()
for fid in f2_list:
# copy handles of families that are not common between the
# two lists
for fid in self.p2.get_parent_family_handle_list():
if fid not in parent_list:
parent_list.append(fid)
for fid in parent_list:
self.convert_child_ids(fid[0], self.new_handle, self.old_handle, trans)
new.add_parent_family_handle(fid[0],fid[1],fid[2])
def merge_family_information(self, new, trans):
self.merge_parents(new, trans)
self.merge_families(new, trans)
def find_family(self,family):
if __debug__:
print "SourceFamily: %s" % family.get_handle()
if self.p1.get_gender() == RelLib.Person.MALE:
mother_handle = family.get_mother_handle()
father_handle = self.p1.get_handle()
else:
father_handle = family.get_father_handle()
mother_handle = self.p1.get_handle()
for myfamily_handle in self.db.get_family_handles():
myfamily = self.db.get_family_from_handle(myfamily_handle)
if (myfamily.get_father_handle() == father_handle and
myfamily.get_mother_handle() == mother_handle and
myfamily_handle != family.get_handle()):
# loop through the combined list, converting the child handles
# of the families, and adding the families to the merged
# person
for (family_handle,mrel,frel) in parent_list:
self.convert_child_ids(family_handle, self.new_handle,
self.old_handle, trans)
new.add_parent_family_handle(family_handle, mrel, frel)
def convert_child_ids(self, fhandle, new_handle, old_handle, trans):
"""
Search the family associated with fhandle, and replace all
child handles that match old_handle with new_handle.
"""
family = self.db.get_family_from_handle(fhandle)
new_child_list = []
orig_list = family.get_child_handle_list()
# loop through original child list. If a handle matches the
# old handle, replace it with the new handle if the new handle
# is not already in the list
for child_id in orig_list:
if child_id == old_handle:
if new_handle not in new_child_list:
new_child_list.append(new_handle)
elif child_id not in new_child_list:
new_child_list.append(child_id)
# compare the new list with the original list. If this list
# is different, we need to save the changes to the database.
if new_child_list != orig_list:
family.set_child_handle_list(new_child_list)
self.db.commit_family(family,trans)
def merge_relationships(self,new,trans):
"""
Merges the relationships associated with the merged people.
"""
family_num = 0
family_list = self.p1.get_family_handle_list()
for src_handle in self.p2.get_family_handle_list():
src_family = self.db.get_family_from_handle(src_handle)
family_num += 1
if not src_family or src_family in family_list:
continue
tgt_family = self.find_modified_family(src_family)
# existing family is found
if tgt_family:
# The target family is already a family in the person's
# family list.
if tgt_family.get_handle() in self.p1.get_family_handle_list():
self.merge_existing_family(new, src_family, tgt_family, trans)
continue
# This is the case the family is not already in the person's
# family list.
else:
self.merge_family_pair(tgt_family,src_family,trans)
# change parents of the family to point to the new
# family
self.adjust_family_pointers(tgt_family, src_family, trans)
new.remove_family_handle(src_handle)
self.db.remove_family(src_handle,trans)
if __debug__:
print "Deleted src_family %s" % src_handle
else:
for fid in self.p1.get_family_handle_list():
if fid not in new.get_family_handle_list():
new.add_family_handle(fid)
if src_handle in new.get_family_handle_list():
continue
src_family = self.db.get_family_from_handle(src_handle)
new.add_family_handle(src_handle)
if src_family.get_father_handle() == self.old_handle:
src_family.set_father_handle(self.new_handle)
if __debug__:
print "TargetFamily: %s" % myfamily.get_handle()
return myfamily
print "Family %s now has father %s" % (
src_handle, self.new_handle)
if src_family.get_mother_handle() == self.old_handle:
src_family.set_mother_handle(self.new_handle)
if __debug__:
print "Family %s now has mother %s" % (
src_handle, self.new_handle)
self.db.commit_family(src_family,trans)
# a little debugging here
cursor = self.db.get_family_cursor()
data = cursor.first()
while data:
fam = RelLib.Family()
fam.unserialize(data[1])
if self.p2 in fam.get_child_handle_list():
fam.remove_child_handle(self.p2)
fam.add_child_handle(self.p1)
if self.p2 == fam.get_father_handle():
fam.set_father_handle(self.p1)
if self.p2 == fam.get_mother_handle():
fam.set_mother_handle(self.p1)
if fam.get_father_handle() == None and fam.get_mother_handle() == None:
self.delete_empty_family(fam,trans)
data = cursor.next()
def find_modified_family(self,family):
"""
Look for a existing family that matches the merged person. This means
looking at the current family, and replacing the secondary person's
handle with the merged person's handle. Search the family table for
a family that matches this new mother/father pair.
If no family is found, return None
"""
family_handle = family.get_handle()
if __debug__:
print "TargetFamily: None"
return None
print "SourceFamily: %s" % family_handle
# Determine the mother and father handles for the search.
# This is determined by replacing the secodnary person's
# handle with the primary person's handle in the mother/father
# pair.
mhandle = family.get_mother_handle()
if mhandle == self.old_handle:
mhandle = self.new_handle
fhandle = family.get_father_handle()
if fhandle == self.old_handle:
fhandle = self.new_handle
# loop through the families using a cursor. Check the handles
# for a mother/father match.
cursor = self.db.get_family_cursor()
node = cursor.next()
myfamily = None
while node:
# data[2] == father_handle field, data[2] == mother_handle field
(thandle,data) = node
if data[2] == fhandle and data[3] == mhandle and thandle != family_handle:
myfamily = RelLib.Family()
myfamily.unserialize(data)
break
node = cursor.next()
if __debug__:
if myfamily:
print "TargetFamily: %s" % myfamily.get_handle()
else:
print "TargetFamily: None"
cursor.close()
return myfamily
def merge_existing_family(self, new, src_family, tgt_family, trans):
src_family_handle = src_family.get_handle()
father_id = tgt_family.get_father_handle()
father = self.db.get_person_from_handle(father_id)
mother_id = tgt_family.get_mother_handle()
mother = self.db.get_person_from_handle(mother_id)
if father and src_family_handle in father.get_family_handle_list():
father.remove_family_handle(src_family_handle)
if __debug__:
print "Removed family %s from father %s" % (src_family_handle, father_id)
self.db.commit_person(father,trans)
if mother and src_family_handle in mother.get_family_handle_list():
mother.remove_family_handle(src_family_handle)
if __debug__:
print "Removed family %s from mother %s" % (src_family_handle, mother_id)
self.db.commit_person(mother,trans)
self.merge_family_pair(tgt_family,src_family,trans)
for child_handle in src_family.get_child_handle_list():
if child_handle != self.new_handle:
child = self.db.get_person_from_handle(child_handle)
if child.remove_parent_family_handle(src_family_handle):
self.db.commit_person(child,trans)
# delete the old source family
self.db.remove_family(src_family_handle,trans)
if __debug__:
print "Deleted src_family %s" % src_family_handle
self.db.commit_family(tgt_family,trans)
new.add_family_handle(tgt_family.get_handle())
def merge_family_pair(self,tgt_family,src_family,trans):
@ -447,156 +760,48 @@ class MergePeople:
for photo in src_family.get_media_list():
tgt_family.add_media_reference(photo)
def merge_families(self,new,trans):
def adjust_family_pointers(self, tgt_family, src_family, trans):
"""
Remove the people from one family and merge them into the other.
It is not necessary to remove from the src_family, since the
src_family is going to be removed.
"""
src_family_handle = src_family.get_handle()
tgt_family_handle = tgt_family.get_handle()
family_num = 0
family_list = self.p1.get_family_handle_list()
for src_family_handle in self.p2.get_family_handle_list():
father_handle = src_family.get_father_handle()
if father_handle:
father = self.db.get_person_from_handle(father_handle)
src_family = self.db.get_family_from_handle(src_family_handle)
family_num += 1
# add to new family
father.add_family_handle(tgt_family_handle)
if __debug__:
print "Added family %s to father %s" % (
tgt_family_handle, father_handle)
if not src_family or src_family in family_list:
continue
# commit the change
self.db.commit_person(father,trans)
tgt_family = self.find_family(src_family)
mother_handle = src_family.get_mother_handle()
if mother_handle:
mother = self.db.get_person_from_handle(mother_handle)
#
# This is the case where a new family to be added to the
# p1 as a result of the merge already exists as a
# family. In this case, we need to remove the old source
# family (with the pre-merge identity of the p1) from
# both the parents
#
# add to new family
mother.add_family_handle(tgt_family_handle)
if __debug__:
print "Added family %s to mother %s" % (
tgt_family_handle, mother_handle)
if tgt_family:
tgt_family_handle = tgt_family.get_handle()
if tgt_family_handle in self.p1.get_family_handle_list():
father_id = tgt_family.get_father_handle()
father = self.db.get_person_from_handle(father_id)
mother_id = tgt_family.get_mother_handle()
mother = self.db.get_person_from_handle(mother_id)
# commit the change
self.db.commit_person(mother,trans)
if father and src_family_handle in father.get_family_handle_list():
father.remove_family_handle(src_family_handle)
if __debug__:
print "Removed family %s from father %s" % (src_family_handle, father_id)
self.db.commit_person(father,trans)
if mother and src_family_handle in mother.get_family_handle_list():
mother.remove_family_handle(src_family_handle)
if __debug__:
print "Removed family %s from mother %s" % (src_family_handle, mother_id)
self.db.commit_person(mother,trans)
self.merge_family_pair(tgt_family,src_family,trans)
for child_handle in src_family.get_child_handle_list():
if child_handle != self.new_handle:
child = self.db.get_person_from_handle(child_handle)
if child.remove_parent_family_handle(src_family_handle):
self.db.commit_person(child,trans)
# remove the children from the old family
for child_handle in src_family.get_child_handle_list():
if child_handle != self.new_handle:
child = self.db.get_person_from_handle(child_handle)
if child.remove_parent_family_handle(src_family_handle):
self.db.commit_person(child,trans)
# delete the old source family
self.db.remove_family(src_family_handle,trans)
if __debug__:
print "Deleted src_family %s" % src_family_handle
self.db.commit_family(tgt_family,trans)
new.add_family_handle(tgt_family_handle)
continue
# This is the case where a new family to be added
# and it is not already in the list.
else:
# tgt_family a duplicate family, transfer children from
# the p2 family, and delete the family. Not sure
# what to do about marriage/divorce date/place yet.
# transfer child to new family, alter children to
# point to the correct family
self.merge_family_pair(tgt_family,src_family,trans)
# change parents of the family to point to the new
# family
father_handle = src_family.get_father_handle()
if father_handle:
father = self.db.get_person_from_handle(father_handle)
father.remove_family_handle(src_family_handle)
if __debug__:
print "Removed family %s from father %s" % (src_family_handle, father_handle)
father.add_family_handle(tgt_family_handle)
if __debug__:
print "Added family %s to father %s" % (tgt_family_handle, father_handle)
self.db.commit_person(father,trans)
mother_handle = src_family.get_mother_handle()
if mother_handle:
mother = self.db.get_person_from_handle(mother_handle)
mother.remove_family_handle(src_family_handle)
if __debug__:
print "Removed family %s from mother %s" % (src_family_handle, mother_handle)
mother.add_family_handle(tgt_family_handle)
if __debug__:
print "Added family %s to mother %s" % (tgt_family_handle, mother_handle)
self.db.commit_person(mother,trans)
for child_handle in src_family.get_child_handle_list():
if child_handle != self.new_handle:
child = self.db.get_person_from_handle(child_handle)
if child.remove_parent_family_handle(src_family_handle):
self.db.commit_person(child,trans)
new.remove_family_handle(src_family_handle)
self.db.remove_family(src_family_handle,trans)
if __debug__:
print "Deleted src_family %s" % src_family_handle
else:
for fid in self.p1.get_family_handle_list():
if fid not in new.get_family_handle_list():
new.add_family_handle(fid)
# for src_family_handle in self.p2.get_family_handle_list():
if src_family_handle in new.get_family_handle_list():
continue
src_family = self.db.get_family_from_handle(src_family_handle)
new.add_family_handle(src_family_handle)
if src_family.get_father_handle() == self.old_handle:
src_family.set_father_handle(self.new_handle)
if __debug__:
print "Family %s now has father %s" % (src_family_handle, self.new_handle)
if src_family.get_mother_handle() == self.old_handle:
src_family.set_mother_handle(self.new_handle)
if __debug__:
print "Family %s now has mother %s" % (src_family_handle, self.new_handle)
self.db.commit_family(src_family,trans)
# a little debugging here
cursor = self.db.get_family_cursor()
data = cursor.first()
while data:
fam = RelLib.Family()
fam.unserialize(data[1])
if self.p2 in fam.get_child_handle_list():
fam.remove_child_handle(self.p2)
fam.add_child_handle(self.p1)
if self.p2 == fam.get_father_handle():
fam.set_father_handle(self.p1)
if self.p2 == fam.get_mother_handle():
fam.set_mother_handle(self.p1)
if fam.get_father_handle() == None and fam.get_mother_handle() == None:
self.delete_empty_family(fam,trans)
data = cursor.next()
def remove_marriage(self,family,person,trans):
if person:
@ -617,13 +822,6 @@ class MergePeople:
if __debug__:
print "Deleted empty family %s" % family_handle
def merge_gramps_ids(self,new):
new.set_gramps_id(self.p1.get_gramps_id())
attr = RelLib.Attribute()
attr.set_type('Merged GRAMPS ID')
attr.set_value(self.p2.get_gramps_id())
new.add_attribute(attr)
def merge_notes(self, note1, note2):
if note1 and not note2:
return note1
@ -635,49 +833,3 @@ class MergePeople:
return note1
return None
def merge_names(self, new):
new.set_primary_name(self.p1.get_primary_name())
new.add_alternate_name(self.p2.get_primary_name())
if self.p1.get_nick_name() == "":
new.set_nick_name(self.p2.get_nick_name())
else:
new.set_nick_name(self.p1.get_nick_name())
def merge_death(self, new, trans):
handle1 = self.p1.get_death_handle()
handle2 = self.p2.get_death_handle()
if handle1:
new.set_death_handle(handle1)
if handle2:
event = self.db.get_event_from_handle(handle2)
event.set_handle(Utils.create_id())
event.set_name('Alternate Death')
new.add_event_handle(event.get_handle())
self.db.add_event(event,trans)
elif not handle1 and handle2:
new.set_death_handle(handle2)
def merge_birth(self, new,trans):
handle1 = self.p1.get_birth_handle()
handle2 = self.p2.get_birth_handle()
if handle1:
new.set_birth_handle(handle1)
if handle2:
event = self.db.get_event_from_handle(handle2)
event.set_name('Alternate Birth')
self.db.add_event(event,trans)
new.add_event_handle(event.get_handle())
elif not handle1 and handle2:
new.set_birth_handle(handle2)
def merge_event_lists(self, new):
data_list = new.get_event_list()
for handle in self.p1.get_event_list():
if handle not in data_list:
data_list.append(handle)
for handle in self.p2.get_event_list():
if handle not in data_list:
data_list.append(handle)
new.set_event_list(data_list)

@ -83,7 +83,7 @@ class NameDisplay:
@rtype: str
"""
name = person.get_primary_name()
if name.display_as == RelLib.Name.FNLN:
if name.get_sort_as() == RelLib.Name.FNLN:
return self._fnln(name)
else:
return self._lnfn(name)

@ -29,6 +29,7 @@ from gettext import gettext as _
import time
import locale
import cgi
import sets
#-------------------------------------------------------------------------
#
@ -84,6 +85,7 @@ class PeopleModel(gtk.GenericTreeModel):
self.visible = {}
self.top_visible = {}
self.invert_result = invert_result
self.sortnames = {}
self.rebuild_data(data_filter)
def rebuild_data(self,data_filter=None,skip=None):
@ -111,38 +113,44 @@ class PeopleModel(gtk.GenericTreeModel):
else:
keys = self.db.get_person_handles(sort_handles=False)
for person_handle in keys:
if person_handle == skip:
continue
person = self.db.get_person_from_handle(person_handle)
grp_as = person.get_primary_name().get_group_as()
sn = person.get_primary_name().get_surname()
if grp_as:
surname = grp_as
else:
surname = self.db.get_name_group_mapping(sn)
flist = sets.Set(keys)
if skip and skip in flist:
flist.remove(skip)
if self.temp_sname_sub.has_key(surname):
self.temp_sname_sub[surname].append(person_handle)
else:
self.temp_sname_sub[surname] = [person_handle]
self.sortnames = {}
cursor = self.db.get_person_cursor()
node = cursor.next()
while node:
if node[0] in flist:
primary_name = node[1][_NAME_COL]
if primary_name.group_as:
surname = primary_name.group_as
else:
surname = self.db.get_name_group_mapping(primary_name.surname)
self.sortnames[node[0]] = primary_name.sname
if self.temp_sname_sub.has_key(surname):
self.temp_sname_sub[surname].append(node[0])
else:
self.temp_sname_sub[surname] = [node[0]]
node = cursor.next()
cursor.close()
self.temp_top_path2iter = self.temp_sname_sub.keys()
self.temp_top_path2iter.sort(locale.strcoll)
for name in self.temp_top_path2iter:
self.build_sub_entry(name)
slist = []
for handle in self.temp_sname_sub[name]:
n = self.db.person_map.get(handle)[_NAME_COL].get_sort_name()
slist.append((n,handle))
slist.sort(self.byname)
entries = map(lambda x: x[1], slist)
val = 0
for person_handle in entries:
tpl = (name,val)
self.temp_iter2path[person_handle] = tpl
self.temp_path2iter[tpl] = person_handle
val += 1
def build_sub_entry(self,name):
slist = map(lambda x: (self.sortnames[x],x),self.temp_sname_sub[name])
slist.sort(self.byname)
entries = map(lambda x: x[1], slist)
val = 0
for person_handle in entries:
tpl = (name,val)
self.temp_iter2path[person_handle] = tpl
self.temp_path2iter[tpl] = person_handle
val += 1
def assign_data(self):
self.top_path2iter = self.temp_top_path2iter

@ -88,13 +88,13 @@ class PeopleView:
self.person_tree = self.parent.gtop.get_widget("person_tree")
self.person_tree.set_rules_hint(True)
self.renderer = gtk.CellRendererText()
self.inactive = False
self.columns = []
self.build_columns()
self.person_selection = self.person_tree.get_selection()
self.person_selection.set_mode(gtk.SELECTION_MULTIPLE)
self.person_selection.connect('changed',self.row_changed)
self.person_selection.connect('changed',self.set_dnd_target)
self.person_tree.connect('row_activated', self.alpha_event)
self.person_tree.connect('button-press-event',
self.on_plist_button_press)
@ -113,20 +113,6 @@ class PeopleView:
sel_data.set(DdTargets.PERSON_LINK_LIST.drag_type,8,
pickle.dumps(selected_ids))
def set_dnd_target(self,obj):
selected_ids = self.get_selected_objects()
if len(selected_ids) == 1:
self.person_tree.drag_source_set(BUTTON1_MASK,
[DdTargets.PERSON_LINK.target()],
ACTION_COPY)
elif len(selected_ids) > 1:
self.person_tree.drag_source_set(BUTTON1_MASK,
[DdTargets.PERSON_LINK_LIST.target()],
ACTION_COPY)
def sort_clicked(self,obj):
for col in self.columns:
if obj == col:
@ -173,13 +159,12 @@ class PeopleView:
self.parent.filter_invert.get_active())
self.person_tree.set_model(self.person_model)
def blist(self, store, path, node, id_list):
idval = self.person_model.get_value(node, PeopleModel.COLUMN_INT_ID)
id_list.append(idval)
def get_selected_objects(self):
(mode,paths) = self.person_selection.get_selected_rows()
mlist = []
self.person_selection.selected_foreach(self.blist,mlist)
for path in paths:
node = self.person_model.on_get_iter(path)
mlist.append(self.person_model.on_get_value(node, PeopleModel.COLUMN_INT_ID))
return mlist
def row_changed(self,obj):
@ -189,24 +174,29 @@ class PeopleView:
selected, set the active person to None"""
selected_ids = self.get_selected_objects()
try:
person = self.parent.db.get_person_from_handle(selected_ids[0])
self.parent.change_active_person(person)
except:
self.parent.change_active_person(None)
if len(selected_ids) == 1:
self.person_tree.drag_source_set(BUTTON1_MASK,
[DdTargets.PERSON_LINK.target()],
ACTION_COPY)
elif len(selected_ids) > 1:
self.person_tree.drag_source_set(BUTTON1_MASK,
[DdTargets.PERSON_LINK_LIST.target()],
ACTION_COPY)
def change_db(self,db):
self.build_columns()
self.person_model = PeopleModel.PeopleModel(db,self.DataFilter)
self.person_tree.set_model(self.person_model)
db.connect('person-add', self.person_added)
db.connect('person-update', self.person_updated)
db.connect('person-delete', self.person_removed)
db.connect('person-rebuild', self.redisplay_person_list)
self.apply_filter()
def remove_from_person_list(self,person):
"""Remove the selected person from the list. A person object is
expected, not an ID"""
@ -239,8 +229,9 @@ class PeopleView:
self.goto_active_person()
def goto_active_person(self):
if not self.parent.active_person:
if not self.parent.active_person or self.inactive:
return
self.inactive = True
p = self.parent.active_person
try:
path = self.person_model.on_get_path(p.get_handle())
@ -248,13 +239,19 @@ class PeopleView:
top_name = self.parent.db.get_name_group_mapping(group_name)
top_path = self.person_model.on_get_path(top_name)
self.person_tree.expand_row(top_path,0)
self.person_selection.unselect_all()
self.person_selection.select_path(path)
self.person_tree.scroll_to_cell(path,None,1,0.5,0)
current = self.person_model.on_get_iter(path)
selected = self.person_selection.path_is_selected(path)
if current != p.get_handle() or not selected:
self.person_selection.unselect_all()
self.person_selection.select_path(path)
self.person_tree.scroll_to_cell(path,None,1,0.5,0)
except KeyError:
self.person_selection.unselect_all()
print "Person not currently available due to filter"
self.parent.active_person = p
self.inactive = False
def alpha_event(self,*obj):
self.parent.load_person(self.parent.active_person)
@ -276,9 +273,9 @@ class PeopleView:
fwd_sensitivity = self.parent.hindex + 1 < len(self.parent.history)
mlist = self.get_selected_objects()
if mlist:
sel_sensitivity = 1
sel_sensitivity = True
else:
sel_sensitivity = 0
sel_sensitivity = False
merge_sensitivity = len(mlist) == 2
entries = [
(gtk.STOCK_GO_BACK,self.parent.back_clicked,back_sensitivity),
@ -361,7 +358,17 @@ class PeopleView:
pnode = self.person_model.get_iter(pathval)
# calculate the new data
self.person_model.calculate_data(self.DataFilter)
if person.primary_name.group_as:
surname = person.primary_name.group_as
else:
surname = self.parent.db.get_name_group_mapping(person.primary_name.surname)
if oldpath[0] == surname:
self.person_model.build_sub_entry(surname)
else:
self.person_model.calculate_data(self.DataFilter)
# find the path of the person in the new data build
newpath = self.person_model.temp_iter2path[node]
@ -400,5 +407,4 @@ class PeopleView:
pnode = self.person_model.get_iter(path)
self.person_model.row_inserted(path,pnode)
#self.parent.change_active_person(person)
self.goto_active_person()

@ -434,13 +434,13 @@ class GedcomParser:
self.text = string.translate(self.text,self.transtable2)
self.index += 1
l = self.text.split(None, 2)
l = self.text.split(' ', 2)
ln = len(l)
try:
if ln == 2:
self.groups = (int(l[0]),unicode(l[1]),u"")
self.groups = (int(l[0]),unicode(l[1]).strip(),u"")
else:
self.groups = (int(l[0]),unicode(l[1]),unicode(l[2]))
self.groups = (int(l[0]),unicode(l[1]).strip(),unicode(l[2]))
except:
if self.text == "":
msg = _("Warning: line %d was blank, so it was ignored.\n") % self.index

@ -59,7 +59,16 @@ def importData(database, filename, callback=None,cl=0,use_trans=True):
else:
ErrorDialog(_("%s could not be opened") % filename)
return
if not other_database.version_supported():
if cl:
print "Error: %s could not be opened.\n%s Exiting." % (filename,\
_("The database version is not supported by this version of GRAMPS.\n"\
"Please upgrade to the corresponding version or use XML for porting data between different database versions."))
else:
ErrorDialog(_("%s could not be opened") % filename,
_("The Database version is not supported by this version of GRAMPS."))
return
# Check for duplicate handles. At the moment we simply exit here,
# before modifying any data. In the future we will need to handle
# this better.

@ -308,6 +308,7 @@ class SelectChild:
self.top)
return
# TODO: Add child ordered by birth day
self.family.add_child_handle(select_child.get_handle())
mrel = self.mrel.get_active()

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2004 Donald N. Allingham
# Copyright (C) 2000-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
@ -27,18 +27,24 @@ and directly use class members. For this reason, care needs to be taken
to make sure these remain in sync with the rest of the design.
"""
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import locale
#-------------------------------------------------------------------------
#
# Imported Modules
# GRAMPS Modules
#
#-------------------------------------------------------------------------
import Date
from NameDisplay import displayer as _nd
#-------------------------------------------------------------------------
#
# Functions
# Constants
#
#-------------------------------------------------------------------------
@ -52,7 +58,6 @@ class Sort:
def __init__(self,database):
self.database = database
def by_last_name(self,first_id,second_id):
"""Sort routine for comparing two last names. If last names are equal,
uses the given name and suffix"""
@ -75,6 +80,19 @@ class Sort:
else:
return locale.strcoll(fsn, ssn)
def by_sorted_name(self,first_id,second_id):
"""
Sort routine for comparing two displayed names.
"""
first = self.database.get_person_from_handle(first_id)
second = self.database.get_person_from_handle(second_id)
name1 = _nd.sorted(first)
name2 = _nd.sorted(second)
return locale.strcoll(name1,name2)
def by_birthdate(self,first_id,second_id):
"""Sort routine for comparing two people by birth dates. If the birth dates
are equal, sorts by name"""

@ -154,11 +154,13 @@ class SourceView:
if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
mlist = []
self.selection.selected_foreach(self.blist,mlist)
handle = mlist[0]
source = self.parent.db.get_source_from_handle(handle)
EditSource.EditSource(source,self.parent.db,self.parent,
self.topWindow)
return True
if mlist:
handle = mlist[0]
source = self.parent.db.get_source_from_handle(handle)
EditSource.EditSource(source,self.parent.db,self.parent,
self.topWindow)
return True
return False
elif event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
self.build_context_menu(event)
return True

@ -34,6 +34,7 @@ import locale
#
#-------------------------------------------------------------------------
import gtk
import gtk.gdk
import gnome
try:
@ -402,17 +403,34 @@ def search_for(name):
# Change label apperance
#
#-------------------------------------------------------------------------
def bold_label(label):
def bold_label(label,widget=None):
text = unicode(label.get_text())
text = text.replace('<i>','')
text = text.replace('</i>','')
label.set_text("<b>%s</b>" % text )
label.set_use_markup(1)
label.set_use_markup(True)
if widget:
widget.window.set_cursor(None)
def unbold_label(label):
def unbold_label(label,widget=None):
text = unicode(label.get_text())
text = text.replace('<b>','')
text = text.replace('</b>','')
text = text.replace('<i>','')
text = text.replace('</i>','')
label.set_text(text)
label.set_use_markup(0)
label.set_use_markup(False)
if widget:
widget.window.set_cursor(None)
def temp_label(label,widget=None):
text = unicode(label.get_text())
text = text.replace('<b>','')
text = text.replace('</b>','')
label.set_text("<i>%s</i>" % text )
label.set_use_markup(True)
if widget:
widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
#-------------------------------------------------------------------------
#
@ -447,14 +465,13 @@ def probably_alive(person,db,current_year=None):
"""
if not current_year:
time_struct = time.localtime(time.time())
current_year = time_struct[0]
death_year = None
# If the recorded death year is before current year then
# things are simple.
if person.death_handle:
if not current_year:
# no current year and we have a death event -> person died
return False
death = db.get_event_from_handle(person.death_handle)
if death.get_date_object().get_start_date() != Date.EMPTY:
death_year = death.get_date_object().get_year()
@ -466,12 +483,19 @@ def probably_alive(person,db,current_year=None):
for ev_handle in person.event_list:
ev = db.get_event_from_handle(ev_handle)
if ev and ev.name in ["Cause Of Death", "Burial", "Cremation"]:
if not current_year:
# no current year and we have an event related to death
return False
if not death_year:
death_year = ev.get_date_object().get_year()
if ev.get_date_object().get_start_date() != Date.EMPTY:
if ev.get_date_object().get_year() < current_year:
return False
if not current_year:
time_struct = time.localtime(time.time())
current_year = time_struct[0]
birth_year = None
# If they were born within 100 years before current year then
# assume they are alive (we already know they are not dead).

@ -809,7 +809,7 @@ class GedcomWriter:
death = self.db.get_event_from_handle(death_handle)
if death_handle and death and not (self.private and death.get_privacy()):
if not death.get_date_object().is_empty() or death.get_place_handle():
if birth.get_description() != "":
if death.get_description() != "":
self.writeln("1 DEAT %s" % death.get_description())
else:
self.writeln("1 DEAT")

@ -827,11 +827,6 @@ class XmlWriter:
path = obj.get_path()
if self.strip_photos:
path = os.path.basename(path)
else:
l = len(self.fileroot)
if len(path) >= l:
if self.fileroot == path[0:l]:
path = path[l+1:]
self.g.write(' <object id="%s" handle="%s" change="%d" src="%s" mime="%s"' %
(handle,obj.get_handle(),obj.get_change_time(),path,mime_type))
self.g.write(' description="%s"' % self.fix(obj.get_description()))

@ -494,6 +494,13 @@ family_relations = [
(_("Other"), _("An unspecified relationship between a man and woman"))
]
family_relations_C = [
"Married",
"Unmarried",
"Civil Union",
"Unknown",
"Other",
]
#-------------------------------------------------------------------------
#
#
@ -501,9 +508,9 @@ family_relations = [
#-------------------------------------------------------------------------
def save_frel(st):
try:
return family_relations[st][0]
return family_relations_C[st]
except:
return _("Unknown")
return "Unknown"
#-------------------------------------------------------------------------
#

@ -112,8 +112,8 @@ class DateParserDE(DateParser):
def init_strings(self):
DateParser.init_strings(self)
self._span = re.compile("(von|vom)\s+(.+)\s+(bis)\s+(.+)",re.IGNORECASE)
self._range = re.compile("(zwischen)\s+(.+)\s+(und)\s+(.+)", re.IGNORECASE)
self._span = re.compile("(von|vom)\s+(?P<start>.+)\s+(bis)\s+(?P<stop>.+)",re.IGNORECASE)
self._range = re.compile("zwischen\s+(?P<start>.+)\s+und\s+(?P<stop>.+)", re.IGNORECASE)
self._text2 = re.compile('(\d+)?.?\s+?%s\s*((\d+)(/\d+)?)?' % self._mon_str,
re.IGNORECASE)
self._jtext2= re.compile('(\d+)?.?\s+?%s\s*((\d+)(/\d+)?)?' % self._jmon_str,
@ -131,7 +131,7 @@ class DateDisplayDE(DateDisplay):
u" (Französisch Republikanisch)", u" (Persisch)", u" (Islamisch)"
)
_mod_str = ("",u"vor ",u"nach ",u"circa ","","","")
_mod_str = ("",u"vor ",u"nach ",u"etwa ","","","")
_qual_str = ("",u"geschätzt ",u"errechnet ")
@ -224,9 +224,5 @@ class DateDisplayDE(DateDisplay):
#
#-------------------------------------------------------------------------
from DateHandler import register_datehandler
register_datehandler(('de_DE','german'),DateParserDE, DateDisplayDE)
register_datehandler(('de_AT','german (Austria)'),DateParserDE, DateDisplayDE)
register_datehandler(('de_CH','german (Switzerland)'),DateParserDE, DateDisplayDE)
register_datehandler(('de_LI','german (Lichtenstein)'),DateParserDE, DateDisplayDE)
register_datehandler(('de_LU','german (Luxembourg)'),DateParserDE, DateDisplayDE)
register_datehandler(('de_BE','german (Belgium)'),DateParserDE, DateDisplayDE)
register_datehandler(('de_DE','german','de_AT','de_CH',
'de_LI','de_LU','de_BE','de'),DateParserDE, DateDisplayDE)

@ -98,10 +98,10 @@ class DateParserES(DateParser):
_span_2 = [u'a']
_range_1 = [u'ent.',u'ent',u'entre']
_range_2 = [u'y']
self._span = re.compile("(%s)\s+(.+)\s+(%s)\s+(.+)" %
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+(.+)\s+(%s)\s+(.+)" %
self._range = re.compile("(%s)\s+(?P<start>.+)\s+(%s)\s+(?P<stop>.+)" %
('|'.join(_range_1),'|'.join(_range_2)),
re.IGNORECASE)
@ -159,4 +159,4 @@ class DateDisplayES(DateDisplay):
#
#-------------------------------------------------------------------------
from DateHandler import register_datehandler
register_datehandler(('es_ES','spanish'),DateParserES, DateDisplayES)
register_datehandler(('es_ES','es','spanish'),DateParserES, DateDisplayES)

@ -95,9 +95,9 @@ class DateParserFI(DateParser):
def init_strings(self):
DateParser.init_strings(self)
# date, whitespace
self._span = re.compile("(?P<start>.+)\s+-\s+(?P<stop>.+)",
self._span = re.compile("(?P<start>.+)\s+(-)\s+(?P<stop>.+)",
re.IGNORECASE)
self._range = re.compile("(?P<start>.+)\s+ja\s+(?P<stop>.+)\s+väliltä",
self._range = re.compile("(vuosien\s*)?(?P<start>.+)\s+ja\s+(?P<stop>.+)\s+väliltä",
re.IGNORECASE)
#-------------------------------------------------------------------------
@ -114,7 +114,7 @@ class DateDisplayFI(DateDisplay):
u"(Persialainen)",
u"(Islamilainen)")
_qual_str = ("", "laskettuna", "arviolta")
_qual_str = ("", "arviolta", "laskettuna")
formats = (
"VVVV-KK-PP (ISO)",
@ -143,9 +143,15 @@ class DateDisplayFI(DateDisplay):
d2 = self.display_cal[cal](date.get_stop_date())
text = "%s - %s" % (d1, d2)
elif mod == Date.MOD_RANGE:
d1 = self.display_cal[cal](start)
d2 = self.display_cal[cal](date.get_stop_date())
text = "%s ja %s väliltä" % (d1, d2)
stop = date.get_stop_date()
if start[0] == 0 and start[1] == 0 and stop[0] == 0 and stop[1] == 0:
d1 = self.display_cal[cal](start)
d2 = self.display_cal[cal](stop)
text = "vuosien %s ja %s väliltä" % (d1, d2)
else:
d1 = self.display_cal[cal](start)
d2 = self.display_cal[cal](stop)
text = "%s ja %s väliltä" % (d1, d2)
else:
text = self.display_cal[date.get_calendar()](start)
if mod == Date.MOD_BEFORE:
@ -171,5 +177,5 @@ class DateDisplayFI(DateDisplay):
#
#-------------------------------------------------------------------------
from DateHandler import register_datehandler
register_datehandler(('fi_FI','finnish'), DateParserFI, DateDisplayFI)
register_datehandler(('fi_FI','fi','finnish'), DateParserFI, DateDisplayFI)

@ -92,10 +92,10 @@ class DateParserFR(DateParser):
_span_2 = [u'à']
_range_1 = [u'ent.',u'ent',u'entre']
_range_2 = [u'et']
self._span = re.compile("(%s)\s+(.+)\s+(%s)\s+(.+)" %
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+(.+)\s+(%s)\s+(.+)" %
self._range = re.compile("(%s)\s+(?P<start>.+)\s+(%s)\s+(?P<stop>.+)" %
('|'.join(_range_1),'|'.join(_range_2)),
re.IGNORECASE)
@ -153,4 +153,4 @@ class DateDisplayFR(DateDisplay):
#
#-------------------------------------------------------------------------
from DateHandler import register_datehandler
register_datehandler(('fr_FR','french'),DateParserFR, DateDisplayFR)
register_datehandler(('fr_FR','fr','french'),DateParserFR, DateDisplayFR)

@ -102,10 +102,10 @@ class DateParserRU(DateParser):
_span_2 = [u'по',u'до']
_range_1 = [u'между',u'меж',u'меж.']
_range_2 = [u'и']
self._span = re.compile("(%s)\s+(.+)\s+(%s)\s+(.+)" %
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+(.+)\s+(%s)\s+(.+)" %
self._range = re.compile("(%s)\s+(?P<start>.+)\s+(%s)\s+(?P<stop>.+)" %
('|'.join(_range_1),'|'.join(_range_2)),
re.IGNORECASE)
@ -168,4 +168,4 @@ class DateDisplayRU(DateDisplay):
#
#-------------------------------------------------------------------------
from DateHandler import register_datehandler
register_datehandler(('ru_RU','russian'),DateParserRU, DateDisplayRU)
register_datehandler(('ru_RU','ru','russian'),DateParserRU, DateDisplayRU)

@ -9,8 +9,9 @@ pkgdata_PYTHON = \
Date_de.py\
Date_ru.py\
Date_fr.py\
Date_es.py\
Date_fi.py
Date_es.py
# Date_fi.py
pkgpyexecdir = @pkgpyexecdir@/dates
pkgpythondir = @pkgpythondir@/dates

@ -1291,14 +1291,17 @@ class Gramps(GrampsDBCallback.GrampsDBCallback):
ErrorDialog(_('Cannot open database'),
_('The database file specified could not be opened.'))
return 0
except ( IOError, OSError ), msg:
except ( IOError, OSError, Errors.FileVersionError), msg:
ErrorDialog(_('Cannot open database'),str(msg))
return 0
except db.DBAccessError, msg:
except (db.DBAccessError,db.DBError), msg:
ErrorDialog(_('Cannot open database'),
_('%s could not be opened.' % filename) + '\n' + msg[1])
return 0
except Exception:
DisplayTrace.DisplayTrace()
return 0
# Undo/Redo always start with standard labels and insensitive state
self.undo_callback(None)
self.redo_callback(None)
@ -1524,6 +1527,15 @@ class Gramps(GrampsDBCallback.GrampsDBCallback):
self.people_view.goto_active_person()
def change_active_person(self,person,force=0):
nph = ""
if person:
nph = person.get_handle()
oph = ""
if self.active_person:
oph = self.active_person.get_handle()
if nph == oph: # no need to change to the current active person again
return
if person == None:
self.set_buttons(0)
self.active_person = None
@ -1731,10 +1743,15 @@ class Gramps(GrampsDBCallback.GrampsDBCallback):
gtk.main_iteration()
def post_load(self,name,callback=None):
if not self.db.version_supported():
raise Errors.FileVersionError(
"The database version is not supported by this version of GRAMPS.\n"
"Please upgrade to the corresponding version or use XML for porting data between different database versions.")
self.db.set_save_path(name)
res = self.db.get_researcher()
owner = GrampsCfg.get_researcher()
if res.get_name() == "" and owner.get_name():
self.db.set_researcher(owner)

@ -0,0 +1,166 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-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$
"Database Processing/Extract information from names"
#-------------------------------------------------------------------------
#
# python modules
#
#-------------------------------------------------------------------------
import os
import popen2
import locale
import time
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# gnome/gtk
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from QuestionDialog import OkDialog, ErrorDialog
import WriteXML
#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
def runTool(database,active_person,callback,parent=None):
try:
Checkpoint(database,callback,parent)
except:
import DisplayTrace
DisplayTrace.DisplayTrace()
#-------------------------------------------------------------------------
#
# Checkpoint
#
#-------------------------------------------------------------------------
class Checkpoint:
def __init__(self,db,callback,parent):
self.cb = callback
self.db = db
self.parent = parent
self.use_custom = False
self.custom_str = "cat > /tmp/temp.file"
self.run()
def run(self):
"""
RCS will be a builtin command, since we can handle all
configuration on our own. This isn't true for most versioning
systems, which usually require external setup, and external
communication.
"""
self.parent.status_text(_("Checkpointing database..."))
if self.use_custom:
self.custom()
else:
self.rcs()
self.parent.progress.set_fraction(0)
self.parent.modify_statusbar()
def timestamp(self):
format = locale.nl_langinfo(locale.D_T_FMT)
return unicode(time.strftime(format,time.localtime(time.time())))
def custom(self):
"""
Passed the generated XML file to the specified command.
"""
proc = popen2.Popen3(self.custom_str, True)
xmlwrite = WriteXML.XmlWriter(self.db,self.callback,False,False)
xmlwrite.write_handle(proc.tochild)
status = proc.wait()
if status:
ErrorDialog(_("Checkpoint failed"),
"\n".join(proc.childerr.readlines()))
del proc
def rcs(self):
"""
Check the generated XML file into RCS. Initialize the RCS file if
it does not already exist.
"""
(archive_base,ext) = os.path.splitext(self.db.get_save_path())
archive = archive_base + ",v"
if not os.path.exists(archive):
proc = popen2.Popen3('rcs -i -U -q -t-"GRAMPS database" %s' % archive,True)
proc.tochild.write(comment)
proc.tochild.close()
status = proc.wait()
if status:
ErrorDialog(_("Checkpoint failed"),
"\n".join(proc.childerr.readlines()))
del proc
return
xmlwrite = WriteXML.XmlWriter(self.db,self.callback,False,False)
xmlwrite.write(archive_base)
comment = self.timestamp()
proc = popen2.Popen3("ci %s" % archive_base,True)
proc.tochild.write(comment)
proc.tochild.close()
status = proc.wait()
if status:
ErrorDialog(_("Checkpoint failed"),
"\n".join(proc.childerr.readlines()))
del proc
def callback(self,value):
"""
Call back function for the WriteXML function that updates the
status progress bar.
"""
self.parent.progress.set_fraction(value)
while(gtk.events_pending()):
gtk.main_iteration()
#------------------------------------------------------------------------
#
#
#
#------------------------------------------------------------------------
from PluginMgr import register_tool
register_tool(
runTool,
_("Checkpoint the database"),
category=_("Revision control"),
description=_("Store a snapshot of the current database into "
"a revision control system"))

@ -486,7 +486,8 @@ class FamilyGroupOptions(ReportOptions.ReportOptions):
"""
spouses = self.get_spouses(dialog.db,dialog.person)
spouse_index = self.spouse_menu.get_active()
self.options_dict['spouse_id'] = spouses[spouse_index][0]
if spouses:
self.options_dict['spouse_id'] = spouses[spouse_index][0]
def make_default_style(self,default_style):
"""Make default output style for the Family Group Report."""

@ -30,7 +30,6 @@ pkgdata_PYTHON = \
IndivComplete.py\
IndivSummary.py\
Merge.py\
NavWebPage.py\
PatchNames.py\
ReadPkg.py\
RelCalc.py\

@ -573,6 +573,11 @@ class ScratchPadListView:
self.treetips = TreeTips.TreeTips(self._widget,2,True)
# Set the column that inline searching will use.
# The search does not appear to work properly so I am disabling it for now.
self._widget.set_enable_search(False)
#self._widget.set_search_column(1)
self._widget.drag_dest_set(gtk.DEST_DEFAULT_ALL,
(ScratchPadListView.LOCAL_DRAG_TARGET,) + \
DdTargets.all_targets(),
@ -793,7 +798,7 @@ class ScratchPadWindow:
"on_clear_clicked": self.on_clear_clicked,
"on_help_clicked": self.on_help_clicked,
"on_objectlist_delete_event": self.on_delete_event,
"on_scratchPad_delete_event": self.on_delete_event
"on_scratch_pad_delete_event": self.on_delete_event
})
self.clear_all_btn.connect_object('clicked', gtk.ListStore.clear, ScratchPadWindow.otree)

@ -899,7 +899,7 @@ class StatisticsChartOptions(ReportOptions.ReportOptions):
tip = _("With fewer items pie chart and legend will be used instead of a bar chart.")
self.bar_items = gtk.Entry(2)
self.bar_items.set_text(str(self.options_dict['bar_items']))
dialog.add_option(_("Min. bar char items"), self.bar_items, tip)
dialog.add_option(_("Max. items for a pie"), self.bar_items, tip)
# -------------------------------------------------
# List of available charts on a separate option tab

@ -144,7 +144,6 @@ class TestcaseGenerator:
if not self.multiple_transactions:
self.trans.set_batch(True)
self.db.disable_signals()
if self.multiple_transactions:
@ -248,6 +247,23 @@ class TestcaseGenerator:
print "DONE."
if generate_bugs or generate_dates or generate_families:
self.default_source = RelLib.Source()
self.default_source.set_title("TestcaseGenerator")
self.db.add_source(self.default_source, self.trans)
self.default_sourceref = RelLib.SourceRef()
self.default_sourceref.set_base_handle(self.default_source.get_handle())
self.default_place = RelLib.Place()
self.default_place.set_title("TestcaseGenerator place")
self.db.add_place(self.default_place, self.trans)
self.default_media = RelLib.MediaObject()
self.default_media.set_description("TestcaseGenerator media")
self.default_media.set_path("/tmp/TestcaseGenerator.png")
self.default_media.set_mime_type("image/png")
self.db.add_object(self.default_media, self.trans)
self.default_mediaref = RelLib.MediaRef()
self.default_mediaref.set_reference_handle(self.default_media.get_handle())
if generate_bugs:
self.generate_broken_relations()
@ -607,6 +623,8 @@ class TestcaseGenerator:
np = RelLib.Person()
self.add_defaults(np)
# Note
if note:
np.set_note(note)
@ -662,6 +680,7 @@ class TestcaseGenerator:
self.parents_todo.append(person2_h)
fam = RelLib.Family()
self.add_defaults(fam)
fam.set_father_handle(person1_h)
fam.set_mother_handle(person2_h)
fam.set_relationship(RelLib.Family.MARRIED)
@ -721,6 +740,15 @@ class TestcaseGenerator:
self.db.commit_person(child,self.trans)
self.commit_transaction() # COMMIT TRANSACTION STEP
def add_defaults(self,object,ref_text = ""):
object.add_source_reference(self.default_sourceref)
object.add_media_reference(self.default_mediaref)
e = RelLib.Event()
e.set_name("TestcaseGenerator")
e.set_place_handle(self.default_place.get_handle())
self.db.add_event(e, self.trans)
object.add_event_handle(e.get_handle())
def commit_transaction(self):
if self.multiple_transactions:
self.db.transaction_commit(self.trans,_("Testcase generator step %d") % self.transaction_count)

@ -29,6 +29,7 @@
#------------------------------------------------------------------------
import os
import shutil
import locale
from gettext import gettext as _
#------------------------------------------------------------------------
@ -57,6 +58,7 @@ import Errors
import Utils
from QuestionDialog import ErrorDialog
import ReportOptions
from NameDisplay import displayer as _nd
#------------------------------------------------------------------------
#
@ -943,8 +945,6 @@ class WebReport(Report.Report):
doc.write_text(_("Family Tree Index"))
doc.end_paragraph()
person_handle_list.sort(self.sort.by_last_name)
a = {}
for person_handle in person_handle_list:
person = self.database.get_person_from_handle(person_handle)
@ -956,7 +956,7 @@ class WebReport(Report.Report):
section_number = 1
link_keys = a.keys()
link_keys.sort()
link_keys.sort(locale.strcoll)
for n in link_keys:
a[n] = section_number
section_number = section_number + 1
@ -980,6 +980,7 @@ class WebReport(Report.Report):
p_id_list = [ p_id for p_id in person_handle_list if \
(self.database.get_person_from_handle(p_id).get_primary_name().get_surname() \
and (self.database.get_person_from_handle(p_id).get_primary_name().get_surname()[0] == n) ) ]
p_id_list.sort(self.sort.by_sorted_name)
doc = HtmlLinkDoc(self.selected_style,None,template,None)
doc.set_extension(self.ext)
doc.set_title(_("Section %s") % n)
@ -998,7 +999,7 @@ class WebReport(Report.Report):
for person_handle in p_id_list:
the_person = self.database.get_person_from_handle(person_handle)
name = the_person.get_primary_name().get_name()
name = _nd.sorted(the_person)
if self.birth_dates:
birth_handle = self.database.get_person_from_handle(person_handle).get_birth_handle()
@ -1040,6 +1041,7 @@ class WebReport(Report.Report):
p_id_list = [ p_id for p_id in person_handle_list if \
(self.database.get_person_from_handle(p_id).get_primary_name().get_surname() \
and (self.database.get_person_from_handle(p_id).get_primary_name().get_surname()[0] == n) ) ]
p_id_list.sort(self.sort.by_sorted_name)
doc.start_paragraph('IndexLabel')
if self.include_alpha_links:
doc.write_linktarget("%03d" % a[n])
@ -1049,7 +1051,7 @@ class WebReport(Report.Report):
for person_handle in p_id_list:
the_person = self.database.get_person_from_handle(person_handle)
name = the_person.get_primary_name().get_name()
name = _nd.sorted(the_person)
if self.birth_dates:
birth_handle = self.database.get_person_from_handle(person_handle).get_birth_handle()

@ -20,6 +20,7 @@
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="has_separator">True</property>
<signal name="delete_event" handler="on_scratch_pad_delete_event" last_modification_time="Wed, 25 May 2005 13:26:32 GMT"/>
<child internal-child="vbox">
<widget class="GtkVBox" id="dialog-vbox1">

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

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