Merge from 2.0.1

svn: r4666
This commit is contained in:
Alex Roitman 2005-05-24 13:08:06 +00:00
parent 62c65fb454
commit d7ce524379
73 changed files with 21569 additions and 14199 deletions

285
ChangeLog
View File

@ -1,6 +1,288 @@
2005-05-23 Alex Roitman <shura@gramps-project.org>
* various: merge changes made in gramps20 branch with main trunk.
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.
* src/Sources.py (drag_data_get): Return if no data.
* src/EditPerson.py (ev_drag_data_get,name_drag_data_get):
Return if no data.
* src/EditPlace.py (url_source_drag_data_get): Properly obtain data;
return if no data.
2005-05-22 Julio Sanchez <jsanchez@users.sourceforge.net>
* src/po/es.po: Updated translation for filters, tips still pending
2005-05-21 Don Allingham <don@gramps-project.org>
* src/ChooseParents.py: handle the addition of a person correctly.
Warn if the person just added is suppressed by the filter.
* src/MergePeople.py: use __debug__ for print statements
2005-05-20 Don Allingham <don@gramps-project.org>
* src/MergePeople.py: fixed name merging, incorporate Martin's
patches.
2005-05-20 Eero Tamminen <eerot@sf>
* src/po/fi.po: Merge PO file and (finally) translate the welcome
message. Otherwise translation is not yet updated
* src/data/gramps.desktop: Add Finnish translations
2005-05-20 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/WriteXML.py: Remove unnecessary database reads, so it does no
longer crash when exporting a corrupt database.
* src/WriteGedcom.py: Some hardening against corrupt database.
2005-05-20 Alex Roitman <shura@gramps-project.org>
* src/SelectObject.py (on_select_row): Properly get mime type.
* src/GrampsBSDDB.py (remove_object): Use correct key for transaction.
* src/ImageSelect.py (add_thumbnail, on_delete_media_clicked):
Identify canvas items by MediaRef instance, not by the handle of the
referred MediaObject.
* src/gramps_main.py (read_file): Remove set_resizable() calls.
* src/MediaView.py (on_drag_drop): Remove drag_get_data() call
as it was calling extraneous 'drag-data-received' signal.
* src/ReadGedcom.py (parse_person_object,parse_family_object):
Always add media references/objects, even if the files are not found
(keep the warnings); set the note for the media references.
* example/gedcom/sample.ged: Correct object format tags.
* src/ChooseParents.py (close_child_windows): Pass no arguments
to child_window.close().
2005-05-19 Don Allingham <don@gramps-project.org>
* src/DisplayModels.py: remove place column
* src/MediaView.py: delete Place option
* src/GrampsDbBase.py: new default for media columns
* src/GrampsBSDDB.py: upgrade database version for media columns
* src/MediaView.py: enable sorting by columns
* src/DisplayModels.py: enable sorting by columns for MediaModel
2005-05-19 Alex Roitman <shura@gramps-project.org>
* src/MergePeople.py (merge_family_pair): Properly use handles.
* src/RelLib.py (SourceNote.replace_source_references): Properly
replace references; (MediaBase.replace_media_references): Properly
replace references.
* src/MergeData.py: Correct comments.
* src/mergedata.glade: Make information panes non-editable.
* src/gramps.glade: Enclose date and place groups into tables,
to allow proper widget order when using tab key.
* src/EditSource.py (button_press): Properly test event names.
* src/po/ru.po: Partial update for 2.0.1.
2005-05-19 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/GenericFilter.py: Catch invalid input in some filters;
(old_names_2_class): Add one name for full 1.0.11 compatibility;
(FilterParser): Properly catch invalid rule names and invalid
module/class names.
2005-05-18 Don Allingham <don@gramps-project.org>
* src/dates/Date_de.py: handle dates in the form of dd. mon year
2005-05-18 Richard Bos <radoeka@xs4all.nl>
* src/data/gramps.desktop: Add Dutch strings.
2005-05-18 James Treacy <treacy@debian.org>
* src/data/tips.xml: Update and rework.
2005-05-18 Alex Roitman <shura@gramps-project.org>
* src/GenericFilter.py: Use class names for internal work; Rework
ID-based filters to use gramps-id instead of a handle.
* src/plugins/FilterEditor.py: Use class names for internal work.
* src/po/template.po: Update for 2.0.1.
* src/gramps_main.py (open_example): Add example database funciton.
* NEWS: Update.
* src/po/ru.po: Partial update for 2.0.1.
2005-05-18 Don Allingham <don@gramps-project.org>
* src/ReadGedcom.py: grab description for birth and death events
* src/WriteGedcom.py: export description for birth and death events
* example/gedcom/sample.ged: add test case
2005-05-18 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/GrampsInMemDB.py: Emit the *-delete signals correctly.
* src/GrampsDbBase.py: Emission of the *-update/*-add signals should not depend
on the existance of a transaction.
2005-05-18 Don Allingham <don@gramps-project.org>
* src/plugins/FilterEditor.py: sort entries in Add Rule dialog
2005-05-18 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/GrampsBSDDB.py, src/GrampsDbBase.py, src/GrampsInMemDB.py,
src/RelLib.py: Catch invalid arguments instead of crashing.
TODO: raise TypeError or HandleError instead of simply returning?
* src/plugins/TestcaseGenerator.py: Added debbuging helpers for signal emissions
2005-05-17 Don Allingham <don@gramps-project.org>
* configure.in: bump up verison number to 2.1.0
2005-05-17 Alex Roitman <shura@gramps-project.org>
* src/GenericFilter.py: Change filter rule names to make them consistent.
* src/gramps_main.py: Change filter names to make them consistent.
* src/Date.py: Import gettext.
* src/DateDisplay.py: Import gettext.
* src/GenericFilter.py: Support existing custom_filters.xml files
by adding an old2new mapping for names.
* src/AddSpouse.py (select_spouse_clicked): Display warning and
provide a way to override when trying to add child/parent as a spouse.
2005-05-17 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/plugins/ImportGeneWeb.py (decode): Decode characters and named
entities. Because gramps is not web browser based we can simply use
unicode.
2005-05-16 Don Allingham <don@gramps-project.org>
* src/PlaceView.py: select correct column for sorting
* src/SourceView.py: select correct column for sorting
* src/WriteGedcom.py: used 'replace' mode on iso-8859-1 string
encoding conversion
2005-05-16 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/ReadGedcom.py (parse_trailer): Catch EOF to warn about premature
EOF only once; Always close file; (parse_record): Properly catch
premature EOF instead of unknown level 0 records; Support single line
SOUR records; (parse_address): Support PHON and NOTE, ignore _NAME.
2005-05-16 Alex Roitman <shura@gramps-project.org>
* src/ansel_utf8.py: Convert to Unix end-of-line.
* src/plugins/StatisticsChart.py: Minor stylistic corrections.
* src/GenericFilter.py: Minor stylistic corrections.
* src/TarFile.py: Indent with spaces, remove string module.
* src/RelImage.py: Remove unused string module.
* src/SubstKeywords.py: Remove string module.
2005-05-16 Don Allingham <don@gramps-project.org>
* src/FamilyView.py: fix reordering of children in family view
2005-05-15 Don Allingham <don@gramps-project.org>
* src/ChooseParents.py: redraw window properly after person add
* src/DisplayModels.py: provide sorting support
* src/PlaceView.py: add sorting by columns
* src/SourceView.py: add sorting by columns
2005-05-14 Don Allingham <don@gramps-project.org>
* src/ReadGedcom.py: add a few more items to parse from Legacy
generated GEDCOM files
2005-05-14 Alex Roitman <shura@gramps-project.org>
* src/data/Makefile.am: Always install gramps.schemas and gramps.xml,
with or without packager mode.
2005-05-14 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/GenericFilter.py (IsSiblingOfFilterMatch): Match only sibling,
not the filterMatch; (HasEvent,HasFamilyEvent): Dont crash in filter
editor.
* src/GenericFilter.py (HasTextMatchingSubstringOf, HasTextMatchingRegexpOf):
Search media objects in full text search.
* src/RelLib.py: Add GRAMPS ID to get_text_data_list so this field is
usable in full text search; Dont crash if get_text_data_list contains
None values instead of empty strings.
* src/EditPerson.py, src/AddMedia.py, src/ImageSelect.py, src/ReportUtils.py,
src/SelectObject.py, src/plugins/Ancestors.py, src/plugins/IndivComplete.py,
src/plugins/IndivSummary.py, src/plugins/WebPage.py, src/plugins/WriteCD.py:
Dont crash with "note only" media object.
2005-05-13 Don Allingham <don@gramps-project.org>
* src/plugins/ScratchPad.py: fix GdkAtom index problem with pygtk2.4
2005-05-13 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/GenericFilter.py (HasEvent,HasFamilyEvent): Correct filter rules
2005-05-13 Alex Roitman <shura@gramps-project.org>
* src/DateDisplay.py (DateDisplayEn): Localize format names.
* src/get_strings: Support extracting strings from tips.xml file.
* src/build_po: Process tips.xml file.
* src/TipOfDay.py (TipOfDay.__init__): Use translated tips.
* src/po/template.po: new translatable strings.
* src/DateEdit.py (parse_and_check): Display date as parsed on
focus-out from the entry fields.
2005-05-13 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/SelectChild.py (on_save_child_clicked) Commit new parent family
of child properly; correct handle/object mismatch; exec parent callback
to do a proper redraw (closes #1201151)
* src/dates/Date_de.py: Register for all variants of german; Add other
variants of month names for parser
* src/Date.py: Raise Exception.DateError on invalid arguments
* src/DateParser.py: Catch DateError and use text only date as fallback
* src/plugins/TestcaseGenerator.py: Handle DateError exception
* src/plugins/ImportGeneWeb.py: Distinguish unknown people
* src/DateDisplay.py: Allow B.C.E. in years to be localized
* src/dates/Date_de.py: Some more translations including B.C.E.
2005-05-12 Don Allingham <don@gramps-project.org>
* src/GrampsBSDDB.py: force database sync on transaction commit
2005-05-12 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/GenericFilter.py (ParamFilter.apply): Set parameter list before
prepare (solves crash in full text search)
* src/gramps_main.py: Enable full text search filters again
2005-05-12 Alex Roitman <shura@gramps-project.org>
* src/plugins/Check.py (cleanup_missing_photos): Typo.
* configure.in: Bump up the version number.
* NEWS: Update.
* src/ReportUtils.py (insert_images): Pass sizes to add_media_object;
(married_str): Quit if no spouse.
* src/data/gramps.xml: Include different cases for file extensions.
* src/po/ru.po: Typo.
2005-05-12 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/plugins/TestcaseGenerator.py: Added generation of multiple date
formats including invalid dates. This is displaying and reparsing every
date to compare the result.
* src/plugins/NavWebPage.py (HomePage): Dont crash on note only object
* src/dates/Date_de.py: Updated translation
2005-05-11 Don Allingham <don@gramps-project.org>
* src/ReadGedcom.py: coerce the name into a unicode value - if the wrong character
encoding is indicated in the file, the screen display can get corrupted due to keys
that aren't unicode values
* src/dates/Date_de.py: first pass at a German date handler
2005-05-11 Martin Hawlisch <Martin.Hawlisch@gmx.de>
* src/DateHandler.py: Fallback to "C" locale instead of the ISO
format. This currently basically falls back to en, but this could
be enhanced by a translated fallback parser later.
2005-05-11 Julio Sanchez <jsanchez@users.sourceforge.net>
* src/po/es.po: remerge from 2.0.0
@ -34,6 +316,9 @@
src/po/ru.po, src/po/sv.po, src/po/template.po:
Merge changes made in gramps20 into HEAD.
2005-05-10 Don Allingham <don@gramps-project.org>
* Release: Version 2.0.0 "The Bright Side of Life"" released.
2005-05-10 Don Allingham <don@gramps-project.org>
* src/DbPrompter.py: add callback for progressbar
* src/GrampsXMLDB.py: pass callback task

11
NEWS
View File

@ -1,3 +1,14 @@
Version 2.0.1 -- the "None shall pass" release
* Example database function is back.
* Entering incestuous relations is possible (with the warning).
* Sorting in list views is back.
* Better support for non-standard GEDCOM tags produced by Legacy.
* ScratchPad works with pygtk2.4.
* Full text search filters are back.
* Date formats for non-localized dates.
* Date localization for German.
* TONS of bug fixes.
Version 2.0.0 -- the "The Bright Side of Life" release
* Bug fixes
* Translation updates.

View File

@ -7,8 +7,8 @@ AC_PREREQ(2.57)
AC_INIT(gramps, 2.1.0, gramps-bugs@lists.sourceforge.net)
AC_CONFIG_SRCDIR(src/gramps.py)
AM_INIT_AUTOMAKE(1.6.3)
dnl RELEASE=0.CVS$(head -c 10 ${srcdir}/ChangeLog | tr -d '-')
RELEASE=1
RELEASE=0.CVS$(head -c 10 ${srcdir}/ChangeLog | tr -d '-')
dnl RELEASE=1
VERSIONSTRING=$VERSION
if test x"$RELEASE" != "x"

View File

@ -60,9 +60,9 @@
1 SEX M
1 TITL Grand Poobah
1 OBJE
2 FROM jpeg
2 FORM jpeg
2 FILE foo/O0.jpg
1 BIRT
1 BIRT Edwin Michael Smith's Birth event
2 DATE 24 MAY 1961
2 PLAC San Jose, Santa Clara Co., CA
1 OCCU
@ -88,7 +88,7 @@
2 SOUR @S1601@
1 SEX F
1 OBJE
2 FROM jpeg
2 FORM jpeg
2 FILE foo/O0.jpg
1 BIRT
2 DATE 22 NOV 1933

View File

@ -159,8 +159,7 @@ class AddMediaObject:
if os.path.isfile(filename):
mtype = GrampsMime.get_type(filename)
if mtype[0:5] == "image":
if mtype and mtype.startswith("image"):
image = RelImage.scale_image(filename,const.thumbScale)
else:
image = Utils.find_mime_type_pixbuf(mtype)

View File

@ -57,7 +57,7 @@ import DateHandler
import Marriage
import NameDisplay
import GenericFilter
from QuestionDialog import ErrorDialog
from QuestionDialog import ErrorDialog, QuestionDialog2
#-------------------------------------------------------------------------
#
@ -114,7 +114,8 @@ class AddSpouse:
name = NameDisplay.displayer.display(person)
title = _("Choose Spouse/Partner of %s") % name
Utils.set_titles(self.glade.get_widget('spouseDialog'),
self.window = self.glade.get_widget('spouseDialog')
Utils.set_titles(self.window,
self.glade.get_widget('title'),title,
_('Choose Spouse/Partner'))
@ -254,14 +255,20 @@ class AddSpouse:
_("A person cannot be linked as his/her spouse"))
return
# don't do anything if adding a parent
# display warning if adding a parent
for (family_handle,frel,mrel) in self.person.get_parent_family_handle_list():
family = self.db.get_family_from_handle(family_handle)
if spouse_id in [family.get_mother_handle(),family.get_father_handle()]:
ErrorDialog(_("Error adding a spouse"),
_("A person cannot be linked as his/her "
"child's spouse"))
return
dialog = QuestionDialog2(
_("Spouse is a parent"),
_("The person selected as a spouse is a parent of the "
"active person. Usually, this is a mistake. You may "
"choose either to proceed with adding a spouse, or to "
"return to the Choose Spouse dialog to fix the problem."),
_("Proceed with adding"), _("Return to dialog"),
self.window)
if not dialog.run():
return
# don't do anything if the marriage already exists
for f in self.person.get_family_handle_list():
@ -273,10 +280,16 @@ class AddSpouse:
_("The spouse is already present in this family"))
return
if spouse_id in fam.get_child_handle_list():
ErrorDialog(_("Error adding a spouse"),
_("A person cannot be linked as his/her "
"parent's spouse"))
return
dialog = QuestionDialog2(
_("Spouse is a child"),
_("The person selected as a spouse is a child of the "
"active person. Usually, this is a mistake. You may "
"choose either to proceed with adding a spouse, or to "
"return to the Choose Spouse dialog to fix the problem."),
_("Proceed with adding"), _("Return to dialog"),
self.window)
if not dialog.run():
return
trans = self.db.transaction_begin()

View File

@ -57,7 +57,7 @@ import Date
import NameDisplay
import DateHandler
import GenericFilter
from QuestionDialog import ErrorDialog
from QuestionDialog import ErrorDialog, WarningDialog
#-------------------------------------------------------------------------
#
@ -90,6 +90,11 @@ class ChooseParents:
self.parent_selected = 0
self.renderer = gtk.CellRendererText()
db.connect('person-add', self.redraw)
db.connect('person-update', self.redraw)
db.connect('person-delete', self.redraw)
db.connect('person-rebuild', self.redraw2)
# set default filters
self.all_males_filter = GenericFilter.GenericFilter()
self.all_males_filter.add_rule(GenericFilter.IsMale([]))
@ -250,7 +255,7 @@ class ChooseParents:
def close_child_windows(self):
for child_window in self.child_windows.values():
child_window.close(None)
child_window.close()
self.child_windows = {}
def add_itself_to_menu(self):
@ -278,6 +283,18 @@ class ChooseParents:
"""Display the relevant portion of GRAMPS manual"""
gnome.help_display('gramps-manual','gramps-edit-quick')
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"""
self.father_model = PeopleModel.PeopleModel(self.db,self.father_filter)
@ -505,19 +522,31 @@ class ChooseParents:
if self.type == RelLib.Family.CIVIL_UNION:
self.parent_relation_changed(self.prel)
elif person.get_gender() == RelLib.Person.MALE:
self.redrawf()
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)
try:
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)
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."))
else:
self.redrawm()
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)
try:
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)
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."))
def add_parent_clicked(self,obj):
"""Called with the Add New Person button is pressed. Calls the QuickAdd

View File

@ -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
@ -25,6 +25,8 @@
__author__ = "Donald N. Allingham"
__version__ = "$Revision$"
from gettext import gettext as _
from Errors import DateError
from CalSdn import *
#-------------------------------------------------------------------------
@ -143,9 +145,9 @@ class Date:
Comparison function. Allows the usage of equality tests.
This allows you do run statements like 'date1 <= date2'
"""
if isinstance(other,Date):
if isinstance(other,Date):
return cmp(self.sortval,other.sortval)
else:
else:
return -1
def is_equal(self,other):
@ -233,6 +235,8 @@ class Date:
"""
Sets the modifier for the date.
"""
if val not in (MOD_NONE,MOD_BEFORE,MOD_AFTER,MOD_ABOUT,MOD_RANGE,MOD_SPAN,MOD_TEXTONLY):
raise DateError("Invalid modifier")
self.modifier = val
def get_quality(self):
@ -250,6 +254,8 @@ class Date:
"""
Sets the quality selected for the date.
"""
if val not in (QUAL_NONE,QUAL_ESTIMATED,QUAL_CALCULATED):
raise DateError("Invalid quality")
self.quality = val
def get_calendar(self):
@ -270,6 +276,8 @@ class Date:
"""
Sets the calendar selected for the date.
"""
if val not in (CAL_GREGORIAN,CAL_JULIAN,CAL_HEBREW,CAL_FRENCH,CAL_PERSIAN,CAL_ISLAMIC):
raise DateError("Invalid calendar")
self.calendar = val
def get_start_date(self):
@ -427,6 +435,18 @@ class Date:
The sort value is recalculated.
"""
if modifier in (MOD_NONE,MOD_BEFORE,MOD_AFTER,MOD_ABOUT) and len(value) < 4:
raise DateError("Invalid value. Should be: (DD,MM,YY,slash)")
if modifier in (MOD_RANGE,MOD_SPAN) and len(value) < 8:
raise DateError("Invalid value. Should be: (DD,MM,YY,slash1,DD,MM,YY,slash2)")
if modifier not in (MOD_NONE,MOD_BEFORE,MOD_AFTER,MOD_ABOUT,MOD_RANGE,MOD_SPAN,MOD_TEXTONLY):
raise DateError("Invalid modifier")
if quality not in (QUAL_NONE,QUAL_ESTIMATED,QUAL_CALCULATED):
raise DateError("Invalid quality")
if calendar not in (CAL_GREGORIAN,CAL_JULIAN,CAL_HEBREW,CAL_FRENCH,CAL_PERSIAN,CAL_ISLAMIC):
raise DateError("Invalid calendar")
self.quality = quality
self.modifier = modifier
self.calendar = calendar

View File

@ -30,6 +30,7 @@ __version__ = "$Revision$"
import Date
import locale
from gettext import gettext as _
class DateDisplay:
@ -111,6 +112,8 @@ class DateDisplay:
_mod_str = ("","before ","after ","about ","","","")
_qual_str = ("","estimated ","calculated ")
_bce_str = "%s B.C.E."
def __init__(self,format=None):
self.display_cal = [
@ -172,15 +175,19 @@ class DateDisplay:
return "%s%s%s%s" % (qual_str,self._mod_str[mod],text,self.calendar[cal])
def _slash_year(self,val,slash):
bc = ""
if val < 0:
val = - val
bc = " B.C.E"
# self._bce_str is a localizes string that prints B.C.E. at the apropriate place
format_string = self._bce_str
else:
format_string = "%s"
if slash:
return "%d/%d%s" % (val,(val%10)+1,bc)
year = "%d/%d" % (val,(val%10)+1)
else:
return "%d%s" % (val,bc)
year = "%d" % (val)
return format_string % year
def display_iso(self,date_val):
# YYYY-MM-DD (ISO)
@ -286,8 +293,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):

View File

@ -146,6 +146,7 @@ class DateEdit:
if text != self.text:
self.text = text
self.date_obj.copy(DateHandler.parser.parse(text))
self.text_obj.set_text(DateHandler.displayer.display(self.date_obj))
self.check()
def invoke_date_editor(self,obj):

View File

@ -80,7 +80,7 @@ def get_date_formats():
try:
return _lang_to_display[_lang].formats
except:
return DateDisplay.DateDisplay.formats
return _lang_to_display["C"].formats
def set_format(value):
try:
@ -126,17 +126,19 @@ try:
parser = _lang_to_parser[_lang]()
except:
print "Date parser for",_lang,"not available, using default"
parser = DateParser.DateParser()
parser = _lang_to_parser["C"]()
try:
import GrampsKeys
val = GrampsKeys.get_date_format(_lang_to_display[_lang].formats)
except:
val = 0
try:
val = GrampsKeys.get_date_format(_lang_to_display["C"].formats)
except:
val = 0
try:
displayer = _lang_to_display[_lang](val)
except:
print "Date displayer for",_lang,"not available, using default"
displayer = DateDisplay.DateDisplay(val)
displayer = _lang_to_display["C"](val)

View File

@ -44,7 +44,7 @@ import calendar
#
#-------------------------------------------------------------------------
import Date
from Errors import DateError
#-------------------------------------------------------------------------
#
# Top-level module functions
@ -587,5 +587,8 @@ class DateParser:
Parses the text, returning a Date object.
"""
new_date = Date.Date()
self.set_date(new_date,text)
try:
self.set_date(new_date,text)
except DateError:
new_date.set_as_text(text)
return new_date

View File

@ -61,14 +61,30 @@ _codeset = locale.nl_langinfo(locale.CODESET)
#-------------------------------------------------------------------------
class BaseModel(gtk.GenericTreeModel):
def __init__(self,db):
def __init__(self,db,scol=0,order=gtk.SORT_ASCENDING):
gtk.GenericTreeModel.__init__(self)
self.set_property("leak_references",False)
self.db = db
self.sort_func = self.smap[scol]
self.sort_col = scol
self.reverse = (order == gtk.SORT_DESCENDING)
self.rebuild_data()
def set_sort_column(self,col):
self.sort_func = self.smap[col]
def sort_keys(self):
return []
cursor = self.gen_cursor()
sarray = []
data = cursor.next()
while data:
sarray.append((self.sort_func(data[1]),data[0]))
data = cursor.next()
cursor.close()
sarray.sort()
if self.reverse:
sarray.reverse()
return map(lambda x: x[1], sarray)
def rebuild_data(self):
if self.db.is_open():
@ -255,9 +271,9 @@ class ChildModel(gtk.ListStore):
#-------------------------------------------------------------------------
class SourceModel(BaseModel):
def __init__(self,db):
self.sort_keys = db.get_source_handles
def __init__(self,db,scol=0,order=gtk.SORT_ASCENDING):
self.map = db.source_map
self.gen_cursor = db.get_source_cursor
self.fmap = [
self.column_title,
self.column_id,
@ -267,7 +283,15 @@ class SourceModel(BaseModel):
self.column_change,
self.column_handle,
]
BaseModel.__init__(self,db)
self.smap = [
self.column_title,
self.column_id,
self.column_author,
self.column_abbrev,
self.column_pubinfo,
self.sort_change,
]
BaseModel.__init__(self,db,scol,order)
def on_get_n_columns(self):
return len(self.fmap)+1
@ -293,6 +317,8 @@ class SourceModel(BaseModel):
def column_change(self,data):
return unicode(time.strftime(_date_format,time.localtime(data[8])),
_codeset)
def sort_change(self,data):
return time.localtime(data[8])
#-------------------------------------------------------------------------
#
@ -301,8 +327,8 @@ class SourceModel(BaseModel):
#-------------------------------------------------------------------------
class PlaceModel(BaseModel):
def __init__(self,db):
self.sort_keys = db.get_place_handles
def __init__(self,db,scol=0,order=gtk.SORT_ASCENDING):
self.gen_cursor = db.get_place_cursor
self.map = db.place_map
self.fmap = [
self.column_name,
@ -318,7 +344,21 @@ class PlaceModel(BaseModel):
self.column_change,
self.column_handle,
]
BaseModel.__init__(self,db)
self.smap = [
self.column_name,
self.column_id,
self.column_parish,
self.column_postal_code,
self.column_city,
self.column_county,
self.column_state,
self.column_country,
self.column_longitude,
self.column_latitude,
self.column_change,
self.column_handle,
]
BaseModel.__init__(self,db,scol,order)
def on_get_n_columns(self):
return len(self.fmap)+1
@ -374,6 +414,9 @@ class PlaceModel(BaseModel):
except:
return u''
def sort_change(self,data):
return time.localtime(data[11])
def column_change(self,data):
return unicode(time.strftime(_date_format,time.localtime(data[11])),
_codeset)
@ -385,8 +428,8 @@ class PlaceModel(BaseModel):
#-------------------------------------------------------------------------
class MediaModel(BaseModel):
def __init__(self,db):
self.sort_keys = db.get_media_object_handles
def __init__(self,db,scol=0,order=gtk.SORT_ASCENDING):
self.gen_cursor = db.get_media_cursor
self.map = db.media_map
self.fmap = [
@ -396,10 +439,18 @@ class MediaModel(BaseModel):
self.column_path,
self.column_change,
self.column_date,
self.column_place,
self.column_handle,
]
BaseModel.__init__(self,db)
self.smap = [
self.column_description,
self.column_id,
self.column_mime,
self.column_path,
self.sort_change,
self.column_date,
self.column_handle,
]
BaseModel.__init__(self,db,scol,order)
def on_get_n_columns(self):
return len(self.fmap)+1
@ -424,16 +475,12 @@ class MediaModel(BaseModel):
return unicode(DateHandler.displayer.display(data[9]))
return u''
def column_place(self,data):
if data[10]:
place = self.db.get_place_from_handle(data[10])
if place:
return place.get_title()
return u''
def column_handle(self,data):
return unicode(data[0])
def sort_change(self,data):
return time.localtime(data[8])
def column_change(self,data):
return unicode(time.strftime(_date_format,time.localtime(data[8])),
_codeset)

View File

@ -225,6 +225,7 @@ class EditPerson:
# event display
<<<<<<< EditPerson.py
self.event_box = ListBox.EventListBox(
self, self.person, self.event_list, events_label,
[event_add_btn,event_edit_btn,event_delete_btn])
@ -244,6 +245,53 @@ class EditPerson:
self.url_box = ListBox.UrlListBox(
self, self.person, self.web_list, web_label,
[web_add_btn, web_edit_btn, web_delete_btn])
=======
event_default = [ 'Event', 'Description', 'Date', 'Place' ]
self.event_trans = TransTable.TransTable(event_default)
evalues = {
'Event' : (_('Event'),-1,150),
'Description' : (_('Description'),-1,150),
'Date' : (_('Date'),-1,100),
'Place' : (_('Place'),-1,100)
}
#if not self.db.readonly:
# values = self.db.metadata.get('event_order',event_default)
#else:
values = event_default
etitles = []
for val in values:
etitles.append(evalues[val])
self.etree = ListModel.ListModel(self.event_list,etitles,
self.on_event_select_row,
self.on_event_update_clicked)
# attribute display
atitles = [(_('Attribute'),-1,150),(_('Value'),-1,150)]
self.atree = ListModel.ListModel(self.attr_list,atitles,
self.on_attr_select_row,
self.on_update_attr_clicked)
# address display
ptitles = [(_('Date'),-1,150),(_('Address'),-1,150)]
self.ptree = ListModel.ListModel(self.addr_list, ptitles,
self.on_addr_select_row,
self.on_update_addr_clicked)
# name display
ntitles = [(_('Name'),-1,250),(_('Type'),-1,100)]
self.ntree = ListModel.ListModel(self.name_list,ntitles,
self.on_name_select_row)
self.ntree.tree.connect('event',self.aka_double_click)
# web display
wtitles = [(_('Path'),-1,250),(_('Description'),-1,100)]
self.wtree = ListModel.ListModel(self.web_list,wtitles,
self.on_web_select_row,
self.on_update_url_clicked)
>>>>>>> 1.194.2.7
self.place_list = self.pdmap.keys()
self.place_list.sort()
@ -400,7 +448,7 @@ class EditPerson:
if progname and len(progname) > 1:
Utils.add_menuitem(menu,_("Open in %s") % progname[1],
photo,self.popup_view_photo)
if mtype[0:5] == "image":
if mtype and mtype.startswith("image"):
Utils.add_menuitem(menu,_("Edit with the GIMP"),
photo,self.popup_edit_photo)
Utils.add_menuitem(menu,_("Edit Object Properties"),photo,
@ -632,6 +680,75 @@ class EditPerson:
def set_lds_seal(self,obj):
self.lds_sealing.set_status(obj.get_active())
<<<<<<< EditPerson.py
=======
def name_drag_data_get(self,widget, context, sel_data, info, time):
name = self.ntree.get_selected_objects()
if not name:
return
bits_per = 8; # we're going to pass a string
pickled = pickle.dumps(name[0]);
data = str((DdTargets.NAME.drag_type,self.person.get_handle(),pickled));
sel_data.set(sel_data.target, bits_per, data)
def name_drag_begin(self, context, a):
return
icon = self.ntree.get_icon()
t = self.ntree.tree
(x,y) = icon.get_size()
mask = gtk.gdk.Pixmap(self.window.window,x,y,1)
mask.draw_rectangle(t.get_style().white_gc, True, 0,0,x,y)
t.drag_source_set_icon(t.get_colormap(),icon,mask)
def name_drag_data_received(self,widget,context,x,y,sel_data,info,time):
row = self.ntree.get_row_at(x,y)
if sel_data and sel_data.data:
exec 'data = %s' % sel_data.data
exec 'mytype = "%s"' % data[0]
exec 'person = "%s"' % data[1]
if mytype != DdTargets.NAME.drag_type:
return
elif person == self.person.get_handle():
self.move_element(self.nlist,self.ntree.get_selected_row(),row)
else:
foo = pickle.loads(data[2]);
for src in foo.get_source_references():
base_handle = src.get_base_handle()
newbase = self.db.get_source_from_handle(base_handle)
src.set_base_handle(newbase.get_handle())
self.nlist.insert(row,foo)
self.lists_changed = True
self.redraw_name_list()
def ev_drag_data_received(self,widget,context,x,y,sel_data,info,time):
row = self.etree.get_row_at(x,y)
if sel_data and sel_data.data:
exec 'data = %s' % sel_data.data
exec 'mytype = "%s"' % data[0]
exec 'person = "%s"' % data[1]
if mytype != DdTargets.EVENT.drag_type:
return
elif person == self.person.get_handle():
self.move_element(self.elist,self.etree.get_selected_row(),row)
else:
foo = pickle.loads(data[2]);
for src in foo.get_source_references():
base_handle = src.get_base_handle()
newbase = self.db.get_source_from_handle(base_handle)
src.set_base_handle(newbase.get_handle())
place = foo.get_place_handle()
if place:
foo.set_place_handle(place.get_handle())
self.elist.insert(row,foo.get_handle())
self.lists_changed = True
self.redraw_event_list()
>>>>>>> 1.194.2.7
def move_element(self,list,src,dest):
if src == -1:
return
@ -639,6 +756,125 @@ class EditPerson:
list.remove(obj)
list.insert(dest,obj)
<<<<<<< EditPerson.py
=======
def ev_drag_data_get(self,widget, context, sel_data, info, time):
ev = self.etree.get_selected_objects()
if not ev:
return
bits_per = 8; # we're going to pass a string
pickled = pickle.dumps(ev[0]);
data = str((DdTargets.EVENT.drag_type,self.person.get_handle(),pickled));
sel_data.set(sel_data.target, bits_per, data)
def ev_drag_begin(self, context, a):
return
icon = self.etree.get_icon()
t = self.etree.tree
(x,y) = icon.get_size()
mask = gtk.gdk.Pixmap(self.window.window,x,y,1)
mask.draw_rectangle(t.get_style().white_gc, True, 0,0,x,y)
t.drag_source_set_icon(t.get_colormap(),icon,mask)
def url_drag_data_received(self,widget,context,x,y,sel_data,info,time):
row = self.wtree.get_row_at(x,y)
if sel_data and sel_data.data:
exec 'data = %s' % sel_data.data
exec 'mytype = "%s"' % data[0]
exec 'person = "%s"' % data[1]
if mytype != DdTargets.URL.drag_type:
return
elif person == self.person.get_handle():
self.move_element(self.ulist,self.wtree.get_selected_row(),row)
else:
foo = pickle.loads(data[2]);
self.ulist.append(foo)
self.lists_changed = True
self.redraw_url_list()
def url_drag_begin(self, context, a):
return
def url_drag_data_get(self,widget, context, sel_data, info, time):
ev = self.wtree.get_selected_objects()
if len(ev):
bits_per = 8; # we're going to pass a string
pickled = pickle.dumps(ev[0]);
data = str((DdTargets.URL.drag_type,self.person.get_handle(),pickled));
sel_data.set(sel_data.target, bits_per, data)
def at_drag_data_received(self,widget,context,x,y,sel_data,info,time):
row = self.atree.get_row_at(x,y)
if sel_data and sel_data.data:
exec 'data = %s' % sel_data.data
exec 'mytype = "%s"' % data[0]
exec 'person = "%s"' % data[1]
if mytype != DdTargets.ATTRIBUTE.drag_type:
return
elif person == self.person.get_handle():
self.move_element(self.alist,self.atree.get_selected_row(),row)
else:
foo = pickle.loads(data[2]);
for src in foo.get_source_references():
base_handle = src.get_base_handle()
newbase = self.db.get_source_from_handle(base_handle)
src.set_base_handle(newbase.get_handle())
self.alist.append(foo)
self.lists_changed = True
self.redraw_attr_list()
def at_drag_begin(self, context, a):
return
def at_drag_data_get(self,widget, context, sel_data, info, time):
ev = self.atree.get_selected_objects()
if len(ev):
bits_per = 8; # we're going to pass a string
pickled = pickle.dumps(ev[0]);
data = str((DdTargets.ATTRIBUTE.drag_type,
self.person.get_handle(),pickled));
sel_data.set(sel_data.target, bits_per, data)
def ad_drag_data_received(self,widget,context,x,y,sel_data,info,time):
row = self.ptree.get_row_at(x,y)
if sel_data and sel_data.data:
exec 'data = %s' % sel_data.data
exec 'mytype = "%s"' % data[0]
exec 'person = "%s"' % data[1]
if mytype != DdTargets.ADDRESS.drag_type:
return
elif person == self.person.get_handle():
self.move_element(self.plist,self.ptree.get_selected_row(),row)
else:
foo = pickle.loads(data[2]);
for src in foo.get_source_references():
base_handle = src.get_base_handle()
newbase = self.db.get_source_from_handle(base_handle)
src.set_base_handle(newbase.get_handle())
self.plist.insert(row,foo)
self.lists_changed = True
self.redraw_addr_list()
def ad_drag_data_get(self,widget, context, sel_data, info, time):
ev = self.ptree.get_selected_objects()
if len(ev):
bits_per = 8; # we're going to pass a string
pickled = pickle.dumps(ev[0]);
data = str((DdTargets.ADDRESS.drag_type,
self.person.get_handle(),pickled));
sel_data.set(sel_data.target, bits_per, data)
def ad_drag_begin(self, context, a):
return
>>>>>>> 1.194.2.7
def menu_changed(self,obj):
self.ldsfam = self.lds_fam_list[obj.get_active()]
@ -1127,7 +1363,8 @@ class EditPerson:
object_handle = ph.get_reference_handle()
obj = self.db.get_object_from_handle(object_handle)
if self.load_obj != obj.get_path():
if obj.get_mime_type()[0:5] == "image":
mime_type = obj.get_mime_type()
if mime_type and mime_type.startswith("image"):
self.load_photo(obj.get_path())
else:
self.load_photo(None)

View File

@ -314,11 +314,14 @@ class EditPlace:
self.redraw_url_list()
def url_source_drag_data_get(self,widget, context, sel_data, info, time):
ev = self.web_model.get_selected_objects()[0]
store,node = self.web_list.get_selection().get_selected()
if not node:
return
row = store.get_path(node)
url = self.ulist[row[0]]
bits_per = 8; # we're going to pass a string
pickled = pickle.dumps(ev);
data = str(('url',self.place.get_handle(),pickled));
pickled = pickle.dumps(url)
data = str(('url',self.place.get_handle(),pickled))
sel_data.set(sel_data.target, bits_per, data)
def update_lists(self):

View File

@ -255,31 +255,38 @@ class EditSource:
def button_press(self,obj):
data = self.model.get_selected_objects()
(type,handle) = data[0]
if type == 0:
if not data:
return
(data_type,handle) = data[0]
if data_type == 0:
import EditPerson
person = self.db.get_person_from_handle(handle)
EditPerson.EditPerson(self.parent,person,self.db)
elif type == 1:
elif data_type == 1:
import Marriage
family = self.db.get_family_from_handle(handle)
Marriage.Marriage(self.parent,family,self.db)
elif type == 2:
elif data_type == 2:
import EventEdit
event = self.db.get_event_from_handle(handle)
if event.get_name() in const.marriageEvents:
event_name = event.get_name()
if const.family_events.has_key(event_name):
EventEdit.EventEditor(
self,", ", const.marriageEvents, const.family_events,
event, None, 0, None, None, self.db.readonly)
elif event.get_name() in const.personalEvents + [_("Birth"),_("Death")]:
elif const.personal_events.has_key(event_name):
EventEdit.EventEditor(
self,", ", const.personalEvents, const.personal_events,
event, None, 0, None, None, self.db.readonly)
elif type == 3:
elif event_name in ["Birth","Death"]:
EventEdit.EventEditor(
self,", ", const.personalEvents, const.personal_events,
event, None, 1, None, None, self.db.readonly)
elif data_type == 3:
import EditPlace
place = self.db.get_place_from_handle(handle)
EditPlace.EditPlace(self.parent,place)
elif type == 5:
elif data_type == 5:
import ImageSelect
media = self.db.get_object_from_handle(handle)
ImageSelect.GlobalMediaProperties(self.db,media,self)

View File

@ -260,8 +260,7 @@ class FamilyView:
DdTargets.PERSON_LINK.target()],
ACTION_COPY)
self.child_list.drag_source_set(BUTTON1_MASK,
[DdTargets.CHILD.target(),
DdTargets.PERSON_LINK.target()],
[DdTargets.CHILD.target()],
ACTION_COPY)
self.child_list.connect('drag_data_get', self.drag_data_get)
self.child_list.connect('drag_data_received',self.drag_data_received)

File diff suppressed because it is too large Load Diff

View File

@ -43,7 +43,7 @@ from bsddb import dbshelve, db
from RelLib import *
from GrampsDbBase import *
_DBVERSION = 5
_DBVERSION = 6
def find_surname(key,data):
return str(data[3].get_surname())
@ -292,6 +292,57 @@ class GrampsBSDDB(GrampsDbBase):
vals.sort()
return vals
<<<<<<< GrampsBSDDB.py
=======
def remove_person(self,handle,transaction):
if not self.readonly and handle and str(handle) in self.person_map:
person = self.get_person_from_handle(handle)
self.genderStats.uncount_person (person)
if transaction != None:
transaction.add(PERSON_KEY,handle,person.serialize())
self.emit('person-delete',([str(handle)],))
self.person_map.delete(str(handle))
def remove_source(self,handle,transaction):
if not self.readonly and handle and str(handle) in self.source_map:
if transaction != None:
old_data = self.source_map.get(str(handle))
transaction.add(SOURCE_KEY,handle,old_data)
self.emit('source-delete',([handle],))
self.source_map.delete(str(handle))
def remove_family(self,handle,transaction):
if not self.readonly and handle and str(handle) in self.family_map:
if transaction != None:
old_data = self.family_map.get(str(handle))
transaction.add(FAMILY_KEY,handle,old_data)
self.emit('family-delete',([str(handle)],))
self.family_map.delete(str(handle))
def remove_event(self,handle,transaction):
if not self.readonly and handle and str(handle) in self.event_map:
if transaction != None:
old_data = self.event_map.get(str(handle))
transaction.add(EVENT_KEY,handle,old_data)
self.event_map.delete(str(handle))
def remove_place(self,handle,transaction):
if not self.readonly and handle and str(handle) in self.place_map:
if transaction != None:
old_data = self.place_map.get(handle)
transaction.add(PLACE_KEY,handle,old_data)
self.emit('place-delete',([handle],))
self.place_map.delete(str(handle))
def remove_object(self,handle,transaction):
if not self.readonly and handle and str(handle) in self.media_map:
if transaction != None:
old_data = self.media_map.get(handle)
transaction.add(MEDIA_KEY,handle,old_data)
self.emit('media-delete',([handle],))
self.media_map.delete(str(handle))
>>>>>>> 1.41.2.5
def get_person_from_gramps_id(self,val):
"""finds a Person in the database from the passed gramps' ID.
If no such Person exists, a new Person is added to the database."""
@ -352,6 +403,25 @@ class GrampsBSDDB(GrampsDbBase):
else:
return None
def transaction_commit(self,transaction,msg):
GrampsDbBase.transaction_commit(self,transaction,msg)
self.family_map.sync()
self.place_map.sync()
self.source_map.sync()
self.media_map.sync()
self.event_map.sync()
self.metadata.sync()
self.person_map.sync()
self.surnames.sync()
self.name_group.sync()
self.id_trans.sync()
self.fid_trans.sync()
self.pid_trans.sync()
self.sid_trans.sync()
self.oid_trans.sync()
self.eventnames.sync()
self.undodb.sync()
def upgrade(self):
child_rel_notrans = [
"None", "Birth", "Adopted", "Stepchild",
@ -366,6 +436,8 @@ class GrampsBSDDB(GrampsDbBase):
self.upgrade_4(child_rel_notrans)
if version < 5:
self.upgrade_5()
if version < 6:
self.upgrade_6()
self.metadata['version'] = _DBVERSION
print 'Successfully finished all upgrades'
@ -674,3 +746,11 @@ class GrampsBSDDB(GrampsDbBase):
self.commit_source(source,None)
data = cursor.next()
cursor.close()
def upgrade_6(self):
print "Upgrading to DB version 6"
order = []
for val in self.get_media_column_order():
if val[1] != 6:
order.append(val)
self.set_media_column_order(order)

View File

@ -270,7 +270,7 @@ class GrampsDbBase(GrampsDBCallback.GrampsDBCallback):
Commits the specified Person to the database, storing the changes
as part of the transaction.
"""
if self.readonly or not obj.handle:
if self.readonly or not obj or not obj.handle:
return
if change_time:
obj.change = int(change_time)
@ -574,13 +574,13 @@ class GrampsDbBase(GrampsDBCallback.GrampsDBCallback):
self.genderStats.count_person (person, self)
return person.handle
def _add_object(self,object,transaction,find_next_func,commit_func):
if not object.gramps_id:
object.gramps_id = find_next_func()
if not object.handle:
object.handle = self.create_id()
commit_func(object,transaction)
return object.handle
def _add_object(self,obj,transaction,find_next_func,commit_func):
if not obj.gramps_id:
obj.gramps_id = find_next_func()
if not obj.handle:
obj.handle = self.create_id()
commit_func(obj,transaction)
return obj.handle
def add_family(self,family,transaction):
"""
@ -1230,8 +1230,20 @@ class GrampsDbBase(GrampsDBCallback.GrampsDBCallback):
Returns the MediaObject display common information stored in the
database's metadata.
"""
<<<<<<< GrampsDbBase.py
default = [(1,1),(0,5),(0,6),(1,2),(1,3),(0,4)]
return self._get_column_order(MEDIA_COL_KEY,default)
=======
default = [(1,1),(0,5),(0,4),(1,2),(1,3)]
if self.metadata == None:
return default
else:
cols = self.metadata.get('media_columns',default)
if len(cols) != len(default):
return cols + default[len(cols):]
else:
return cols
>>>>>>> 1.53.2.3
class Transaction:
"""

View File

@ -145,59 +145,124 @@ class GrampsInMemDB(GrampsDbBase):
vals.sort()
return vals
<<<<<<< GrampsInMemDB.py
def _del_person(self,handle):
=======
def remove_person(self,handle,transaction):
if self.readonly or not handle or str(handle) not in self.person_map:
return
person = self.get_person_from_handle(handle)
self.genderStats.uncount_person (person)
if transaction != None:
old_data = self.person_map.get(handle)
transaction.add(PERSON_KEY,handle,old_data)
self.emit('person-delete',([handle],))
>>>>>>> 1.23.2.2
del self.id_trans[person.get_gramps_id()]
del self.person_map[handle]
<<<<<<< GrampsInMemDB.py
def _del_source(self,handle):
=======
def remove_source(self,handle,transaction):
if self.readonly or not handle or str(handle) not in self.source_map:
return
source = self.get_source_from_handle(handle)
if transaction != None:
old_data = self.source_map.get(str(handle))
transaction.add(SOURCE_KEY,handle,old_data)
self.emit('source-delete',([handle],))
>>>>>>> 1.23.2.2
del self.sid_trans[source.get_gramps_id()]
del self.source_map[str(handle)]
<<<<<<< GrampsInMemDB.py
def _del_place(self,handle):
=======
def remove_place(self,handle,transaction):
if self.readonly or not handle or str(handle) not in self.place_map:
return
place = self.get_place_from_handle(handle)
if transaction != None:
old_data = self.place_map.get(str(handle))
transaction.add(PLACE_KEY,handle,old_data)
self.emit('place-delete',([handle],))
>>>>>>> 1.23.2.2
del self.pid_trans[place.get_gramps_id()]
del self.place_map[str(handle)]
<<<<<<< GrampsInMemDB.py
def _del_media(self,handle):
=======
def remove_object(self,handle,transaction):
if self.readonly or not handle or str(handle) not in self.media_map:
return
obj = self.get_object_from_handle(handle)
if transaction != None:
old_data = self.media_map.get(str(handle))
transaction.add(MEDIA_KEY,handle,old_data)
self.emit('media-delete',([handle],))
>>>>>>> 1.23.2.2
del self.oid_trans[obj.get_gramps_id()]
del self.media_map[str(handle)]
<<<<<<< GrampsInMemDB.py
def _del_family(self,handle):
=======
def remove_family(self,handle,transaction):
if self.readonly or not handle or str(handle) not in self.family_map:
return
family = self.get_family_from_handle(handle)
if transaction != None:
old_data = self.family_map.get(str(handle))
transaction.add(FAMILY_KEY,handle,old_data)
self.emit('family-delete',([handle],))
>>>>>>> 1.23.2.2
del self.fid_trans[family.get_gramps_id()]
del self.family_map[str(handle)]
<<<<<<< GrampsInMemDB.py
def _del_event(self,handle):
=======
def remove_event(self,handle,transaction):
if self.readonly or not handle or str(handle) not in self.event_map:
return
if transaction != None:
old_data = self.event_map.get(str(handle))
transaction.add(EVENT_KEY,handle,old_data)
>>>>>>> 1.23.2.2
del self.event_map[str(handle)]
def commit_person(self,person,transaction,change_time=None):
if self.readonly or not person.get_handle():
if self.readonly or not person or not person.get_handle():
return
gid = person.get_gramps_id()
self.id_trans[gid] = person.get_handle()
GrampsDbBase.commit_person(self,person,transaction,change_time)
def commit_place(self,place,transaction,change_time=None):
if self.readonly or not place.get_handle():
if self.readonly or not place or not place.get_handle():
return
gid = place.get_gramps_id()
self.pid_trans[gid] = place.get_handle()
GrampsDbBase.commit_place(self,place,transaction,change_time)
def commit_family(self,family,transaction,change_time=None):
if self.readonly or not family.get_handle():
if self.readonly or not family or not family.get_handle():
return
gid = family.get_gramps_id()
self.fid_trans[gid] = family.get_handle()
GrampsDbBase.commit_family(self,family,transaction,change_time)
def commit_media_object(self,obj,transaction,change_time=None):
if self.readonly or not obj.get_handle():
if self.readonly or not obj or not obj.get_handle():
return
gid = obj.get_gramps_id()
self.oid_trans[gid] = obj.get_handle()
GrampsDbBase.commit_media_object(self,obj,transaction,change_time)
def commit_source(self,source,transaction,change_time=None):
if self.readonly or not source.get_handle():
if self.readonly or not source or not source.get_handle():
return
gid = source.get_gramps_id()
self.sid_trans[gid] = source.get_handle()

View File

@ -147,7 +147,7 @@ class ImageSelect:
if os.path.isfile(filename):
mtype = GrampsMime.get_type(filename)
if mtype[0:5] == "image":
if mtype and mtype.startswith("image"):
image = RelImage.scale_image(filename,const.thumbScale)
self.image.set_from_pixbuf(image)
else:
@ -284,6 +284,8 @@ class Gallery(ImageSelect):
self.drag_item = widget.get_item_at(self.remember_x,
self.remember_y)
icon_index = self.get_index(widget,event.x,event.y)-1
if icon_index == -1:
return
self.sel_obj = self.dataobj.get_media_list()[icon_index]
if self.drag_item:
widget.drag_begin([DdTargets.MEDIAOBJ.target()]+_drag_targets,
@ -361,20 +363,19 @@ class Gallery(ImageSelect):
def add_thumbnail(self, photo):
"""Scale the image and add it to the IconList."""
oid = photo.get_reference_handle()
obj = self.db.get_object_from_handle(oid)
if self.canvas_list.has_key(oid):
(grp,item,text,x,y) = self.canvas_list[oid]
media_obj = self.db.get_object_from_handle(oid)
if self.canvas_list.has_key(photo):
(grp,item,text,x,y) = self.canvas_list[photo]
if x != self.cx or y != self.cy:
grp.move(self.cx-x,self.cy-y)
else:
description = obj.get_description()
description = media_obj.get_description()
if len(description) > 20:
description = "%s..." % description[0:20]
try:
media_obj = self.db.get_object_from_handle(oid)
mtype = media_obj.get_mime_type()
if mtype[0:5] == "image":
if mtype and mtype.startswith("image"):
image = ImgManip.get_thumbnail_image(media_obj.get_path())
else:
image = Utils.find_mime_type_pixbuf(mtype)
@ -417,7 +418,7 @@ class Gallery(ImageSelect):
self.p_map[i] = (item,text,box,photo,oid)
i.show()
self.canvas_list[oid] = (grp,item,text,self.cx,self.cy)
self.canvas_list[photo] = (grp,item,text,self.cx,self.cy)
self.cx += _PAD + _IMAGEX
@ -575,7 +576,7 @@ class Gallery(ImageSelect):
if self.sel:
(i,t,b,photo,oid) = self.p_map[self.sel]
val = self.canvas_list[photo.get_reference_handle()]
val = self.canvas_list[photo]
val[0].hide()
val[1].hide()
val[2].hide()
@ -607,7 +608,7 @@ class Gallery(ImageSelect):
if progname and len(progname) > 1:
Utils.add_menuitem(menu,_("Open in %s") % progname[1],
photo,self.popup_view_photo)
if mtype[0:5] == "image":
if mtype and mtype.startswith("image"):
Utils.add_menuitem(menu,_("Edit with the GIMP"),
photo,self.popup_edit_photo)
Utils.add_menuitem(menu,_("Edit Object Properties"),photo,

View File

@ -60,7 +60,6 @@ column_names = [
_('Path'),
_('Last Changed'),
_('Date'),
_('Place'),
]
_HANDLE_COL = len(column_names)
@ -84,6 +83,7 @@ class MediaView:
self.topWindow = glade.get_widget("gramps")
self.renderer = gtk.CellRendererText()
self.model = DisplayModels.MediaModel(self.db)
self.sort_col = 0
self.selection = self.list.get_selection()
self.list.set_model(self.model)
@ -130,13 +130,51 @@ class MediaView:
self.build_columns()
self.build_tree()
def column_clicked(self,obj,data):
if self.sort_col != data:
order = gtk.SORT_ASCENDING
else:
if (self.columns[data].get_sort_order() == gtk.SORT_DESCENDING
or self.columns[data].get_sort_indicator() == False):
order = gtk.SORT_ASCENDING
else:
order = gtk.SORT_DESCENDING
self.sort_col = data
handle = self.first_selected()
self.model = DisplayModels.MediaModel(self.parent.db,
self.sort_col,order)
self.list.set_model(self.model)
colmap = self.parent.db.get_place_column_order()
if handle:
path = self.model.on_get_path(handle)
self.selection.select_path(path)
self.list.scroll_to_cell(path,None,1,0.5,0)
for i in range(0,len(self.columns)):
self.columns[i].set_sort_indicator(i==colmap[data][1]-1)
self.columns[self.sort_col].set_sort_order(order)
def first_selected(self):
mlist = []
self.selection.selected_foreach(self.blist,mlist)
if mlist:
return mlist[0]
else:
return None
def blist(self,store,path,iter,list):
handle = store.get_value(iter,_HANDLE_COL)
list.append(handle)
def build_columns(self):
for column in self.columns:
self.list.remove_column(column)
column = gtk.TreeViewColumn(_('Title'), self.renderer,text=0)
column.set_resizable(True)
column.connect('clicked',self.column_clicked,0)
column.set_clickable(True)
column.set_min_width(225)
self.list.append_column(column)
self.columns = [column]
@ -149,6 +187,8 @@ class MediaView:
column = gtk.TreeViewColumn(name, self.renderer, text=pair[1])
column.set_resizable(True)
column.set_min_width(75)
column.set_clickable(True)
column.connect('clicked',self.column_clicked,index)
self.columns.append(column)
self.list.append_column(column)
index += 1
@ -326,7 +366,6 @@ class MediaView:
def on_drag_drop(self, tree, context, x, y, time):
self.list.emit_stop_by_name('drag-drop')
self.list.drag_get_data(context,context.targets[-1],time)
return 1
def on_drag_begin(self,obj,context):

View File

@ -168,8 +168,8 @@ class MergePlaces:
#-------------------------------------------------------------------------
class MergeSources:
"""
Merges to places into a single place. Displays a dialog box that
allows the places to be combined into one.
Merges to sources into a single source. Displays a dialog box that
allows the sources to be combined into one.
"""
def __init__(self,database,new_handle,old_handle,update):
self.db = database
@ -291,7 +291,7 @@ class MergeSources:
event = self.db.get_event_from_handle(handle)
if event.has_source_reference(self.old_handle):
event.replace_source_references(self.old_handle,self.new_handle)
self.db.commit_event(event,self.trans)
self.db.commit_event(event,self.trans)
# sources
for handle in self.db.get_source_handles():

View File

@ -281,26 +281,78 @@ class MergePeople:
else:
one.add_source_reference(xsrc)
def debug_person(self,person, msg=""):
if __debug__:
print "## %s person handle %s" % (msg,person.get_handle())
for h in person.get_family_handle_list():
fam = self.db.get_family_from_handle(h)
print " - family %s has father: %s, mother: %s" % \
(h,fam.get_father_handle(),fam.get_mother_handle())
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())
# copy names
new.set_alternate_names(self.p1.get_alternate_names() +
self.p2.get_alternate_names())
# copy addresses
new.set_address_list(self.p1.get_address_list() + self.p2.get_address_list())
@ -320,68 +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)
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.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:
new_list.append(id1)
change = True
else:
new_list.append(child_id)
if change:
family.set_child_handle_list(new_list)
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):
"""
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.
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()
# 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)
# 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_parents(self, new, trans):
f1_list = self.p1.get_parent_family_handle_list()
f2_list = self.p2.get_parent_family_handle_list()
parent_list = f1_list
for fid in f2_list:
self.convert_child_ids(fid[0], self.new_handle, self.old_handle, trans)
parent_list.append(fid)
for fid in parent_list:
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 merge_relationships(self,new,trans):
"""
Merges the relationships associated with the merged people.
"""
def find_family(self,family):
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()
family_num = 0
family_list = self.p1.get_family_handle_list()
for src_handle in self.p2.get_family_handle_list():
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):
return myfamily
return None
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 "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 "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):
@ -391,13 +721,13 @@ class MergePeople:
if child_handle not in tgt_family.get_child_handle_list():
child = self.db.get_person_from_handle(child_handle)
parents = child.get_parent_family_handle_list()
tgt_family.add_child_handle(child)
if child.get_main_parents_family_handle() == src_family:
child.set_main_parent_family_handle(tgt_family)
tgt_family.add_child_handle(child_handle)
if child.get_main_parents_family_handle() == src_family.get_handle():
child.set_main_parent_family_handle(tgt_family.get_handle())
i = 0
for fam in parents[:]:
if fam[0] == src_family.get_handle():
parents[i] = (tgt_family,fam[1],fam[2])
parents[i] = (tgt_family.get_handle(),fam[1],fam[2])
i += 1
self.db.commit_person(child,trans)
@ -430,135 +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)
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)
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)
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)
father.add_family_handle(tgt_family_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)
mother.add_family_handle(tgt_family_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)
else:
for fid in self.p1.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 self.p1.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 src_family.get_mother_handle() == self.old_handle:
src_family.set_mother_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:
@ -576,13 +819,8 @@ class MergePeople:
child.remove_parent_family_handle(family_handle)
self.db.commit_person(child,trans)
self.db.remove_family(family_handle,trans)
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)
if __debug__:
print "Deleted empty family %s" % family_handle
def merge_notes(self, note1, note2):
if note1 and not note2:
@ -595,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)

View File

@ -82,21 +82,49 @@ class PlaceView:
self.list.set_model(self.model)
self.topWindow = self.glade.get_widget("gramps")
self.sort_col = 0
self.columns = []
self.change_db(db)
def column_clicked(self,obj,data):
if self.sort_col != data:
order = gtk.SORT_ASCENDING
else:
if (self.columns[data].get_sort_order() == gtk.SORT_DESCENDING
or self.columns[data].get_sort_indicator() == False):
order = gtk.SORT_ASCENDING
else:
order = gtk.SORT_DESCENDING
self.sort_col = data
handle = self.first_selected()
self.model = DisplayModels.PlaceModel(self.parent.db,
self.sort_col,order)
self.list.set_model(self.model)
colmap = self.parent.db.get_place_column_order()
if handle:
path = self.model.on_get_path(handle)
self.selection.select_path(path)
self.list.scroll_to_cell(path,None,1,0.5,0)
for i in range(0,len(self.columns)):
self.columns[i].set_sort_indicator(i==colmap[data][1]-1)
self.columns[self.sort_col].set_sort_order(order)
def build_columns(self):
for column in self.columns:
self.list.remove_column(column)
column = gtk.TreeViewColumn(_('Place Name'), self.renderer,text=0)
column.set_resizable(True)
column.set_min_width(225)
column.connect('clicked',self.column_clicked,0)
column.set_clickable(True)
self.list.append_column(column)
self.columns = [column]
index = 1
for pair in self.parent.db.get_place_column_order():
if not pair[0]:
continue
@ -104,6 +132,9 @@ class PlaceView:
column = gtk.TreeViewColumn(name, self.renderer, text=pair[1])
column.set_resizable(True)
column.set_min_width(75)
column.set_clickable(True)
column.connect('clicked',self.column_clicked,index)
index += 1
self.columns.append(column)
self.list.append_column(column)
@ -236,6 +267,14 @@ class PlaceView:
place = self.parent.db.get_place_from_handle(place_handle)
EditPlace.EditPlace(self.parent, place,self.topWindow)
def first_selected(self):
mlist = []
self.selection.selected_foreach(self.blist,mlist)
if mlist:
return mlist[0]
else:
return None
def blist(self,store,path,iter,list):
handle = store.get_value(iter,_HANDLE_COL)
list.append(handle)

View File

@ -438,9 +438,9 @@ class GedcomParser:
ln = len(l)
try:
if ln == 2:
self.groups = (int(l[0]),l[1],"")
self.groups = (int(l[0]),unicode(l[1]),u"")
else:
self.groups = (int(l[0]),l[1],l[2])
self.groups = (int(l[0]),unicode(l[1]),unicode(l[2]))
except:
if self.text == "":
msg = _("Warning: line %d was blank, so it was ignored.\n") % self.index
@ -528,9 +528,9 @@ class GedcomParser:
def parse_trailer(self):
matches = self.get_next()
if matches[1] != "TRLR":
if matches[0] >= 0 and matches[1] != "TRLR":
self.barf(0)
self.f.close()
self.f.close()
def parse_header(self):
self.parse_header_head()
@ -551,7 +551,7 @@ class GedcomParser:
self.backup()
return
elif matches[1] == "NAME":
self.def_src.set_author(unicode(matches[2]))
self.def_src.set_author(matches[2])
elif matches[1] == ["ADDR"]:
self.ignore_sub_junk(level+1)
@ -573,7 +573,7 @@ class GedcomParser:
title = matches[2] + self.parse_continue_data(level+1)
title = title.replace('\n',' ')
self.source.set_title(title)
elif matches[1] == "TAXT" or matches[1] == "PERI": # EasyTree Sierra On-Line
elif matches[1] in ["TAXT","PERI"]: # EasyTree Sierra On-Line
if self.source.get_title() == "":
title = matches[2] + self.parse_continue_data(level+1)
title = title.replace('\n',' ')
@ -603,7 +603,7 @@ class GedcomParser:
note = "%s %s" % (matches[1],matches[2])
def parse_record(self):
while 1:
while True:
matches = self.get_next()
if matches[2] == "FAM":
if self.fam_count % UPDATE == 0 and self.window:
@ -654,6 +654,12 @@ class GedcomParser:
self.ignore_sub_junk(1)
elif matches[2] == "SOUR":
self.parse_source(matches[1],1)
elif matches[2].startswith("SOUR "):
# A source formatted in a single line, for example:
# 0 @S62@ SOUR This is the title of the source
source = self.find_or_create_source(matches[1][1:-1])
source.set_title( matches[2][5:])
self.db.commit_source(source, self.trans)
elif matches[2][0:4] == "NOTE":
if self.nmap.has_key(matches[1]):
noteobj = self.nmap[matches[1]]
@ -668,7 +674,7 @@ class GedcomParser:
# TODO: Add support for extended Locations.
# See: http://en.wiki.genealogy.net/index.php/Gedcom_5.5EL
self.ignore_sub_junk(1)
elif matches[0] < 1 or matches[1] == "TRLR":
elif matches[0] < 0 or matches[1] == "TRLR":
self.backup()
return
else:
@ -914,9 +920,9 @@ class GedcomParser:
def parse_individual(self):
name_cnt = 0
note = ""
while 1:
while True:
matches = self.get_next()
if int(matches[0]) < 1:
self.backup()
return
@ -1019,6 +1025,8 @@ class GedcomParser:
self.person.add_address(addr)
elif matches[1] == "BIRT":
event = RelLib.Event()
if matches[2]:
event.set_description(matches[2])
self.db.add_event(event, self.trans)
if self.person.get_birth_handle():
event.set_name("Alternate Birth")
@ -1037,6 +1045,8 @@ class GedcomParser:
self.db.commit_event(event, self.trans)
elif matches[1] == "DEAT":
event = RelLib.Event()
if matches[2]:
event.set_description(matches[2])
self.db.add_event(event, self.trans)
if self.person.get_death_handle():
event.set_name("Alternate Death")
@ -1074,7 +1084,7 @@ class GedcomParser:
attr.set_type(matches[1])
attr.set_value(matches[2])
self.person.add_attribute(attr)
elif matches[1] in ["CHAN","ASSO","ANCI","DESI","RIN"]:
elif matches[1] in ["CHAN","ASSO","ANCI","DESI","RIN","_TODO"]:
self.ignore_sub_junk(2)
else:
event = RelLib.Event()
@ -1150,9 +1160,12 @@ class GedcomParser:
filename = ""
title = "no title"
note = ""
while 1:
while True:
matches = self.get_next()
if matches[1] == "FORM":
if int(matches[0]) < level:
self.backup()
break
elif matches[1] == "FORM":
form = matches[2].lower()
elif matches[1] == "TITL":
title = matches[2]
@ -1162,9 +1175,6 @@ class GedcomParser:
note = matches[2] + self.parse_continue_data(level+1)
elif matches[1][0] == "_":
self.ignore_sub_junk(level+1)
elif int(matches[0]) < level:
self.backup()
break
else:
self.barf(level+1)
@ -1180,21 +1190,22 @@ class GedcomParser:
self.warn(_("\tThe following paths were tried:\n\t\t"))
self.warn("\n\t\t".join(path))
self.warn('\n')
path = filename.replace('\\','/')
photo_handle = self.media_map.get(path)
if photo_handle == None:
photo = RelLib.MediaObject()
photo.set_path(path)
photo.set_description(title)
photo.set_mime_type(GrampsMime.get_type(os.path.abspath(path)))
self.db.add_object(photo, self.trans)
self.media_map[path] = photo.get_handle()
else:
photo_handle = self.media_map.get(path)
if photo_handle == None:
photo = RelLib.MediaObject()
photo.set_path(path)
photo.set_description(title)
photo.set_mime_type(GrampsMime.get_type(os.path.abspath(path)))
self.db.add_object(photo, self.trans)
self.media_map[path] = photo.get_handle()
else:
photo = self.db.get_object_from_handle(photo_handle)
oref = RelLib.MediaRef()
oref.set_reference_handle(photo.get_handle())
self.person.add_media_reference(oref)
self.db.commit_person(self.person, self.trans)
photo = self.db.get_object_from_handle(photo_handle)
oref = RelLib.MediaRef()
oref.set_reference_handle(photo.get_handle())
oref.set_note(note)
self.person.add_media_reference(oref)
self.db.commit_person(self.person, self.trans)
def parse_family_object(self,level):
form = ""
@ -1224,21 +1235,22 @@ class GedcomParser:
self.warn(_("\tThe following paths were tried:\n\t\t"))
self.warn("\n\t\t".join(path))
self.warn('\n')
path = filename.replace('\\','/')
photo_handle = self.media_map.get(path)
if photo_handle == None:
photo = RelLib.MediaObject()
photo.set_path(path)
photo.set_description(title)
photo.set_mime_type(GrampsMime.get_type(os.path.abspath(path)))
self.db.add_object(photo, self.trans)
self.media_map[path] = photo.get_handle()
else:
photo_handle = self.media_map.get(path)
if photo_handle == None:
photo = RelLib.MediaObject()
photo.set_path(path)
photo.set_description(title)
photo.set_mime_type(GrampsMime.get_type(os.path.abspath(path)))
self.db.add_object(photo, self.trans)
self.media_map[path] = photo.get_handle()
else:
photo = self.db.get_object_from_handle(photo_handle)
oref = RelLib.MediaRef()
oref.set_reference_handle(photo.get_handle())
self.family.add_media_reference(oref)
self.db.commit_family(self.family, self.trans)
photo = self.db.get_object_from_handle(photo_handle)
oref = RelLib.MediaRef()
oref.set_reference_handle(photo.get_handle())
oref.set_note(note)
self.family.add_media_reference(oref)
self.db.commit_family(self.family, self.trans)
def parse_residence(self,address,level):
note = ""
@ -1296,8 +1308,14 @@ class GedcomParser:
address.set_postal_code(matches[2])
elif matches[1] == "CTRY":
address.set_country(matches[2])
elif matches[1] == "PHON":
address.set_phone(matches[2])
elif matches[1] == "NOTE":
note = self.parse_note(matches,address,level+1,note)
elif matches[1] == "_LOC":
pass # ignore unsupported extended location syntax
elif matches[1] == "_NAME":
pass # ignore
else:
self.barf(level+1)
@ -1357,6 +1375,8 @@ class GedcomParser:
event.set_name(name)
else:
event.set_description(matches[2])
elif matches[1] == "_PRIV" and matches[2] == "Y":
event.set_privacy(True)
elif matches[1] == "DATE":
event.set_date_object(self.extract_date(matches[2]))
elif matches[1] == "SOUR":
@ -1585,10 +1605,13 @@ class GedcomParser:
return
elif matches[1] == "PAGE":
source.set_page(matches[2] + self.parse_continue_data(level+1))
elif matches[1] == "DATE":
source.set_date_object(self.extract_date(matches[2]))
elif matches[1] == "DATA":
date,text = self.parse_source_data(level+1)
d = self.dp.parse(date)
source.set_date_object(d)
if date:
d = self.dp.parse(date)
source.set_date_object(d)
source.set_text(text)
elif matches[1] in ["OBJE","REFN","TEXT"]:
self.ignore_sub_junk(level+1)
@ -1721,9 +1744,9 @@ class GedcomParser:
pass
elif matches[1] == "FILE":
filename = os.path.basename(matches[2]).split('\\')[-1]
self.def_src.set_title(_("Import from %s") % unicode(filename))
self.def_src.set_title(_("Import from %s") % filename)
elif matches[1] == "COPR":
self.def_src.set_publication_info(unicode(matches[2]))
self.def_src.set_publication_info(matches[2])
elif matches[1] in ["CORP","DATA","SUBM","SUBN","LANG"]:
self.ignore_sub_junk(2)
elif matches[1] == "DEST":
@ -1751,7 +1774,7 @@ class GedcomParser:
elif matches[1] == "DATE":
date = self.parse_date(2)
date.date = matches[2]
self.def_src.set_data_item('Creation date',unicode(matches[2]))
self.def_src.set_data_item('Creation date',matches[2])
elif matches[1] == "NOTE":
note = matches[2] + self.parse_continue_data(2)
elif matches[1][0] == "_":

View File

@ -24,7 +24,6 @@
#
#-------------------------------------------------------------------------
import os
import string
#-------------------------------------------------------------------------
#

View File

@ -96,6 +96,8 @@ class BaseObject:
# Run through its own items
patern_upper = pattern.upper()
for item in self.get_text_data_list():
if not item:
continue
if case_sensitive:
if item.find(pattern) != -1:
return True
@ -127,7 +129,7 @@ class BaseObject:
else:
pattern_obj = re.compile(pattern,re.IGNORECASE)
for item in self.get_text_data_list():
if pattern_obj.match(item):
if item and pattern_obj.match(item):
return True
# Run through child objects
@ -521,10 +523,13 @@ class SourceNote(BaseObject,NoteBase):
@param new_handle: The source handle to replace the old one with.
@type new_handle: str
"""
while old_handle in self.source_list:
ix = self.source_list.index(old_handle)
self.source_list[ix] = new_handle
refs_list = [ src_ref.ref for src_ref in self.source_list ]
n_replace = refs_list.count(old_handle)
for ix_replace in xrange(n_replace):
ix = refs_list.index(old_handle)
self.source_list[ix].ref = new_handle
refs_list.pop(ix)
for item in self.get_sourcref_child_list():
item.replace_source_references(old_handle,new_handle)
@ -618,9 +623,12 @@ class MediaBase:
@param new_handle: The media handle to replace the old one with.
@type new_handle: str
"""
while old_handle in self.media_list:
ix = self.media_list.index(old_handle)
self.media_list[ix] = new_handle
refs_list = [ media_ref.ref for media_ref in self.media_list ]
n_replace = refs_list.count(old_handle)
for ix_replace in xrange(n_replace):
ix = refs_list.index(old_handle)
self.media_list[ix].ref = new_handle
refs_list.pop(ix)
class DateBase:
"""
@ -1038,7 +1046,7 @@ class Person(PrimaryObject,PrivateSourceNote,MediaBase,AttributeBase):
@return: Returns the list of all textual attributes of the object.
@rtype: list
"""
return [self.nickname]
return [self.nickname,self.gramps_id]
def get_text_data_child_list(self):
"""
@ -1768,6 +1776,15 @@ class Family(PrimaryObject,SourceNote,MediaBase,AttributeBase):
if self.lds_seal and self.lds_seal.place == old_handle:
self.lds_seal.place = new_handle
def get_text_data_list(self):
"""
Returns the list of all textual attributes of the object.
@return: Returns the list of all textual attributes of the object.
@rtype: list
"""
return [self.gramps_id]
def get_text_data_child_list(self):
"""
Returns the list of child objects that may carry textual data.
@ -2119,7 +2136,7 @@ class Event(PrimaryObject,PrivateSourceNote,MediaBase,DateBase,PlaceBase):
@return: Returns the list of all textual attributes of the object.
@rtype: list
"""
return [self.description,self.name,self.cause,self.get_date()]
return [self.description,self.name,self.cause,self.get_date(),self.gramps_id]
def get_text_data_child_list(self):
"""
@ -2394,7 +2411,7 @@ class Place(PrimaryObject,SourceNote,MediaBase):
@return: Returns the list of all textual attributes of the object.
@rtype: list
"""
return [self.long,self.lat,self.title]
return [self.long,self.lat,self.title,self.gramps_id]
def get_text_data_child_list(self):
"""
@ -2653,7 +2670,7 @@ class MediaObject(PrimaryObject,SourceNote,DateBase,AttributeBase):
@return: Returns the list of all textual attributes of the object.
@rtype: list
"""
return [self.path,self.mime,self.desc,self.get_date()]
return [self.path,self.mime,self.desc,self.get_date(),self.gramps_id]
def get_text_data_child_list(self):
"""
@ -2757,7 +2774,7 @@ class Source(PrimaryObject,MediaBase,NoteBase):
@return: Returns the list of all textual attributes of the object.
@rtype: list
"""
return [self.title,self.author,self.pubinfo,self.abbrev]
return [self.title,self.author,self.pubinfo,self.abbrev,self.gramps_id]
def get_text_data_child_list(self):
"""
@ -2939,7 +2956,7 @@ class LdsOrd(SourceNote,DateBase,PlaceBase):
if self.place:
return [('Place',self.place)]
else:
return []
return []
def get_handle_referents(self):
"""
@ -3879,7 +3896,7 @@ class Witness(BaseObject,PrivacyBase):
if self.type == Event.ID:
return [('Person',self.val)]
else:
return []
return []
def set_type(self,type):
self.type = type
@ -4035,6 +4052,8 @@ class GenderStats:
return (0, 0, 0)
def count_person (self, person, db, undo = 0):
if not person:
return
# Let the Person do their own counting later
person.db = db

View File

@ -416,9 +416,10 @@ def insert_images(database, doc, person, w_cm=4.0, h_cm=4.0):
for photo in photos :
object_handle = photo.get_reference_handle()
media_object = database.get_object_from_handle(object_handle)
if media_object.get_mime_type()[0:5] == "image":
mime_type = media_object.get_mime_type()
if mime_type and mime_type.startswith("image"):
filename = media_object.get_path()
doc.add_media_object(filename,"row")
doc.add_media_object(filename,"row",w_cm,h_cm)
#-------------------------------------------------------------------------
#
@ -795,6 +796,10 @@ def married_str(database,person,spouse,event,endnotes=None,
@rtype: unicode
"""
# not all families have a spouse.
if not spouse:
return u""
if not endnotes:
endnotes = empty_notes
@ -1803,4 +1808,4 @@ def old_calc_age(database,person):
if age == 0:
age = death.get_day() + 31 - birth.get_day() # calc age in days
units = 3 # day
return (age,units)
return (age,units)

View File

@ -295,10 +295,12 @@ class SelectChild:
self.family = RelLib.Family()
self.db.add_family(self.family,trans)
self.person.add_family_handle(self.family.get_handle())
self.db.commit_person(self.person,trans)
if self.person.get_gender() == RelLib.Person.MALE:
self.family.set_father_handle(self.person)
self.family.set_father_handle(self.person.get_handle())
else:
self.family.set_mother_handle(self.person)
self.family.set_mother_handle(self.person.get_handle())
self.db.commit_family(self.family,trans)
if handle in (self.family.get_father_handle(),self.family.get_mother_handle()):
ErrorDialog(_("Error selecting a child"),
@ -328,6 +330,7 @@ class SelectChild:
n = select_child.get_primary_name().get_regular_name()
self.db.transaction_commit(trans,_("Add Child to Family (%s)") % n)
self.close(obj)
self.callback()
def on_show_toggled(self,obj):
self.redraw_child_list(not obj.get_active())
@ -378,4 +381,3 @@ class SelectChild:
return ("","%sdóttir" % fname)
else:
return ("","")

View File

@ -113,15 +113,14 @@ class SelectObject:
data = self.object_model.get_data(node,range(self.ncols))
handle = data[4]
obj = self.db.get_object_from_handle(handle)
the_type = Utils.get_mime_description(obj.get_mime_type())
the_type = obj.get_mime_type()
path = obj.get_path()
if the_type[0:5] == "image":
image = ImgManip.get_thumbnail_image(obj.get_path())
self.preview.set_from_pixbuf(image)
if the_type and the_type[0:5] == "image":
image = ImgManip.get_thumbnail_image(path)
else:
icon_image = Utils.find_mime_type_pixbuf(the_type)
self.preview.set_from_pixbuf(icon_image)
image = Utils.find_mime_type_pixbuf(the_type)
self.preview.set_from_pixbuf(image)
self.object_handle.set_text(obj.get_gramps_id())
self.object_type.set_text(the_type)

View File

@ -67,21 +67,47 @@ class SourceView:
def __init__(self,parent,db,glade):
self.parent = parent
self.parent.connect('database-changed',self.change_db)
self.glade = glade
self.list = glade.get_widget("source_list")
#self.list.set_property('fixed-height-mode',True)
self.list.connect('button-press-event',self.button_press)
self.list.connect('key-press-event',self.key_press)
self.selection = self.list.get_selection()
self.selection.set_mode(gtk.SELECTION_MULTIPLE)
self.renderer = gtk.CellRendererText()
self.model = DisplayModels.SourceModel(self.parent.db)
self.model = DisplayModels.SourceModel(self.parent.db,0)
self.sort_col = 0
self.list.set_model(self.model)
self.list.set_headers_clickable(True)
self.topWindow = self.glade.get_widget("gramps")
self.columns = []
self.change_db(db)
def column_clicked(self,obj,data):
if self.sort_col != data:
order = gtk.SORT_ASCENDING
else:
if (self.columns[data].get_sort_order() == gtk.SORT_DESCENDING
or self.columns[data].get_sort_indicator() == False):
order = gtk.SORT_ASCENDING
else:
order = gtk.SORT_DESCENDING
self.sort_col = data
handle = self.first_selected()
self.model = DisplayModels.SourceModel(self.parent.db,
self.sort_col,order)
self.list.set_model(self.model)
colmap = self.parent.db.get_place_column_order()
if handle:
path = self.model.on_get_path(handle)
self.selection.select_path(path)
self.list.scroll_to_cell(path,None,1,0.5,0)
for i in range(0,len(self.columns)):
self.columns[i].set_sort_indicator(i==colmap[data][1]-1)
self.columns[self.sort_col].set_sort_order(order)
def build_columns(self):
for column in self.columns:
@ -90,21 +116,24 @@ class SourceView:
column = gtk.TreeViewColumn(_('Title'), self.renderer,text=0)
column.set_resizable(True)
column.set_min_width(225)
column.set_clickable(True)
column.connect('clicked',self.column_clicked,0)
self.list.append_column(column)
self.columns = [column]
index = 1
for pair in self.parent.db.get_source_column_order():
if not pair[0]:
continue
name = column_names[pair[1]]
column = gtk.TreeViewColumn(name, self.renderer, text=pair[1])
column.connect('clicked',self.column_clicked,index)
column.set_resizable(True)
column.set_min_width(75)
column.set_clickable(True)
self.columns.append(column)
self.list.append_column(column)
def on_click(self,column):
self.click_col = column
index += 1
def change_db(self,db):
db.connect('source-add', self.source_add)
@ -116,7 +145,7 @@ class SourceView:
def build_tree(self):
self.list.set_model(None)
self.model = DisplayModels.SourceModel(self.parent.db)
self.model = DisplayModels.SourceModel(self.parent.db,self.sort_col)
self.list.set_model(self.model)
self.selection = self.list.get_selection()
self.selection.set_mode(gtk.SELECTION_MULTIPLE)
@ -216,6 +245,14 @@ class SourceView:
for handle in handle_list:
self.model.delete_row_by_handle(handle)
def first_selected(self):
mlist = []
self.selection.selected_foreach(self.blist,mlist)
if mlist:
return mlist[0]
else:
return None
def blist(self,store,path,iter,sel_list):
handle = store.get_value(iter,_HANDLE_COL)
sel_list.append(handle)

View File

@ -286,6 +286,8 @@ class SourceTab:
def drag_data_get(self,widget, context, sel_data, info, time):
store,node = self.selection.get_selected()
if not node:
return
ev = store.get_value(node,2)
bits_per = 8; # we're going to pass a string

View File

@ -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
@ -37,10 +37,9 @@ __version__ = "$Revision$"
#------------------------------------------------------------------------
#
# python classes
# Gramps modules
#
#------------------------------------------------------------------------
import string
import NameDisplay
@ -126,15 +125,15 @@ class SubstKeywords:
def replace(self,line):
"""Returns a new line of text with the substitutions performed."""
line = string.replace(line,"$n",self.n)
line = string.replace(line,"$N",self.N)
line = string.replace(line,"$b",self.b)
line = string.replace(line,"$B",self.B)
line = string.replace(line,"$d",self.d)
line = string.replace(line,"$D",self.D)
line = string.replace(line,"$i",self.i)
line = string.replace(line,"$S",self.S)
line = string.replace(line,"$s",self.s)
line = string.replace(line,"$m",self.m)
line = string.replace(line,"$M",self.M)
return string.replace(line,"$$",'$')
line = line.replace("$n",self.n)
line = line.replace("$N",self.N)
line = line.replace("$b",self.b)
line = line.replace("$B",self.B)
line = line.replace("$d",self.d)
line = line.replace("$D",self.D)
line = line.replace("$i",self.i)
line = line.replace("$S",self.S)
line = line.replace("$s",self.s)
line = line.replace("$m",self.m)
line = line.replace("$M",self.M)
return line.replace("$$",'$')

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000 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
@ -17,9 +17,11 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
import gzip
import cStringIO
import string
_BLKSIZE=512
nul = '\0'
@ -87,75 +89,74 @@ class TarFile:
class ReadTarFile:
def __init__(self,name,wd="/tmp"):
self.name = name
self.wd = wd
self.wd = wd
self.f = gzip.open(name,"rb")
self.pos = 0
def extract_files(self):
data = {}
while 1:
buf = self.f.read(100)
while 1:
buf = self.f.read(100)
if buf == '':
return
return
index = 0
for b in buf:
if b != nul:
index = index + 1
else:
if index == 0:
for b in buf:
if b != nul:
index = index + 1
else:
if index == 0:
return data
continue
filename = buf[0:index]
continue
filename = buf[0:index]
if filename == None:
return data
self.f.read(24) # modes
l = string.replace(self.f.read(12),chr(0),' ')
self.f.read(24) # modes
l = self.f.read(12)(chr(0),' ')
length = int(l,8)
self.f.read(12)
self.f.read(6)
self.f.read(111)
self.f.read(12)
self.f.read(6)
self.f.read(111)
self.f.read(64)
self.f.read(183)
self.f.read(64)
self.f.read(183)
foo = cStringIO.StringIO()
data[filename] = foo
foo.write(self.f.read(length))
foo.reset()
self.f.read(_BLKSIZE-(length%_BLKSIZE))
foo.write(self.f.read(length))
foo.reset()
self.f.read(_BLKSIZE-(length%_BLKSIZE))
return data
def extract(self):
while 1:
buf = self.f.read(100)
while 1:
buf = self.f.read(100)
if buf == '':
return
return
index = 0
for b in buf:
if b != nul:
index = index + 1
else:
if index == 0:
for b in buf:
if b != nul:
index = index + 1
else:
if index == 0:
return
continue
filename = buf[0:index]
self.f.read(24) # modes
continue
filename = buf[0:index]
self.f.read(24) # modes
l = self.f.read(12)
length_string = "";
for char in l:
if ord(char) != 0:
length_string = length_string + char
length = int(length_string,8)
self.f.read(12)
self.f.read(6)
self.f.read(111)
self.f.read(12)
self.f.read(6)
self.f.read(111)
self.f.read(64)
self.f.read(183)
self.f.read(64)
self.f.read(183)
foo = open("%s/%s" % (self.wd,filename),"wb")
foo.write(self.f.read(length))
foo.close()
self.f.read(_BLKSIZE-(length%_BLKSIZE))
foo.write(self.f.read(length))
foo.close()
self.f.read(_BLKSIZE-(length%_BLKSIZE))
def close(self):
self.f.close()

View File

@ -27,6 +27,7 @@
#-------------------------------------------------------------------------
from xml.parsers.expat import ParserCreate
from random import Random
from gettext import gettext as _
#-------------------------------------------------------------------------
#
@ -68,7 +69,7 @@ class TipOfDay:
index = 0
rval = 0
while rval == 0:
tip.set_text(tip_list[new_index[index]])
tip.set_text(_(tip_list[new_index[index]]))
tip.set_use_markup(1)
rval = top.run()
if index >= len(tip_list)-1:

View File

@ -59,7 +59,7 @@ def keep_utf8(s):
return s
def iso8859(s):
return s.encode('iso-8859-1')
return s.encode('iso-8859-1','replace')
#-------------------------------------------------------------------------
#
@ -136,6 +136,8 @@ def add_persons_sources(db,person,slist,private):
for event_handle in elist:
if event_handle:
event = db.get_event_from_handle(event_handle)
if not event:
continue
if private and event.get_privacy():
continue
for source_ref in event.get_source_references():
@ -713,6 +715,8 @@ class GedcomWriter:
if not self.plist.has_key(person_handle):
continue
person = self.db.get_person_from_handle(person_handle)
if not person:
continue
self.writeln("1 CHIL @%s@" % person.get_gramps_id())
if self.adopt == GedcomInfo.ADOPT_FTW:
if person.get_main_parents_family_handle() == family.get_handle():
@ -737,6 +741,8 @@ class GedcomWriter:
sorted = []
for key in self.slist.keys():
source = self.db.get_source_from_handle(key)
if not source:
continue
data = (self.sid (source.get_gramps_id ()), source)
sorted.append (data)
sorted.sort ()
@ -791,16 +797,22 @@ class GedcomWriter:
if not restricted:
birth_handle = person.get_birth_handle()
birth = self.db.get_event_from_handle(birth_handle)
if birth_handle and not (self.private and birth.get_privacy()):
if birth_handle and birth and not (self.private and birth.get_privacy()):
if not birth.get_date_object().is_empty() or birth.get_place_handle():
self.writeln("1 BIRT")
if birth.get_description() != "":
self.writeln("1 BIRT %s" % birth.get_description())
else:
self.writeln("1 BIRT")
self.dump_event_stats(birth)
death_handle = person.get_death_handle()
death = self.db.get_event_from_handle(death_handle)
if death_handle and not (self.private and death.get_privacy()):
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():
self.writeln("1 DEAT")
if birth.get_description() != "":
self.writeln("1 DEAT %s" % death.get_description())
else:
self.writeln("1 DEAT")
self.dump_event_stats(death)
ad = 0
@ -813,6 +825,8 @@ class GedcomWriter:
if not event_handle:
continue
event = self.db.get_event_from_handle(event_handle)
if not event:
continue
if self.private and event.get_privacy():
continue
name = event.get_name()

View File

@ -306,13 +306,11 @@ class XmlWriter:
frel=' frel="%s"' % const.child_rel_notrans[alt[2]]
else:
frel=''
parent_family = self.db.get_family_from_handle (alt[0])
self.g.write(" <childof hlink=\"%s\"%s%s/>\n" % \
(parent_family.get_handle(), mrel, frel))
(alt[0], mrel, frel))
for family_handle in person.get_family_handle_list():
family = self.db.get_family_from_handle (family_handle)
self.write_ref("parentin",family.get_handle(),3)
self.write_ref("parentin",family_handle,3)
self.write_note("note",person.get_note_object(),3)
for s in person.get_source_references():
@ -341,11 +339,9 @@ class XmlWriter:
fhandle = family.get_father_handle()
mhandle = family.get_mother_handle()
if fhandle:
fid = self.db.get_person_from_handle (fhandle).get_handle()
self.write_ref("father",fid,3)
self.write_ref("father",fhandle,3)
if mhandle:
mid = self.db.get_person_from_handle (mhandle).get_handle()
self.write_ref("mother",mid,3)
self.write_ref("mother",mhandle,3)
for event_handle in family.get_event_list():
event = self.db.get_event_from_handle(event_handle)
self.dump_event(event,3)
@ -355,8 +351,7 @@ class XmlWriter:
if len(family.get_child_handle_list()) > 0:
for person_handle in family.get_child_handle_list():
person = self.db.get_person_from_handle (person_handle)
self.write_ref("child",person.get_handle(),3)
self.write_ref("child",person_handle,3)
self.write_attribute_list(family.get_attribute_list())
self.write_note("note",family.get_note_object(),3)
for s in family.get_source_references():

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2003 Donald N. Allingham
# Copyright (C) 2003-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
@ -18,6 +18,8 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
import cStringIO
_onebyte = {
@ -331,6 +333,3 @@ def utf8_to_ansel(s):
ans = buff.getvalue()
buff.close()
return ans

View File

@ -4,5 +4,5 @@ then
mv po/template.po po/template.po.bak
fi
./get_strings -o po/template.po *.py */*.py *.glade */*.glade
./get_strings -o po/template.po *.py */*.py *.glade */*.glade data/tips.xml

View File

@ -1,4 +1,6 @@
# This is the src/data level Makefile
# $Id$
#
SUBDIRS = templates
pkgdatadir = $(datadir)/@PACKAGE@/data
@ -31,24 +33,18 @@ SHARED_MIME_UNINSTALLATION =
if !PACKAGER_MODE
if GCONF_SCHEMAS_INSTALL
GCONF_SCHEMAS_INSTALLATION += \
$(INSTALL) -d $(DESTDIR)$(GCONF_SCHEMA_FILE_DIR) ;\
$(INSTALL_DATA) $(top_srcdir)/src/data/gramps.schemas $(DESTDIR)$(GCONF_SCHEMA_FILE_DIR) ;\
GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) \
gconftool-2 --makefile-install-rule $(top_srcdir)/src/data/gramps.schemas ;\
gconftool-2 --makefile-install-rule $(DESTDIR)$(GCONF_SCHEMA_FILE_DIR)/gramps.schemas ;\
pkill gconfd ; echo Restarting gconfd
GCONF_SCHEMAS_UNINSTALLATION += \
rm $(DESTDIR)$(GCONF_SCHEMA_FILE_DIR)/gramps.schemas ;\
GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) \
gconftool-2 --makefile-uninstall-rule $(top_srcdir)/src/data/gramps.schemas
gconftool-2 --makefile-uninstall-rule $(DESTDIR)$(GCONF_SCHEMA_FILE_DIR)/gramps.schemas
endif
if SHARED_MIME_INSTALL
SHARED_MIME_INSTALLATION += \
$(INSTALL) -d $(DESTDIR)$(SHARED_MIME_DIR)/packages ;\
$(INSTALL_DATA) $(top_srcdir)/src/data/gramps.xml $(DESTDIR)$(SHARED_MIME_DIR)/packages ;\
update-mime-database $(DESTDIR)$(SHARED_MIME_DIR)
SHARED_MIME_UNINSTALLATION += \
rm $(DESTDIR)$(SHARED_MIME_DIR)/packages/gramps.xml ;\
update-mime-database $(DESTDIR)$(SHARED_MIME_DIR)
endif
endif
@ -63,6 +59,10 @@ install-data-local:
$(INSTALL) -d $(DESTDIR)$(prefix)/share/mime-info
$(INSTALL_DATA) $(top_srcdir)/src/data/gramps.keys $(DESTDIR)$(prefix)/share/mime-info
$(INSTALL_DATA) $(top_srcdir)/src/data/gramps.mime $(DESTDIR)$(prefix)/share/mime-info
$(INSTALL) -d $(DESTDIR)$(SHARED_MIME_DIR)/packages
$(INSTALL_DATA) $(top_srcdir)/src/data/gramps.xml $(DESTDIR)$(SHARED_MIME_DIR)/packages
$(INSTALL) -d $(DESTDIR)$(GCONF_SCHEMA_FILE_DIR)
$(INSTALL_DATA) $(top_srcdir)/src/data/gramps.schemas $(DESTDIR)$(GCONF_SCHEMA_FILE_DIR)
$(SHARED_MIME_INSTALLATION)
$(GCONF_SCHEMAS_INSTALLATION)
@ -72,5 +72,7 @@ uninstall-local:
-rm $(DESTDIR)$(prefix)/share/mime-info/gramps.keys
-rm $(DESTDIR)$(prefix)/share/mime-info/gramps.mime
-rm $(DESTDIR)$(prefix)/share/application-registry/gramps.applications
$(SHARED_MIME_UNINSTALLATION)
$(GCONF_SCHEMAS_UNINSTALLATION)
-rm $(DESTDIR)$(GCONF_SCHEMA_FILE_DIR)/gramps.schemas
-rm $(DESTDIR)$(SHARED_MIME_DIR)/packages/gramps.xml
$(SHARED_MIME_UNINSTALLATION)

View File

@ -7,13 +7,17 @@ Name[nb]=GRAMPS
Name[ru]=GRAMPS
Name[de]=GRAMPS
Name[hu]=GRAMPS
Name[nl]=GRAMPS genealogie
Name[fi]=GRAMPS sukututkimusohjelma
Comment=Manage genealogical information, perform genealogical research and analysis
Comment[nl]=Een programma voor genealogie infomatie beheer en genealogisch onderzoek en analyse
Comment[sv]=Ett släktforskningsprogram
Comment[no]=Et slektsforskningsprogram
Comment[nb]=Et slektsforskningsprogram
Comment[ru]=Система исследования и анализа генеалогической информации
Comment[de]=Ein Programm zur Ahnenforschung
Comment[hu]=Örökléskutató és elemző program
Comment[fi]=Hallinnoi, tutki ja analysoi sukutietoa
Icon=gramps.png
Terminal=false
Type=Application

View File

@ -10,6 +10,9 @@
<mime-type type="application/x-gedcom">
<comment xml:lang="en">GEDCOM</comment>
<glob pattern="*.ged"/>
<glob pattern="*.gedcom"/>
<glob pattern="*.GED"/>
<glob pattern="*.GEDCOM"/>
<magic priority="80">
<match type="string" value="0 HEAD" offset="0:1"/>
</magic>
@ -29,6 +32,7 @@
<mime-type type="application/x-geneweb">
<comment xml:lang="en">GeneWeb source file</comment>
<glob pattern="*.gw"/>
<glob pattern="*.GW"/>
<magic priority="80">
<match type="string" value="fam " offset="0:64"/>
</magic>

View File

@ -4,339 +4,341 @@
<tips>
<tip><i>You can represent a range of dates by using the format
of &quot;between January 4, 2000 and March 20, 2003&quot;</i></tip>
<tip>You can drag and drop an image from either the Media View or any
gallery into another gallery</tip>
<tip>You can add an image to any gallery or the Media View by dragging and
dropping from a file manager or a web browser.</tip>
<tip>You can set the birth order of children in a family even if you do not
have birth dates by using drag and drop.</tip>
<tip>You can convert an alternate name to the person's preferred name by
selecting the desired name in the person's name list, bringing up the context
menu by clicking the right mouse button, and selecting from the menu.</tip>
<tip>
<b>ASKING RELATIVES BEFORE IT IS TOO LATE</b>:
Your oldest relatives could be your
most important source of information. They usually know things about the
family that hasn't been written down. They might tell you nuggets about
people, the information about whom might one day be reduced to numbers. We
often wonder why we didn't write down pieces of information that grandfather
told us while we were young. Don't wait till it's too late...
<tip>A range of dates can be given by using the format
&quot;between January 4, 2000 and March 20, 2003&quot;
</tip>
<!--
<tip>
<b>EXAMPLES OF A FAMILY TREE</b>: To see how a Gramps family tree database looks,
check Help &gt; Open example database. You'll find the elaborate Smith family
database, It includes 42 individuals and 15 families, with fairly complete
basic data about many of these individuals.
In most cases double clicking on a name, source, place or media entry
will bring up a window to allow you to edit the object. Note that the
result can be dependent on context. For example, in the Family View
clicking on a parent or child will bring up the relationship editor.
</tip>
<tip>An image can be added to any gallery or the Media View by dragging and
dropping it from a file manager or a web browser.
</tip>
<tip>Birth order of children in a family can be set, even if they do not
have birth dates, by using drag and drop.
</tip>
<tip>
<b>Talk to Relatives Before It Is Too Late</b>:
Your oldest relatives can be your most important source of information.
They usually know things about the family that haven't been written down.
They might tell you nuggets about
people that may one day lead to a new avenue of research.
At the very least, you will get to hear some great stories.
Don't forget to record the conversations!
</tip>
<tip>
<b>Example of a Family Tree</b>: To see an example of what a family
looks like in GRAMPS, check <b>Help &gt; Open example database</b>.
You will then be viewing the elaborate Smith family database, which
includes 42 individuals and 15 families, with fairly complete
data about many of the individuals.
</tip>
-->
<tip>
<b>THE PEOPLE VIEW</b>: The People view throws up a list of all individuals
<b>The People View</b>: The People View shows a list of all individuals
in the database.
<!--
You can sort the listing simply by clicking on numerous headings
such as name, gender, birth date or death date. Clicking heading the second
The listings can be sorted by simply clicking on a heading
such as name, gender, birth date or death date. Clicking the heading a second
time will reverse the sort.
-->
</tip>
<tip>
<b>FILTERING PEOPLE OUT</b>: In the People view, you can 'filter' out individuals
based on certain criteria. Go to the Filter (just to the right of the People
icon) and choose one of the dozen different presets. For instance, all
<b>Filtering People</b>: In the People View, you can 'filter' individuals
based on many criteria. Go to the Filter (just to the right of the People
icon) and choose one of the dozen different presets. For example, all
adopted people in the family tree can be located. People without a birth
date mentioned can also be filtered. To get the results, click on Apply.
date mentioned can also be filtered. To get the results click Apply.
If the filter controls are not visible, enable them by choosing
<b>View &gt; Filter</b>.
</tip>
<tip>
<b>INVERTED FILTERING</b>: You can get another set of results by using the 'invert'
option. For instance, if you choose to filter the 'People with children'
preset filter, and then invert it, you'll find all the people without
children in the family tree.
<b>Inverted Filtering</b>:
Filters can easily be reversed by using the 'invert' option.
For instance, by inverting the 'People with children' filter you can
select all people without children.
</tip>
<tip>
<b>LOCATING PEOPLE</b>: In the People view, you can locate any individual by
through the list of surnames. Then, click on the names
themselves to unfold display of all the individuals with the same last name.
<b>Locating People</b>: By default, each surname in the People View is
listed only once. By clicking on the arrow to the left of a name, the list
will expand to show all individuals with that last name.
</tip>
<tip>
<b>TO ADD INFORMATION TO SELECTED PEOPLE</b>: First, locate them in the People
view. (Use the list of surnames, and click on the names to unfold
the display of all individuals sharing the name). Then, go to the Family
view, and add the relevant information.
<b>The Family View</b>: The Family View is used to display a typical
family unit---the parents, spouses and children of an individual.
</tip>
<tip>
<b>THE FAMILY VIEW</b>: The Family view display a family of parents, grandparents
and children along with the birth and death dates (if relevant) and
relationships. You can navigate to nearby relatives with a single click.
<b>Shifting a Family View</b>: Changing the Active Person in
the Family View is easy. A spouse can be made the Active Person by
clicking the button just to the right of the Active Person. A father
can be made the Active Person by clicking on the arrow to the right of
their name. A child can be made the Active Person by selecting them
from the Children list and then clicking the arrow button to the right
of the Children.
</tip>
<tip>
<b>IMPROVING GRAMPS</b>: Users are entitled to request enhancements to GRAMPS.
<b>Who Was Born When</b>: The 'Compare individual events' tool allows you to
compare data of all (or some of) the individuals in your database. This is
useful, say, if you wish to list the birth dates of everyone in your
database.
</tip>
<tip>
GRAMPS comes with a rich set of tools. These allows you to undertake
operations such as checking database for errors and consistency, as well as
research and analysis tools such as event comparison, finding duplicate
people, interactive descendant browser, and others.
All tools can be accessed through the <b>Tools</b> menu.
</tip>
<tip>
<b>Calculating Relationships</b>: This tool, under <b>Tools &gt;
Utilities &gt; Relationship calculator</b> allows you to check if someone
else in the family is related (by blood, not marriage) to you. Precise
relationships as well as the common ancestors are reported.
</tip>
<tip>
<b>SoundEx can help with family research</b>:
SoundEx solves a long standing problem in genealogy---how to handle
spelling variations. The SoundEx utility takes a surname and generates
a simplified form that is equivalent for similar sounding names.
Knowing the SoundEx Code for a surname is very
helpful for researching Census Data files (microfiche) at a library
or other research facility. To get the SoundEx codes for surnames in
your database, go to <b>Tools &gt; Utilities &gt; Generate SoundEx codes</b>.
</tip>
<tip>
<b>Setting Your Preferences</b>: Not happy with some default behavior of GRAMPS?
<b>Edit &gt; Preferences</b> lets you to modify a
number of settings, allowing you to tailor GRAMPS to your needs.
</tip>
<tip>
<b>GRAMPS Reports</b>: GRAMPS offers a wide variety of reports.
The Text Reports are particularly useful if you want to send
the results of your family tree to members of the family via email.
</tip>
<tip>
<b>Starting a New Family Tree</b>: A good way to start a new family tree is
to enter all the members of the family into the database (use <b>Edit
&gt; Add</b> or click on the Add button under the People menu). Then go to
the Family View and create relationships between people.
Then go about tracing the relationships among them all under the Family menu.
</tip>
<tip>
Unsure what a button does? Simply hold the mouse over a button and a tooltip
will appear.
</tip>
<tip>
<b>Unsure of a Date?</b> If you're unsure about the date an event occurred
(for example birth or death), GRAMPS allows you to enter a wide
range of date formats based on a guess or an estimate. For instance,
&quot;about 1908&quot; is a valid entry for a birth date in GRAMPS.
See section 3.7.2.2 of the GRAMPS manual for a complete description of
date entry options.
</tip>
<tip>
<b>Duplicate Entries</b>: <b>Tools &gt; Database Processing &gt; Find
possible duplicate</b> people allows you to located (and merge) entries
of the same person entered more than once in the database.
</tip>
<tip>
The 'merge' function allows you to combine separately listed people into
one. This is very useful for combining two databases with overlapping
people, or combining erroneously entered differing names for one individual.
</tip>
<tip>
To easily merge two people, select them both (a second person can be selected
by holding the Control key while clicking) and clicking on <b>Edit &gt; Fast
Merge</b>.
</tip>
<tip>
GRAMPS maintains a list of previous Active People. You can move forward and
backward through the list using <b>Go &gt; Forward</b> and <b>Go &gt;
Back</b>.
</tip>
<tip>
Tired of having to take your hand off the keyboard to use the mouse?
Many functions in GRAMPS have keyboard shortcuts. If one exists for a
function it is displayed on the right side of the menu.
</tip>
<tip>
Don't forget to read the GRAMPS manual, <b>Help &gt; User Manual</b>.
The developers have worked hard to make most operations intuitive
but the manual is full of information that will make your time spent
on genealogy more productive.
</tip>
<tip>
<b>Adding Children</b>: To add children in GRAMPS make either of the parents
the Active Person then switch to the Family View.
If the child is already in the database, click on the third button down to the
right of the Children list.
If the person is not already in the database, click on the second button down
to the right of the Children list. After the child's information is entered
they will automatically be listed as a child of the Active Person.
</tip>
<tip>
<b>Editing The Relationship of a Child</b>: Not all children are the related by
birth to their parents. You can edit the relationship of a
child to each parent by selecting the child, right-clicking, and choosing
&quot;Edit the child parent relationship&quot;.
Relationships can be any of Birth, Adopted, Stepchild, Sponsored, Foster, or
Unknown.
</tip>
<tip>
<b>Show All Checkbutton</b>: When adding a spouse or child, the
list of people shown is filtered to display only people who could
realistically fit the role (based on dates in the database). In case
GRAMPS is wrong in making this choice, you can override that
filter by checking the &quot;Show All&quot; checkbutton.
</tip>
<tip>
<b>GRAMPS Manual</b>: The GRAMPS manual is quite elaborate and well written.
It includes details on keybindings and includes some useful tips that will
help you in your genealogy work.
Check it out.
</tip>
<tip>
<b>Improving GRAMPS</b>: Users are encouraged to request enhancements to
GRAMPS.
Requesting an enhancement can be done either through the gramps-users or
gramps-devel mailing lists, or by creating a Request for Enhancement (RFE) at
http://sourceforge.net/tracker/?group_id=25770&amp;atid=385140
The last is preferred.
http://sourceforge.net/tracker/?group_id=25770&amp;atid=385140
Filing an RFE is preferred.
</tip>
<tip>
<b>WHO WAS BORN WHEN</b>: The 'Compare individual events' tool allows you to
compare data of all (or some of) the individuals in your database. This is
useful, say, if you wish to list the birth-dates of everyone in your
database. For best results, your data needs to be complete.
<b>GRAMPS Mailing Lists</b>: Want answers to your queries about GRAMPS?
Check out the gramps-users list.
Many people are on the list, so you're likely to get an answer quickly.
If you have questions related to the development of GRAMPS,
try gramps-devel. Information on both mailing lists can be found at
lists.sf.net.
</tip>
<tip>
<b>WHO'S THE OLDEST OF US ALL?</b> You can find out a lot of statistical
information about your entire family, using the Tools &gt; Utilities &gt; Verify
the database facility. For instance, what was the maximum age of any
individual in the family? Or the largest husband-wife age difference. Or the
minimum age at which anyone in your family ever married. Or even the minimum
age at which a woman bore a child.
<b>Contributing to GRAMPS</b>:
Want to help with GRAMPS but can't program? Not a problem. A project
as large as GRAMPS requires people with a wide variety of skills.
Contributions can vary from writing documentation to testing development
versions to helping with the web site.
Start by subscribing to the gramps developers mailing list, gramps-devel
and introducing yourself.
Subscription information can be found at lists.sf.net.
</tip>
<tip>
<b>CALCULATING RELATIONSHIPS</b>: This allows you to check if someone else in the
entire family is related (by blood, not marriage) to you. Precise
relationships as well as the common ancestors are reported. See Tools &gt;
Utilities &gt; Relationship calculator.
GRAMPS is the Genealogical Research and Analysis Management Program System.
It is a full-featured genealogy program letting you store, edit, and
research genealogical data. Gramps database back end is so robust that
some users are managing genealogies containing hundreds of thousands of
people.
</tip>
<tip>
<b>USEFUL CODES FOR SURNAMES</b>: SoundEx is a utility that will allow you to type
in a surname, then give you the SoundEx Code for that name. Knowing the
SoundEx Code for a surname is very helpful for researching Census Data files
(microfiche) at a library or other research facility. To get your Soundex
codes for surnames in your database, go to Tools &gt; Utilities &gt; Generate
SoundEx codes.
</tip>
<tip>
<b>SETTING YOUR PREFERENCES</b>: Edit &gt; Preferences will allow you to choose a
number of settings, determining how your GRAMPS program should work.
</tip>
<tip>
<b>GRAMPS REPORTS</b>: GRAMPS offers a wide number of reports that can be
generated. The Text Reports are particularly useful if you want to send out
the results of your family tree to members of the family, via e-mail.
</tip>
<tip>
<b>STARTING A NEW FAMILY TREE</b>: The best way to start a new family tree is
probably to add-in all the members of the family into the database (use Edit
&gt; Add or click on the Add button under the People menu). Then go about
tracing the relationships among them all under the Family menu.
</tip>
<tip>
<b>TRACING RELATIONSHIPS</b>: People from an existing database can easily be all
linked into the family. Go to Family, and choose the second button to the
right of the Relationship window. (The first button to the right of the
relationship window adds a new person to the database, and adds to a new
relationship.)
</tip>
<tip>
<b>ASKING RELATIONS FOR DETAILS</b>: To get inputs for building your family tree,
ask key members of your extended family (including other families connected
to yours via marriage) to send in information. Most important is the full
name, date and places of birth and death (if expired), relationship within
the family.
</tip>
<tip>
<b>UNSURE ABOUT BIRTH-DATES?</b> If you're unsure about the birth-dates about
individuals in your family, GRAMPS allows you to enter a wide range, based on
a guess or an estimate. For instance, &quot;about 1908&quot; is also a valid entry. for a
birth date in GRAMPS. Subsequently, the precise dates could be included once
it is available.
</tip>
<tip>
<b>DUPLICATE ENTRIES</b>: Tools &gt; Database Processing &gt; Find possible duplicate
people allows you to located (and merge) entries of the same person entered
more than once in the database.
</tip>
<tip>
<b>ADDING A SIBLING</b>: To add siblings in Gramps, make either of your parents
an active person (i.e. navigate to either of your parents). Then switch to the
Family View and add a new child by clicking the button second from the top on
the right of the Children list (the &quot;New&quot; button). Enter the data for the
new person and click OK.
</tip>
<tip>
<b>EDITING THE RELATIONSHIP OF A CHILD</b>: You can edit the relationship of the
child to each parent by selecting the child, right-clicking, and choosing
&quot;Edit the child-parent relationship&quot; item. If this is not your child but
your wife's child, you would select &quot;Birth&quot; in relationship to her and
&quot;Stepchild&quot; in relationship to you.
</tip>
<tip>
<b>ADDING A CHILD</b>: If the child is already in the database, then you don't need
to add him to the database. Just add the child to the family, which can be
done by pressing the third button from the top (the &quot;Select&quot; button). Then,
select the person from the list.
</tip>
<tip>
<b>SHOW-ALL CHECKBUTTON</b>: The list of people you can add into a family is
filtered to display only people who could possibly be the child (based on he
birth-dates). In case GRAMPS is wrong in making this choice, you can always
over-ride that filtering by checking &quot;Show all&quot; checkbutton.
</tip>
<tip>
<b>KEYBINDINGS</b>: GRAMPS's manual is quite elaborate and well written; it also is
detailed about keybindings (in a separate appendix) and other matters. Check
it out.
</tip>
<tip>
<b>GRAMPS-USERS</b>: Want to answer your queries about GRAMPS? Check out the
gramps-users list. Many users are on the list, so you're likely to get an
answer faster. If you need to ask questions -- use either gramps-devel or
gramps-users at lists.sf.net, as appropriate for your questions.
</tip>
<tip>
<b>TIPS OF THE DAY</b>: GRAMPS's has the option of popping up a
window with the tip of the day about the use of GRAMPS. The tip is chosen
randomly from the pool of tips. To add your own tip, send it in to
gramps-users@lists.sf.net
</tip>
<tip>
GRAMPS (Genealogical Research and Analysis Management Programming System)
offers you a well-designed user interface to make entering data easy, and
browser-like controls to allow you to navigate your family tree with ease.
</tip>
<tip>
<b>DIFFERENT VIEWS</b>: There are six different views for navigating your family:
<b>Different Views</b>: There are six different views for navigating your
family:
People, Family, Pedigree, Sources, Places, Media. Each helps you to achieve
one or more specific tasks.
</tip>
<tip>
<b>CHANGING A CHILD/PARENT RELATIONSHIP</b>: In the Family view, a right-click on
the Children allows you to edit the child/parent relationship. This is used
to mark out children as adopted or step-children.
<b>Bookmarking Individuals</b>:
The Bookmark menu at the top of the window is a convenient place to store
the names of frequently used individuals. Clicking on a bookmarked
individual will make that person the Active Person.
To create a bookmark for a person, make them the Active Person, right click on
their name and click on 'add bookmark'.
</tip>
<tip>
<b>BOOKMARKING INDIVIDUALS</b>: To 'bookmark' individuals in your database,
navigate to them using the Family view, then right-click and 'add bookmark'.
You can visit these bookmarks much like in your browser, simply via Bookmark
&gt; Go to bookmark.
<b>Incorrect Dates</b>: Everyone occasionally enters dates with a nonvalid
format.
Incorrect date formats will show up with the red button next to the
date. Green means okay, and amber signifies acceptable.
The Date Selection dialog can be invoked by clicking on the colored button.
</tip>
<tip>
<b>DATES</b>: Incorrect date formats will show up with the red button alongside the
date. Green means okay, and amber signifies acceptable. Click on the colored
button to invoke Date Selection dialog, if you like.
<b>Listing Events</b>: Events in the life of any individual may be
added to the database via the <b>Person &gt; Edit Person &gt;
Events</b> option. This space can be used to include a wide range
of options ranging from adoptions, to baptisms (and other religious
ceremonies), burials, causes of death, Census listings, degrees
earned, elections, emigration, military service, nobility titles,
occupations, ordination, property, religion, retirement, wills, etc.
</tip>
<tip>
<b>LISTING EVENTS</b>: Events in the life of any individual in the database may be
added via the Person &gt; Edit Person &gt; Events option. This space can be used
to include a wide range of options ranging from adoptions, to baptisms (and
other religious ceremonies), burials, causes of death, Census listings,
degrees earned in education, divorce filings, elections, emigration,
military service, nobility titles, number of marriages, occupations,
ordination, property, religion, retirement, wills, etc.
</tip>
<!--
<tip>
GRAMPS' People view gives you a list of all individuals in the database. You
can sort the listing by differing priorities simply by clicking on headings
like name, gender, bate date or death date.
</tip>
-->
<tip>
<b>CHANGING PREFERRED NAME</b>: If a person has several names, it is very easy
to manage these names in Gramps. Find the person in the Family view,
double-click on the record, and open Names tab. You can add different
types of names here, like Married Name, Birth Name, etc. Selecting a
preferred name is just a matter of right-clicking on the name and
<b>Changing The Preferred Name</b>:
It is easy to manage people with several names in GRAMPS.
Make the person the Active Person,
doubleclick on the record, and select the Names tab. Different
types of names can be added. For example, Married Name, Birth Name, etc.
Selecting a preferred name is just a matter of right-clicking on the name and
choosing the only item in the menu.
</tip>
<tip>
The Pedigree view display the family in the traditional pedigree view. Hold
the mouse over individuals to see more information about them and to move to
more distant parts of the tree.
The Pedigree View displays a traditional pedigree chart.
Hold the mouse over an individual to see more information about them or
right click on an individual to view a menu to quickly access their spouses,
siblings, children, or parents.
</tip>
<tip>
The Sources view shows all the family's referenced sources in a single view.
<!--
The Sources View shows a list of all sources in a single window.
Double-click on each to edit, add notes, and to see which individuals
reference the source.-->
reference the source.
</tip>
<tip>
The Places view shows all places referred to in the database.
<!--
It also allows
you to sort the list by half-a-dozen different criteria, such as City,
The Places View shows a list of all places in the database.
The list can be sorted by a number of different criteria, such as City,
County or State.
-->
</tip>
<tip>
The Media list includes all forms of media referenced by the database. These
could be graphic images, videos, sound clips, spreadsheets, documents, and
The Media View shows a list of all media entered in the database. These
can be graphic images, videos, sound clips, spreadsheets, documents, and
more.
</tip>
<tip>
GRAMPS allows you to bookmark key individuals in your family tree, for quick
access. The number able to be marked is unlimited.
</tip>
<tip>
GRAMPS comes with a rich set of tools. This allows you to undertake
operations such as checking database for errors and consistency, as well as
the research and analysis tools such as event comparison, finding duplicate
people, interactive descendant browser, and others.
</tip>
<tip>
The 'merge' function allows you to combine separately-listed people into
one. This is very useful for combining two databases with overlapping
people, or combining erroneously-entered differing names for one individual.
</tip>
<tip>
The Soundex generator allows you to generate the standard codes commonly
used in genealogy, to compare similar sounding names even though spelled
differently.
</tip>
<tip>
Custom filters allow you to dig out family data and interesting facts, in a
number of interesting selections. Such custom filters can be used in addition
to the numerous preset filters.
Filters allow you to limit the people seen in the People View. In addition
to the many preset filters, Custom Filters
can be created that allow you to create filters limited only by your
imagination.
Custom filters can be created from <b>Tools &gt; Utilities &gt; Custom
Filter Editor</b>.
</tip>
<tip>
@ -347,168 +349,23 @@ programs.
</tip>
<tip>
You can convert your data into a GRAMPS 'package', which is a compressed
file containing your family tree data and any other files used. This is
useful for backup or sharing with other GRAMPS users.
You can convert your data into a GRAMPS package, which is a
compressed file containing your family tree data and includes all
other files used by the database, such as images. This file is
completely portable so is useful for backups or sharing with other
GRAMPS users. This format has advantages over GEDCOM in that no
information is ever lost in exporting and importing.
</tip>
<tip>
Make your data portable -- you can export your family tree data and media
Make your data portable --- your family tree data and media can be exported
directly to the GNOME file manager (Nautilus), for burning onto a CD.
</tip>
<tip>
Web Family Tree (WFT) allows you to display your family tree online with
only a single file, instead of many html files. GRAMPS allows you to export
data to the WFT format.
</tip>
<tip>
GRAMPS currently runs on Linux, BSD, and Solaris.
</tip>
<tip>
There are several ways to report a bug, including the GRAMPS Bugs mailing
list. The best way to report a bug is to use the GRAMPS Bug Tracker at
Sourceforge. Using the bug tracker will make sure that your issue will be
handled, and doesn't miss the developers' attention.
</tip>
<tip>
GRAMPS is taken forward by a set of useful mailing-lists, which any serious
user needs to consider joining. These lists include gramps-announce
(announcements relating to the software project), gramps-bugs (to track
bugs), gramps-devel (for developers), and gramps-users (for all users,
including beginners).
</tip>
<tip>
Tonnes of GRAMPS-related information at http://gramps.sourceforge.net/
</tip>
<tip>
GRAMPS stands for Genealogical Research and Analysis Management Programming
System. It allows you to store, edit, and research genealogical data, with
similar functionality to other genealogical programs.
</tip>
<tip>
GRAMPS offers some unique features, including the ability to input any bits
and pieces of information directly into GRAMPS and rearrange/manipulate any
data events in the entire data base (in any order or sequence) to assist the
user in doing research, analysis and correlation with the potential of
filling relationship gaps.
</tip>
<tip>
Respect the privacy of people in your family tree. Genealogy shouldn't
reveal anyone's current health condition, their financial information, and
other information they would prefer be kept confidential.
</tip>
<tip>
Be accurate when recording genealogical information. Don't make assumptions
while recording primary information; write it exactly as you see it. Use
bracketed comments to indicate your additions, deletions or comments. Use of
the Latin 'sic' is recommended to confirm the accurate transcription of what
seems to be an error.
</tip>
<tip>
You can link any 'media' (including non-text information) and other
file-types to your GRAMPS family tree.
</tip>
<tip>
Privacy options allow the restriction of any information marked or
information about living individuals. Data marked with this option can be
excluded from reports and data exports.
</tip>
<tip>
GRAMPS allows you to generate brief or detailed reports for the ancestors or
descendents of any individual in your family tree, depending on your
requirements.
</tip>
<tip>
Multiple styles of reports are currently available by default. Users can
also create their own custom styles.
</tip>
<tip>
Eight output formats are supported by GRAMPS -- PDF, AbiWord, KWord,
OpenOffice Writer, HTML, Rich Text Format (RTF), Latex, and plain text.
These formats generate data which can be read on all computers, making
it easy for anyone to access it.
</tip>
<tip>
Custom reports can be created by advanced users under the "plugin" system
which allows the sharing of custom report styles between users.
</tip>
<tip>
Book report allows the user to collect a variety of reports in a single
document, which in turn is easier to distribute, especially in a paper
format.
</tip>
<tip>
Want improvements in GRAMPS? You can do it yourself too. Since GRAMPS is
free/libre and open source software, nobody prevents you from taking all of
the code and continuing its development in whatever direction you see fit.
</tip>
<tip>
Interested in getting notified when a GRAMPS release is made? Sign up on the
gramps-announce mailing list ultra-low bandwidth, at
http://lists.sourceforge.net/lists/listinfo/gramps-announce
</tip>
<tip>
Have questions about GRAMPS, or are you looking to discuss GRAMPS
related items? The best place is the gramps-users mailing list
http://lists.sourceforge.net/lists/listinfo/gramps-users You need to
first sign-up to be able to post.
</tip>
<tip>
Need enhancements for GRAMPS? Requesting an enhancement can be done either
through the gramps-users or gramps-devel mailing lists, or by creating a
Request for Enhancement (RFE)
http://sourceforge.net/tracker/?group_id=25770&amp;atid=385140
</tip>
<tip>
Good genealogy tip: Information collated about your family is only as good
as the source it came from. Take time and trouble to write down all the
details of where the information came from.
</tip>
<tip>
Go from what you know to what you do not. Always record everything that is
known before making conjecture. Often the facts at hand suggest plenty of
direction for more research. Don't waste time looking through thousands of
records hoping for a trail when you have other unexplored options.
</tip>
<tip>
Genealogy isn't only about dates and names. It is about people. Be
descriptive. Include the <b>why</b> of how things happened, and how descendents
might have been shaped by the events they went through. Narratives go a long
way in making your family interesting to others too.
</tip>
<tip>
Join the gramps-users mailing list at
http://lists.sourceforge.net/lists/listinfo/gramps-users
</tip>
<tip>
You can create graphical ancestor or descendent charts in several formats --
box charts, a fan chart, multiple formats (OpenOffice Draw, PDF, PostScript,
SVG), and custom charts.
GRAMPS can export data to the Web Family Tree (WFT) format. This format
allows a family tree to be displayed online using a single file, instead
of many html files.
</tip>
<tip>
@ -518,15 +375,94 @@ ready for upload to the World Wide Web.
</tip>
<tip>
Multiple calendars and date ranges are supported by GRAMPS.
The best way to report a bug in GRAMPS is to use the GRAMPS Bug Tracker
at Sourceforge, http://sourceforge.net/tracker/?group_id=25770&amp;atid=385137
</tip>
<tip>
Support is mature for multiple languages and cultures.
The GRAMPS homepage is at http://gramps-project.org/
</tip>
<tip>
GRAMPS offers translations for 15 languages.
GRAMPS has some unique features, including the ability to input any
piece of information directly into GRAMPS.
All data in the data base can be rearranged/manipulated to assist the
user in doing research, analysis and correlation with the potential of
filling relationship gaps.
</tip>
<tip>
GRAMPS helps you to keep personal information secure by allowing you to
mark information as private. Data marked as private can be excluded from
reports and data exports.
</tip>
<tip>
Be accurate when recording genealogical information. Don't make assumptions
while recording primary information; write it exactly as you see it. Use
bracketed comments to indicate your additions, deletions or comments. Use of
the Latin 'sic' is recommended to confirm the accurate transcription of what
appears to be an error in a source.
</tip>
<tip>
You can link any electronic media (including non-text information) and
other file types to your GRAMPS family tree.
</tip>
<tip>
GRAMPS allows you to generate a number of reports (both text and graphical)
based on your genealogical information. There is great flexibility in
selecting what people are included in the reports as well as the output
format (html, pdf, OpenOffice, RTF, AbiWord, KWord, LaTeX and plain text).
Experiment with the reports under the <b>Reports</b> menu to get an idea
of how powerful GRAMPS is.
</tip>
<tip>
Custom reports can be created by advanced users under the "plugin" system.
More information on custom reports can be found at
http://developers.gramps-project.org
</tip>
<tip>
The Book report, <b>Reports &gt; Books &gt; Book Report</b>, allows users
to collect a variety of reports into a single document. This single report
is easier to distribute than multiple reports, especially when printed.
</tip>
<tip>
Interested in getting notified when a new version of GRAMPS is released?
Join the gramps-announce mailing list at
http://lists.sourceforge.net/lists/listinfo/gramps-announce
</tip>
<tip>
<b>Good genealogy tip</b>: Information collected about your family is only as
good as the source it came from.
Take time and trouble to record all the
details of where the information came from. Whenever possible get a copy of
original documents.
</tip>
<tip>
Go from what you know to what you do not. Always record everything that is
known before making conjecture. Often the facts at hand suggest plenty of
direction for more research. Don't waste time looking through thousands of
records hoping for a trail when you have other unexplored leads.
</tip>
<tip>
Genealogy isn't only about dates and names. It is about people. Be
descriptive. Include the <b>why</b> of how things happened, and how descendants
might have been shaped by the events they went through. Narratives go a long
way in making your family history come alive.
</tip>
<tip>
GRAMPS has been translated to 15 languages. If GRAMPS supports your
language and it is not being displayed, set the default language on
your machine and restart GRAMPS.
</tip>
<tip>
@ -536,7 +472,7 @@ email gramps-devel@lists.sf.net
</tip>
<tip>
Relationship calculators in GRAMPS are available in four languages.
Relationship calculators in GRAMPS are available in ten languages.
</tip>
<tip>
@ -545,41 +481,26 @@ properly displayed.
</tip>
<tip>
You can choose anyone as your 'home person' in GRAMPS. Use Edit -> Set Home
Person. The home person is the person who is selected when the database is
opened, when the home-button is pressed in your browser-like GRAMPS
interface, and when Home is selected from the context menu anywhere.
Anyone can be chosen as the 'home person' in GRAMPS. Use <b>Edit -> Set Home
Person</b>. The home person is the person who is selected when the database is
opened or when the home button is pressed.
</tip>
<tip>
You can specify several names for a single person -- such as, birth name,
marriage name, etc.
Multiple names can be specified for individuals. Examples are birth name,
marriage name or aliases.
</tip>
<tip>An alternate name can be selected as a person's preferred name by
selecting the desired name in the person's name list, bringing up the context
menu by clicking the right mouse button, and selecting from the menu.
</tip>
<tip>
To switch between the different names of a single individual (birth name,
marriage name, etc) right-click on the name wanted in the list of
alternative names (under the Names tag in the EditPerson dialog) and select
an item from the context menu. This name will become the primary name, and
will be used in all display-related places.
</tip>
<tip>
Many current GRAMPS users contribute reports, suggestions, and feedback to
the developers through various public mailing lists. The program is only a
few years old and already has wide capabilities and features. Would you like
to help too?
</tip>
<tip>
Numerous GRAMPS releases are made each year.
</tip>
<tip>
GRAMPS is written in a computer language called Python using GTK and GNOME
libraries. While only well supported in certain Unix and Linux environments,
these are multi-platform development libraries, meaning that GRAMPS can be
ported to any platform the required libraries are ported to.
GRAMPS is written in a computer language called Python using the GTK and GNOME
libraries for the graphical interface.
GRAMPS is supported on any computer system where these programs have been
ported.
</tip>
<tip>
@ -590,40 +511,11 @@ freely available under its license.
<tip>
GRAMPS is freely distributable under the General Public License, see
http://www.gnu.org/licenses/licenses.html#GPL !
http://www.gnu.org/licenses/licenses.html#GPL
</tip>
<tip>
GRAMPS does not
support TempleReady GEDCOM extensions, and offers limited drag-and-drop
support. Currently, there is no support for drag and drop between databases.
Graph reports are also limited in functionality.
</tip>
<tip>
GRAMPS is the Genealogical Research and Analysis Management Program System.
In other words, it a personal genealogy program letting you store, edit, and
research genealogical data using the powers of your computer.
</tip>
<tip>
GRAMPS can be downloaded from Sourceforge http://sf.net/projects/gramps at
no charge. GRAMPS is an Free/Libre and Open Source Software project covered
by the GNU General Public License http://www.gnu.org/copyleft/gpl.html .
You have full access to the source code and are allowed to distribute the
program and source code freely.
</tip>
<tip>
A port of GRAMPS to Mac OS X exists from the Fink project
http://fink.sourceforge.net/pdb/package.php/gramps . It is not unusual for
this version to lag behind the Linux version. The port is not supported by
the GRAMPS project (since few if any of us have Macs), but we try to help
out where we can.
</tip>
<tip>
GRAMPS works with KDE too, as long as the required GNOME libraries are
GRAMPS works even when using KDE, as long as the required GNOME libraries are
installed.
</tip>
@ -634,16 +526,8 @@ running the GNOME desktop.
<tip>
GRAMPS makes every effort to maintain compatibility with GEDCOM, the general
standard of recording genealogical information. We have import and export
filters that enable GRAMPS to read and write GEDCOM files. Please do inform
us about any GEDCOM flavor not supported by GRAMPS, and we will do our best
to support it!
</tip>
<tip>
GRAMPS can produce many different charts and reports. Moreover, the plugin
architecture enables a user (you) to create his own plugins which could be
new reports, charts, or research tools.
standard of recording genealogical information. Filters exist that make
importing and exporting GEDCOM files trivial.
</tip>
</tips>

232
src/dates/Date_de.py Normal file
View File

@ -0,0 +1,232 @@
# -*- coding: utf-8 -*-
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2004-2005 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
German-specific classes for parsing and displaying dates.
"""
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import re
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import Date
from DateParser import DateParser
from DateDisplay import DateDisplay
#-------------------------------------------------------------------------
#
# French parser
#
#-------------------------------------------------------------------------
class DateParserDE(DateParser):
month_to_int = DateParser.month_to_int
# Always add german and austrian name variants no matter what the current locale is
month_to_int[u"januar"] = 1
month_to_int[u"jan"] = 1
month_to_int[u"jänner"] = 1
month_to_int[u"jän"] = 1
# Add other common latin, local and historical variants
month_to_int[u"januaris"] = 1
month_to_int[u"jenner"] = 1
month_to_int[u"feber"] = 2
month_to_int[u"februaris"] = 2
month_to_int[u"merz"] = 2
month_to_int[u"aprilis"] = 4
month_to_int[u"maius"] = 5
month_to_int[u"junius"] = 6
month_to_int[u"julius"] = 7
month_to_int[u"augst"] = 8
month_to_int[u"7ber"] = 9
month_to_int[u"7bris"] = 9
month_to_int[u"8ber"] = 10
month_to_int[u"8bris"] = 10
month_to_int[u"9ber"] = 11
month_to_int[u"9bris"] = 11
month_to_int[u"10ber"] = 12
month_to_int[u"10bris"] = 12
month_to_int[u"xber"] = 12
month_to_int[u"xbris"] = 12
modifier_to_int = {
u'vor' : Date.MOD_BEFORE,
u'nach' : Date.MOD_AFTER,
u'gegen' : Date.MOD_ABOUT,
u'um' : Date.MOD_ABOUT,
u'etwa' : Date.MOD_ABOUT,
u'circa' : Date.MOD_ABOUT,
u'ca.' : Date.MOD_ABOUT,
}
calendar_to_int = {
u'Gregorianisch' : Date.CAL_GREGORIAN,
u'Greg.' : Date.CAL_GREGORIAN,
u'Julianisch' : Date.CAL_JULIAN,
u'Jul.' : Date.CAL_JULIAN,
u'Hebräisch' : Date.CAL_HEBREW,
u'Hebr.' : Date.CAL_HEBREW,
u'Islamisch' : Date.CAL_ISLAMIC,
u'Isl.' : Date.CAL_ISLAMIC,
u'Französisch Republikanisch': Date.CAL_FRENCH,
u'Franz.' : Date.CAL_FRENCH,
u'Persisch' : Date.CAL_PERSIAN,
}
quality_to_int = {
u'geschätzt' : Date.QUAL_ESTIMATED,
u'gesch.' : Date.QUAL_ESTIMATED,
u'errechnet' : Date.QUAL_CALCULATED,
u'berechnet' : Date.QUAL_CALCULATED,
u'ber.' : Date.QUAL_CALCULATED,
}
bce = DateParser.bce + ["vor (unserer|der) Zeit(rechnung)?", "v\. (u|d)\. Z\.", "vor Christus", "vor Christi Geburt", "v\. Chr\."]
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._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,
re.IGNORECASE)
#-------------------------------------------------------------------------
#
# French display
#
#-------------------------------------------------------------------------
class DateDisplayDE(DateDisplay):
calendar = (
"", u" (Julianisch)", u" (Hebräisch)",
u" (Französisch Republikanisch)", u" (Persisch)", u" (Islamisch)"
)
_mod_str = ("",u"vor ",u"nach ",u"circa ","","","")
_qual_str = ("",u"geschätzt ",u"errechnet ")
_bce_str = "%s v. u. Z."
formats = (
"JJJJ-MM-DD (ISO)", "Numerisch", "Monat Tag Jahr",
"MONAT Tag Jahr", "Tag. Monat Jahr", "Tag. MONAT Jahr"
)
def _display_gregorian(self,date_val):
year = self._slash_year(date_val[2],date_val[3])
if self.format == 0:
value = self.display_iso(date_val)
elif self.format == 1:
if date_val[0] == 0 and date_val[1] == 0:
value = str(date_val[2])
else:
value = self._tformat.replace('%m',str(date_val[1]))
value = value.replace('%d',str(date_val[0]))
value = value.replace('%Y',str(date_val[2]))
elif self.format == 2:
# Month Day, Year
if date_val[0] == 0:
if date_val[1] == 0:
value = year
else:
value = "%s %s" % (self._months[date_val[1]],year)
else:
value = "%s %d, %s" % (self._months[date_val[1]],date_val[0],year)
elif self.format == 3:
# MON Day, Year
if date_val[0] == 0:
if date_val[1] == 0:
value = year
else:
value = "%s %s" % (self._MONS[date_val[1]],year)
else:
value = "%s %d, %s" % (self._MONS[date_val[1]],date_val[0],year)
elif self.format == 4:
# Day Month Year
if date_val[0] == 0:
if date_val[1] == 0:
value = year
else:
value = "%s %s" % (self._months[date_val[1]],year)
else:
value = "%d. %s %s" % (date_val[0],self._months[date_val[1]],year)
else:
# Day MON Year
if date_val[0] == 0:
if date_val[1] == 0:
value = year
else:
value = "%s %s" % (self._MONS[date_val[1]],year)
else:
value = "%d. %s %s" % (date_val[0],self._MONS[date_val[1]],year)
return value
def display(self,date):
"""
Returns a text string representing the date.
"""
mod = date.get_modifier()
cal = date.get_calendar()
qual = date.get_quality()
start = date.get_start_date()
qual_str = self._qual_str[qual]
if mod == Date.MOD_TEXTONLY:
return date.get_text()
elif start == Date.EMPTY:
return ""
elif mod == Date.MOD_SPAN:
d1 = self.display_cal[cal](start)
d2 = self.display_cal[cal](date.get_stop_date())
return "%s%s %s %s %s%s" % (qual_str,u'von',d1,u'bis',d2,self.calendar[cal])
elif mod == Date.MOD_RANGE:
d1 = self.display_cal[cal](start)
d2 = self.display_cal[cal](date.get_stop_date())
return "%szwischen %s und %s%s" % (qual_str,d1,d2,self.calendar[cal])
else:
text = self.display_cal[date.get_calendar()](start)
return "%s%s%s%s" % (qual_str,self._mod_str[mod],text,self.calendar[cal])
#-------------------------------------------------------------------------
#
# Register classes
#
#-------------------------------------------------------------------------
from DateHandler import register_datehandler
register_datehandler(('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)

View File

@ -1,175 +0,0 @@
# -*- coding: utf-8 -*-
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2004-2005 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
Finnish-specific classes for parsing and displaying dates.
"""
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
import re
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import Date
from DateParser import DateParser
from DateDisplay import DateDisplay
#-------------------------------------------------------------------------
#
# Finnish parser
#
# This handles only dates where days and months are given as numeric, as:
# - That's how they are normally used in Finland
# - Parsing Finnish is much more complicated than English
#-------------------------------------------------------------------------
class DateParserFI(DateParser):
# NOTE: these need to be in lower case because the "key" comparison
# is done as lower case. In the display method correct capitalization
# can be used.
modifier_to_int = {
# examples:
# - ennen 1.1.2005
# - 1.1.2005 jälkeen
# - noin 1.1.2005
u'ennen' : Date.MOD_BEFORE,
u'e.' : Date.MOD_BEFORE,
u'jälkeen' : Date.MOD_AFTER,
u'j.' : Date.MOD_AFTER,
u'noin' : Date.MOD_ABOUT,
u'n.' : Date.MOD_ABOUT,
}
bce = ["ekr", "ekr\."]
calendar_to_int = {
u'gregoriaaninen' : Date.CAL_GREGORIAN,
u'greg.' : Date.CAL_GREGORIAN,
u'juliaaninen' : Date.CAL_JULIAN,
u'jul.' : Date.CAL_JULIAN,
u'heprealainen' : Date.CAL_HEBREW,
u'hepr.' : Date.CAL_HEBREW,
u'islamilainen' : Date.CAL_ISLAMIC,
u'isl.' : Date.CAL_ISLAMIC,
u'ranskan vallankumouksen aikainen': Date.CAL_FRENCH,
u'ranskan v.' : Date.CAL_FRENCH,
u'persialainen' : Date.CAL_PERSIAN,
u'pers.' : Date.CAL_PERSIAN,
}
quality_to_int = {
u'arviolta' : Date.QUAL_ESTIMATED,
u'arv.' : Date.QUAL_ESTIMATED,
u'laskettuna' : Date.QUAL_CALCULATED,
u'lask.' : Date.QUAL_CALCULATED,
}
def init_strings(self):
DateParser.init_strings(self)
# date, whitespace
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ä",
re.IGNORECASE)
#-------------------------------------------------------------------------
#
# Finnish display
#
#-------------------------------------------------------------------------
class DateDisplayFI(DateDisplay):
calendar = ("",
u"(Juliaaninen)",
u"(Heprealainen)",
u"(Ranskan v.)",
u"(Persialainen)",
u"(Islamilainen)")
_qual_str = ("", "laskettuna", "arviolta")
formats = (
"VVVV-KK-PP (ISO)",
"PP.KK.VVVV"
)
def display(self,date):
"""
Returns a text string representing the date.
"""
mod = date.get_modifier()
qual = date.get_quality()
cal = date.get_calendar()
start = date.get_start_date()
if mod == Date.MOD_TEXTONLY:
return date.get_text()
if start == Date.EMPTY:
return ""
# select numerical date format
self.format = 1
if mod == Date.MOD_SPAN:
d1 = self.display_cal[cal](start)
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)
else:
text = self.display_cal[date.get_calendar()](start)
if mod == Date.MOD_BEFORE:
text = "ennen " + text
elif mod == Date.MOD_AFTER:
# kludge: should be actually after the date
text = "jälkeen " + text
elif mod == Date.MOD_ABOUT:
text = "noin " + text
if qual:
# prepend quality
text = "%s %s" % (self._qual_str[qual], text)
if cal:
# append calendar type
text = "%s %s" % (text, self.calendar[cal])
return text
#-------------------------------------------------------------------------
#
# Register classes
#
#-------------------------------------------------------------------------
from DateHandler import register_datehandler
register_datehandler(('fi_FI','finnish'), DateParserFI, DateDisplayFI)

View File

@ -6,10 +6,10 @@
pkgdatadir = $(datadir)/@PACKAGE@/dates
pkgdata_PYTHON = \
Date_de.py\
Date_ru.py\
Date_fr.py\
Date_es.py\
Date_fi.py
Date_es.py
pkgpyexecdir = @pkgpyexecdir@/dates
pkgpythondir = @pkgpythondir@/dates

View File

@ -9,6 +9,7 @@
# Completely butchered to add glade support for the GRAMPS
# project by Don Allingham (dallingham@users.sourceforge.net)
#
# Further bastardized by Alex Roitman to support tips.xml file
# $Id$
@ -120,7 +121,6 @@ import getopt
import tokenize
import operator
import re
import string
import os
from xml.sax import make_parser,handler,SAXParseException
@ -213,6 +213,87 @@ class GladeParser(handler.ContentHandler):
def characters(self, data):
self.text = self.text + data
class TipExtractor:
def __init__(self,msgs):
self.strings = msgs
def add_string(self, str, lineno):
if str.strip() == "":
return
if _ignore.has_key(str):
return
entry = (self.file, lineno)
if self.strings.has_key(str):
self.strings[str][entry] = 0
else:
self.strings[str] = {entry: 0}
def parse(self,file):
self.p = make_parser()
self.p.setContentHandler(TipParser(self,file))
filename = "file://" + os.path.abspath(file)
self.file = file
self.p.parse(filename)
class TipParser(handler.ContentHandler):
"""
SAX parsing class for the Tips XML file.
This parser needs to extract strings in *exactly* the same way
as the TipOfDay.TipParser does. Otherwise, msgid's won't be correctly
matched.
"""
def __init__(self,parent,filename):
"""
Creates a SheetParser class that populates the passed StyleSheetList
class.
sheetlist - StyleSheetList instance to be loaded from the file.
"""
handler.ContentHandler.__init__(self)
self.parent = parent
self.translate = 0
self.text = ""
self.filename = filename
self.lineno = 0
def startElement(self,tag,attrs):
"""
Overridden class that handles the start of a XML element
"""
if tag == "tip":
self.text = ""
elif tag != "tips":
# let all the other tags through, except for the "tips" tag
self.text = self.text + "<%s>" % tag
def endElement(self,tag):
"Overridden class that handles the start of a XML element"
if tag == "tip":
if not _int_re.match(self.text):
text = self.escape(self.text)
self.parent.add_string(' '.join(text.split()),
self.locator.getLineNumber())
elif tag != "tips":
# let all the other tags through, except for the "tips" tag
self.text = self.text + "</%s>" % tag
def setDocumentLocator(self,locator):
self.locator = locator
def characters(self, data):
self.text = self.text + data
def escape(self,text):
"""
The tip's text will be interpreted as a markup, so we need to escape
some special chars.
"""
text = text.replace('&','&amp;'); # Must be first
return text
# The normal pot-file header. msgmerge and Emacs's po-mode work better if it's
# there.
pot_header = _('''\
@ -270,7 +351,7 @@ def escape(s):
s = list(s)
for i in range(len(s)):
s[i] = escapes[ord(s[i])]
return string.join(s,'')
return ''.join(s)
def safe_eval(s):
@ -281,7 +362,7 @@ def safe_eval(s):
def normalize(s):
# This converts the various Python string types into a format that is
# appropriate for .po files, namely much closer to C style.
lines = string.split(s,'\n')
lines = s.split('\n')
if len(lines) == 1:
s = '"' + escape(s) + '"'
else:
@ -291,7 +372,7 @@ def normalize(s):
for i in range(len(lines)):
lines[i] = escape(lines[i])
lineterm = '\\n"\n"'
s = '""\n"' + string.join(lines,lineterm) + '"'
s = '""\n"' + lineterm.join(lines) + '"'
return s
class TokenEater:
@ -342,7 +423,7 @@ class TokenEater:
# of messages seen. Reset state for the next batch. If there
# were no strings inside _(), then just ignore this entry.
if self.__data:
self.__addentry(string.join(self.__data,''))
self.__addentry(''.join(self.__data))
self.__state = self.__waiting
elif ttype == tokenize.STRING:
self.__data.append(safe_eval(tstring))
@ -499,13 +580,18 @@ def main():
# slurp through all the files
eater = TokenEater(options)
p = GladeExtractor(eater.get_messages())
tp = TipExtractor(eater.get_messages())
for filename in args:
if filename[-5:] == 'glade':
print 'Working on %s' % filename
p.parse(filename)
elif filename[-3:] == 'xml':
elif filename[-8:] == 'tips.xml':
# Using our own custom Tips parser for tips.xml
print 'Working on %s' % filename
tp.parse(filename)
elif filename[-3:] == 'xml':
# THIS IS NOT WORKING -- something has changed in SAX/Expat
try:
parser = make_parser()
pxml = XMLParser(filename,eater.get_messages())

View File

@ -7802,37 +7802,6 @@ Other</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="button99">
<property name="border_width">1</property>
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Invoke birth event editor</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_edit_birth_clicked" object="editPerson"/>
<child>
<widget class="GtkImage" id="image2262">
<property name="visible">True</property>
<property name="pixbuf">edit_sm.png</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
<packing>
<property name="left_attach">4</property>
<property name="right_attach">5</property>
<property name="top_attach">13</property>
<property name="bottom_attach">14</property>
<property name="x_options"></property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="surname">
<property name="visible">True</property>
@ -7938,97 +7907,6 @@ Other</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="button126">
<property name="border_width">1</property>
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Invoke death event editor</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_edit_death_clicked" object="editPerson"/>
<child>
<widget class="GtkImage" id="image2263">
<property name="visible">True</property>
<property name="pixbuf">edit_sm.png</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
<packing>
<property name="left_attach">10</property>
<property name="right_attach">11</property>
<property name="top_attach">13</property>
<property name="bottom_attach">14</property>
<property name="x_options">shrink</property>
<property name="y_options">shrink</property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox98">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkEntry" id="deathDate">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="death_stat">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Invoke date editor</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NONE</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_edit_date_death_clicked" last_modification_time="Sat, 18 Sep 2004 02:30:11 GMT"/>
<child>
<widget class="GtkImage" id="death_stat_child">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">8</property>
<property name="right_attach">10</property>
<property name="top_attach">13</property>
<property name="bottom_attach">14</property>
<property name="y_options">fill</property>
</packing>
</child>
<child>
<widget class="GtkFrame" id="frame5">
<property name="visible">True</property>
@ -8067,10 +7945,6 @@ Other</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="type">label_item</property>
@ -8131,6 +8005,366 @@ Other</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkTable" id="table52">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">3</property>
<property name="homogeneous">False</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<child>
<widget class="GtkLabel" id="label25">
<property name="visible">True</property>
<property name="label" translatable="yes">_Date:</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
<packing>
<property name="left_attach">0</property>
<property name="right_attach">1</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label123">
<property name="visible">True</property>
<property name="label" translatable="yes">_Place:</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="mnemonic_widget">birth_place</property>
</widget>
<packing>
<property name="left_attach">0</property>
<property name="right_attach">1</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="birth_place">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkButton" id="button99">
<property name="border_width">1</property>
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Invoke birth event editor</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_edit_birth_clicked" object="editPerson"/>
<child>
<widget class="GtkImage" id="image2262">
<property name="visible">True</property>
<property name="pixbuf">edit_sm.png</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="x_options">shrink|fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox97">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkEntry" id="birthDate">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="birth_stat">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Invoke date editor</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NONE</property>
<property name="focus_on_click">True</property>
<child>
<widget class="GtkImage" id="birth_stat_child">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="y_options">fill</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">5</property>
<property name="top_attach">13</property>
<property name="bottom_attach">15</property>
<property name="x_options">expand|shrink|fill</property>
<property name="y_options">fill</property>
</packing>
</child>
<child>
<widget class="GtkTable" id="table53">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">3</property>
<property name="homogeneous">False</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<child>
<widget class="GtkLabel" id="label302">
<property name="visible">True</property>
<property name="label" translatable="yes">D_ate:</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="mnemonic_widget">deathDate</property>
</widget>
<packing>
<property name="left_attach">0</property>
<property name="right_attach">1</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkHBox" id="hbox98">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
<child>
<widget class="GtkEntry" id="deathDate">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="death_stat">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Invoke date editor</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NONE</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_edit_date_death_clicked" last_modification_time="Sat, 18 Sep 2004 02:30:11 GMT"/>
<child>
<widget class="GtkImage" id="death_stat_child">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="y_options">fill</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="button126">
<property name="border_width">1</property>
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Invoke death event editor</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_edit_death_clicked" object="editPerson"/>
<child>
<widget class="GtkImage" id="image2263">
<property name="visible">True</property>
<property name="pixbuf">edit_sm.png</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
</child>
</widget>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">0</property>
<property name="bottom_attach">1</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label303">
<property name="visible">True</property>
<property name="label" translatable="yes">Plac_e:</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="mnemonic_widget">death_place</property>
</widget>
<packing>
<property name="left_attach">0</property>
<property name="right_attach">1</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">fill</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="death_place">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="visibility">True</property>
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char">*</property>
<property name="activates_default">False</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">7</property>
<property name="right_attach">11</property>
<property name="top_attach">13</property>
<property name="bottom_attach">15</property>
<property name="x_options">fill</property>
<property name="y_options">fill</property>
</packing>
</child>
</widget>
<packing>
<property name="left_attach">0</property>
@ -31617,7 +31851,7 @@ Family name Given name
<property name="max_length">0</property>
<property name="text" translatable="yes"></property>
<property name="has_frame">True</property>
<property name="invisible_char" translatable="yes">*</property>
<property name="invisible_char">*</property>
<property name="activates_default">False</property>
</widget>
<packing>

View File

@ -961,23 +961,28 @@ class Gramps(GrampsDBCallback.GrampsDBCallback):
all.add_rule(GenericFilter.IsMale([]))
filter_list.append(all)
all = GenericFilter.GenericFilter()
all.set_name(_("People with unknown gender"))
all.add_rule(GenericFilter.HasUnknownGender([]))
filter_list.append(all)
all = GenericFilter.GenericFilter()
all.set_name(_("Disconnected individuals"))
all.add_rule(GenericFilter.Disconnected([]))
filter_list.append(all)
all = GenericFilter.ParamFilter()
all.set_name(_("Name contains..."))
all.set_name(_("People with names containing..."))
all.add_rule(GenericFilter.SearchName([]))
filter_list.append(all)
all = GenericFilter.GenericFilter()
all.set_name(_("People who were adopted"))
all.set_name(_("Adopted people"))
all.add_rule(GenericFilter.HaveAltFamilies([]))
filter_list.append(all)
all = GenericFilter.GenericFilter()
all.set_name(_("People who have images"))
all.set_name(_("People with images"))
all.add_rule(GenericFilter.HavePhotos([]))
filter_list.append(all)
@ -1002,7 +1007,7 @@ class Gramps(GrampsDBCallback.GrampsDBCallback):
filter_list.append(all)
all = GenericFilter.GenericFilter()
all.set_name(_("People without a birth date"))
all.set_name(_("People without a known birth date"))
all.add_rule(GenericFilter.NoBirthdate([]))
filter_list.append(all)
@ -1031,15 +1036,15 @@ class Gramps(GrampsDBCallback.GrampsDBCallback):
all.add_rule(GenericFilter.IsWitness([]))
filter_list.append(all)
# all = GenericFilter.ParamFilter()
# all.set_name(_("Any textual record contains..."))
# all.add_rule(GenericFilter.HasTextMatchingSubstringOf([]))
# filter_list.append(all)
all = GenericFilter.ParamFilter()
all.set_name(_("People with records containing..."))
all.add_rule(GenericFilter.HasTextMatchingSubstringOf([]))
filter_list.append(all)
# all = GenericFilter.ParamFilter()
# all.set_name(_("Any textual record matches regular expression..."))
# all.add_rule(GenericFilter.HasTextMatchingRegexpOf([]))
# filter_list.append(all)
all = GenericFilter.ParamFilter()
all.set_name(_("People with records matching regular expression..."))
all.add_rule(GenericFilter.HasTextMatchingRegexpOf([]))
filter_list.append(all)
self.filter_model = GenericFilter.FilterStore(filter_list)
self.filter_list.set_model(self.filter_model)
@ -1248,7 +1253,6 @@ class Gramps(GrampsDBCallback.GrampsDBCallback):
self.progress.set_fraction(0)
def read_file(self,filename,callback=None):
self.topWindow.set_resizable(False)
mode = "w"
filename = os.path.normpath(os.path.abspath(filename))
@ -1289,9 +1293,11 @@ class Gramps(GrampsDBCallback.GrampsDBCallback):
except db.DBAccessError, msg:
ErrorDialog(_('Cannot open database'),
_('%s could not be opened.' % filename) + '\n' + msg[1])
return 0
except (db.DBError), msg:
ErrorDialog(_('Cannot open database'),
_('%s could not be opened.' % filename) + '\n' + msg[1])
gtk.main_quit()
self.topWindow.set_resizable(True)
# Undo/Redo always start with standard labels and insensitive state
self.undo_callback(None)
self.redo_callback(None)
@ -1878,7 +1884,40 @@ class Gramps(GrampsDBCallback.GrampsDBCallback):
task(self.db,self.active_person,self.tool_callback,self)
def open_example(self,obj):
pass
import shutil
dest = os.path.expanduser("~/.gramps/example")
if not os.path.isdir(dest):
try:
os.mkdir(dest)
except IOError,msg:
ErrorDialog(_('Could not create example database'),
_('The directory ~/.gramps/example could not '
'be created.') + '\n' + str(msg) )
except OSError,msg:
ErrorDialog(_('Could not create example database'),
_('The directory ~/.gramps/example could not '
'be created.') + '\n' + str(msg) )
except:
ErrorDialog(_('Could not create example database'),
_('The directory ~/.gramps/example could not '
'be created.'))
try:
example_dir = "%s/share/gramps/example" % const.prefixdir
for filename in os.listdir(example_dir):
shutil.copyfile("%s/%s" % (example_dir,filename),
"%s/%s" % (dest,filename) )
try:
shutil.copystat("%s/%s" % (example_dir,filename),
"%s/%s" % (dest,filename))
except:
pass
except IOError,msg:
ErrorDialog(_('Could not create example database'),str(msg))
except OSError,msg:
ErrorDialog(_('Could not create example database'),str(msg))
filename = "%s/%s" % (dest,const.xmlFile)
DbPrompter.open_native(self,filename,const.app_gramps_xml)
DARKEN = 1.4

View File

@ -17,7 +17,6 @@
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
@ -100,10 +99,6 @@
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">6</property>
@ -156,10 +151,6 @@
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
@ -184,10 +175,6 @@
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
@ -306,7 +293,6 @@
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
@ -404,10 +390,6 @@
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">10</property>
@ -438,7 +420,7 @@
<widget class="GtkTextView" id="text1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="editable">False</property>
<property name="overwrite">False</property>
<property name="accepts_tab">True</property>
<property name="justification">GTK_JUSTIFY_LEFT</property>
@ -475,7 +457,7 @@
<widget class="GtkTextView" id="text2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">True</property>
<property name="editable">False</property>
<property name="overwrite">False</property>
<property name="accepts_tab">True</property>
<property name="justification">GTK_JUSTIFY_LEFT</property>
@ -576,7 +558,6 @@
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
@ -660,10 +641,6 @@
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="left_attach">0</property>
@ -687,10 +664,6 @@
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="left_attach">0</property>
@ -715,10 +688,6 @@
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="left_attach">4</property>
@ -1190,7 +1159,6 @@
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="has_separator">False</property>
<child internal-child="vbox">
@ -1273,10 +1241,6 @@
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
@ -1298,10 +1262,6 @@
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">6</property>
@ -1332,10 +1292,6 @@
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="left_attach">1</property>
@ -1360,10 +1316,6 @@
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="left_attach">1</property>

View File

@ -370,7 +370,8 @@ class ComprehensiveAncestorsReport (Report.Report):
for media_ref in partner.get_media_list ()[:1]:
object_handle = media_ref.get_reference_handle()
mobject = self.database.get_object_from_handle(object_handle)
if mobject.get_mime_type()[0:5] == "image":
mime_type = mobject.get_mime_type()
if mime_type and mime_type.startswith("image"):
spouse.append ((self.doc.add_media_object,
[mobject.get_path (),
'right', 2, 2]))
@ -403,7 +404,8 @@ class ComprehensiveAncestorsReport (Report.Report):
for media_ref in photos[:1]:
object_handle = media_ref.get_reference_handle()
mobject = self.database.get_object_from_handle(object_handle)
if mobject.get_mime_type()[0:5] == "image":
mime_type = mobject.get_mime_type()
if mime_type and mime_type.startswith("image"):
ret.append ((self.doc.add_media_object,
[mobject.get_path (), 'left', 2, 2]))
ret.append ((self.doc.end_cell, []))

View File

@ -239,7 +239,7 @@ class CheckIntegrity:
place = self.db.get_place_from_handle(handle)
if place.has_media_reference(ObjectId):
place.remove_media_references([ObjectId])
self.db.commit_place(p,self.trans)
self.db.commit_place(place,self.trans)
self.removed_photo.append(ObjectId)
self.db.remove_object(ObjectId,self.trans)

View File

@ -65,6 +65,14 @@ _menulist = {
_('Relationship type:') : const.family_relations,
}
#-------------------------------------------------------------------------
#
# Sorting function for the filter rules
#
#-------------------------------------------------------------------------
def by_rule_name(f,s):
return cmp(f.name,s.name)
#-------------------------------------------------------------------------
#
# MyBoolean - check button with standard interface
@ -213,7 +221,7 @@ class MyID(gtk.HBox):
if val == None:
self.set_text('')
else:
self.set_text(val.get_handle())
self.set_text(val.get_gramps_id())
def get_text(self):
return unicode(self.entry.get_text())
@ -550,7 +558,7 @@ class EditFilter:
def draw_rules(self):
self.rlist.clear()
for r in self.filter.get_rules():
self.rlist.add([r.trans_name(),r.display_values()],r)
self.rlist.add([r.name,r.display_values()],r)
def on_ok_clicked(self,obj):
n = unicode(self.fname.get_text()).strip()
@ -636,26 +644,21 @@ class EditRule:
self.valuebox.add(self.notebook)
self.page_num = 0
self.page = []
self.name2page = {}
self.class2page = {}
the_map = {}
the_list = []
keylist = GenericFilter.tasks.keys()
keylist.sort()
for name in keylist:
cname = GenericFilter.tasks[name]
arglist = cname.labels
for class_obj in GenericFilter.editor_rule_list:
arglist = class_obj.labels
vallist = []
tlist = []
self.page.append((name,cname,vallist,tlist))
self.page.append((class_obj,vallist,tlist))
pos = 0
l2 = gtk.Label(name)
l2 = gtk.Label(class_obj.name)
l2.set_alignment(0,0.5)
l2.show()
c = gtk.TreeView()
c.set_data('d',pos)
c.show()
the_list.append(c)
the_map[name] = c
the_map[class_obj] = c
# Only add a table with parameters if there are any parameters
if arglist:
table = gtk.Table(3,len(arglist))
@ -698,11 +701,11 @@ class EditRule:
table.attach(l,1,2,pos,pos+1,gtk.FILL,0,5,5)
table.attach(t,2,3,pos,pos+1,gtk.EXPAND|gtk.FILL,0,5,5)
pos = pos + 1
self.notebook.append_page(table,gtk.Label(name))
self.name2page[name] = self.page_num
self.notebook.append_page(table,gtk.Label(class_obj.name))
self.class2page[class_obj] = self.page_num
self.page_num = self.page_num + 1
self.page_num = 0
self.store = gtk.TreeStore(gobject.TYPE_STRING)
self.store = gtk.TreeStore(gobject.TYPE_STRING,gobject.TYPE_PYOBJECT)
self.selection = self.rname.get_selection()
col = gtk.TreeViewColumn(_('Rule Name'),gtk.CellRendererText(),text=0)
self.rname.append_column(col)
@ -719,38 +722,46 @@ class EditRule:
#
sel_node = None
if self.active_rule:
self.sel_name = unicode(_(self.active_rule.name()))
self.sel_class = self.active_rule.__class__
else:
self.sel_name = ""
for v in the_map.keys():
the_filter = GenericFilter.tasks[v]([None])
category = the_filter.category()
if top_level.has_key(category):
top_level[category].append(v)
else:
top_level[category] = [v]
top_node[category] = self.store.insert_after(None,last_top)
last_top = top_node[category]
self.store.set(last_top,0,category)
self.sel_class = None
keys = the_map.keys()
keys.sort(by_rule_name)
keys.reverse()
catlist = []
for class_obj in keys:
category = class_obj.category
if category not in catlist:
catlist.append(category)
catlist.sort()
for category in catlist:
top_node[category] = self.store.insert_after(None,last_top)
top_level[category] = []
last_top = top_node[category]
self.store.set(last_top,0,category,1,None)
for class_obj in keys:
category = class_obj.category
top_level[category].append(class_obj.name)
node = self.store.insert_after(top_node[category],prev)
self.store.set(node,0,v)
self.store.set(node,0,class_obj.name,1,class_obj)
#
# if this is an edit rule, save the node
if v == self.sel_name:
if class_obj == self.sel_class:
sel_node = node
if sel_node:
self.selection.select_iter(sel_node)
page = self.name2page[self.sel_name]
page = self.class2page[self.active_rule.__class__]
self.notebook.set_current_page(page)
self.display_values(self.sel_name)
(n,c,v,t) = self.page[page]
self.display_values(self.active_rule.__class__)
(class_obj,vallist,tlist) = self.page[page]
r = self.active_rule.values()
for i in range(0,len(t)):
t[i].set_text(r[i])
for i in range(0,len(tlist)):
tlist[i].set_text(r[i])
self.selection.connect('changed', self.on_node_selected)
self.rule.signal_autoconnect({
@ -777,7 +788,10 @@ class EditRule:
def add_itself_to_menu(self):
self.parent.child_windows[self.win_key] = self
label = self.sel_name
if self.sel_class:
label = self.sel_class.name
else:
label = ''
if not label.strip():
label = _("New Rule")
label = "%s: %s" % (_('Rule'),label)
@ -800,32 +814,32 @@ class EditRule:
store,iter = self.selection.get_selected()
if iter:
try:
key = unicode(store.get_value(iter,0))
self.display_values(key)
class_obj = store.get_value(iter,1)
self.display_values(class_obj)
except:
self.valuebox.set_sensitive(0)
self.rule_name.set_text(_('No rule selected'))
self.rule.get_widget('description').set_text('')
def display_values(self,key):
page = self.name2page[key]
def display_values(self,class_obj):
page = self.class2page[class_obj]
self.notebook.set_current_page(page)
self.valuebox.set_sensitive(1)
self.rule_name.set_text(key)
the_filter = GenericFilter.tasks[key]([None])
self.rule.get_widget('description').set_text(the_filter.description())
self.rule_name.set_text(class_obj.name)
self.rule.get_widget('description').set_text(class_obj.description)
def rule_ok(self,obj):
name = unicode(self.rule_name.get_text())
class_def = GenericFilter.tasks[name]
obj = class_def(None)
if self.rule_name.get_text() == _('No rule selected'):
return
try:
page = self.name2page[name]
(n,c,v,t) = self.page[page]
page = self.notebook.get_current_page()
(class_obj,vallist,tlist) = self.page[page]
value_list = []
for x in t:
for x in tlist:
value_list.append(unicode(x.get_text()))
store,iter = self.parent.rlist.get_selected()
new_rule = c(value_list)
new_rule = class_obj(value_list)
if self.active_rule:
rule = self.parent.rlist.get_object(iter)
self.parent.filter.delete_rule(rule)
@ -839,7 +853,6 @@ class EditRule:
self.window.destroy()
DisplayTrace.DisplayTrace()
#-------------------------------------------------------------------------
#
#

View File

@ -52,6 +52,7 @@ import Utils
import const
from QuestionDialog import ErrorDialog
from DateHandler import parser as _dp
from htmlentitydefs import name2codepoint
#-------------------------------------------------------------------------
#
@ -419,6 +420,8 @@ class GeneWebParser:
person.set_primary_name(name)
if gender != None:
person.set_gender(gender)
else:
person.set_gender(RelLib.Person.UNKNOWN)
self.db.commit_person(person,self.trans)
personDataRe = re.compile("^[0-9<>~#\[({!].*$")
dateRe = re.compile("^[0-9~<>?]+.*$")
@ -660,7 +663,7 @@ class GeneWebParser:
def get_or_create_person(self,firstname,lastname):
person = None
mykey = firstname+lastname
if mykey in self.ikeys:
if mykey in self.ikeys and firstname != "?" and lastname != "?":
person = self.db.get_person_from_handle(self.ikeys[mykey])
else:
person = RelLib.Person()
@ -696,7 +699,29 @@ class GeneWebParser:
return sref
def decode(self,s):
return( latin_utf8.latin_to_utf8( s.replace('_',' ')))
s = latin_utf8.latin_to_utf8( s.replace('_',' '))
charref_re = re.compile('(&#)(x?)([0-9a-zA-Z]+)(;)')
for match in charref_re.finditer(s):
try:
if match.group(2): # HEX
nchar = unichr(int(match.group(3),16))
else: # Decimal
nchar = unichr(int(match.group(3)))
s = s.replace(match.group(0),nchar)
except UnicodeDecodeError:
pass
# replace named entities
entref_re = re.compile('(&)([a-zA-Z]+)(;)')
for match in entref_re.finditer(s):
try:
if match.group(2) in name2codepoint:
nchar = unichr(name2codepoint[match.group(2)])
s = s.replace(match.group(0),nchar)
except UnicodeDecodeError:
pass
return( s)
def cnv(seld,s):
return( latin_utf8.latin_to_utf8(s))

View File

@ -392,7 +392,8 @@ class IndivCompleteReport(Report.Report):
if len(media_list) > 0:
object_handle = media_list[0].get_reference_handle()
object = self.database.get_object_from_handle(object_handle)
if object.get_mime_type()[0:5] == "image":
mime_type = object.get_mime_type()
if mime_type and mime_type.startswith("image"):
file = object.get_path()
self.doc.start_paragraph("IDS-Normal")
self.doc.add_media_object(file,"row",4.0,4.0)

View File

@ -211,7 +211,8 @@ class IndivSummary(Report.Report):
if len(media_list) > 0:
object_handle = media_list[0].get_reference_handle()
object = self.database.get_object_from_handle(object_handle)
if object.get_mime_type()[0:5] == "image":
mime_type = object.get_mime_type()
if mime_type and mime_type.startswith("image"):
file = object.get_path()
self.doc.start_paragraph("IVS-Normal")
self.doc.add_media_object(file,"row",4.0,4.0)

View File

@ -401,7 +401,8 @@ class HomePage(BasePage):
if not obj:
print "%s object not found" % note_id
else:
if obj.get_mime_type()[0:5] == "image":
mime_type = obj.get_mime_type()
if mime_type and mime_type.startswith("image"):
newpath = obj.gramps_id + os.path.splitext(obj.get_path())[1]
shutil.copyfile(obj.get_path(),
os.path.join(html_dir,newpath))

View File

@ -680,7 +680,7 @@ class ScratchPadListView:
return
# Just select the first match.
wrapper_class = self._target_type_to_wrapper_class_map[possible_wrappers[0]]
wrapper_class = self._target_type_to_wrapper_class_map[str(possible_wrappers[0])]
o = wrapper_class(self._gramps_model,sel_data)

View File

@ -412,7 +412,7 @@ class Extract:
genders - which gender(s) to include into statistics
year_from - use only persons who've born this year of after
year_to - use only persons who've born this year or before
no_years - use also people without any birth year
no_years - use also people without known birth year
Returns an array of tuple of:
- Extraction method title
@ -774,7 +774,7 @@ class StatisticsChartOptions(ReportOptions.ReportOptions):
"Earlier than 'year_to' value"),
'year_to' : ("=num", "Birth year until which to include people",
"Smaller than %d" % self.options_dict['year_to']),
'no_years' : ("=0/1", "Whether to include people without birth years",
'no_years' : ("=0/1", "Whether to include people without known birth years",
["Do not include", "Include"], True),
'bar_items' : ("=num", "Use barchart instead of piechart with this many or more items",
"Number of items with which piecharts still look good...")
@ -878,9 +878,9 @@ class StatisticsChartOptions(ReportOptions.ReportOptions):
dialog.add_option(_('People born between'), box, tip)
box.show_all()
# include people without birth year?
tip = _("Check this if you want people who have no birth date or year to be accounted also in the statistics.")
self.no_years = gtk.CheckButton(_("Include people without birth years"))
# include people without known birth year?
tip = _("Check this if you want people who have no known birth date or year to be accounted also in the statistics.")
self.no_years = gtk.CheckButton(_("Include people without known birth years"))
self.no_years.set_active(self.options_dict['no_years'])
dialog.add_option(None, self.no_years, tip)
self.no_years.show()
@ -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

View File

@ -30,6 +30,8 @@
import os
import re
import time
import traceback
import sys
from random import randint,choice
from gettext import gettext as _
@ -47,12 +49,14 @@ import gtk.glade
#
#-------------------------------------------------------------------------
import Errors
import Date
import RelLib
import latin_utf8
import Utils
import const
from QuestionDialog import ErrorDialog
from DateHandler import parser as _dp
from DateHandler import displayer as _dd
#-------------------------------------------------------------------------
#
@ -80,6 +84,10 @@ class TestcaseGenerator:
self.check_bugs.set_active(True)
self.top.vbox.pack_start(self.check_bugs,0,0,5)
self.check_dates = gtk.CheckButton( _("Generate date tests"))
self.check_dates.set_active(True)
self.top.vbox.pack_start(self.check_dates,0,0,5)
self.check_persons = gtk.CheckButton( _("Generate dummy families"))
self.check_persons.set_active(True)
self.top.vbox.pack_start(self.check_persons,0,0,5)
@ -99,16 +107,17 @@ class TestcaseGenerator:
response = self.top.run()
bugs = self.check_bugs.get_active()
dates = self.check_dates.get_active()
persons = self.check_persons.get_active()
multiple_trans = self.check_trans.get_active()
person_count = int(self.entry_count.get_text())
self.top.destroy()
if response == gtk.RESPONSE_OK:
self.run_generator(bugs,persons,person_count,multiple_trans)
self.run_generator(bugs,dates,persons,person_count,multiple_trans)
def run_generator( self, generate_bugs = 1, generate_families = 1, generate_max_persons = 2000, multiple_transactions=False):
def run_generator( self, generate_bugs = 1, generate_dates = 1, generate_families = 1, generate_max_persons = 2000, multiple_transactions=False):
title = "%s - GRAMPS" % _("Generate testcases")
self.top = gtk.Window()
self.top.set_title(title)
@ -136,8 +145,114 @@ class TestcaseGenerator:
self.trans.set_batch(True)
self.db.disable_signals()
if self.multiple_transactions:
print "TESTING SIGNALS..."
print "\nCREATE PERSON"
p = RelLib.Person()
self.db.add_person( p, self.trans)
print "\nUPDATE PERSON"
self.db.commit_person( p, self.trans)
print "\nDELETE PERSON"
self.db.remove_person( p.get_handle(), self.trans)
print "\nCREATE FAMILY"
f = RelLib.Family()
self.db.add_family( f, self.trans)
print "\nUPDATE FAMILY"
self.db.commit_family( f, self.trans)
print "\nDELETE FAMILY"
self.db.remove_family( f.get_handle(), self.trans)
print "\nCREATE EVENT"
e = RelLib.Event()
self.db.add_event( e, self.trans)
print "\nUPDATE EVENT"
self.db.commit_event( e, self.trans)
print "\nDELETE EVENT"
self.db.remove_event( e.get_handle(), self.trans)
print "\nCREATE PLACE"
p = RelLib.Place()
self.db.add_place( p, self.trans)
print "\nUPDATE PLACE"
self.db.commit_place( p, self.trans)
print "\nDELETE PLACE"
self.db.remove_place( p.get_handle(), self.trans)
print "\nCREATE SOURCE"
s = RelLib.Source()
self.db.add_source( s, self.trans)
print "\nUPDATE SOURCE"
self.db.commit_source( s, self.trans)
print "\nDELETE SOURCE"
self.db.remove_source( s.get_handle(), self.trans)
print "\nCREATE MEDIA"
m = RelLib.MediaObject()
self.db.add_object( m, self.trans)
print "\nUPDATE MEDIA"
self.db.commit_media_object( m, self.trans)
print "\nDELETE MEDIA"
self.db.remove_object( m.get_handle(), self.trans)
print "DONE."
print "TESTING DB..."
print "\nCREATE PERSON None"
self.db.add_person( None, self.trans)
print "\nUPDATE PERSON None"
self.db.commit_person( None, self.trans)
print "\nDELETE PERSON Invalid Handle"
self.db.remove_person( "Invalid Handle", self.trans)
print "\nCREATE FAMILY None"
self.db.add_family( None, self.trans)
print "\nUPDATE FAMILY None"
self.db.commit_family( None, self.trans)
print "\nDELETE FAMILY Invalid Handle"
self.db.remove_family( "Invalid Handle", self.trans)
print "\nCREATE EVENT None"
self.db.add_event( None, self.trans)
print "\nUPDATE EVENT None"
self.db.commit_event( None, self.trans)
print "\nDELETE EVENT Invalid Handle"
self.db.remove_event( "Invalid Handle", self.trans)
print "\nCREATE PLACE None"
self.db.add_place( None, self.trans)
print "\nUPDATE PLACE None"
self.db.commit_place( None, self.trans)
print "\nDELETE PLACE Invalid Handle"
self.db.remove_place( "Invalid Handle", self.trans)
print "\nCREATE SOURCE None"
self.db.add_source( None, self.trans)
print "\nUPDATE SOURCE None"
self.db.commit_source( None, self.trans)
print "\nDELETE SOURCE Invalid Handle"
self.db.remove_source( "Invalid Handle", self.trans)
print "\nCREATE MEDIA None"
self.db.add_object( None, self.trans)
print "\nUPDATE MEDIA None"
self.db.commit_media_object( None, self.trans)
print "\nDELETE MEDIA Invalid Handle"
self.db.remove_object( "Invalid Handle", self.trans)
print "DONE."
if generate_bugs:
self.generate_broken_relations()
if generate_dates:
self.generate_date_tests()
if generate_families:
self.persons_todo.append( self.generate_person(0))
@ -384,6 +499,103 @@ class TestcaseGenerator:
self.commit_transaction() # COMMIT TRANSACTION STEP
def generate_date_tests(self):
dates = []
# first some valid dates
calendar = Date.CAL_GREGORIAN
for quality in (Date.QUAL_NONE, Date.QUAL_ESTIMATED, Date.QUAL_CALCULATED):
for modifier in (Date.MOD_NONE, Date.MOD_BEFORE, Date.MOD_AFTER, Date.MOD_ABOUT):
for slash1 in (False,True):
d = Date.Date()
d.set(quality,modifier,calendar,(4,7,1789,slash1),"Text comment")
dates.append( d)
for modifier in (Date.MOD_RANGE, Date.MOD_SPAN):
for slash1 in (False,True):
for slash2 in (False,True):
d = Date.Date()
d.set(quality,modifier,calendar,(4,7,1789,slash1,5,8,1876,slash2),"Text comment")
dates.append( d)
modifier = Date.MOD_TEXTONLY
d = Date.Date()
d.set(quality,modifier,calendar,Date.EMPTY,"This is a textual date")
dates.append( d)
# test invalid dates
dateval = (4,7,1789,False,5,8,1876,False)
for l in range(1,len(dateval)):
d = Date.Date()
try:
d.set(Date.QUAL_NONE,Date.MOD_NONE,Date.CAL_GREGORIAN,dateval[:l],"Text comment")
dates.append( d)
except Errors.DateError, e:
d.set_as_text("Date identified value correctly as invalid.\n%s" % e)
dates.append( d)
except:
d = Date.Date()
d.set_as_text("Date.set Exception %s" % ("".join(traceback.format_exception(*sys.exc_info())),))
dates.append( d)
for l in range(1,len(dateval)):
d = Date.Date()
try:
d.set(Date.QUAL_NONE,Date.MOD_SPAN,Date.CAL_GREGORIAN,dateval[:l],"Text comment")
dates.append( d)
except Errors.DateError, e:
d.set_as_text("Date identified value correctly as invalid.\n%s" % e)
dates.append( d)
except:
d = Date.Date()
d.set_as_text("Date.set Exception %s" % ("".join(traceback.format_exception(*sys.exc_info())),))
dates.append( d)
d = Date.Date()
d.set(Date.QUAL_NONE,Date.MOD_NONE,Date.CAL_GREGORIAN,(44,7,1789,False),"Text comment")
dates.append( d)
d = Date.Date()
d.set(Date.QUAL_NONE,Date.MOD_NONE,Date.CAL_GREGORIAN,(4,77,1789,False),"Text comment")
dates.append( d)
d = Date.Date()
d.set(Date.QUAL_NONE,Date.MOD_SPAN,Date.CAL_GREGORIAN,(4,7,1789,False,55,8,1876,False),"Text comment")
dates.append( d)
d = Date.Date()
d.set(Date.QUAL_NONE,Date.MOD_SPAN,Date.CAL_GREGORIAN,(4,7,1789,False,5,88,1876,False),"Text comment")
dates.append( d)
# now add them as birth to new persons
for dateval in dates:
bevent = RelLib.Event()
bevent.set_name("Birth")
bevent.set_date_object(dateval)
bevent_h = self.db.add_event(bevent,self.trans)
# for the death event display the date as text and parse it back to a new date
ndate = None
try:
datestr = _dd.display( dateval)
try:
ndate = _dp.parse( datestr)
if not ndate:
ndate = Date.Date()
ndate.set_as_text("DateParser None")
except:
ndate = Date.Date()
ndate.set_as_text("DateParser Exception %s" % ("".join(traceback.format_exception(*sys.exc_info())),))
except:
ndate = Date.Date()
ndate.set_as_text("DateDisplay Exception: %s" % ("".join(traceback.format_exception(*sys.exc_info())),))
if dateval.get_modifier() != Date.MOD_TEXTONLY and ndate.get_modifier() == Date.MOD_TEXTONLY:
# parser was unable to correctly parse the string
ndate.set_as_text( "TEXTONLY: "+ndate.get_text())
devent = RelLib.Event()
devent.set_name("Death")
devent.set_date_object(ndate)
devent_h = self.db.add_event(devent,self.trans)
person_h = self.generate_person(None, "DateTest")
person = self.db.get_person_from_handle(person_h)
person.set_birth_handle(bevent_h)
person.set_death_handle(devent_h)
self.db.commit_person(person,self.trans)
self.commit_transaction() # COMMIT TRANSACTION STEP
def generate_person(self,gender=None,lastname=None,note=None):
self.progress.set_fraction(min(1.0,max(0.0, 1.0*self.person_count/self.max_person_count)))

View File

@ -294,7 +294,8 @@ class IndividualPage:
if self.photos and len(media_list) > 0:
object_handle = media_list[0].get_reference_handle()
object = self.db.get_object_from_handle(object_handle)
if object.get_mime_type()[0:5] == "image":
mime_type = object.get_mime_type()
if mime_type and mime_type.startswith("image"):
src = object.get_path()
junk,ext = os.path.splitext(src)
base = '%s%s' % (object.get_gramps_id(),ext)
@ -390,7 +391,8 @@ class IndividualPage:
for object_ref in self.person.get_media_list():
obj_id = object_ref.get_reference_handle()
obj = self.db.get_object_from_handle(obj_id)
if obj.get_mime_type()[0:5] != "image":
mime_type = obj.get_mime_type()
if not mime_type or not mime_type.startswith("image"):
continue
if object_ref.get_privacy():
continue

View File

@ -121,7 +121,8 @@ class PackageWriter:
root = os.path.basename(oldfile)
if os.path.isfile(oldfile):
self.copy_file(oldfile,'burn:///%s/%s' % (base,root))
if obj.get_mime_type()[0:5] == "image":
mime_type = obj.get_mime_type()
if mime_type and mime_type.startswith("image"):
self.make_thumbnail(base,root,obj.get_path())
else:
print "Warning: media file %s was not found," % root,\
@ -223,7 +224,7 @@ class PackageWriter:
if os.path.isfile(newfile):
self.copy_file(newfile,'burn:///%s/%s' % (base,obase))
ntype = GrampsMime.get_type(newfile)
if ntype[0:5] == "image":
if ntype and ntype.startswith("image"):
self.make_thumbnail(base,obase,newfile)
fs_top = gtk.FileSelection("%s - GRAMPS" % _("Select file"))
@ -244,7 +245,8 @@ class PackageWriter:
root = os.path.basename(oldfile)
if os.path.isfile(oldfile):
self.copy_file(oldfile,'burn:///%s/%s' % (base,root))
if obj.get_mime_type()[0:5] == "image":
mime_type = obj.get_mime_type()
if mime_type and mime_type.startswith("image"):
self.make_thumbnail(base,root,obj.get_path())
else:
# File is lost => ask what to do

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

File diff suppressed because it is too large Load Diff