Merged geps21 branch, changes r15866-16034, into trunk

svn: r16035
This commit is contained in:
Benny Malengier 2010-10-24 14:43:47 +00:00
commit e109e3d743
48 changed files with 3589 additions and 1548 deletions

View File

@ -59,6 +59,7 @@ DATABASE
bookmarks?, namemaps?)>
<!ATTLIST database xmlns CDATA #FIXED "http://gramps-project.org/xml/1.4.0/">
<!-- ************************************************************
HEADER
@ -98,7 +99,7 @@ PEOPLE
home IDREF #IMPLIED
>
<!ELEMENT person (gender, name*, nick?, eventref*, lds_ord*,
<!ELEMENT person (gender, name*, eventref*, lds_ord*,
objref*, address*, attribute*, url*, childof*,
parentin*, personref*, noteref*, sourceref*, tagref*)>
<!ATTLIST person
@ -114,7 +115,7 @@ GENDER has values of M, F, or U.
-->
<!ELEMENT gender (#PCDATA)>
<!ELEMENT name (first?, call?, last?, suffix?, patronymic?, title?,
<!ELEMENT name (first?, call?, surname*, nick?, familynick?, suffix?, title?, group?
(daterange|datespan|dateval|datestr)?, noteref*, sourceref*)>
<!ATTLIST name
alt (0|1) #IMPLIED
@ -126,16 +127,18 @@ GENDER has values of M, F, or U.
<!ELEMENT first (#PCDATA)>
<!ELEMENT call (#PCDATA)>
<!ELEMENT last (#PCDATA)>
<!ATTLIST last
prefix CDATA #IMPLIED
group CDATA #IMPLIED
>
<!ELEMENT suffix (#PCDATA)>
<!ELEMENT patronymic (#PCDATA)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT nick (#PCDATA)>
<!ELEMENT familynick (#PCDATA)>
<!ELEMENT group (#PCDATA)>
<!ELEMENT surname (#PCDATA)>
<!ATTLIST surname
prefix CDATA #IMPLIED
primary (1|0) #IMPLIED
derivation CDATA #IMPLIED
connector CDATA #IMPLIED
>
<!ELEMENT childof EMPTY>
<!ATTLIST childof hlink IDREF #REQUIRED

View File

@ -161,7 +161,6 @@
<zeroOrMore><element name="name">
<ref name="name-content"/>
</element></zeroOrMore>
<optional><element name="nick"><text/></element></optional>
<zeroOrMore><element name="eventref">
<ref name="eventref-content"/>
</element></zeroOrMore>
@ -235,13 +234,13 @@
<optional><attribute name="display"><text/></attribute></optional>
<optional><element name="first"><text/></element></optional>
<optional><element name="call"><text/></element></optional>
<optional><element name="last">
<text/>
<optional><attribute name="prefix"><text/></attribute></optional>
<optional><attribute name="group"><text/></attribute></optional>
</element></optional>
<optional><element name="nick"><text/></element></optional>
<optional><element name="familynick"><text/></element></optional>
<optional><element name="group"><text/></element></optional>
<zeroOrMore><element name="surname">
<ref name="surname-content"/>
</element></zeroOrMore>
<optional><element name="suffix"><text/></element></optional>
<optional><element name="patronymic"><text/></element></optional>
<optional><element name="title"><text/></element></optional>
<optional><ref name="date-content"/></optional>
<zeroOrMore><element name="noteref">
@ -252,6 +251,24 @@
</element></zeroOrMore>
</define>
<define name="surname-content">
<element name="surname">
<text/>
<optional><attribute name="prefix"><text/></attribute></optional>
<optional><attribute name="primary"><choice>
<value>1</value>
<value>0</value>
</choice></attribute></optional>
<optional><attribute name="derivation"><choice>
<value>inherited</value>
<value>patronymic</value>
<value>matronymic</value>
<value>other</value>
</choice></attribute></optional>
<optional><attribute name="connector"><text/></attribute></optional>
</element>
</define>
<define name="address-content">
<optional><attribute name="priv">
<ref name="priv-content"/>

View File

@ -110,12 +110,15 @@ src/gen/lib/eventref.py
src/gen/lib/privsrcnote.py
src/gen/lib/placebase.py
src/gen/lib/name.py
src/gen/lib/nametype.py
src/gen/lib/nameorigintype.py
src/gen/lib/addressbase.py
src/gen/lib/family.py
src/gen/lib/event.py
src/gen/lib/nametype.py
src/gen/lib/secondaryobj.py
src/gen/lib/srcbase.py
src/gen/lib/surname.py
src/gen/lib/surnamebase.py
src/gen/lib/eventtype.py
src/gen/lib/researcher.py
src/gen/lib/familyreltype.py
@ -270,6 +273,8 @@ src/gui/editors/displaytabs/reporefmodel.py
src/gui/editors/displaytabs/sourcebackreflist.py
src/gui/editors/displaytabs/sourceembedlist.py
src/gui/editors/displaytabs/sourcerefmodel.py
src/gui/editors/displaytabs/surnametab.py
src/gui/editors/displaytabs/surnamemodel.py
src/gui/editors/displaytabs/webembedlist.py
src/gui/editors/displaytabs/webmodel.py
src/gui/editors/displaytabs/__init__.py

View File

@ -133,6 +133,7 @@ class _DdTargets(object):
self.SOURCEREF = _DdType(self, 'srcref')
self.SOURCE_LINK = _DdType(self, 'source-link')
self.URL = _DdType(self, 'url')
self.SURNAME = _DdType(self, 'surname')
# List of all types that are used between
# gramps widgets but should not be exported
@ -159,6 +160,7 @@ class _DdTargets(object):
self.SOURCEREF,
self.SOURCE_LINK,
self.URL,
self.SURNAME
]
self.CHILD = _DdType(self, 'child')

View File

@ -34,6 +34,7 @@ from gen.ggettext import sgettext as _
#
#-------------------------------------------------------------------------
from Filters.Rules._Rule import Rule
from gen.lib import NameOriginType
#-------------------------------------------------------------------------
#
@ -43,41 +44,76 @@ from Filters.Rules._Rule import Rule
class HasNameOf(Rule):
"""Rule that checks for full or partial name matches"""
labels = [ _('Given name:'),
_('Family name:'),
_('Suffix:'),
labels = [ _('Given name:'),
_('Full Family name:'),
_('person|Title:'),
_('Suffix:'),
_('Call Name:'),
_('Nick Name:'),
_('Prefix:'),
_('Single Surname:'),
_('Connector'),
_('Patronymic:'),
_('Call Name:'),]
_('Family Nick Name:')]
name = _('People with the <name>')
description = _("Matches people with a specified (partial) name")
category = _('General filters')
def apply(self,db,person):
self.firstn = self.list[0]
self.lastn = self.list[1]
self.surn = self.list[2]
self.title = self.list[3]
self.prefix = self.list[4]
self.patr = self.list[5]
self.calln = self.list[6]
def prepare(self, db):
self.firstn = self.list[0].upper()
self.lastn = self.list[1].upper()
self.title = self.list[2].upper()
self.suffix = self.list[3].upper()
self.calln = self.list[4].upper()
self.nick = self.list[5].upper()
self.famnick = self.list[10].upper()
#surname parts
self.prefix = self.list[6].upper()
self.surn = self.list[7].upper()
self.con = self.list[8].upper()
self.patr = self.list[9].upper()
def apply(self, db, person):
for name in [person.get_primary_name()] + person.get_alternate_names():
val = 1
if self.firstn and name.get_first_name().upper().find(self.firstn.upper()) == -1:
valpref = 0
if not self.prefix:
valpref = 1
valsurn = 0
if not self.surn:
valsurn = 1
valcon = 0
if not self.con:
valcon = 1
valpatr = 0
if not self.patr:
valpatr = 1
if self.firstn and name.get_first_name().upper().find(self.firstn) == -1:
val = 0
if self.lastn and name.get_surname().upper().find(self.lastn.upper()) == -1:
elif self.lastn and name.get_surname().upper().find(self.lastn) == -1:
val = 0
if self.surn and name.get_suffix().upper().find(self.surn.upper()) == -1:
elif self.suffix and name.get_suffix().upper().find(self.surn) == -1:
val = 0
if self.title and name.get_title().upper().find(self.title.upper()) == -1:
elif self.title and name.get_title().upper().find(self.title) == -1:
val = 0
if self.prefix and name.get_prefix().upper().find(self.prefix.upper()) == -1:
elif self.calln and name.get_call_name().upper().find(self.calln) == -1:
val = 0
if self.patr and name.get_patronymic().upper().find(self.patr.upper()) == -1:
elif self.nick and name.get_nick_name().upper().find(self.nick) == -1:
val = 0
if self.calln and name.get_call_name().upper().find(self.calln.upper()) == -1:
elif self.famnick and name.get_family_nick_name().upper().find(self.famnick) == -1:
val = 0
if val == 1:
else:
#obtain surnames
for surn in name.get_surname_list():
if self.prefix and surn.get_prefix().upper().find(self.prefix) != -1:
valpref = 1
if self.surn and surn.get_surname().upper().find(self.surn) != -1:
valsurn = 1
if self.con and surn.get_connector().upper().find(self.con) != -1:
valcon = 1
if self.patr and surn.get_origintype().value == NameOriginType.PATRONYMIC \
and surn.get_surname().upper().find(self.patr) != -1:
valpatr = 1
if val == 1 and valpref == 1 and valsurn == 1 and valcon == 1 and valpatr ==1:
return True
return False

View File

@ -48,8 +48,9 @@ class IncompleteNames(Rule):
def apply(self,db,person):
for name in [person.get_primary_name()] + person.get_alternate_names():
if name.get_first_name() == "":
return True
if name.get_surname() == "":
if name.get_first_name().strip() == "":
return True
for surn in name.get_surname_list():
if surn.get_surname().strip() == "":
return True
return False

View File

@ -59,8 +59,8 @@ class RegExpName(Rule):
def apply(self,db,person):
for name in [person.get_primary_name()] + person.get_alternate_names():
for field in [name.first_name, name.surname, name.suffix, name.title,
name.prefix, name.patronymic, name.call]:
for field in [name.first_name, name.get_surname(), name.suffix,
name.title, name.nick, name.famnick, name.call]:
if self.match.match(field):
return True
else:

View File

@ -49,12 +49,13 @@ class SearchName(Rule):
category = _('General filters')
def apply(self, db, person):
src = self.list[0].upper()
if not src:
return False
for name in [person.get_primary_name()] + person.get_alternate_names():
for field in [name.first_name, name.surname, name.suffix, name.title,
name.prefix, name.patronymic, name.call]:
for field in [name.first_name, name.get_surname(), name.suffix,
name.title, name.nick, name.famnick, name.call]:
if src and field.upper().find(src) != -1:
return True
else:

View File

@ -507,6 +507,19 @@ class ScratchName(ScratchObjWrapper):
self._title = str(self._obj.get_type())
self._value = self._obj.get_name()
class ScratchSurname(ScratchObjWrapper):
DROP_TARGETS = [DdTargets.SURNAME]
DRAG_TARGET = DdTargets.SURNAME
ICON = ICONS['name']
def __init__(self, dbstate, obj):
super(ScratchSurname, self).__init__(dbstate, obj)
self._type = _("Surname")
if self._obj:
self._title = self._obj.get_surname()
self._value = self._obj.get_surname()
class ScratchText(ScratchWrapper):
DROP_TARGETS = DdTargets.all_text()

View File

@ -1139,13 +1139,18 @@ def profile(func, *args):
# keyword, code, translated standard, translated upper
KEYWORDS = [("title", "t", _("Person|Title"), _("Person|TITLE")),
("given", "f", _("Given"), _("GIVEN")),
("prefix", "p", _("Prefix"), _("PREFIX")),
("surname", "l", _("Surname"), _("SURNAME")),
("surname", "l", _("Surname"), _("SURNAME")),
("call", "c", _("Name|Call"), _("Name|CALL")),
("common", "x", _("Name|Common"), _("Name|COMMON")),
("initials", "i", _("Initials"), _("INITIALS")),
("suffix", "s", _("Suffix"), _("SUFFIX")),
("patronymic","y", _("Patronymic"),_("PATRONYMIC")),
("call", "c", _("Call"), _("CALL")),
("common", "x", _("Common"), _("COMMON")),
("initials", "i", _("Initials"), _("INITIALS"))
("rawsurnames", "q", _("Rawsurnames"), _("RAWSURNAMES")),
("patronymic", "y", _("Patronymic"), _("PATRONYMIC")),
("notpatronymic", "o", _("Notpatronymic"),_("NOTPATRONYMIC")),
("primary", "m", _("Primary"), _("PRIMARY")),
("prefix", "p", _("Prefix"), _("PREFIX")),
("nickname", "n", _("Nickname"), _("NICKNAME")),
("familynick", "g", _("Familynick"), _("FAMILYNICK")),
]
KEY_TO_TRANS = {}
TRANS_TO_KEY = {}

View File

@ -211,7 +211,6 @@ register('interface.note-height', 500)
register('interface.note-sel-height', 450)
register('interface.note-sel-width', 600)
register('interface.note-width', 700)
register('interface.patro-title', 0)
register('interface.pedview-layout', 0)
register('interface.pedview-show-images', True)
register('interface.pedview-show-marriage', False)
@ -228,7 +227,6 @@ register('interface.place-height', 450)
register('interface.place-sel-height', 450)
register('interface.place-sel-width', 600)
register('interface.place-width', 650)
register('interface.prefix-suffix', 0)
register('interface.repo-height', 450)
register('interface.repo-ref-height', 450)
register('interface.repo-ref-width', 600)

View File

@ -356,6 +356,13 @@ class DbReadBase(object):
"""
raise NotImplementedError
def get_origin_types(self):
"""
Return a list of all custom origin types associated with Person/Surname
instances in the database.
"""
raise NotImplementedError
def get_note_bookmarks(self):
"""
Return the list of Note handles in the bookmarks.

View File

@ -47,7 +47,8 @@ import logging
#
#-------------------------------------------------------------------------
from gen.lib import (MediaObject, Person, Family, Source, Event, Place,
Repository, Note, Tag, GenderStats, Researcher)
Repository, Note, Tag, GenderStats, Researcher,
NameOriginType)
from gen.db.dbconst import *
from gen.utils.callback import Callback
from gen.db import (BsddbBaseCursor, DbReadBase)
@ -68,6 +69,41 @@ _SIGBASE = ('person', 'family', 'source', 'event',
DBERRS = (db.DBRunRecoveryError, db.DBAccessError,
db.DBPageNotFoundError, db.DBInvalidArgError)
#-------------------------------------------------------------------------
#
# Helper functions
#
#-------------------------------------------------------------------------
def find_surname(key, data):
"""
Creating a surname from raw data of a person, to use for sort and index
"""
return __index_surname(data[3][5])
def find_surname_name(key, data):
"""
Creating a surname from raw name, to use for sort and index
"""
return __index_surname(data[5])
def __index_surname(surn_list):
"""
All non pa/matronymic surnames are used in indexing.
pa/matronymic not as they change for every generation!
"""
if surn_list:
surn = " ".join([x[0] for x in surn_list if not (x[3][0] in [
NameOriginType.PATRONYMIC, NameOriginType.MATRONYMIC]) ])
else:
surn = ""
return str(surn)
#-------------------------------------------------------------------------
#
# class DbBookmarks
#
#-------------------------------------------------------------------------
class DbBookmarks(object):
def __init__(self, default=[]):
self.bookmarks = list(default) # want a copy (not an alias)
@ -269,6 +305,7 @@ class DbBsddbRead(DbReadBase, Callback):
self.family_rel_types = set()
self.event_role_names = set()
self.name_types = set()
self.origin_types = set()
self.repository_types = set()
self.note_types = set()
self.source_media_types = set()
@ -1252,6 +1289,13 @@ class DbBsddbRead(DbReadBase, Callback):
"""
return list(self.name_types)
def get_origin_types(self):
"""
Return a list of all custom origin types assocated with Person/Surname
instances in the database.
"""
return list(self.origin_types)
def get_repository_types(self):
"""
Return a list of all custom repository types assocated with Repository
@ -1385,7 +1429,8 @@ class DbBsddbRead(DbReadBase, Callback):
return self.__has_handle(self.tag_map, handle)
def __sortbyperson_key(self, person):
return locale.strxfrm(self.person_map.get(str(person))[3][5])
return locale.strxfrm(find_surname(str(person),
self.person_map.get(str(person))))
def __sortbyplace(self, first, second):
return locale.strcoll(self.place_map.get(str(first))[2],

View File

@ -21,22 +21,29 @@
# $Id$
from __future__ import with_statement
from gen.db import BSDDBTxn
from gen.lib.markertype import MarkerType
from gen.lib.tag import Tag
import time
"""
upgrade
methods to upgrade a database from version 13 to current version
"""
from bsddb import db
from gen.db import BSDDBTxn
from gen.lib.nameorigintype import NameOriginType
from gen.db.write import _mkname, SURNAMES
def gramps_upgrade_15(self):
"""Upgrade database from version 14 to 15."""
# This upgrade adds tagging
"""Upgrade database from version 14 to 15. This upgrade adds:
* tagging
* surname list
* remove marker
"""
length = (len(self.note_map) + len(self.person_map) +
len(self.event_map) + len(self.family_map) +
len(self.repository_map) + len(self.media_map) +
len(self.place_map) + len(self.source_map))
len(self.place_map) + len(self.source_map)) + 10
self.set_total(length)
self.tags = {}
@ -46,16 +53,70 @@ def gramps_upgrade_15(self):
# Replace the old marker field with the new tag list field.
for handle in self.person_map.keys():
person = self.person_map[handle]
new_person = list(person)
tag_handle = convert_marker(self, new_person[18])
(junk_handle, # 0
gramps_id, # 1
gender, # 2
primary_name, # 3
alternate_names, # 4
death_ref_index, # 5
birth_ref_index, # 6
event_ref_list, # 7
family_list, # 8
parent_family_list, # 9
media_list, # 10
address_list, # 11
attribute_list, # 12
urls, # 13
ord_list, # 14
psource_list, # 15
pnote_list, # 16
change, # 17
marker, # 18
pprivate, # 19
person_ref_list, # 20
) = person
tag_handle = convert_marker(self, marker)
if tag_handle:
new_person[18] = [tag_handle]
tags = [tag_handle]
else:
new_person[18] = []
new_person = tuple(new_person)
tags = []
new_primary_name = convert_name_15(primary_name)
new_alternate_names = [convert_name_15(altname) for altname in
alternate_names]
new_person = (junk_handle, # 0
gramps_id, # 1
gender, # 2
new_primary_name, # 3
new_alternate_names,# 4
death_ref_index, # 5
birth_ref_index, # 6
event_ref_list, # 7
family_list, # 8
parent_family_list, # 9
media_list, # 10
address_list, # 11
attribute_list, # 12
urls, # 13
ord_list, # 14
psource_list, # 15
pnote_list, # 16
change, # 17
tags, # 18
pprivate, # 19
person_ref_list # 20
)
with BSDDBTxn(self.env, self.person_map) as txn:
txn.put(str(handle), new_person)
self.update()
self.update(length)
#surname is now different, remove secondary index with names
_db = db.DB(self.env)
try:
_db.remove(_mkname(self.full_name, SURNAMES), SURNAMES)
except db.DBNoSuchFileError:
pass
# ---------------------------------
# Modify Family
@ -182,6 +243,33 @@ def convert_marker(self, marker_field):
else:
return None
def convert_name_15(name):
(privacy, source_list, note_list, date,
first_name, surname, suffix, title,
name_type, prefix, patronymic,
group_as, sort_as, display_as, call) = name
connector = u""
origintype = (NameOriginType.NONE, u"")
patorigintype = (NameOriginType.PATRONYMIC, u"")
if patronymic.strip() == u"":
#no patronymic, create a single surname
surname_list = [(surname, prefix, True, origintype, connector)]
else:
#a patronymic, if no surname or equal as patronymic, a single surname
if (surname.strip() == u"") or (surname == patronymic and prefix == u""):
surname_list = [(patronymic, prefix, True, patorigintype, connector)]
else:
#two surnames, first patronymic, then surname which is primary
surname_list = [(patronymic, u"", False, patorigintype, u""),
(surname, prefix, True, origintype, connector)]
#return new value, add two empty strings for nick and family nick
return (privacy, source_list, note_list, date,
first_name, surname_list, suffix, title, name_type,
group_as, sort_as, display_as, call, u"", u"")
def gramps_upgrade_14(self):
"""Upgrade database from version 13 to 14."""
# This upgrade modifies notes and dates

View File

@ -53,7 +53,7 @@ from gen.lib import (GenderStats, Person, Family, Event, Place, Source,
MediaObject, Repository, Note, Tag)
from gen.db import (DbBsddbRead, DbWriteBase, BSDDBTxn,
DbTxn, BsddbBaseCursor, DbVersionError,
DbUpgradeRequiredError,
DbUpgradeRequiredError, find_surname, find_surname_name,
DbUndoBSDDB as DbUndo)
from gen.db.dbconst import *
from gen.utils.callback import Callback
@ -125,10 +125,7 @@ KEY_TO_CLASS_MAP = {PERSON_KEY: Person.__name__,
#
# Helper functions
#
#-------------------------------------------------------------------------
def find_surname(key, data):
return str(data[3][5])
#-------------------------------------------------------------------------
def find_idmap(key, data):
return str(data[1])
@ -557,6 +554,7 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
self.family_rel_types = set(meta('family_rels'))
self.event_role_names = set(meta('event_roles'))
self.name_types = set(meta('name_types'))
self.origin_types = set(meta('origin_types'))
self.repository_types = set(meta('repo_types'))
self.note_types = set(meta('note_types'))
self.source_media_types = set(meta('sm_types'))
@ -986,6 +984,7 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
txn.put('family_rels', list(self.family_rel_types))
txn.put('event_roles', list(self.event_role_names))
txn.put('name_types', list(self.name_types))
txn.put('origin_types', list(self.origin_types))
txn.put('repo_types', list(self.repository_types))
txn.put('note_types', list(self.note_types))
txn.put('sm_types', list(self.source_media_types))
@ -1316,7 +1315,8 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
"""
Build surname list for use in autocompletion
"""
self.surname_list = sorted(map(unicode, set(self.surnames.keys())), key=locale.strxfrm)
self.surname_list = sorted(map(unicode, set(self.surnames.keys())),
key=locale.strxfrm)
def add_to_surname_list(self, person, batch_transaction):
"""
@ -1324,7 +1324,8 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
"""
if batch_transaction:
return
name = unicode(person.get_primary_name().get_surname())
name = unicode(find_surname_name(person.handle,
person.get_primary_name().serialize()))
i = bisect.bisect(self.surname_list, name)
if 0 < i <= len(self.surname_list):
if self.surname_list[i-1] != name:
@ -1341,7 +1342,8 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
If not then we need to remove the name from the list.
The function must be overridden in the derived class.
"""
name = str(person.get_primary_name().get_surname())
name = str(find_surname_name(person.handle,
person.get_primary_name().serialize()))
try:
cursor = self.surnames.cursor(txn=self.txn)
cursor.set(name)
@ -1401,7 +1403,10 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
self.genderStats.count_person(person)
# Update surname list if necessary
if (old_person.primary_name.surname !=person.primary_name.surname):
if (find_surname_name(old_person.handle,
old_person.primary_name.serialize()) !=
find_surname_name(person.handle,
person.primary_name.serialize())):
self.remove_from_surname_list(old_person)
self.add_to_surname_list(person, transaction.batch)
else:
@ -1420,7 +1425,13 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback):
for name in ([person.primary_name]
+ person.alternate_names)
if name.type.is_custom()])
all_surn = person.primary_name.get_surname_list()
for asurname in person.alternate_names:
all_surn += asurname.get_surname_list()
self.origin_types.update([str(surn.origintype) for surn in all_surn
if surn.origintype.is_custom()])
self.url_types.update([str(url.type) for url in person.urls
if url.type.is_custom()])

View File

@ -23,6 +23,22 @@
"""
Class handling language-specific displaying of names.
Specific symbols for parts of a name are defined:
't' : title
'f' : given (first names)
'l' : full surname (lastname)
'c' : callname
'x' : callname if existing, otherwise first first name (common name)
'i' : initials of the first names
'y' : patronymic surname (father)
'o' : surnames without patronymic
'm' : primary surname (main)
'p' : list of all prefixes
'q' : surnames without prefixes and connectors
's' : suffix
'n' : nick name
'g' : family nick name
"""
#-------------------------------------------------------------------------
@ -38,7 +54,7 @@ import re
# GRAMPS modules
#
#-------------------------------------------------------------------------
from gen.lib import Name
from gen.lib import Name, NameOriginType
try:
import config
@ -52,17 +68,23 @@ except ImportError:
# Constants
#
#-------------------------------------------------------------------------
_FIRSTNAME = 4
_SURNAME = 5
_SUFFIX = 6
_TITLE = 7
_TYPE = 8
_PREFIX = 9
_PATRONYM = 10
_GROUP = 11
_SORT = 12
_DISPLAY = 13
_CALL = 14
_FIRSTNAME = 4
_SURNAME_LIST = 5
_SUFFIX = 6
_TITLE = 7
_TYPE = 8
_GROUP = 9
_SORT = 10
_DISPLAY = 11
_CALL = 12
_NICK = 13
_FAMNICK = 14
_SURNAME_IN_LIST = 0
_PREFIX_IN_LIST = 1
_PRIMARY_IN_LIST = 2
_TYPE_IN_LIST = 3
_CONNECTOR_IN_LIST = 4
_ORIGINPATRO = NameOriginType.PATRONYMIC
_ACT = True
_INA = False
@ -79,7 +101,11 @@ _F_RAWFN = 4 # name format raw function
#
#-------------------------------------------------------------------------
# Because of occurring in an exec(), this couldn't be in a lambda:
def _make_cmp(a, b): return -cmp(a[1], b[1])
# we sort names first on longest first, then last letter first, this to
# avoid translations of shorter terms which appear in longer ones, eg
# namelast may not be mistaken with name, so namelast must first be
# converted to %k before name is converted.
def _make_cmp(a, b): return -cmp((len(a[1]),a[1]), (len(b[1]), b[1]))
#-------------------------------------------------------------------------
#
@ -97,6 +123,63 @@ class NameDisplayError(Exception):
def __str__(self):
return self.value
#-------------------------------------------------------------------------
#
# Functions to extract data from raw lists (unserialized objects)
#
#-------------------------------------------------------------------------
def _raw_full_surname(raw_surn_data_list):
"""method for the 'l' symbol: full surnames"""
result = ""
for raw_surn_data in raw_surn_data_list:
result += "%s %s %s " % (raw_surn_data[_PREFIX_IN_LIST],
raw_surn_data[_SURNAME_IN_LIST],
raw_surn_data[_CONNECTOR_IN_LIST])
return ' '.join(result.split()).strip()
def _raw_primary_surname(raw_surn_data_list):
"""method for the 'm' symbol: primary surname"""
for raw_surn_data in raw_surn_data_list:
if raw_surn_data[_PRIMARY_IN_LIST]:
result = "%s %s" % (raw_surn_data[_PREFIX_IN_LIST],
raw_surn_data[_SURNAME_IN_LIST])
return ' '.join(result.split())
return ''
def _raw_patro_surname(raw_surn_data_list):
"""method for the 'y' symbol: patronymic surname"""
for raw_surn_data in raw_surn_data_list:
if raw_surn_data[_TYPE_IN_LIST][0] == _ORIGINPATRO:
result = "%s %s" % (raw_surn_data[_PREFIX_IN_LIST],
raw_surn_data[_SURNAME_IN_LIST])
return ' '.join(result.split())
return ''
def _raw_nonpatro_surname(raw_surn_data_list):
"""method for the 'o' symbol: full surnames without patronymic"""
result = ""
for raw_surn_data in raw_surn_data_list:
if raw_surn_data[_TYPE_IN_LIST][0] != _ORIGINPATRO:
result += "%s %s %s " % (raw_surn_data[_PREFIX_IN_LIST],
raw_surn_data[_SURNAME_IN_LIST],
raw_surn_data[_CONNECTOR_IN_LIST])
return ' '.join(result.split()).strip()
def _raw_prefix_surname(raw_surn_data_list):
"""method for the 'p' symbol: all prefixes"""
result = ""
for raw_surn_data in raw_surn_data_list:
result += "%s " % (raw_surn_data[_PREFIX_IN_LIST])
return ' '.join(result.split()).strip()
def _raw_single_surname(raw_surn_data_list):
"""method for the 'q' symbol: surnames without prefix and connectors"""
result = ""
for raw_surn_data in raw_surn_data_list:
result += "%s " % (raw_surn_data[_SURNAME_IN_LIST])
return ' '.join(result.split()).strip()
#-------------------------------------------------------------------------
#
# NameDisplay class
@ -112,10 +195,11 @@ class NameDisplay(object):
STANDARD_FORMATS = [
(Name.DEF,_("Default format (defined by Gramps preferences)"),'',_ACT),
(Name.LNFN,_("Surname, Given Patronymic"),'%p %l, %f %y %s',_ACT),
(Name.FNLN,_("Given Surname"),'%f %y %p %l %s',_ACT),
(Name.PTFN,_("Patronymic, Given"),'%p %y, %s %f',_ACT),
(Name.FN,_("Given"),'%f',_ACT)
(Name.LNFN,_("Surname, Given"),'%l, %f %s',_ACT),
(Name.FN,_("Given"),'%f',_ACT),
(Name.FNLN,_("Given Surname"),'%f %l %s',_ACT),
# DEPRECATED FORMATS
(Name.PTFN,_("Patronymic, Given"),'%y, %s %f',_INA),
]
def __init__(self):
@ -125,11 +209,12 @@ class NameDisplay(object):
if WITH_GRAMPS_CONFIG:
self.default_format = config.get('preferences.name-format')
if self.default_format == 0:
if self.default_format == 0 \
or self.default_format not in Name.NAMEFORMATS :
self.default_format = Name.LNFN
config.set('preferences.name-format', self.default_format)
else:
self.default_format = 1
self.default_format = Name.LNFN
self.set_default_format(self.default_format)
@ -138,28 +223,17 @@ class NameDisplay(object):
def _format_raw_fn(self, fmt_str):
return lambda x: self.format_str_raw(x, fmt_str)
def _raw_lnfn(self, raw_data):
result = "%s %s, %s %s %s" % (raw_data[_PREFIX],
raw_data[_SURNAME],
raw_data[_FIRSTNAME],
raw_data[_PATRONYM],
raw_data[_SUFFIX])
result = "%s, %s %s" % (_raw_full_surname(raw_data[_SURNAME_LIST]),
raw_data[_FIRSTNAME],
raw_data[_SUFFIX])
return ' '.join(result.split())
def _raw_fnln(self, raw_data):
result = "%s %s %s %s %s" % (raw_data[_FIRSTNAME],
raw_data[_PATRONYM],
raw_data[_PREFIX],
raw_data[_SURNAME],
raw_data[_SUFFIX])
return ' '.join(result.split())
def _raw_ptfn(self, raw_data):
result = "%s %s, %s %s" % (raw_data[_PREFIX],
raw_data[_PATRONYM],
raw_data[_SUFFIX],
raw_data[_FIRSTNAME])
result = "%s %s %s" % (raw_data[_FIRSTNAME],
_raw_full_surname(raw_data[_SURNAME_LIST]),
raw_data[_SUFFIX])
return ' '.join(result.split())
def _raw_fn(self, raw_data):
@ -170,7 +244,6 @@ class NameDisplay(object):
raw_func_dict = {
Name.LNFN : self._raw_lnfn,
Name.FNLN : self._raw_fnln,
Name.PTFN : self._raw_ptfn,
Name.FN : self._raw_fn,
}
@ -279,31 +352,65 @@ class NameDisplay(object):
The new function is of the form:
def fn(raw_data):
return "%s %s %s %s %s" % (raw_data[_TITLE],
return "%s %s %s" % (raw_data[_TITLE],
raw_data[_FIRSTNAME],
raw_data[_PREFIX],
raw_data[_SURNAME],
raw_data[_SUFFIX])
Specific symbols for parts of a name are defined (keywords given):
't' : title = title
'f' : given = given (first names)
'l' : surname = full surname (lastname)
'c' : call = callname
'x' : common = callname if existing, otherwise first first name (common name)
'i' : initials = initials of the first names
'y' : patronymic = patronymic surname (father)
'o' : notpatronymic = surnames without patronymic
'm' : primary = primary surname (main)
'p' : prefix = list of all prefixes
'q' : rawsurnames = surnames without prefixes and connectors
's' : suffix = suffix
'n' : nickname = nick name
'g' : familynick = family nick name
"""
# we need the names of each of the variables or methods that are
# called to fill in each format flag.
# Dictionary is "code": ("expression", "keyword", "i18n-keyword")
d = {"t": ("raw_data[_TITLE]", "title", _("Person|title")),
"f": ("raw_data[_FIRSTNAME]", "given", _("given")),
"p": ("raw_data[_PREFIX]", "prefix", _("prefix")),
"l": ("raw_data[_SURNAME]", "surname", _("surname")),
"s": ("raw_data[_SUFFIX]", "suffix", _("suffix")),
"y": ("raw_data[_PATRONYM]", "patronymic", _("patronymic")),
"c": ("raw_data[_CALL]", "call", _("call")),
d = {"t": ("raw_data[_TITLE]", "title",
_("Person|title")),
"f": ("raw_data[_FIRSTNAME]", "given",
_("given")),
"l": ("_raw_full_surname(raw_data[_SURNAME_LIST])", "surname",
_("surname")),
"s": ("raw_data[_SUFFIX]", "suffix",
_("suffix")),
"c": ("raw_data[_CALL]", "call",
_("Name|call")),
"x": ("(raw_data[_CALL] or raw_data[_FIRSTNAME].split(' ')[0])",
"common",
_("common")),
"common",
_("Name|common")),
"i": ("''.join([word[0] +'.' for word in ('. ' +" +
" raw_data[_FIRSTNAME]).split()][1:])",
"initials",
_("initials"))
"initials",
_("initials")),
"y": ("_raw_patro_surname(raw_data[_SURNAME_LIST])", "patronymic",
_("patronymic")),
"o": ("_raw_nonpatro_surname(raw_data[_SURNAME_LIST])", "notpatronymic",
_("notpatronymic")),
"m": ("_raw_primary_surname(raw_data[_SURNAME_LIST])",
"primary",
_("Name|primary")),
"p": ("_raw_prefix_surname(raw_data[_SURNAME_LIST])",
"prefix",
_("prefix")),
"q": ("_raw_single_surname(raw_data[_SURNAME_LIST])",
"rawsurnames",
_("rawsurnames")),
"n": ("raw_data[_NICK]", "nickname",
_("nickname")),
"g": ("raw_data[_FAMNICK]", "familynick",
_("familynick")),
}
args = "raw_data"
return self._make_fn(format_str, d, args)
@ -321,26 +428,61 @@ class NameDisplay(object):
The new function is of the form:
def fn(first,surname,prefix,suffix,patronymic,title,call,):
return "%s %s %s %s %s" % (first,surname,prefix,suffix,patronymic)
def fn(first, raw_surname_list, suffix, title, call,):
return "%s %s" % (first,suffix)
Specific symbols for parts of a name are defined (keywords given):
't' : title = title
'f' : given = given (first names)
'l' : surname = full surname (lastname)
'c' : call = callname
'x' : common = callname if existing, otherwise first first name (common name)
'i' : initials = initials of the first names
'y' : patronymic = patronymic surname (father)
'o' : notpatronymic = surnames without patronymic
'm' : primary = primary surname (main)
'p' : prefix = list of all prefixes
'q' : rawsurnames = surnames without prefixes and connectors
's' : suffix = suffix
'n' : nickname = nick name
'g' : familynick = family nick name
"""
# we need the names of each of the variables or methods that are
# called to fill in each format flag.
# Dictionary is "code": ("expression", "keyword", "i18n-keyword")
d = {"t": ("title", "title", _("Person|title")),
"f": ("first", "given", _("given")),
"p": ("prefix", "prefix", _("prefix")),
"l": ("surname", "surname", _("surname")),
"s": ("suffix", "suffix", _("suffix")),
"y": ("patronymic", "patronymic", _("patronymic")),
"c": ("call", "call", _("call")),
"x": ("(call or first.split(' ')[0])", "common", _("common")),
d = {"t": ("title", "title",
_("Person|title")),
"f": ("first", "given",
_("given")),
"l": ("_raw_full_surname(raw_surname_list)", "surname",
_("surname")),
"s": ("suffix", "suffix",
_("suffix")),
"c": ("call", "call",
_("Name|call")),
"x": ("(call or first.split(' ')[0])", "common",
_("Name|common")),
"i": ("''.join([word[0] +'.' for word in ('. ' + first).split()][1:])",
"initials", _("initials"))
"initials",
_("initials")),
"y": ("_raw_patro_surname(raw_surname_list)", "patronymic",
_("patronymic")),
"o": ("_raw_nonpatro_surname(raw_surname_list)", "notpatronymic",
_("notpatronymic")),
"m": ("_raw_primary_surname(raw_surname_list)", "primary",
_("Name|primary")),
"p": ("_raw_prefix_surname(raw_surname_list)", "prefix",
_("prefix")),
"q": ("_raw_single_surname(raw_surname_list)", "rawsurnames",
_("rawsurnames")),
"n": ("nick", "nickname",
_("nickname")),
"g": ("famnick", "familynick",
_("familynick")),
}
args = "first,surname,prefix,suffix,patronymic,title,call"
args = "first,raw_surname_list,suffix,title,call,nick,famnick"
return self._make_fn(format_str, d, args)
def _make_fn(self, format_str, d, args):
@ -360,7 +502,7 @@ class NameDisplay(object):
pass
else:
d_keys = [(code, _tuple[2]) for code, _tuple in d.iteritems()]
d_keys.sort(_make_cmp) # reverse sort by ikeyword
d_keys.sort(_make_cmp) # reverse on length and by ikeyword
for (code, ikeyword) in d_keys:
exp, keyword, ikeyword = d[code]
#ikeyword = unicode(ikeyword, "utf8")
@ -376,7 +518,7 @@ class NameDisplay(object):
pass
else:
d_keys = [(code, _tuple[1]) for code, _tuple in d.iteritems()]
d_keys.sort(_make_cmp) # reverse sort by keyword
d_keys.sort(_make_cmp) # reverse sort on length and by keyword
# if in double quotes, just use % codes
for (code, keyword) in d_keys:
exp, keyword, ikeyword = d[code]
@ -410,7 +552,7 @@ class NameDisplay(object):
# find each format flag in the original format string
# for each one we find the variable name that is needed to
# replace it and add this to a list. This list will be used
# replace it and add this to a list. This list will be used to
# generate the replacement tuple.
# This compiled pattern should match all of the format codes.
@ -442,9 +584,10 @@ def fn(%s):
return fn
def format_str(self, name, format_str):
return self._format_str_base(name.first_name, name.surname, name.prefix,
name.suffix, name.patronymic, name.title,
name.call,format_str)
return self._format_str_base(name.first_name, name.surname_list,
name.suffix, name.title,
name.call, name.nick, name.famnick,
format_str)
def format_str_raw(self, raw_data, format_str):
"""
@ -463,22 +606,27 @@ def fn(%s):
return ' '.join(s.split())
def _format_str_base(self, first, surname, prefix, suffix, patronymic,
title, call, format_str):
def _format_str_base(self, first, surname_list, suffix, title, call,
nick, famnick, format_str):
"""
Generates name from a format string.
The following substitutions are made:
%t -> title
%f -> given (first name)
%p -> prefix
%s -> suffix
%l -> surname (last name)
%y -> patronymic
%c -> call
%x -> common
%i -> initials
The capital letters are substituted for capitalized name components.
'%t' : title
'%f' : given (first names)
'%l' : full surname (lastname)
'%c' : callname
'%x' : callname if existing, otherwise first first name (common name)
'%i' : initials of the first names
'%y' : patronymic surname (father)
'%o' : surnames without patronymic
'%m' : primary surname (main)
'%p' : list of all prefixes
'%q' : surnames without prefixes and connectors
'%s' : suffix
'%n' : nick name
'%g' : family nick name
The capital letters are substituted for capitalized name components.
The %% is substituted with the single % character.
All the other characters in the fmt_str are unaffected.
"""
@ -487,7 +635,8 @@ def fn(%s):
func = self._gen_cooked_func(format_str)
self.__class__.format_funcs[format_str] = func
try:
s = func(first,surname,prefix,suffix,patronymic,title,call)
s = func(first, [surn.serialize() for surn in surname_list],
suffix, title, call, nick, famnick)
except (ValueError, TypeError,):
raise NameDisplayError, "Incomplete format string"
@ -496,7 +645,8 @@ def fn(%s):
#-------------------------------------------------------------------------
def sort_string(self, name):
return u"%-25s%-30s%s" % (name.surname, name.first_name, name.suffix)
return u"%-25s%-30s%s" % (name.get_primary_surname, name.first_name,
name.suffix)
def sorted(self, person):
"""
@ -573,7 +723,7 @@ def fn(%s):
def display_formal(self, person):
"""
Return a text string representing the L{gen.lib.Person} instance's
L{Name} in a manner that should be used for normal displaying.
L{Name} in a manner that should be used for formal displaying.
@param person: L{gen.lib.Person} instance that contains the
L{Name} that is to be displayed. The primary name is used for
@ -603,7 +753,7 @@ def fn(%s):
return self.name_formats[num][_F_FN](name)
def display_given(self, person):
return self.format_str(person.get_primary_name(),'%f %y')
return self.format_str(person.get_primary_name(),'%f')
def name_grouping(self, db, person):
return self.name_grouping_name(db, person.primary_name)
@ -612,26 +762,29 @@ def fn(%s):
if pn.group_as:
return pn.group_as
sv = pn.sort_as
if sv == Name.LNFN or sv == Name.DEF:
return db.get_name_group_mapping(pn.surname)
elif sv == Name.PTFN:
return db.get_name_group_mapping(pn.patronymic)
if sv == Name.DEF:
return db.get_name_group_mapping(pn.get_primary_surname())
elif sv == Name.LNFN:
return db.get_name_group_mapping(pn.get_surname())
elif sv == Name.FN:
return db.get_name_group_mapping(pn.first_name)
else:
return db.get_name_group_mapping(pn.surname)
return db.get_name_group_mapping(pn.get_primary_surname())
def name_grouping_data(self, db, pn):
if pn[_GROUP]:
return pn[_GROUP]
sv = pn[_SORT]
if sv == Name.LNFN or sv == Name.DEF:
return db.get_name_group_mapping(pn[_SURNAME])
elif sv == Name.PTFN:
return db.get_name_group_mapping(pn[_PATRONYM])
if sv == Name.DEF:
return db.get_name_group_mapping(_raw_primary_surname(
pn[_SURNAME_LIST]))
elif sv == Name.LNFN:
return db.get_name_group_mapping(_raw_full_surname(
pn[_SURNAME_LIST]))
elif sv == Name.FN:
return db.get_name_group_mapping(pn[_FIRSTNAME])
else:
return db.get_name_group_mapping(pn[_SURNAME])
return db.get_name_group_mapping(_raw_primary_surname(
pn[_SURNAME_LIST]))
displayer = NameDisplay()

View File

@ -37,6 +37,7 @@ pkgdata_PYTHON = \
mediaref.py \
name.py \
nametype.py \
nameorigintype.py \
notebase.py \
note.py \
notetype.py \
@ -58,6 +59,8 @@ pkgdata_PYTHON = \
srcnote.py \
src.py \
srcref.py \
surname.py \
surnamebase.py \
styledtext.py \
styledtexttag.py \
styledtexttagtype.py \

View File

@ -36,6 +36,7 @@ from gen.lib.mediaref import MediaRef
from gen.lib.name import Name
from gen.lib.reporef import RepoRef
from gen.lib.srcref import SourceRef
from gen.lib.surname import Surname
from gen.lib.url import Url
from gen.lib.witness import Witness
from gen.lib.childref import ChildRef
@ -71,6 +72,7 @@ from gen.lib.familyreltype import FamilyRelType
from gen.lib.srcmediatype import SourceMediaType
from gen.lib.eventroletype import EventRoleType
from gen.lib.markertype import MarkerType
from gen.lib.nameorigintype import NameOriginType
from gen.lib.notetype import NoteType
from gen.lib.styledtexttagtype import StyledTextTagType

View File

@ -35,6 +35,7 @@ from gen.lib.privacybase import PrivacyBase
from gen.lib.srcbase import SourceBase
from gen.lib.notebase import NoteBase
from gen.lib.datebase import DateBase
from gen.lib.surnamebase import SurnameBase
from gen.lib.nametype import NameType
from gen.lib.const import IDENTICAL, EQUAL, DIFFERENT
@ -43,18 +44,23 @@ from gen.lib.const import IDENTICAL, EQUAL, DIFFERENT
# Personal Name
#
#-------------------------------------------------------------------------
class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
class Name(SecondaryObject, PrivacyBase, SurnameBase, SourceBase, NoteBase,
DateBase):
"""
Provide name information about a person.
A person may have more that one name throughout his or her life.
A person may have more that one name throughout his or her life. The Name
object stores one of them
"""
DEF = 0 # Default format (determined by gramps-wide prefs)
LNFN = 1 # last name first name [patronymic]
LNFN = 1 # last name first name
FNLN = 2 # first name last name
PTFN = 3 # patronymic first name
FN = 4 # first name
NAMEFORMATS = (DEF, LNFN, FNLN, FN)
#deprecated :
PTFN = 3 # patronymic first name
def __init__(self, source=None, data=None):
"""Create a new Name instance, copying from the source if provided.
@ -65,43 +71,43 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
saved differently.
"""
PrivacyBase.__init__(self, source)
SurnameBase.__init__(self, source)
SourceBase.__init__(self, source)
NoteBase.__init__(self, source)
DateBase.__init__(self, source)
if data:
(privacy, source_list, note, date,
self.first_name, self.surname, self.suffix, self.title,
name_type, self.prefix, self.patronymic,
self.group_as, self.sort_as, self.display_as, self.call) = data
self.first_name, surname_list, self.suffix, self.title, name_type,
self.group_as, self.sort_as, self.display_as, self.call,
self.nick, self.famnick) = data
self.type = NameType(name_type)
SurnameBase.unserialize(self, surname_list)
PrivacyBase.unserialize(self, privacy)
SourceBase.unserialize(self, source_list)
NoteBase.unserialize(self, note)
DateBase.unserialize(self, date)
elif source:
self.first_name = source.first_name
self.surname = source.surname
self.suffix = source.suffix
self.title = source.title
self.type = source.type
self.prefix = source.prefix
self.patronymic = source.patronymic
self.group_as = source.group_as
self.sort_as = source.sort_as
self.display_as = source.display_as
self.call = source.call
self.nick = source.nick
self.famnick = source.famnick
else:
self.first_name = ""
self.surname = ""
self.suffix = ""
self.title = ""
self.type = NameType()
self.prefix = ""
self.patronymic = ""
self.group_as = ""
self.sort_as = self.DEF
self.display_as = self.DEF
self.call = u''
self.nick = u''
self.famnick = u''
def serialize(self):
"""
@ -111,28 +117,35 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
SourceBase.serialize(self),
NoteBase.serialize(self),
DateBase.serialize(self),
self.first_name, self.surname, self.suffix, self.title,
self.type.serialize(), self.prefix, self.patronymic,
self.group_as, self.sort_as, self.display_as, self.call)
self.first_name,
SurnameBase.serialize(self),
self.suffix, self.title,
self.type.serialize(),
self.group_as, self.sort_as, self.display_as, self.call,
self.nick, self.famnick)
def is_empty(self):
"""
Indicate if the name is empty.
"""
return (self.first_name == u"" and self.surname == u"" and
self.suffix == u"" and self.title == u"" and
self.prefix == u"" and self.patronymic == u"")
namefieldsempty = (self.first_name == u"" and
self.suffix == u"" and self.title == u"" and self.nick ==u""
and self.famnick == u"")
surnamefieldsempty = not (False in
[surn.is_empty() for surn in self.surname_list])
return namefieldsempty and surnamefieldsempty
def unserialize(self, data):
"""
Convert a serialized tuple of data to an object.
"""
(privacy, source_list, note_list, date,
self.first_name, self.surname, self.suffix, self.title,
name_type, self.prefix, self.patronymic,
self.group_as, self.sort_as, self.display_as, self.call) = data
self.first_name, surname_list, self.suffix, self.title, name_type,
self.group_as, self.sort_as, self.display_as, self.call,
self.nick, self.famnick) = data
self.type = NameType(name_type)
PrivacyBase.unserialize(self, privacy)
SurnameBase.unserialize(self, surname_list)
SourceBase.unserialize(self, source_list)
NoteBase.unserialize(self, note_list)
DateBase.unserialize(self, date)
@ -145,8 +158,8 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
:returns: Returns the list of all textual attributes of the object.
:rtype: list
"""
return [self.first_name, self.surname, self.suffix, self.title,
str(self.type), self.prefix, self.patronymic, self.call]
return [self.first_name, self.suffix, self.title,
str(self.type), self.call, self.nick, self.famnick]
def get_text_data_child_list(self):
"""
@ -155,7 +168,7 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
:returns: Returns the list of child objects that may carry textual data.
:rtype: list
"""
return self.source_list
return self.source_list + self.surname_list
def get_note_child_list(self):
"""
@ -189,8 +202,8 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
def is_equivalent(self, other):
"""
Return if this name is equivalent, that is agrees in type, first
call, last, suffix, patronymic, title and date, to other.
Return if this name is equivalent, that is agrees in type, first,
call, surname_list, suffix, title and date, to other.
:param other: The name to compare this name to.
:rtype other: Name
@ -199,7 +212,8 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
"""
# TODO what to do with sort and display?
if self.get_text_data_list() != other.get_text_data_list() or \
self.get_date_object() != other.get_date_object():
self.get_date_object() != other.get_date_object() or \
SurnameBase.serialize(self) != SurnameBase.serialize(other):
return DIFFERENT
else:
if self.is_equal(other):
@ -210,8 +224,10 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
def merge(self, acquisition):
"""
Merge the content of acquisition into this name.
Normally the person merge code should opt for adding an alternate
name if names are actually different (like not equal surname list)
Lost: type, first, call, last, suffix, patronymic, title and date of
Lost: type, first, call, suffix, title, nick, famnick and date of
acquisition.
:param acquisition: The name to merge with the present name.
@ -219,6 +235,7 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
"""
# TODO what to do with sort and display?
self._merge_privacy(acquisition)
self._merge_surname_list(acquisition)
self._merge_note_list(acquisition)
self._merge_source_reference_list(acquisition)
@ -249,7 +266,7 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
if self.group_as:
return self.group_as
else:
return self.surname
return self.get_primary_surname().get_surname()
def set_sort_as(self, value):
"""
@ -305,22 +322,42 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
"""
self.call = val
def get_surname_prefix(self):
def get_nick_name(self):
"""
Return the prefix (or article) of a surname.
Return the nick name.
The prefix is not used for sorting or grouping.
The nick name of the person, a not official name the person is known
with.
"""
return self.prefix
return self.nick
def set_surname_prefix(self, val):
def set_nick_name(self, val):
"""
Set the prefix (or article) of a surname.
Set the nick name.
Examples of articles would be 'de' or 'van'.
The nick name of the person, a not official name the person is known
with.
"""
self.prefix = val
self.nick = val
def get_family_nick_name(self):
"""
Return the family nick name.
The family nick name of the family of the person, a not official name
use to denote the entire family.
"""
return self.famnick
def set_family_nick_name(self, val):
"""
Set the family nick name.
The family nick name of the family of the person, a not official name
use to denote the entire family.
"""
self.famnick = val
def set_type(self, the_type):
"""Set the type of the Name instance."""
self.type.set(the_type)
@ -333,33 +370,13 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
"""Set the given name for the Name instance."""
self.first_name = name
def set_patronymic(self, name):
"""Set the patronymic name for the Name instance."""
self.patronymic = name
def set_surname(self, name):
"""Set the surname (or last name) for the Name instance."""
self.surname = name
def set_suffix(self, name):
"""Set the suffix (such as Jr., III, etc.) for the Name instance."""
self.suffix = name
def get_first_name(self):
"""Return the given name for the Name instance."""
return self.first_name
def get_patronymic(self):
"""Return the patronymic name for the Name instance."""
return self.patronymic
def get_surname(self):
"""Return the surname (or last name) for the Name instance."""
return self.surname
def get_upper_surname(self):
"""Return the surname (or last name) for the Name instance."""
return self.surname.upper()
def set_suffix(self, name):
"""Set the suffix (such as Jr., III, etc.) for the Name instance."""
self.suffix = name
def get_suffix(self):
"""Return the suffix for the Name instance."""
@ -376,85 +393,55 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
def get_name(self):
"""
Return a name string built from the components of the Name instance,
in the form of surname, Firstname.
in the form of: surname, Firstname.
"""
if self.patronymic:
first = "%s %s" % (self.first_name, self.patronymic)
else:
first = self.first_name
first = self.first_name
surname = self.get_surname()
if self.suffix:
if self.prefix:
return "%s %s, %s %s" % (self.prefix, self.surname,
first, self.suffix)
else:
return "%s, %s %s" % (self.surname, first, self.suffix)
return "%s, %s %s" % (surname, first, self.suffix)
else:
if self.prefix:
return "%s %s, %s" % (self.prefix, self.surname, first)
else:
return "%s, %s" % (self.surname, first)
return "%s, %s" % (surname, first)
def get_upper_name(self):
"""
Return a name string built from the components of the Name instance,
in the form of surname, Firstname.
in the form of SURNAME, Firstname.
"""
if self.patronymic:
first = "%s %s" % (self.first_name, self.patronymic)
else:
first = self.first_name
first = self.first_name
surname = self.get_surname().upper()
if self.suffix:
if self.prefix:
return "%s %s, %s %s" % (self.prefix.upper(),
self.surname.upper(), first,
self.suffix)
else:
return "%s, %s %s" % (self.surname.upper(), first, self.suffix)
return "%s, %s %s" % (surname, first, self.suffix)
else:
if self.prefix:
return "%s %s, %s" % (self.prefix.upper(),
self.surname.upper(),
first)
else:
return "%s, %s" % (self.surname.upper(), first)
return "%s, %s" % (surname, first)
def get_regular_name(self):
"""
Return a name string built from the components of the Name instance,
in the form of Firstname surname.
"""
if self.patronymic:
first = "%s %s" % (self.first_name, self.patronymic)
else:
first = self.first_name
first = self.first_name
surname = self.get_surname()
if (self.suffix == ""):
if self.prefix:
return "%s %s %s" % (first, self.prefix, self.surname)
else:
return "%s %s" % (first, self.surname)
return "%s %s" % (first, surname)
else:
if self.prefix:
return "%s %s %s, %s" % (first, self.prefix, self.surname,
self.suffix)
else:
return "%s %s, %s" % (first, self.surname, self.suffix)
return "%s %s, %s" % (first, surname, self.suffix)
def get_gedcom_parts(self):
"""
Returns a GEDCOM-formatted name dictionary.
Note, field patronymic and prefix are deprecated, prefix_list and
surname list, added.
"""
retval = {}
retval['given'] = self.first_name.strip()
retval['patronymic'] = self.patronymic.strip()
if retval['patronymic']:
retval['given'] = "%s %s" % (retval['given'],
retval['patronymic'])
retval['surname'] = self.surname.replace('/', '?')
retval['prefix'] = self.prefix.replace('/', '?')
retval['surname'] = self.get_surname().replace('/', '?')
retval['suffix'] = self.suffix
retval['title'] = self.title
retval['surnamelist'] = self.get_surnames()
retval['prefixes'] = self.get_prefixes()
retval['connectors'] = self.get_connectors()
retval['nick'] = self.nick
retval['famnick'] = self.famnick
return retval
def get_gedcom_name(self):
@ -462,21 +449,10 @@ class Name(SecondaryObject, PrivacyBase, SourceBase, NoteBase, DateBase):
Returns a GEDCOM-formatted name.
"""
firstname = self.first_name.strip()
patron = self.patronymic.strip()
if patron:
firstname = "%s %s" % (firstname, patron)
surname = self.surname.replace('/', '?')
surprefix = self.prefix.replace('/', '?')
surname = self.get_surname().replace('/', '?')
suffix = self.suffix
title = self.title
if suffix == "":
if surprefix == "":
return '%s /%s/' % (firstname, surname)
else:
return '%s /%s %s/' % (firstname, surprefix, surname)
elif surprefix == "":
return '%s /%s/ %s' % (firstname, surname, suffix)
return '%s /%s/' % (firstname, surname)
else:
return '%s /%s %s/ %s' % (firstname, surprefix, surname, suffix)
return '%s /%s/ %s' % (firstname, surname, suffix)

View File

@ -0,0 +1,87 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# 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$
"""
Name types.
"""
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gen.ggettext import sgettext as _
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
from gen.lib.grampstype import GrampsType
class NameOriginType(GrampsType):
"""
Name Origina Types
.. attribute UNKNOWN: Unknown origin
.. attribute CUSTOM: Custom user defined origin
.. attribute NONE: no given origin
.. attribute INHERITED: name was inherited from parents
.. attribute GIVEN: name was bestowed on the individual
.. attribute TAKEN: name was chosen by the individual
.. attribute PATRONYMIC: name is derived from father's given name
.. attribute MATRONYMIC: name is derived from mother's given name
.. attribute FEUDAL: name refers to the holding of land in a fief
.. attribute PSEUDONYM: name is fictitious
"""
UNKNOWN = -1
CUSTOM = 0
NONE = 1
INHERITED = 2
GIVEN = 3
TAKEN = 4
PATRONYMIC = 5
MATRONYMIC = 6
FEUDAL = 7
PSEUDONYM = 8
_CUSTOM = CUSTOM
_DEFAULT = NONE
_DATAMAP = [
(UNKNOWN , _("Unknown"), "Unknown"),
(CUSTOM , _("Custom"), "Custom"),
(NONE , "", ""),
(INHERITED , _("Surname|Inherited"), "Inherited"),
(GIVEN , _("Surname|Given"), "Given"),
(TAKEN , _("Surname|Taken"), "Taken"),
(PATRONYMIC, _("Patronymic"), "Patronymic"),
(MATRONYMIC, _("Matronymic"), "Matronymic"),
(FEUDAL , _("Surname|Feudal"), "Feudal"),
(PSEUDONYM , _("Pseudonym"), "Pseudonym"),
]
def __init__(self, value=None):
GrampsType.__init__(self, value)

196
src/gen/lib/surname.py Normal file
View File

@ -0,0 +1,196 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# 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$
"""
Surname class for GRAMPS.
"""
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
from gen.lib.secondaryobj import SecondaryObject
from gen.lib.nameorigintype import NameOriginType
from gen.lib.const import IDENTICAL, EQUAL, DIFFERENT
#-------------------------------------------------------------------------
#
# Personal Name
#
#-------------------------------------------------------------------------
class Surname(SecondaryObject):
"""
Provide surname information of a name.
A person may have more that one surname in his name
"""
def __init__(self, source=None, data=None):
"""Create a new Surname instance, copying from the source if provided.
By default a surname is created as primary, use set_primary to change
"""
if source:
self.surname = source.surname
self.prefix = source.prefix
self.primary = source.primary
self.origintype = source.origintype
self.connector = source.connector
else:
self.surname = ""
self.prefix = ""
self.primary = True
self.origintype = NameOriginType()
self.connector = ""
if data:
self.unserialize(data)
def serialize(self):
"""
Convert the object to a serialized tuple of data.
"""
return (self.surname, self.prefix, self.primary,
self.origintype.serialize(), self.connector)
def is_empty(self):
"""
Indicate if the surname is empty.
"""
return (self.surname == u"" and self.prefix == u"" and
self.connector == u"")
def unserialize(self, data):
"""
Convert a serialized tuple of data to an object.
"""
(self.surname, self.prefix, self.primary, origin_type,
self.connector) = data
self.origintype = NameOriginType(origin_type)
return self
def get_text_data_list(self):
"""
Return the list of all textual attributes of the object.
:returns: Returns the list of all textual attributes of the object.
:rtype: list
"""
return [self.surname, self.prefix, self.connector,
str(self.origintype)]
def is_equivalent(self, other):
"""
Return if this surname is equivalent, that is agrees in type, surname,
..., to other.
:param other: The surname to compare this name to.
:rtype other: Surame
:returns: Constant indicating degree of equivalence.
:rtype: int
"""
# TODO what to do with sort and display?
if self.get_text_data_list() != other.get_text_data_list() or \
self.primary != other.primary:
return DIFFERENT
else:
if self.is_equal(other):
return IDENTICAL
else:
return EQUAL
def merge(self, acquisition):
"""
Merge the content of acquisition into this surname.
Lost: primary, surname, prefix, connector, origintype
:param acquisition: The surname to merge with the present surname.
:rtype acquisition: Surname
"""
pass
def get_surname(self):
"""
Return the surname.
The surname is one of the not given names coming from the parents
"""
return self.surname
def set_surname(self, val):
"""
Set the surname.
The surname is one of the not given names coming from the parents
"""
self.surname = val
def get_prefix(self):
"""
Return the prefix (or article) of the surname.
The prefix is not used for sorting or grouping.
"""
return self.prefix
def set_prefix(self, val):
"""
Set the prefix (or article) of the surname.
Examples of articles would be 'de' or 'van'.
"""
self.prefix = val
def set_origintype(self, the_type):
"""Set the origin type of the Surname instance."""
self.origintype.set(the_type)
def get_origintype(self):
"""Return the origin type of the Surname instance."""
return self.origintype
def set_connector(self, connector):
"""Set the connector for the Surname instance. This defines how a
surname connects to the next surname (eg in Spanish names).
"""
self.connector = connector
def get_connector(self):
"""Get the connector for the Surname instance. This defines how a
surname connects to the next surname (eg in Spanish names).
"""
return self.connector
def get_primary(self):
"""Return if this surname is the primary surname"""
return self.primary
def set_primary(self, primary=True):
"""Set if this surname is the primary surname.replace
Use :class:`~gen.lib.surname.SurnameBase` to set the primary surname
via :method:`~gen.lib.surname.SurnameBase.set_primary_surname`
:param primary: primay surname or not
:type primary: bool
"""
self.primary = primary

230
src/gen/lib/surnamebase.py Normal file
View File

@ -0,0 +1,230 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010 Benny Malengier
#
# 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$
"""
SurnameBase class for GRAMPS.
"""
from gen.ggettext import gettext as _
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
from gen.lib.surname import Surname
from gen.lib.const import IDENTICAL, EQUAL
#-------------------------------------------------------------------------
#
# SurnameBase classes
#
#-------------------------------------------------------------------------
class SurnameBase(object):
"""
Base class for surname-aware objects.
"""
def __init__(self, source=None):
"""
Initialize a SurnameBase.
If the source is not None, then object is initialized from values of
the source object.
:param source: Object used to initialize the new object
:type source: SurnameBase
"""
self.surname_list = map(Surname, source.surname_list) if source else []
def serialize(self):
"""
Convert the object to a serialized tuple of data.
"""
return [surname.serialize() for surname in self.surname_list]
def unserialize(self, data):
"""
Convert a serialized tuple of data to an object.
"""
self.surname_list = [Surname().unserialize(item) for item in data]
def add_surname(self, surname):
"""
Add the :class:`~gen.lib.surname.Surname` instance to the object's
list of surnames.
:param surname: :class:`~gen.lib.surname.Surname` instance to add to
the object's address list.
:type address: list
"""
self.surname_list.append(surname)
def remove_surname(self, surname):
"""
Remove the specified :class:`~gen.lib.surname.Surname` instance from
the surname list.
If the instance does not exist in the list, the operation has
no effect.
:param surname: :class:`~gen.lib.surname.Surname` instance to remove
from the list
:type surname: :class:`~gen.lib.surname.Surname`
:returns: True if the surname was removed, False if it was not in the list.
:rtype: bool
"""
if surname in self.surname_list:
self.surname_list.remove(surname)
return True
else:
return False
def get_surname_list(self):
"""
Return the list of :class:`~gen.lib.surname.Surname` instances a
ssociated with the object.
:returns: Returns the list of :class:`~gen.lib.surname.Surname` instances
:rtype: list
"""
return self.surname_list
def set_surname_list(self, surname_list):
"""
Assign the passed list to the object's list of
:class:`~gen.lib.surname.Surname` instances.
:param surname_list: List of :class:`~gen.lib.surname.surname` instances
to be associated with the object
:type surname_list: list
"""
self.surname_list = surname_list
def get_primary_surname(self):
"""
Return the string of the surname that is the primary surname
:returns: Returns the surname instance that
is the primary surname. If primary not set, and there is a surname,
the first surname is given, if no surnames, None is returned
:rtype: :class:`~gen.lib.surname.Surname` or None
"""
for surname in self.surname_list:
if surname.primary:
return surname
if self.surname_list:
return self.surname_list[0]
return None
def set_primary_surname(self, surnamenr=0):
"""
Set the surname with surnamenr in the surname list as primary surname
Counting starts at 0
"""
if surnamenr >= len(self.surname_list):
return
for surname in self.surname_list:
surname.set_primary(False)
self.surname_list[surnamenr].set_primary(True)
def _merge_surname_list(self, acquisition):
"""
Merge the list of surname from acquisition with our own.
This method is normally only called when surnames are equal, if they
are different, the merge code should fall back to storing an
alternate name. For completeness, the code is present nevertheless.
:param acquisition: the surname list of this object will be merged with
the current surname list.
:rtype acquisition: SurnameBase
"""
surname_list = self.surname_list[:]
for addendum in acquisition.get_surname_list():
for surname in surname_list:
equi = surname.is_equivalent(addendum)
if equi == IDENTICAL:
break
elif equi == EQUAL:
#This should normally never happen, an alternate name
# should be added
surname.merge(addendum)
break
else:
self.surname_list.append(addendum)
def get_surname(self):
"""
Return a fully formatted surname utilizing the surname_list
"""
totalsurn = ""
for surn in self.surname_list:
partsurn = surn.get_surname()
if surn.get_prefix():
fsurn = _('%(first)s %(second)s') % {'first': surn.get_prefix(),
'second': partsurn}
else:
fsurn = partsurn
fsurn = fsurn.strip()
if surn.get_connector():
fsurn = _('%(first)s %(second)s') % {'first': fsurn,
'second': surn.get_connector()}
fsurn = fsurn.strip()
totalsurn = _('%(first)s %(second)s') % {'first': totalsurn,
'second': fsurn}
return totalsurn.strip()
def get_upper_surname(self):
"""Return a fully formatted surname capitalized"""
return self.get_surname().upper()
def get_surnames(self):
"""
Return a list of surnames (no prefix or connectors)
"""
surnl = []
for surn in self.surname_list:
realsurn = surn.get_surname()
if realsurn:
surnl.append(realsurn)
def get_prefixes(self):
"""
Return a list of prefixes
"""
prefixl = []
for surn in self.surname_list:
prefix = surn.get_prefix()
if prefix:
prefixl.append(prefix)
def get_connectors(self):
"""
Return a list of surnames (no prefix or connectors)
"""
connl = []
for surn in self.surname_list:
conn = surn.get_connector()
if conn:
connl.append(conn)

View File

@ -623,6 +623,11 @@ class ProxyDbBase(DbReadBase):
instances in the database"""
return self.db.get_name_types()
def get_origin_types(self):
"""returns a list of all custom origin types associated with Person/Surname
instances in the database"""
return self.db.get_origin_types()
def get_repository_types(self):
"""returns a list of all custom repository types associated with
Repository instances in the database"""

View File

@ -12,275 +12,331 @@
<child>
<object class="GtkVBox" id="vbox33">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkTable" id="table65">
<object class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<property name="border_width">12</property>
<property name="n_rows">4</property>
<property name="n_columns">5</property>
<property name="column_spacing">12</property>
<property name="row_spacing">6</property>
<child>
<object class="GtkLabel" id="label592">
<object class="GtkHBox" id="hbox110">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Given:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">alt_given</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label597">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">P_atronymic:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">patronymic</property>
</object>
<packing>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="patronymic">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label598">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Family:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">alt_surname</property>
</object>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="alt_surname">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label596">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Prefix:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">alt_prefix</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label595">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Tit_le:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">alt_title</property>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="alt_title">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label593">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Suffi_x:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">alt_suffix</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label594">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<property name="xpad">1</property>
<property name="label" translatable="yes">_Type:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">name_type</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="alt_prefix">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">5</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkComboBoxEntry" id="name_type">
<property name="visible">True</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">5</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="alt_suffix">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="priv">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="image2683">
<object class="GtkLabel" id="label269">
<property name="visible">True</property>
<property name="icon_name">gtk-dialog-authentication</property>
<property name="icon-size">1</property>
<property name="xalign">0</property>
<property name="xpad">4</property>
<property name="label" translatable="yes">_Type:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">ntype</property>
</object>
<packing>
<property name="expand">False</property>
<property name="padding">8</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkComboBoxEntry" id="ntype">
<property name="visible">True</property>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<object class="GtkToggleButton" id="priv">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="relief">none</property>
<child>
<object class="GtkImage" id="image2683">
<property name="visible">True</property>
<property name="icon_name">gtk-dialog-authentication</property>
<property name="icon-size">1</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">6</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">3</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<object class="GtkFrame" id="givenframe">
<property name="visible">True</property>
<property name="label_xalign">0.029999999329447746</property>
<child>
<object class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<object class="GtkTable" id="table2">
<property name="visible">True</property>
<property name="n_rows">2</property>
<property name="n_columns">6</property>
<property name="column_spacing">7</property>
<property name="row_spacing">7</property>
<child>
<object class="GtkLabel" id="label21">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Given:</property>
<property name="use_underline">True</property>
<property name="justify">center</property>
<property name="mnemonic_widget">given_name</property>
</object>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="titlelabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">T_itle:</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Suffi_x:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">suffix</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label444">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">C_all Name:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">call</property>
</object>
<packing>
<property name="left_attach">4</property>
<property name="right_attach">5</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="given_name">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">4</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label6">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Nick Name:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">nickname</property>
</object>
<packing>
<property name="left_attach">4</property>
<property name="right_attach">5</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="ValidatableMaskedEntry" id="call">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="left_attach">5</property>
<property name="right_attach">6</property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="title_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="suffix">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">4</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="nickname">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="left_attach">5</property>
<property name="right_attach">6</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;i&gt;Given Name(s) &lt;/i&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">4</property>
<property name="right_attach">5</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">3</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="alt_given">
<object class="GtkFrame" id="multsurnamefr">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="label_xalign">0.029999999329447746</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox1">
<property name="visible">True</property>
<child>
<object class="GtkHBox" id="hboxmultsurnames">
<property name="visible">True</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<child>
<object class="GtkLabel" id="label7">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">_Family Nick Name:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">familynickname</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="familynickname">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
<property name="width_chars">25</property>
</object>
<packing>
<property name="expand">False</property>
<property name="padding">3</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="padding">3</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="label" translatable="yes">&lt;i&gt;Family Names &lt;/i&gt;</property>
<property name="use_markup">True</property>
</object>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label654">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Call _Name:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">call</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
<object class="UndoableEntry" id="call">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="right_attach">5</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="padding">2</property>
<property name="position">3</property>
</packing>
</child>
</object>
@ -288,6 +344,12 @@
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<object class="GtkNotebook" id="notebook">
<property name="visible">True</property>
@ -367,7 +429,6 @@
<child>
<object class="GtkComboBox" id="display_as">
<property name="visible">True</property>
<property name="model">liststore2</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext2"/>
<attributes>
@ -405,7 +466,6 @@
<child>
<object class="GtkComboBox" id="sort_as">
<property name="visible">True</property>
<property name="model">liststore1</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
@ -555,7 +615,7 @@
</child>
</object>
<packing>
<property name="position">1</property>
<property name="position">3</property>
</packing>
</child>
</object>
@ -591,7 +651,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="receives_default">True</property>
<property name="has_tooltip">True</property>
<property name="tooltip_markup">Accept changes and close window</property>
@ -634,16 +693,4 @@
<action-widget response="-11">button131</action-widget>
</action-widgets>
</object>
<object class="GtkListStore" id="liststore1">
<columns>
<!-- column-name item -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkListStore" id="liststore2">
<columns>
<!-- column-name item -->
<column type="gchararray"/>
</columns>
</object>
</interface>

File diff suppressed because it is too large Load Diff

View File

@ -53,7 +53,7 @@ from gen.display.name import displayer as _nd
from gen.display.name import NameDisplayError
import Utils
import gen.lib
from gen.lib import Name
from gen.lib import Name, Surname, NameOriginType
import ManagedWindow
from gui.widgets import MarkupLabel, BasicLabel
from QuestionDialog import ErrorDialog, QuestionDialog2, OkDialog
@ -98,21 +98,28 @@ class DisplayNameEditor(ManagedWindow.ManagedWindow):
table = self.dialog._build_custom_name_ui()
label = gtk.Label(_("""The following keywords will be replaced with the name:
<tt>
<b>Given</b> - given name (first name)
<b>Surname</b> - surname (last name)
<b>Title</b> - title (Dr., Mrs.)
<b>Prefix</b> - prefix (von, de, de la)
<b>Suffix</b> - suffix (Jr., Sr.)
<b>Call</b> - call name, or nickname
<b>Common</b> - call name, otherwise first part of Given
<b>Patronymic</b> - patronymic (father's name)
<b>Initials</b> - persons's first letters of given names
<b>Given</b> - given name (first name) | <b>Surname</b> - surnames (with prefix and connectors)
<b>Title</b> - title (Dr., Mrs.) | <b>Suffix</b> - suffix (Jr., Sr.)
<b>Call</b> - call name | <b>Nickname</b> - nick name
<b>Initials</b> - first letters of Given | <b>Common</b> - Call, otherwise first of Given
<b>Primary</b> - primary surname (main) | <b>Familynick</b> - Family nick name
Also:
<b>Patronymic</b> - patronymic surname (father's name)
<b>Notpatronymic</b> - all surnames except patronymic
<b>Prefix</b> - all surnames prefixes (von, de, de la)
<b>Rawsurnames</b> - all surnames without prefixes and connectors
</tt>
Use the same keyword in UPPERCASE to force to upper. Parentheses and commas
will be removed around empty fields. Other text will appear literally."""))
will be removed around empty fields. Other text will appear literally.
<b>Example fictituous name</b>: 'Dr. Edwin Jose von der Smith and Weston Wilson Sr ("Ed") - Underhills'
Here <i>Edwin Jose</i> are given names, <i>Smith</i> and <i>Weston</i> surnames, <i>Wilson</i> patronymic surname,
<i>Dr.</i> a title, <i>Sr</i> a suffix, <i>Ed</i> the nick name, <i>Underhills</i> family nick name.
Callname is <i>Jose</i>.
"""))
label.set_use_markup(True)
self.window.vbox.add(label)
self.window.vbox.add(table)
self.window.vbox.pack_start(label, expand=False)
self.window.vbox.pack_start(table)
self.window.set_default_size(600, 550)
self.window.connect('response', self.close)
self.show()
@ -485,7 +492,7 @@ class GrampsPreferences(ConfigureDialog):
gobject.TYPE_STRING,
gobject.TYPE_STRING,
gobject.TYPE_STRING)
index = 0
index = 0
the_index = 0
for num, name, fmt_str, act in _nd.get_name_format():
translation = fmt_str
@ -503,40 +510,49 @@ class GrampsPreferences(ConfigureDialog):
lyst = ["%s, %s %s (%s)" % (_("Surname"), _("Given"), _("Suffix"),
_("Common")),
"%s, %s %s (%s)" % (_("Surname"), _("Given"), _("Suffix"),
_("Call")),
_("Nickname")),
"%s, %s %s (%s)" % (_("Surname"), _("Name|Common"), _("Suffix"),
_("Nickname")),
"%s, %s %s" % (_("Surname"), _("Name|Common"), _("Suffix")),
"%s, %s %s (%s)" % (_("SURNAME"), _("Given"), _("Suffix"),
_("Call")),
"%s, %s (%s)" % (_("Surname"), _("Given"), _("Common")),
"%s, %s (%s)" % (_("Surname"), _("Given"), _("Call")),
"%s, %s (%s)" % (_("Surname"), _("Given"), _("Name|Common")),
"%s, %s (%s)" % (_("Surname"), _("Name|Common"), _("Nickname")),
"%s %s" % (_("Given"), _("Surname")),
"%s %s, %s" % (_("Given"), _("Surname"), _("Suffix")),
"%s %s %s" % (_("Given"), _("Surname"), _("Patronymic")),
"%s %s %s" % (_("Given"), _("NotPatronymic"), _("Patronymic")),
"%s, %s %s (%s)" % (_("SURNAME"), _("Given"), _("Suffix"),
_("Common")),
"%s, %s (%s)" % (_("SURNAME"), _("Given"), _("Common")),
"%s, %s (%s)" % (_("SURNAME"), _("Given"), _("Call")),
"%s, %s (%s)" % (_("SURNAME"), _("Given"), _("Name|Common")),
"%s, %s (%s)" % (_("SURNAME"), _("Given"), _("Nickname")),
"%s %s" % (_("Given"), _("SURNAME")),
"%s %s, %s" % (_("Given"), _("SURNAME"), _("Suffix")),
"%s /%s/" % (_("Given"), _("SURNAME")),
"%s %s, %s" % (_("Given"), _("Rawsurnames"), _("Suffix")),
]
fmtlyst = ["%s, %s %s (%s)" % ("Surname", "Given", "Suffix",
"Common"),
"%s, %s %s (%s)" % ("Surname", "Given", "Suffix",
"Call"),
"%s, %s %s (%s)" % ("SURNAME", "Given", "Suffix",
"Call"),
"%s, %s (%s)" % ("Surname", "Given", "Common"),
"%s, %s (%s)" % ("Surname", "Given", "Call"),
"%s %s" % ("Given", "Surname"),
"%s %s, %s" % ("Given", "Surname", "Suffix"),
"%s %s %s" % ("Given", "Surname", "Patronymic"),
"%s, %s %s (%s)" % ("SURNAME", "Given", "Suffix",
"Common"),
"%s, %s (%s)" % ("SURNAME", "Given", "Common"),
"%s, %s (%s)" % ("SURNAME", "Given", "Call"),
"%s %s" % ("Given", "SURNAME"),
"%s %s, %s" % ("Given", "SURNAME", "Suffix"),
"%s /%s/" % ("Given", "SURNAME"),
#repeat above list, but not translated.
fmtlyst = ["%s, %s %s (%s)" % (("Surname"), ("Given"), ("Suffix"),
("Common")),
"%s, %s %s (%s)" % (("Surname"), ("Given"), ("Suffix"),
("Nickname")),
"%s, %s %s (%s)" % (("Surname"), ("Name|Common"), ("Suffix"),
("Nickname")),
"%s, %s %s" % (("Surname"), ("Name|Common"), ("Suffix")),
"%s, %s %s (%s)" % (("SURNAME"), ("Given"), ("Suffix"),
("Call")),
"%s, %s (%s)" % (("Surname"), ("Given"), ("Name|Common")),
"%s, %s (%s)" % (("Surname"), ("Name|Common"), ("Nickname")),
"%s %s" % (("Given"), ("Surname")),
"%s %s, %s" % (("Given"), ("Surname"), ("Suffix")),
"%s %s %s" % (("Given"), ("NotPatronymic"), ("Patronymic")),
"%s, %s %s (%s)" % (("SURNAME"), ("Given"), ("Suffix"),
("Common")),
"%s, %s (%s)" % (("SURNAME"), ("Given"), ("Name|Common")),
"%s, %s (%s)" % (("SURNAME"), ("Given"), ("Nickname")),
"%s %s" % (("Given"), ("SURNAME")),
"%s %s, %s" % (("Given"), ("SURNAME"), ("Suffix")),
"%s /%s/" % (("Given"), ("SURNAME")),
"%s %s, %s" % (("Given"), ("Rawsurnames"), ("Suffix")),
]
rand = int(random.random() * len(lyst))
f = lyst[rand]
@ -687,11 +703,9 @@ class GrampsPreferences(ConfigureDialog):
self.insert_button = gtk.Button(stock=gtk.STOCK_ADD)
self.insert_button.connect('clicked', self.__new_name)
#self.cb_insert_fmt_str)
self.edit_button = gtk.Button(stock=gtk.STOCK_EDIT)
self.edit_button.connect('clicked', self.__edit_name)
#self.cb_edit_fmt_str)
self.edit_button.set_sensitive(False)
self.remove_button = gtk.Button(stock=gtk.STOCK_REMOVE)
@ -746,44 +760,6 @@ class GrampsPreferences(ConfigureDialog):
self.edit_button.set_sensitive(idx)
self.name_renderer.set_property('editable', idx)
def cb_edit_fmt_str(self, obj):
"""
Name format editor Edit button callback
"""
num, name, fmt = self.selected_fmt[COL_NUM:COL_EXPL]
dlg = NameFormatEditDlg(name, fmt, self.examplename)
dlg.dlg.set_transient_for(self.window)
(res, name, fmt) = dlg.run()
if res == gtk.RESPONSE_OK and (name != self.selected_fmt[COL_NAME] or
fmt != self.selected_fmt[COL_FMT]):
exmpl = _nd.format_str(self.examplename, fmt)
self.fmt_model.set(self.iter, COL_NAME, name,
COL_FMT, fmt,
COL_EXPL, exmpl)
self.selected_fmt = (num, name, fmt, exmpl)
_nd.edit_name_format(num, name, fmt)
self.dbstate.db.name_formats = _nd.get_name_format(only_custom=True,
only_active=False)
def cb_insert_fmt_str(self, obj):
"""
Name format editor Insert button callback
"""
dlg = NameFormatEditDlg('', '', self.examplename)
dlg.dlg.set_transient_for(self.window)
(res, n, f) = dlg.run()
if res == gtk.RESPONSE_OK:
i = _nd.add_name_format(n, f)
self.fmt_model.append(row=[i, n, f,
_nd.format_str(self.examplename, f)])
self.dbstate.db.name_formats = _nd.get_name_format(only_custom=True,
only_active=False)
def cb_del_fmt_str(self, obj):
"""
Name format editor Remove button callback
@ -807,13 +783,26 @@ class GrampsPreferences(ConfigureDialog):
# Display name:
self.examplename = Name()
examplesurname = Surname()
examplesurnamesecond = Surname()
examplesurnamepat = Surname()
self.examplename.set_title('Dr.')
self.examplename.set_first_name('Edwin Jose')
self.examplename.set_surname_prefix('von der')
self.examplename.set_surname('Smith')
examplesurname.set_prefix('von der')
examplesurname.set_surname('Smith')
examplesurname.set_connector('and')
self.examplename.add_surname(examplesurname)
examplesurnamesecond.set_surname('Weston')
self.examplename.add_surname(examplesurnamesecond)
examplesurnamepat.set_surname('Wilson')
examplesurnamepat.set_origintype(
NameOriginType(NameOriginType.PATRONYMIC))
self.examplename.add_surname(examplesurnamepat)
self.examplename.set_primary_surname(0)
self.examplename.set_suffix('Sr')
self.examplename.set_patronymic('Wilson')
self.examplename.set_call_name('Ed')
self.examplename.set_call_name('Jose')
self.examplename.set_nick_name('Ed')
self.examplename.set_family_nick_name('Underhills')
# get the model for the combo and the treeview
active = _nd.get_default_format()
self.fmt_model, active = self._build_name_format_model(active)
@ -1151,71 +1140,3 @@ class GrampsPreferences(ConfigureDialog):
button.add(image)
button.show()
return button
class NameFormatEditDlg(object):
"""
"""
def __init__(self, fmt_name, fmt_str, name):
self.fmt_name = fmt_name
self.fmt_str = fmt_str
self.name = name
self.valid = True
self.top = Glade()
self.dlg = self.top.get_object('namefmt_edit')
ManagedWindow.set_titles(self.dlg, None, _('Name Format Editor'))
self.examplelabel = self.top.get_object('example_label')
self.nameentry = self.top.get_object('name_entry')
self.nameentry.set_text('<span weight="bold">%s</span>' % self.fmt_name)
self.nameentry.set_use_markup(True)
self.formatentry = self.top.get_object('format_entry')
self.formatentry.connect('changed', self.cb_format_changed)
self.formatentry.set_text(self.fmt_str)
def run(self):
running = True
while running:
self.response = self.dlg.run()
running = False
self.fmt_name = self.nameentry.get_text()
self.fmt_str = self.formatentry.get_text()
if self.response == gtk.RESPONSE_OK:
if not self.valid:
q = QuestionDialog2(
_('The format definition is invalid'),
_('What would you like to do?'),
_('_Continue anyway'), _('_Modify format'),
parent=self.dlg)
running = not q.run()
self.response = gtk.RESPONSE_CANCEL
elif self.fmt_name == '' and self.fmt_str == '':
self.response = gtk.RESPONSE_CANCEL
elif (self.fmt_name == '') ^ (self.fmt_str == ''):
ErrorDialog(
_('Both Format name and definition have to be defined.'),
parent=self.dlg)
running = True
self.dlg.destroy()
return (self.response, self.fmt_name, self.fmt_str)
def cb_format_changed(self, obj):
try:
t = (_nd.format_str(self.name, escape(obj.get_text())))
sample = '<span weight="bold" style="italic">%s</span>' % t
self.valid = True
except NameDisplayError:
t = _("Invalid or incomplete format definition.")
sample = '<span foreground="#FF0000">%s</span>' % t
self.valid = False
self.examplelabel.set_text(sample)
self.examplelabel.set_use_markup(True)
self.nameentry.set_text('<span weight="bold">%s</span>' % obj.get_text())
self.nameentry.set_use_markup(True)

View File

@ -42,6 +42,8 @@ pkgdata_PYTHON = \
sourcebackreflist.py \
sourceembedlist.py \
sourcerefmodel.py \
surnamemodel.py \
surnametab.py \
webembedlist.py \
webmodel.py \
__init__.py

View File

@ -55,6 +55,7 @@ from personrefembedlist import PersonRefEmbedList
from personbackreflist import PersonBackRefList
from placebackreflist import PlaceBackRefList
from repoembedlist import RepoEmbedList
from surnametab import SurnameTab
from sourcebackreflist import SourceBackRefList
from sourceembedlist import SourceEmbedList
from webembedlist import WebEmbedList

View File

@ -443,6 +443,7 @@ class EmbeddedList(ButtonTab):
# insert the colum into the tree
column.set_resizable(True)
column.set_clickable(True)
column.set_expand(True)
column.set_min_width(self._column_names[pair[1]][2])
column.set_sort_column_id(self._column_names[pair[1]][1])
self.columns.append(column)

View File

@ -0,0 +1,55 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# Copyright (C) 2010 Benny Malengier
#
# 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$
#-------------------------------------------------------------------------
#
# GTK libraries
#
#-------------------------------------------------------------------------
import gtk
import gobject
#-------------------------------------------------------------------------
#
# GRAMPS classes
#
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
#
# SurnamModel
#
#-------------------------------------------------------------------------
class SurnameModel(gtk.ListStore):
def __init__(self, surn_list, db):
#setup model for the treeview
gtk.ListStore.__init__(self, str, str, str, str,
bool, object)
for surn in surn_list:
# fill the liststore
self.append(row=[surn.get_prefix(), surn.get_surname(),
surn.get_connector(), str(surn.get_origintype()),
surn.get_primary(), surn])
self.db = db

View File

@ -0,0 +1,385 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# Copyright (C) 2010 Benny Malengier
#
# 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$
#-------------------------------------------------------------------------
#
# Python classes
#
#-------------------------------------------------------------------------
from gen.ggettext import gettext as _
import locale
#-------------------------------------------------------------------------
#
# GTK classes
#
#-------------------------------------------------------------------------
import gtk
import gobject
import pango
_TAB = gtk.gdk.keyval_from_name("Tab")
_ENTER = gtk.gdk.keyval_from_name("Enter")
#-------------------------------------------------------------------------
#
# GRAMPS classes
#
#-------------------------------------------------------------------------
from surnamemodel import SurnameModel
from embeddedlist import EmbeddedList
from DdTargets import DdTargets
import AutoComp
from gen.lib import Surname, NameOriginType
#-------------------------------------------------------------------------
#
# SurnameTab
#
#-------------------------------------------------------------------------
class SurnameTab(EmbeddedList):
_HANDLE_COL = 5
_DND_TYPE = DdTargets.SURNAME
_MSG = {
'add' : _('Create and add a new surname'),
'del' : _('Remove the selected surname'),
'edit' : _('Edit the selected surname'),
'up' : _('Move the selected surname upwards'),
'down' : _('Move the selected surname downwards'),
}
#index = column in model. Value =
# (name, sortcol in model, width, markup/text
_column_names = [
(_('Prefix'), -1, 150, 0, -1),
(_('Surname'), -1, 250, 0, -1),
(_('Connector'), -1, 100, 0, -1),
]
_column_combo = (_('Origin'), -1, 150, 3) # name, sort, width, modelcol
_column_toggle = (_('Primary'), -1, 80, 4)
def __init__(self, dbstate, uistate, track, name):
self.obj = name
self.curr_col = -1
self.curr_cellr = None
self.curr_celle = None
EmbeddedList.__init__(self, dbstate, uistate, track, _('Family Surnames'),
SurnameModel, move_buttons=True)
def build_columns(self):
#first the standard text columns with normal method
EmbeddedList.build_columns(self)
# Need to add attributes to renderers
# and connect renderers to the 'edited' signal
for colno in range(len(self.columns)):
for renderer in self.columns[colno].get_cell_renderers():
renderer.set_property('editable', not self.dbstate.db.readonly)
renderer.connect('editing_started', self.on_edit_start, colno)
renderer.connect('edited', self.on_edit_inline, self.column_order()[colno][1])
# now we add the two special columns
# combobox for type
colno = len(self.columns)
name = self._column_combo[0]
renderer = gtk.CellRendererCombo()
renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
# set up the comboentry editable
no = NameOriginType()
self.cmborig = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING)
self.cmborigmap = no.get_map().copy()
keys = sorted(self.cmborigmap, self.by_value)
for key in keys:
if key != no.get_custom():
self.cmborig.append(row=[key, self.cmborigmap[key]])
additional = self.dbstate.db.get_origin_types()
if additional:
for type in additional:
if type:
self.cmborig.append(row=[no.get_custom(), type])
renderer.set_property("model", self.cmborig)
renderer.set_property("text-column", 1)
renderer.set_property('editable', not self.dbstate.db.readonly)
renderer.connect('editing_started', self.on_edit_start_cmb, colno)
renderer.connect('edited', self.on_orig_edited, self._column_combo[3])
# add to treeview
column = gtk.TreeViewColumn(name, renderer, text=self._column_combo[3])
column.set_resizable(True)
column.set_sort_column_id(self._column_combo[1])
column.set_min_width(self._column_combo[2])
column.set_expand(True)
self.columns.append(column)
self.tree.append_column(column)
# toggle box for primary
colno += 1
name = self._column_toggle[0]
renderer = gtk.CellRendererToggle()
renderer.set_property('activatable', True)
renderer.set_property('radio', True)
renderer.connect( 'toggled', self.on_prim_toggled, self._column_toggle[3])
# add to treeview
column = gtk.TreeViewColumn(name, renderer, active=self._column_toggle[3])
column.set_resizable(False)
column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
column.set_alignment(0.5)
column.set_sort_column_id(self._column_toggle[1])
column.set_min_width(self._column_toggle[2])
self.columns.append(column)
self.tree.append_column(column)
def by_value(self, first, second):
"""
Method for sorting keys based on the values.
"""
fvalue = self.cmborigmap[first]
svalue = self.cmborigmap[second]
return locale.strcoll(fvalue, svalue)
def get_data(self):
return self.obj.get_surname_list()
def is_empty(self):
return len(self.model)==0
def _get_surn_from_model(self):
"""
Return new surname_list for storing in the name based on content of
the model
"""
new_list = []
for idx in range(len(self.model)):
node = self.model.get_iter(idx)
surn = self.model.get_value(node, 5)
surn.set_prefix(unicode(self.model.get_value(node, 0)))
surn.set_surname(unicode(self.model.get_value(node, 1)))
surn.set_connector(unicode(self.model.get_value(node, 2)))
surn.get_origintype().set(unicode(self.model.get_value(node, 3)))
surn.set_primary(self.model.get_value(node, 4))
new_list += [surn]
return new_list
def update(self):
"""
Store the present data in the model to the name object
"""
new_map = self._get_surn_from_model()
self.obj.set_surname_list(new_map)
# update name in title name editor
# TODO
def column_order(self):
# order of columns for EmbeddedList. Only the text columns here
return ((1, 0), (1, 1), (1, 2))
def add_button_clicked(self, obj):
"""Add button is clicked, add a surname to the person"""
prim = False
if len(self.obj.get_surname_list()) == 0:
prim = true
node = self.model.append(row=['', '', '', NameOriginType(), prim,
Surname()])
self.selection.select_iter(node)
path = self.model.get_path(node)
self.tree.set_cursor_on_cell(path,
focus_column=self.columns[0],
focus_cell=None,
start_editing=True)
def del_button_clicked(self, obj):
"""
Delete button is clicked. Remove from the model
"""
(model, node) = self.selection.get_selected()
if node:
self.model.remove(node)
self.update()
def on_edit_start(self, cellr, celle, path, colnr):
""" start of editing. Store stuff so we know when editing ends where we
are
"""
self.curr_col = colnr
self.curr_cellr = cellr
self.curr_celle = celle
def on_edit_start_cmb(self, cellr, celle, path, colnr):
"""
An edit starts in the origin type column
This means a cmb has been created as celle, and we can set up the stuff
we want this cmb to contain: autocompletion, stop edit when selection
in the cmb happens.
"""
self.on_edit_start(cellr, celle, path, colnr)
#set up autocomplete
completion = gtk.EntryCompletion()
completion.set_model(self.cmborig)
completion.set_minimum_key_length(1)
completion.set_text_column(1)
celle.child.set_completion(completion)
#
celle.connect('changed', self.on_origcmb_change, path, colnr)
def on_edit_start_toggle(self, cellr, celle, path, colnr):
"""
Edit
"""
self.on_edit_start(cellr, celle, path, colnr)
def on_edit_inline(self, cell, path, new_text, colnr):
"""
Edit is happening. The model is updated and the surname objects updated.
colnr must be the column in the model.
"""
node = self.model.get_iter(path)
self.model.set_value(node, colnr, new_text)
self.update()
def on_orig_edited(self, cellr, path, new_text, colnr):
"""
An edit is finished in the origin type column. For a cmb in an editor,
the model may only be updated when typing is finished, as editing stops
automatically on update of the model.
colnr must be the column in the model.
"""
self.on_edit_inline(cellr, path, new_text, colnr)
def on_origcmb_change(self, cmb, path, colnr):
"""
A selection occured in the cmb of the origin type column. colnr must
be the column in the model.
"""
act = cmb.get_active()
if act == -1:
return
self.on_orig_edited(None, path,
self.cmborig.get_value(
self.cmborig.get_iter((act,)),1),
colnr)
def on_prim_toggled(self, cell, path, colnr):
"""
Primary surname on path is toggled. colnr must be the col
in the model
"""
#obtain current value
node = self.model.get_iter(path)
old_val = self.model.get_value(node, colnr)
for nr in range(len(self.obj.get_surname_list())):
if nr == int(path[0]):
if old_val:
#True remains True
break
else:
#This value becomes True
self.model.set_value(self.model.get_iter((nr,)), colnr, True)
else:
self.model.set_value(self.model.get_iter((nr,)), colnr, False)
self.update()
return
def edit_button_clicked(self, obj):
""" Edit button clicked
"""
(model, node) = self.selection.get_selected()
if node:
path = self.model.get_path(node)
self.tree.set_cursor_on_cell(path,
focus_column=self.columns[0],
focus_cell=None,
start_editing=True)
def key_pressed(self, obj, event):
"""
Handles the key being pressed.
Here we make sure tab moves to next or previous value in row on TAB
"""
if not EmbeddedList.key_pressed(self, obj, event):
if event.type == gtk.gdk.KEY_PRESS and event.keyval in (_TAB,):
if event.state not in (gtk.gdk.SHIFT_MASK, gtk.gdk.CONTROL_MASK):
return self.next_cell()
elif event.state in (gtk.gdk.SHIFT_MASK, gtk.gdk.CONTROL_MASK):
return self.prev_cell()
else:
return
else:
return
return True
def next_cell(self):
"""
Move to the next cell to edit it
"""
(model, node) = self.selection.get_selected()
if node:
path = int(self.model.get_path(node)[0])
nccol = self.curr_col+1
if nccol < 4:
self.tree.set_cursor_on_cell(path,
focus_column=self.columns[nccol],
focus_cell=None,
start_editing=True)
elif nccol == 4:
#go to next line if there is one
if path < len(self.obj.get_surname_list()):
newpath = (path+1,)
self.selection.select_path(newpath)
self.tree.set_cursor_on_cell(newpath,
focus_column=self.columns[0],
focus_cell=None,
start_editing=True)
else:
#stop editing
self.curr_celle.editing_done()
return
return True
def prev_cell(self):
"""
Move to the next cell to edit it
"""
(model, node) = self.selection.get_selected()
if node:
path = int(self.model.get_path(node)[0])
if self.curr_col > 0:
self.tree.set_cursor_on_cell(path,
focus_column=self.columns[self.curr_col-1],
focus_cell=None,
start_editing=True)
elif self.curr_col == 0:
#go to prev line if there is one
if path > 0:
newpath = (path-1,)
self.selection.select_path(newpath)
self.tree.set_cursor_on_cell(newpath,
focus_column=self.columns[-2],
focus_cell=None,
start_editing=True)
else:
#stop editing
self.curr_celle.editing_done()
return
return True

View File

@ -28,7 +28,9 @@
# Standard python modules
#
#-------------------------------------------------------------------------
import gobject
from gen.ggettext import gettext as _
from copy import copy
#-------------------------------------------------------------------------
#
@ -45,7 +47,7 @@ import gtk
from gen.display.name import displayer as name_displayer
from editsecondary import EditSecondary
from gen.lib import NoteType
from displaytabs import GrampsTab,SourceEmbedList,NoteTab
from displaytabs import GrampsTab, SourceEmbedList, NoteTab, SurnameTab
from gui.widgets import (MonitoredEntry, MonitoredMenu, MonitoredDate,
MonitoredDataType, PrivacyButton)
from glade import Glade
@ -111,12 +113,13 @@ class EditName(EditSecondary):
self.top = Glade()
self.set_window(self.top.toplevel,
self.top.get_object("title"),
_("Name Editor"))
self.set_window(self.top.toplevel, None, _("Name Editor"))
tblgnam = self.top.get_object('table23')
notebook = self.top.get_object('notebook')
hbox_surn = self.top.get_object('hboxmultsurnames')
hbox_surn.pack_start(SurnameTab(self.dbstate, self.uistate, self.track,
self.obj))
#recreate start page as GrampsTab
notebook.remove_page(0)
self.gennam = GeneralNameTab(self.dbstate, self.uistate, self.track,
@ -147,7 +150,19 @@ class EditName(EditSecondary):
def _connect_signals(self):
self.define_cancel_button(self.top.get_object('button119'))
self.define_help_button(self.top.get_object('button131'))
self.define_ok_button(self.top.get_object('button118'),self.save)
self.define_ok_button(self.top.get_object('button118'), self.save)
def _validate_call(self, widget, text):
""" a callname must be a part of the given name, see if this is the
case """
validcall = self.given_field.obj.get_text().split()
dummy = copy(validcall)
for item in dummy:
validcall += item.split('-')
if text in validcall:
return
return ValidationError(_("Call name must be the given name that "
"is normally used."))
def _setup_fields(self):
self.group_as = MonitoredEntry(
@ -180,7 +195,7 @@ class EditName(EditSecondary):
self.db.readonly)
self.given_field = MonitoredEntry(
self.top.get_object("alt_given"),
self.top.get_object("given_name"),
self.obj.set_first_name,
self.obj.get_first_name,
self.db.readonly)
@ -190,39 +205,42 @@ class EditName(EditSecondary):
self.obj.set_call_name,
self.obj.get_call_name,
self.db.readonly)
self.call_field.connect("validate", self._validate_call)
#force validation now with initial entry
self.call_field.obj.validate(force=True)
self.title_field = MonitoredEntry(
self.top.get_object("alt_title"),
self.top.get_object("title_field"),
self.obj.set_title,
self.obj.get_title,
self.db.readonly)
self.suffix_field = MonitoredEntry(
self.top.get_object("alt_suffix"),
self.top.get_object("suffix"),
self.obj.set_suffix,
self.obj.get_suffix,
self.db.readonly)
self.patronymic_field = MonitoredEntry(
self.top.get_object("patronymic"),
self.obj.set_patronymic,
self.obj.get_patronymic,
self.nick = MonitoredEntry(
self.top.get_object("nickname"),
self.obj.set_nick_name,
self.obj.get_nick_name,
self.db.readonly)
self.surname_field = MonitoredEntry(
self.top.get_object("alt_surname"),
self.obj.set_surname,
self.obj.get_surname,
self.db.readonly,
autolist=self.db.get_surname_list() if not self.db.readonly else [],
changed=self.update_group_as)
self.prefix_field = MonitoredEntry(
self.top.get_object("alt_prefix"),
self.obj.set_surname_prefix,
self.obj.get_surname_prefix,
self.famnick = MonitoredEntry(
self.top.get_object("familynickname"),
self.obj.set_family_nick_name,
self.obj.get_family_nick_name,
self.db.readonly)
#self.surname_field = MonitoredEntry(
# self.top.get_object("alt_surname"),
# self.obj.set_surname,
# self.obj.get_surname,
# self.db.readonly,
# autolist=self.db.get_surname_list() if not self.db.readonly else [],
# changed=self.update_group_as)
self.date = MonitoredDate(
self.top.get_object("date_entry"),
self.top.get_object("date_stat"),
@ -232,7 +250,7 @@ class EditName(EditSecondary):
self.db.readonly)
self.obj_combo = MonitoredDataType(
self.top.get_object("name_type"),
self.top.get_object("ntype"),
self.obj.set_type,
self.obj.get_type,
self.db.readonly,
@ -322,7 +340,7 @@ class EditName(EditSecondary):
surname = self.obj.get_surname()
self.group_as.set_text(surname)
def save(self,*obj):
def save(self, *obj):
"""Save the name setting. All is ok, except grouping. We need to
consider:
1/ global set, not local set --> unset (ask if global unset)

View File

@ -32,6 +32,7 @@ to edit information about a particular Person.
# Standard python modules
#
#-------------------------------------------------------------------------
from copy import copy
from gen.ggettext import sgettext as _
#-------------------------------------------------------------------------
@ -59,11 +60,12 @@ from editmediaref import EditMediaRef
from editname import EditName
import config
from QuestionDialog import ErrorDialog, ICON
from Errors import ValidationError
from displaytabs import (PersonEventEmbedList, NameEmbedList, SourceEmbedList,
AttrEmbedList, AddrEmbedList, NoteTab, GalleryTab,
WebEmbedList, PersonRefEmbedList, LdsEmbedList,
PersonBackRefList)
PersonBackRefList, SurnameTab)
from gen.plug import CATEGORY_QR_PERSON
#-------------------------------------------------------------------------
@ -104,7 +106,11 @@ class EditPerson(EditPrimary):
This is used by the base class (EditPrimary).
"""
return gen.lib.Person()
person = gen.lib.Person()
#the editor requires a surname
person.primary_name.add_surname(gen.lib.Surname())
person.primary_name.set_primary_surname(0)
return person
def get_menu_title(self):
if self.obj and self.obj.get_handle():
@ -143,9 +149,14 @@ class EditPerson(EditPrimary):
self.obj_photo = self.top.get_object("personPix")
self.eventbox = self.top.get_object("eventbox1")
self.singsurnfr = self.top.get_object("surnamefr")
self.multsurnfr = self.top.get_object("multsurnamefr")
self.singlesurn_active = True
self.surntab = SurnameTab(self.dbstate, self.uistate, self.track,
self.obj.get_primary_name())
self.top.get_object("hboxmultsurnames").pack_start(self.surntab)
self.set_contexteventbox(self.top.get_object("eventboxtop"))
def _post_init(self):
"""
@ -158,10 +169,18 @@ class EditPerson(EditPrimary):
"""
self.load_person_image()
if self.pname.get_surname() and not self.pname.get_first_name():
self.given.grab_focus()
self.given.grab_focus()
if len(self.obj.get_primary_name().get_surname_list()) > 1:
self.singsurnfr.hide_all()
self.singlesurn_active = False
else:
self.surname_field.grab_focus()
self.multsurnfr.hide_all()
self.singlesurn_active = True
#if self.pname.get_surname() and not self.pname.get_first_name():
# self.given.grab_focus()
#else:
# self.surname_field.grab_focus()
def _connect_signals(self):
"""
@ -173,8 +192,10 @@ class EditPerson(EditPrimary):
self.define_help_button(self.top.get_object("button134"))
self.given.connect("focus_out_event", self._given_focus_out_event)
self.top.get_object("button177").connect("clicked",
self.top.get_object("editnamebtn").connect("clicked",
self._edit_name_clicked)
self.top.get_object("multsurnamebtn").connect("clicked",
self._mult_surn_clicked)
self.eventbox.connect('button-press-event',
self._image_button_press)
@ -229,6 +250,18 @@ class EditPerson(EditPrimary):
# we just rebuild the view always
self.event_list.rebuild_callback()
def _validate_call(self, widget, text):
""" a callname must be a part of the given name, see if this is the
case """
validcall = self.given.obj.get_text().split()
dummy = copy(validcall)
for item in dummy:
validcall += item.split('-')
if text in validcall:
return
return ValidationError(_("Call name must be the given name that "
"is normally used."))
def _setup_fields(self):
"""
Connect the GrampsWidget objects to field in the interface.
@ -260,44 +293,64 @@ class EditPerson(EditPrimary):
self.pname.get_type,
self.db.readonly,
self.db.get_name_types())
self.prefix_suffix = widgets.MonitoredComboSelectedEntry(
self.top.get_object("prefixcmb"),
self.top.get_object("prefixentry"),
[_('Prefix'), _('Suffix')],
[self.pname.set_surname_prefix, self.pname.set_suffix],
[self.pname.get_surname_prefix, self.pname.get_suffix],
default = config.get('interface.prefix-suffix'),
read_only = self.db.readonly)
self.patro_title = widgets.MonitoredComboSelectedEntry(
self.top.get_object("patrocmb"),
self.top.get_object("patroentry"),
[_('Patronymic'), _('Person|Title')],
[self.pname.set_patronymic, self.pname.set_title],
[self.pname.get_patronymic, self.pname.get_title],
default = config.get('interface.patro-title'),
read_only = self.db.readonly)
self.call = widgets.MonitoredEntry(
self.top.get_object("call"),
self.pname.set_call_name,
self.pname.get_call_name,
self.db.readonly)
#part of Given Name section
self.given = widgets.MonitoredEntry(
self.top.get_object("given_name"),
self.pname.set_first_name,
self.pname.get_first_name,
self.db.readonly)
self.call = widgets.MonitoredEntry(
self.top.get_object("call"),
self.pname.set_call_name,
self.pname.get_call_name,
self.db.readonly)
self.call.connect("validate", self._validate_call)
#force validation now with initial entry
self.call.obj.validate(force=True)
self.title = widgets.MonitoredEntry(
self.top.get_object("title"),
self.pname.set_title,
self.pname.get_title,
self.db.readonly)
self.suffix = widgets.MonitoredEntry(
self.top.get_object("suffix"),
self.pname.set_suffix,
self.pname.get_suffix,
self.db.readonly)
self.nick = widgets.MonitoredEntry(
self.top.get_object("nickname"),
self.pname.set_nick_name,
self.pname.get_nick_name,
self.db.readonly)
#part of Single Surname section
self.surname_field = widgets.MonitoredEntry(
self.top.get_object("surname"),
self.pname.set_surname,
self.pname.get_surname,
self.pname.get_primary_surname().set_surname,
self.pname.get_primary_surname().get_surname,
self.db.readonly,
autolist=self.db.get_surname_list() if not self.db.readonly else [])
self.prefix = widgets.MonitoredEntry(
self.top.get_object("prefix"),
self.pname.get_primary_surname().set_prefix,
self.pname.get_primary_surname().get_prefix,
self.db.readonly)
self.ortype_field = widgets.MonitoredDataType(
self.top.get_object("cmborigin"),
self.pname.get_primary_surname().set_origintype,
self.pname.get_primary_surname().get_origintype,
self.db.readonly,
self.db.get_origin_types())
#other fields
self.tags = widgets.MonitoredTagList(
self.top.get_object("tag_label"),
self.top.get_object("tag_button"),
@ -314,11 +367,11 @@ class EditPerson(EditPrimary):
self.db.readonly)
#make sure title updates automatically
for obj in [self.top.get_object("surname"),
self.top.get_object("given_name"),
self.top.get_object("patroentry"),
for obj in [self.top.get_object("given_name"),
self.top.get_object("call"),
self.top.get_object("prefixentry"),
self.top.get_object("suffix"),
self.top.get_object("prefix"),
self.top.get_object("surname"),
]:
obj.connect('changed', self._changed_name)
@ -767,6 +820,14 @@ class EditPerson(EditPrimary):
EditName(self.dbstate, self.uistate, self.track,
self.pname, self._update_name)
def _mult_surn_clicked(self, obj):
"""
Show the list entry of multiple surnames
"""
self.singsurnfr.hide_all()
self.singlesurn_active = False
self.multsurnfr.show_all()
def _update_name(self, name):
"""
Called when the primary name has been changed by the EditName
@ -775,9 +836,15 @@ class EditPerson(EditPrimary):
This allows us to update the main form in response to any changes.
"""
for obj in (self.prefix_suffix, self.patro_title, self.given,
self.ntype_field, self.surname_field, self.call):
for obj in (self.ntype_field, self.given, self.call, self.title,
self.suffix, self.nick, self.surname_field, self.prefix,
self.ortype_field):
obj.update()
if len(self.obj.get_primary_name().get_surname_list()) > 1:
#TODO: multiple surname must be activated if not yet the case
print 'person editor TODO'
#TODO: update list of surnames
print 'person editor TODO 2'
def load_person_image(self):
"""
@ -887,9 +954,8 @@ class EditPerson(EditPrimary):
return child_ref_list
def _cleanup_on_exit(self):
config.set('interface.prefix-suffix', self.prefix_suffix.active_key)
config.set('interface.patro-title', self.patro_title.active_key)
config.save()
pass
#config.save()
class GenderDialog(gtk.MessageDialog):

View File

@ -32,6 +32,7 @@ class EditSecondary(ManagedWindow.ManagedWindow, DbGUIElement):
"""Create an edit window. Associates a person with the window."""
self.obj = obj
self.old_obj = obj.serialize()
self.dbstate = state
self.uistate = uistate
self.db = state.db
@ -113,13 +114,20 @@ class EditSecondary(ManagedWindow.ManagedWindow, DbGUIElement):
button.set_sensitive(not self.db.readonly)
def define_cancel_button(self,button):
button.connect('clicked',self.close)
button.connect('clicked', self.canceledits)
def define_help_button(self, button, webpage='', section=''):
button.connect('clicked', lambda x: GrampsDisplay.help(webpage,
section))
def close(self,*obj):
def canceledits(self, *obj):
"""
Undo the edits that happened on this secondary object
"""
self.obj.unserialize(self.old_obj)
self.close(obj)
def close(self, *obj):
self._cleanup_db_connects()
self._cleanup_on_exit()
ManagedWindow.ManagedWindow.close(self)

View File

@ -185,7 +185,7 @@ class PeopleBaseModel(object):
def sort_name(self, data):
n = Name()
n.unserialize(data[COLUMN_NAME])
return (n.get_surname(), n.get_first_name())
return (n.get_primary_surname().get_surname(), n.get_first_name())
def column_name(self, data):
handle = data[0]
@ -512,7 +512,6 @@ class PersonTreeModel(PeopleBaseModel, TreeBaseModel):
data The object data.
"""
ngn = name_displayer.name_grouping_data
nsn = name_displayer.raw_sorted_name
name_data = data[COLUMN_NAME]
group_name = ngn(self.db, name_data)

View File

@ -498,14 +498,12 @@ class GedcomWriter(UpdateCallback):
"""
Write the names associated with the person to the current level.
Since nicknames are now separate from the name structure, we search
the attribute list to see if we can find a nickname. Because we do
not know the mappings, we just take the first nickname we find, and
add it to the primary name.
Since nicknames in version < 3.3 are separate from the name structure,
we search the attribute list to see if we can find a nickname.
Because we do not know the mappings, we just take the first nickname
we find, and add it to the primary name.
If a nickname is present in the name structure, it has precedence
All other names are assumed to not have a nickname, even if other
nicknames exist in the attribute list.
"""
nicknames = [ attr.get_value() for attr in person.get_attribute_list()
if int(attr.get_type()) == gen.lib.AttributeType.NICKNAME ]
@ -1193,7 +1191,7 @@ class GedcomWriter(UpdateCallback):
elif date.get_text():
self.__writeln(level, 'DATE', date.get_text())
def __person_name(self, name, nick):
def __person_name(self, name, attr_nick):
"""
n NAME <NAME_PERSONAL> {1:1}
+1 NPFX <NAME_PIECE_PREFIX> {0:1}
@ -1208,13 +1206,21 @@ class GedcomWriter(UpdateCallback):
gedcom_name = name.get_gedcom_name()
firstname = name.get_first_name().strip()
patron = name.get_patronymic().strip()
if patron:
firstname = "%s %s" % (firstname, patron)
surname = name.get_surname().replace('/', '?')
surprefix = name.get_surname_prefix().replace('/', '?')
surns = []
surprefs = []
for surn in name.get_surname_list():
surns.append(surn.get_surname().replace('/', '?'))
if surn.get_connector():
#we store connector with the surname
surns[-1] = surns[-1] + ' ' + surn.get_connector()
surprefs.append(surn.get_prefix().replace('/', '?'))
surname = ', '.join(surns)
surprefix = ', '.join(surprefs)
suffix = name.get_suffix()
title = name.get_title()
nick = name.get_nick_name()
if nick.strip() == '':
nick = attr_nick
self.__writeln(1, 'NAME', gedcom_name)
@ -1224,7 +1230,6 @@ class GedcomWriter(UpdateCallback):
self.__writeln(2, 'SPFX', surprefix)
if surname:
self.__writeln(2, 'SURN', surname)
if name.get_suffix():
self.__writeln(2, 'NSFX', suffix)
if name.get_title():

View File

@ -783,16 +783,26 @@ class GrampsXmlWriter(UpdateCallback):
if rel != "":
self.g.write(' %s<rel type="%s"/>\n' % (sp,rel) )
def write_last(self, name,indent=1):
p = name.get_surname_prefix()
n = name.get_surname()
g = name.get_group_as()
self.g.write('%s<last' % (' '*indent))
if p:
self.g.write(' prefix="%s"' % escxml(p))
if g:
self.g.write(' group="%s"' % escxml(g))
self.g.write('>%s</last>\n' % self.fix(n))
def write_surname(self, surname, indent=1):
"""
Writes a surname of the name
"""
pre = surname.get_prefix()
con = surname.get_connector()
nam = surname.get_surname()
der = surname.get_origintype().xml_str()
pri = surname.get_primary()
self.g.write('%s<surname' % (' '*indent))
if pre:
self.g.write(' prefix="%s"' % escxml(pre))
if not pri:
self.g.write(' prim="0"')
if con:
self.g.write(' connector="%s"' % escxml(con))
if der:
self.g.write(' derivation="%s"' % escxml(der))
self.g.write('>%s</surname>\n' % self.fix(nam))
def write_line(self,tagname,value,indent=1):
if value:
@ -915,12 +925,15 @@ class GrampsXmlWriter(UpdateCallback):
if name.get_display_as() != 0:
self.g.write(' display="%d"' % name.get_display_as())
self.g.write('>\n')
self.write_line("first", name.get_first_name(),index+1)
self.write_line("call", name.get_call_name(),index+1)
self.write_last(name,index+1)
self.write_line("suffix", name.get_suffix(),index+1)
self.write_line("patronymic", name.get_patronymic(),index+1)
self.write_line("title", name.get_title(),index+1)
self.write_line("first", escxml(name.get_first_name()),index+1)
self.write_line("call", escxml(name.get_call_name()),index+1)
for surname in name.get_surname_list():
self.write_surname(surname,index+1)
self.write_line("suffix", escxml(name.get_suffix()),index+1)
self.write_line("title", escxml(name.get_title()),index+1)
self.write_line("nick", escxml(name.get_nick_name()), index+1)
self.write_line("familynick", escxml(name.get_family_nick_name()), index+1)
self.write_line("group", escxml(name.get_group_as()), index+1)
if name.date:
self.write_date(name.date,4)
self.write_note_list(name.get_note_list(),index+1)

View File

@ -77,8 +77,9 @@ def find_surname(key, data):
"""
Return the surname from the data stream. Used for building a secondary
index.
This function is not needed, as we don't use the secondary index.
"""
return str(data[3][5])
return str("a")
def find_idmap(key, data):
"""
@ -138,6 +139,10 @@ class GrampsBSDDB(DbGrdb, UpdateCallback):
This is replaced for internal use by gen/db/dbdir.py
However, this class is still used for import of the 2.2.x
GRDB format. In 3.0+ this format is no longer used.
We only need to upgrade the old main tables.
That will be used to append data to the database this GrampsBSDDB is
imported to.
"""
def __init__(self, use_txn = True):
@ -1247,19 +1252,6 @@ class GrampsBSDDB(DbGrdb, UpdateCallback):
self.surname_list = list(set(self.surnames.keys()))
self.sort_surname_list()
def remove_from_surname_list(self, person):
"""
Check whether there are persons with the same surname left in
the database. If not then we need to remove the name from the list.
The function must be overridden in the derived class.
"""
name = str(person.get_primary_name().get_surname())
try:
if self.surnames.keys().count(name) == 1:
self.surname_list.remove(unicode(name))
except ValueError:
pass
def __get_obj_from_gramps_id(self, val, tbl, class_init, prim_tbl):
if tbl.has_key(str(val)):
#if str(val) in tbl:
@ -1563,6 +1555,8 @@ class GrampsBSDDB(DbGrdb, UpdateCallback):
self.gramps_upgrade_13()
if version < 14:
self.gramps_upgrade_14()
if version < 15:
self.gramps_upgrade_15()
LOG.debug("Upgrade time: %s %s", int(time.time()-t), "seconds")
def gramps_upgrade_10(self):
@ -2589,6 +2583,108 @@ class GrampsBSDDB(DbGrdb, UpdateCallback):
name_type, prefix, patronymic,
group_as, sort_as, display_as, call)
def gramps_upgrade_15(self):
"""Upgrade database from version 14 to 15. This upgrade adds:
* tagging
* surname list
"""
length = len(self.person_map)+10
self.set_total(length)
# ---------------------------------
# Modify Person
# ---------------------------------
for handle in self.person_map.keys():
person = self.person_map[handle]
(junk_handle, # 0
gramps_id, # 1
gender, # 2
primary_name, # 3
alternate_names, # 4
death_ref_index, # 5
birth_ref_index, # 6
event_ref_list, # 7
family_list, # 8
parent_family_list, # 9
media_list, # 10
address_list, # 11
attribute_list, # 12
urls, # 13
ord_list, # 14
psource_list, # 15
pnote_list, # 16
change, # 17
marker, # 18
pprivate, # 19
person_ref_list, # 20
) = person
new_primary_name = self.convert_name_15(primary_name)
new_alternate_names = [self.convert_name_15(altname) for altname in
alternate_names]
new_person = (junk_handle, # 0
gramps_id, # 1
gender, # 2
new_primary_name, # 3
new_alternate_names,# 4
death_ref_index, # 5
birth_ref_index, # 6
event_ref_list, # 7
family_list, # 8
parent_family_list, # 9
media_list, # 10
address_list, # 11
attribute_list, # 12
urls, # 13
ord_list, # 14
psource_list, # 15
pnote_list, # 16
change, # 17
marker, # 18
pprivate, # 19
person_ref_list, # 20
[] # 21, tags
)
the_txn = self.env.txn_begin()
self.person_map.put(str(handle), new_person, txn=the_txn)
the_txn.commit()
self.update(length)
#surname is now different, normally remove secondary index with names
#we skip this, as this database will not be used after the import
# Bump up database version. Separate transaction to save metadata.
the_txn = self.env.txn_begin()
self.metadata.put('version', 15, txn=the_txn)
the_txn.commit()
def convert_name_15(self, name):
(privacy, source_list, note_list, date,
first_name, surname, suffix, title,
name_type, prefix, patronymic,
group_as, sort_as, display_as, call) = name
connector = u""
origintype = (NameOriginType.NONE, u"")
patorigintype = (NameOriginType.PATRONYMIC, u"")
if patronymic.strip() == u"":
#no patronymic, create a single surname
surname_list = [(surname, prefix, True, origintype, connector)]
else:
#a patronymic, if no surname or equal as patronymic, a single surname
if (surname.strip() == u"") or (surname == patronymic and prefix == u""):
surname_list = [(patronymic, prefix, True, patorigintype, connector)]
else:
#two surnames, first patronymic, then surname which is primary
surname_list = [(patronymic, u"", False, patorigintype, u""),
(surname, prefix, True, origintype, connector)]
#return new value, add two empty strings for nick and family nick
return (privacy, source_list, note_list, date,
first_name, surname_list, suffix, title, name_type,
group_as, sort_as, display_as, call, u"", u"")
def set_auto_remove(self):
"""
BSDDB change log settings using new method with renamed attributes

View File

@ -96,9 +96,23 @@ def importData(database, filename, callback=None, cl=0):
database.smap = {}
database.pmap = {}
database.fmap = {}
xml_file = open_file(filename, cl)
versionparser = VersionParser(xml_file)
if xml_file is None or \
version_is_valid(versionparser, cl) is False:
if cl:
sys.exit(1)
else:
return
version_string = versionparser.get_xmlns_version()
#reset file to the start
xml_file.seek(0)
change = os.path.getmtime(filename)
parser = GrampsParser(database, callback, change)
parser = GrampsParser(database, callback, change, version_string)
linecounter = LineParser(filename)
line_cnt = linecounter.get_count()
@ -107,17 +121,7 @@ def importData(database, filename, callback=None, cl=0):
read_only = database.readonly
database.readonly = False
xml_file = open_file(filename, cl)
if xml_file is None or \
version_is_valid(xml_file, cl) is False:
if cl:
sys.exit(1)
else:
return
try:
xml_file.seek(0)
info = parser.parse(xml_file, line_cnt, person_cnt)
except IOError, msg:
if cl:
@ -348,8 +352,10 @@ class LineParser(object):
#-------------------------------------------------------------------------
class GrampsParser(UpdateCallback):
def __init__(self, database, callback, change):
def __init__(self, database, callback, change, version_string):
UpdateCallback.__init__(self, callback)
#version of the xml file
self.version_string = version_string
self.stext_list = []
self.scomments_list = []
self.note_list = []
@ -423,6 +429,8 @@ class GrampsParser(UpdateCallback):
self.childref = None
self.personref = None
self.name = None
self.surname = None
self.surnamepat = None
self.home = None
self.owner = gen.lib.Researcher()
self.func_list = [None]*50
@ -440,17 +448,33 @@ class GrampsParser(UpdateCallback):
self.eidswap = {}
self.func_map = {
#name part
"name": (self.start_name, self.stop_name),
"first": (None, self.stop_first),
"call": (None, self.stop_call),
"aka": (self.start_name, self.stop_aka), #deprecated < 1.3.0
"last": (self.start_last, self.stop_last), #deprecated in 1.4.0
"nick": (None, self.stop_nick),
"title": (None, self.stop_title),
"suffix": (None, self.stop_suffix),
"patronymic": (self.start_patronymic, self.stop_patronymic), #deprecated in 1.4.0
"familynick": (None, self.stop_familynick), #new in 1.4.0
"group": (None, self.stop_group), #new in 1.4.0, replaces attribute
#new in 1.4.0
"surname": (self.start_surname, self.stop_surname),
#
"namemaps": (None, None),
"name-formats": (None, None),
#other
"address": (self.start_address, self.stop_address),
"addresses": (None, None),
"childlist": (None, None),
"aka": (self.start_name, self.stop_aka),
"childlist": (None, None),
"attribute": (self.start_attribute, self.stop_attribute),
"attr_type": (None, self.stop_attr_type),
"attr_value": (None, self.stop_attr_value),
"bookmark": (self.start_bmark, None),
"bookmarks": (None, None),
"format": (self.start_format, None),
"name-formats": (None, None),
"child": (self.start_child, None),
"childof": (self.start_childof, None),
"childref": (self.start_childref, self.stop_childref),
@ -476,17 +500,11 @@ class GrampsParser(UpdateCallback):
"rel": (self.start_rel, None),
"region": (self.start_region, None),
"father": (self.start_father, None),
"first": (None, self.stop_first),
"call": (None, self.stop_call),
"gender": (None, self.stop_gender),
"header": (None, None),
"last": (self.start_last, self.stop_last),
"map": (self.start_namemap, None),
"mediapath": (None, self.stop_mediapath),
"mother": (self.start_mother, None),
"name": (self.start_name, self.stop_name),
"namemaps": (None, None),
"nick": (None, self.stop_nick),
"note": (self.start_note, self.stop_note),
"noteref": (self.start_noteref, None),
"p": (None, self.stop_ptag),
@ -511,7 +529,6 @@ class GrampsParser(UpdateCallback):
"status": (self.start_status, None),
"sealed_to": (self.start_sealed_to, None),
"coord": (self.start_coord, None),
"patronymic": (None, self.stop_patronymic),
"pos": (self.start_pos, None),
"postal": (None, self.stop_postal),
"range": (self.start_range, None),
@ -536,13 +553,11 @@ class GrampsParser(UpdateCallback):
"stext": (None, self.stop_stext),
"stitle": (None, self.stop_stitle),
"street": (None, self.stop_street),
"style": (self.start_style, None),
"suffix": (None, self.stop_suffix),
"style": (self.start_style, None),
"tag": (self.start_tag, None),
"tagref": (self.start_tagref, None),
"tags": (None, None),
"text": (None, self.stop_text),
"title": (None, self.stop_title),
"url": (self.start_url, None),
"repository": (self.start_repo, self.stop_repo),
"reporef": (self.start_reporef, self.stop_reporef),
@ -743,6 +758,11 @@ class GrampsParser(UpdateCallback):
return self.nidswap[gramps_id]
def parse(self, ifile, linecount=0, personcount=0):
"""
Parse the xml file
:param ifile: must be a file handle that is already open, with position
at the start of the file
"""
if personcount < 1000:
no_magic = True
else:
@ -1305,6 +1325,14 @@ class GrampsParser(UpdateCallback):
except KeyError:
pass
def start_surname(self, attrs):
self.surname = gen.lib.Surname()
self.surname.set_prefix(attrs.get("prefix", ""))
self.surname.set_primary(bool(attrs.get("primary",0)))
self.surname.set_connector(attrs.get("connector", ""))
origin_type = attrs.get("derivation", "")
self.surname.origintype.set_from_xml_str(origin_type)
def start_namemap(self, attrs):
type = attrs.get('type')
key = attrs['key']
@ -1321,9 +1349,17 @@ class GrampsParser(UpdateCallback):
self.db.set_name_group_mapping(key, value)
def start_last(self, attrs):
self.name.prefix = attrs.get('prefix', '')
""" This is the element in version < 1.4.0 to do the surname"""
self.surname = gen.lib.Surname()
self.surname.prefix = attrs.get('prefix', '')
self.name.group_as = attrs.get('group', '')
def start_patronymic(self, attrs):
""" This is the element in version < 1.4.0 to do the patronymic"""
self.surnamepat = gen.lib.Surname()
self.surnamepat.set_origintype(gen.lib.NameTypeOrigin(
gen.lib.NameTypeOrigin.PATRONYMIC))
def start_style(self, attrs):
"""
Styled text tag in notes (v1.4.0 onwards).
@ -1927,14 +1963,8 @@ class GrampsParser(UpdateCallback):
self.num_places = 0
def start_database(self, attrs):
try:
# This is a proper way to get the XML version
xmlns = attrs.get('xmlns')
self.version_string = xmlns.split('/')[4]
except:
# Before we had a proper DTD, the version was hard to determine
# so we're setting it to 1.0.0
self.version_string = '1.0.0'
# we already parsed xml once in VersionParser to obtain version
pass
def start_pos(self, attrs):
self.person.position = (int(attrs["x"]), int(attrs["y"]))
@ -2078,15 +2108,62 @@ class GrampsParser(UpdateCallback):
self.db.commit_note(note, self.trans, self.change)
self.info.add('new-object', NOTE_KEY, note)
self.event.add_note(note.handle)
elif self.alt_name:
# former aka tag -- alternate name
if self.name.get_type() == "":
self.name.set_type(gen.lib.NameType.AKA)
self.person.add_alternate_name(self.name)
else:
#first correct old xml that has no nametype set
if self.alt_name:
# alternate name or former aka tag
if self.name.get_type() == "":
self.name.set_type(gen.lib.NameType.AKA)
else:
if self.name.get_type() == "":
self.name.set_type(gen.lib.NameType.BIRTH)
#same logic as bsddb upgrade for xml < 1.4.0 which will
#have a surnamepat and/or surname. From 1.4.0 surname has been
#added to name in self.stop_surname
if not self.surnamepat:
#no patronymic, only add surname if present
if self.surname:
self.name.add_surname(self.surname)
self.name.set_primary_surname(0)
else:
#a patronymic, if no surname, a single surname
if not self.surname:
self.name.add_surname(self.surnamepat)
self.name.set_primary_surname(0)
else:
#two surnames, first patronymic, then surname which is primary
self.name.add_surname(self.surnamepat)
self.name.add_surname(self.surname)
self.name.set_primary_surname(1)
if self.alt_name:
self.person.add_alternate_name(self.name)
else:
self.person.set_primary_name(self.name)
self.name = None
self.surname = None
self.surnamepat = None
def stop_aka(self, tag):
if self.name.get_type() == "":
self.name.set_type(gen.lib.NameType.AKA)
if not self.surnamepat:
#no patronymic, only add surname if present
if self.surname:
self.name.add_surname(self.surname)
self.name.set_primary_surname(0)
else:
if self.name.get_type() == "":
self.name.set_type(gen.lib.NameType.BIRTH)
self.person.set_primary_name (self.name)
#a patronymic, if no surname, a single surname
if not self.surname:
self.name.add_surname(self.surnamepat)
self.name.set_primary_surname(0)
else:
#two surnames, first patronymic, then surname which is primary
self.name.add_surname(self.surnamepat)
self.name.add_surname(self.surname)
self.name.set_primary_surname(1)
self.person.add_alternate_name(self.name)
self.name = None
def stop_rname(self, tag):
@ -2256,28 +2333,53 @@ class GrampsParser(UpdateCallback):
self.source_ref.add_note(note.handle)
def stop_last(self, tag):
if self.surname:
self.surname.set_surname(tag)
if not tag.strip() and not self.surname.get_prefix().strip():
#consider empty surname as no surname
self.surname = None
def stop_surname(self, tag):
if self.name:
self.name.set_surname(tag)
self.surname.set_surname(tag)
self.name.add_surname(self.surname)
self.surname = None
def stop_group(self, tag):
""" group name of a name"""
if self.name:
self.name.set_group_as(tag)
def stop_suffix(self, tag):
if self.name:
self.name.set_suffix(tag)
def stop_patronymic(self, tag):
if self.name:
self.name.set_patronymic(tag)
if self.surnamepat:
self.surnamepat.set_surname(tag)
if not tag.strip():
self.surnamepat = None
def stop_title(self, tag):
if self.name:
self.name.set_title(tag)
def stop_nick(self, tag):
if self.person:
"""in < 1.3.0 nick is on person and mapped to attribute
from 1.4.0 it is a name element
"""
if self.name:
self.name.set_nick_name(tag)
elif self.person:
attr = gen.lib.Attribute()
attr.set_type(gen.lib.AttributeType.NICKNAME)
attr.set_value(tag)
self.person.add_attribute(attr)
def stop_familynick(self, tag):
if self.name:
self.name.set_family_nick_name(tag)
def stop_text(self, tag):
self.note_text = tag
@ -2379,12 +2481,6 @@ class GrampsParser(UpdateCallback):
elif self.in_scomments:
self.scomments_list.append(tag)
def stop_aka(self, tag):
self.person.add_alternate_name(self.name)
if self.name.get_type() == "":
self.name.set_type(gen.lib.NameType.AKA)
self.name = None
def startElement(self, tag, attrs):
self.func_list[self.func_index] = (self.func, self.tlist)
self.func_index += 1
@ -2469,7 +2565,6 @@ class VersionParser(object):
self.__p.StartElementHandler = self.__element_handler
self.__gramps_version = 'unknown'
self.__xml_version = '1.0.0'
xml_file.seek(0)
self.__p.ParseFile(xml_file)
@ -2541,25 +2636,25 @@ def open_file(filename, cli):
return xml_file
def version_is_valid(filename, cli):
def version_is_valid(versionparser, cli):
"""
Validate the xml version.
:param versionparser: A VersionParser object to work with
"""
parser = VersionParser(filename)
if parser.get_xmlns_version() > libgrampsxml.GRAMPS_XML_VERSION:
if versionparser.get_xmlns_version() > libgrampsxml.GRAMPS_XML_VERSION:
msg = _("The .gramps file you are importing was made by version %(newer)s of "
"Gramps, while you are running an older version %(older)s. "
"The file will not be imported. Please upgrade to the latest "
"version of Gramps and try again." ) % {
'newer' : parser.get_gramps_version(), 'older' : const.VERSION }
'newer' : versionparser.get_gramps_version(), 'older' : const.VERSION }
if cli:
LOG.warn(msg)
return False
else:
ErrorDialog(msg)
return False
if parser.get_xmlns_version() < '1.0.0':
if versionparser.get_xmlns_version() < '1.0.0':
msg = _("The .gramps file you are importing was made by version "
"%(oldgramps)s of Gramps, while you are running a more "
"recent version %(newgramps)s.\n\n"
@ -2567,9 +2662,9 @@ def version_is_valid(filename, cli):
" Gramps that supports version %(xmlversion)s of the xml.\nSee"
"\n http://gramps-project.org/wiki/index.php?title=GRAMPS_XML\n "
"for more info."
) % {'oldgramps': parser.get_gramps_version(),
) % {'oldgramps': versionparser.get_gramps_version(),
'newgramps': const.VERSION,
'xmlversion': parser.get_xmlns_version(),
'xmlversion': versionparser.get_xmlns_version(),
}
if cli:
LOG.warn(msg)
@ -2577,7 +2672,7 @@ def version_is_valid(filename, cli):
else:
ErrorDialog(_('The file will not be imported'), msg)
return False
elif parser.get_xmlns_version() < '1.1.0':
elif versionparser.get_xmlns_version() < '1.1.0':
msg = _("The .gramps file you are importing was made by version "
"%(oldgramps)s of Gramps, while you are running a much "
"more recent version %(newgramps)s.\n\n"
@ -2587,9 +2682,9 @@ def version_is_valid(filename, cli):
"is version %(xmlversion)s of the xml.\nSee"
"\n http://gramps-project.org/wiki/index.php?title=GRAMPS_XML\n"
"for more info."
) % {'oldgramps': parser.get_gramps_version(),
) % {'oldgramps': versionparser.get_gramps_version(),
'newgramps': const.VERSION,
'xmlversion': parser.get_xmlns_version(),
'xmlversion': versionparser.get_xmlns_version(),
}
if cli:
LOG.warn(msg)

View File

@ -1673,16 +1673,25 @@ class GedcomParser(UpdateCallback):
match = SURNAME_RE.match(text)
if match:
#/surname/ extra, we assume extra is given name
names = match.groups()
name.set_first_name(names[1].strip())
name.set_surname(names[0].strip())
surn = gen.lib.Surname()
surn.set_surname(names[0].strip())
surn.set_primary()
name.set_surname_list([surn])
else:
try:
names = NAME_RE.match(text).groups()
# given /surname/ extra, we assume extra is suffix
name.set_first_name(names[0].strip())
name.set_surname(names[2].strip())
surn = gen.lib.Surname()
surn.set_surname(names[2].strip())
surn.set_primary()
name.set_surname_list([surn])
name.set_suffix(names[4].strip())
except:
# something strange, set as first name
name.set_first_name(text.strip())
return name
@ -2782,7 +2791,7 @@ class GedcomParser(UpdateCallback):
sub_state.name = name
sub_state.level = 2
self.__parse_level(sub_state, self.name_parse_tbl, self.__undefined)
self.__parse_level(sub_state, self.name_parse_tbl, self.__undefined)
def __person_object(self, line, state):
"""
@ -3164,7 +3173,13 @@ class GedcomParser(UpdateCallback):
@param state: The current state
@type state: CurrentState
"""
state.name.set_surname_prefix(line.data.strip())
if state.name.get_surname_list():
state.name.get_surname_list()[0].set_prefix(line.data.strip())
else:
surn = gen.lib.Surname()
surn.set_prefix(line.data.strip())
surn.set_primary()
state.name.set_surname_list([surn])
self.__skip_subordinate_levels(state.level+1)
def __name_surn(self, line, state):
@ -3174,7 +3189,13 @@ class GedcomParser(UpdateCallback):
@param state: The current state
@type state: CurrentState
"""
state.name.set_surname(line.data.strip())
if state.name.get_surname_list():
state.name.get_surname_list()[0].set_surname(line.data.strip())
else:
surn = gen.lib.Surname()
surn.set_surname(line.data.strip())
surn.set_primary()
state.name.set_surname_list([surn])
self.__skip_subordinate_levels(state.level+1)
def __name_marnm(self, line, state):
@ -3188,7 +3209,10 @@ class GedcomParser(UpdateCallback):
data = text.split()
if len(data) == 1:
name = gen.lib.Name(state.person.primary_name)
name.set_surname(data[0].strip())
surn = gen.lib.Surname()
surn.set_surname(data[0].strip())
surn.set_primary()
name.set_surname_list([surn])
name.set_type(gen.lib.NameType.MARRIED)
state.person.add_alternate_name(name)
elif len(data) > 1:
@ -3203,8 +3227,12 @@ class GedcomParser(UpdateCallback):
@param state: The current state
@type state: CurrentState
"""
if state.name.get_suffix() == "":
if state.name.get_suffix() == "" or state.name.get_suffix() == line.data:
#suffix might be set before when parsing name string
state.name.set_suffix(line.data)
else:
#previously set suffix different, to not loose information, append
state.name.set_suffix(state.name.get_suffix() + ' ' + line.data)
self.__skip_subordinate_levels(state.level+1)
def __name_nick(self, line, state):
@ -3214,10 +3242,7 @@ class GedcomParser(UpdateCallback):
@param state: The current state
@type state: CurrentState
"""
attr = gen.lib.Attribute()
attr.set_type(gen.lib.AttributeType.NICKNAME)
attr.set_value(line.data)
state.person.add_attribute(attr)
state.name.set_nick_name(line.data.strip())
self.__skip_subordinate_levels(state.level+1)
def __name_aka(self, line, state):

View File

@ -211,6 +211,7 @@ class DbGrdb(Callback):
self.family_rel_types = set()
self.event_role_names = set()
self.name_types = set()
self.origin_types = set()
self.repository_types = set()
self.note_types = set()
self.source_media_types = set()

View File

@ -259,9 +259,12 @@ class BasePersonView(ListView):
Add a new person to the database.
"""
person = gen.lib.Person()
#the editor requires a surname
person.primary_name.add_surname(gen.lib.Surname())
person.primary_name.set_primary_surname(0)
try:
EditPerson(self.dbstate, self.uistate, [], gen.lib.Person())
EditPerson(self.dbstate, self.uistate, [], person)
except Errors.WindowActiveError:
pass

View File

@ -54,7 +54,7 @@ class SameSurname(Rule):
def apply(self, db, person):
src = self.list[0].upper()
for name in [person.get_primary_name()] + person.get_alternate_names():
if name.surname and name.surname.upper() == src.upper():
if name.get_surname() and name.get_surname().upper() == src.upper():
return True
return False
@ -103,7 +103,7 @@ def run(database, document, person):
surname = person
rsurname = person
# display the title
sdoc.title(_("People with the surname '%s'") % surname)
sdoc.title(_("People sharing the surname '%s'") % surname)
sdoc.paragraph("")
stab.columns(_("Person"), _("Birth Date"), _("Name type"))
filter = GenericFilterFactory('Person')()

View File

@ -37,6 +37,7 @@ import gtk
# gramps modules
#
#-------------------------------------------------------------------------
from gen.db import find_surname_name
import const
from gui.utils import ProgressMeter
import GrampsDisplay
@ -243,11 +244,12 @@ class ChangeNames(tool.BatchTool, ManagedWindow.ManagedWindow):
#person = Person(data)
change = False
for name in [person.get_primary_name()] + person.get_alternate_names():
sname = name.get_surname()
sname = find_surname_name(handle, name.serialize())
if sname in changelist:
change = True
sname = self.name_cap(sname)
name.set_surname(sname)
for surn in name.get_surname_list():
sname = self.name_cap(surn.get_surname())
surn.set_surname(sname)
if change:
#cursor.update(handle, person.serialize())
self.db.commit_person(person, transaction=self.trans)

View File

@ -144,7 +144,7 @@ class Merge(tool.Tool,ManagedWindow.ManagedWindow):
GrampsDisplay.help(WIKI_HELP_PAGE , WIKI_HELP_SEC)
def ancestors_of(self,p1_id,id_list):
def ancestors_of(self, p1_id, id_list):
if (not p1_id) or (p1_id in id_list):
return
id_list.append(p1_id)
@ -181,7 +181,7 @@ class Merge(tool.Tool,ManagedWindow.ManagedWindow):
except Errors.WindowActiveError:
pass
def find_potentials(self,thresh):
def find_potentials(self, thresh):
self.progress = ProgressMeter(_('Find Duplicates'),
_('Looking for duplicate people'))
@ -197,7 +197,7 @@ class Merge(tool.Tool,ManagedWindow.ManagedWindow):
for p1_id in self.db.iter_person_handles():
self.progress.step()
p1 = self.db.get_person_from_handle(p1_id)
key = self.gen_key(p1.get_primary_name().get_surname())
key = self.gen_key(get_surnames(p1.get_primary_name()))
if p1.get_gender() == gen.lib.Person.MALE:
if key in males:
males[key].append(p1_id)
@ -216,7 +216,7 @@ class Merge(tool.Tool,ManagedWindow.ManagedWindow):
self.progress.step()
p1 = self.db.get_person_from_handle(p1key)
key = self.gen_key(p1.get_primary_name().get_surname())
key = self.gen_key(get_surnames(p1.get_primary_name()))
if p1.get_gender() == gen.lib.Person.MALE:
remaining = males[key]
else:
@ -246,7 +246,7 @@ class Merge(tool.Tool,ManagedWindow.ManagedWindow):
self.length = len(self.list)
self.progress.close()
def gen_key(self,val):
def gen_key(self, val):
if self.use_soundex:
try:
return soundex.soundex(val)
@ -255,7 +255,7 @@ class Merge(tool.Tool,ManagedWindow.ManagedWindow):
else:
return val
def compare_people(self,p1,p2):
def compare_people(self, p1, p2):
name1 = p1.get_primary_name()
name2 = p2.get_primary_name()
@ -397,7 +397,7 @@ class Merge(tool.Tool,ManagedWindow.ManagedWindow):
chance += value
return chance
def name_compare(self,s1,s2):
def name_compare(self, s1, s2):
if self.use_soundex:
try:
return soundex.compare(s1,s2)
@ -406,7 +406,7 @@ class Merge(tool.Tool,ManagedWindow.ManagedWindow):
else:
return s1 == s2
def date_match(self,date1,date2):
def date_match(self, date1, date2):
if date1.is_empty() or date2.is_empty():
return 0
if date1.is_equal(date2):
@ -425,7 +425,7 @@ class Merge(tool.Tool,ManagedWindow.ManagedWindow):
else:
return -1
def range_compare(self,date1,date2):
def range_compare(self, date1, date2):
start_date_1 = date1.get_start_date()[0:3]
start_date_2 = date2.get_start_date()[0:3]
stop_date_1 = date1.get_stop_date()[0:3]
@ -454,9 +454,9 @@ class Merge(tool.Tool,ManagedWindow.ManagedWindow):
if not name1 or not name:
return 0
srn1 = name.get_surname()
srn1 = get_surnames(name)
sfx1 = name.get_suffix()
srn2 = name1.get_surname()
srn2 = get_surnames(name1)
sfx2 = name1.get_suffix()
if not self.name_compare(srn1,srn2):
@ -476,7 +476,7 @@ class Merge(tool.Tool,ManagedWindow.ManagedWindow):
else:
return self.list_reduce(list2,list1)
def place_match(self,p1_id,p2_id):
def place_match(self, p1_id, p2_id):
if p1_id == p2_id:
return 1
@ -509,7 +509,7 @@ class Merge(tool.Tool,ManagedWindow.ManagedWindow):
value += 0.25
return min(value,1) if value else -1
def list_reduce(self,list1,list2):
def list_reduce(self, list1, list2):
value = 0
for name in list1:
for name2 in list2:
@ -526,7 +526,7 @@ class Merge(tool.Tool,ManagedWindow.ManagedWindow):
class ShowMatches(ManagedWindow.ManagedWindow):
def __init__(self,dbstate,uistate,track,the_list,the_map,callback):
def __init__(self, dbstate, uistate, track, the_list, the_map, callback):
ManagedWindow.ManagedWindow.__init__(self,uistate,track,self.__class__)
self.dellist = {}
@ -632,7 +632,11 @@ def get_name_obj(person):
return person.get_primary_name()
else:
return None
def get_surnames(name):
"""Construct a full surname of the surnames"""
' '.join([surn.get_surname() for surn in name.get_surname_list()])
#-------------------------------------------------------------------------
#
#

View File

@ -70,24 +70,19 @@ WIKI_HELP_SEC = _('manual|Extract_Information_from_Names')
# List of possible surname prefixes. Notice that you must run the tool
# multiple times for prefixes such as "van der".
prefix_list = [
PREFIX_LIST = [
"de", "van", "von", "di", "le", "du", "dela", "della",
"des", "vande", "ten", "da", "af", "den", "das", "dello",
"del", "en", "ein", "el" "et", "les", "lo", "los", "un",
"um", "una", "uno", "der", "ter", "te", "die",
]
CONNECTOR_LIST = ['e', 'y', ]
CONNECTOR_LIST_NONSPLIT = ['de', 'van']
_title_re = re.compile(r"^ ([A-Za-z][A-Za-z]+\.) \s+ (.+) $", re.VERBOSE)
_nick_re = re.compile(r"(.+) \s* [(\"] (.+) [)\"]", re.VERBOSE)
# Find a prefix in the first_name
_fn_prefix_re = re.compile("(\S+)\s+(%s)\s*$" % '|'.join(prefix_list),
re.IGNORECASE)
# Find a prefix in the surname
_sn_prefix_re = re.compile("^\s*(%s)\s+(.+)" % '|'.join(prefix_list),
re.IGNORECASE)
#-------------------------------------------------------------------------
#
@ -101,7 +96,11 @@ _sn_prefix_re = re.compile("^\s*(%s)\s+(.+)" % '|'.join(prefix_list),
class PatchNames(tool.BatchTool, ManagedWindow.ManagedWindow):
titleid = 1
nickid = 2
pref1id = 3
compid = 4
def __init__(self, dbstate, uistate, options_class, name, callback=None):
self.label = _('Name and title extraction tool')
ManagedWindow.ManagedWindow.__init__(self, uistate, [], self.__class__)
@ -110,12 +109,63 @@ class PatchNames(tool.BatchTool, ManagedWindow.ManagedWindow):
tool.BatchTool.__init__(self, dbstate, options_class, name)
if self.fail:
return
winprefix = gtk.Dialog("Default prefix and connector settings",
self.uistate.window,
gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
winprefix.set_has_separator(False)
winprefix.vbox.set_spacing(5)
hboxpref = gtk.HBox()
hboxpref.pack_start(gtk.Label(_('Prefixes to search for:')),
expand=False, padding=5)
self.prefixbox = gtk.Entry()
self.prefixbox.set_text(', '.join(PREFIX_LIST))
hboxpref.pack_start(self.prefixbox)
winprefix.vbox.pack_start(hboxpref)
hboxcon = gtk.HBox()
hboxcon.pack_start(gtk.Label(_('Connectors splitting surnames:')),
expand=False, padding=5)
self.conbox = gtk.Entry()
self.conbox.set_text(', '.join(CONNECTOR_LIST))
hboxcon.pack_start(self.conbox)
winprefix.vbox.pack_start(hboxcon)
hboxconns = gtk.HBox()
hboxconns.pack_start(gtk.Label(_('Connectors not splitting surnames:')),
expand=False, padding=5)
self.connsbox = gtk.Entry()
self.connsbox.set_text(', '.join(CONNECTOR_LIST_NONSPLIT))
hboxconns.pack_start(self.connsbox)
winprefix.vbox.pack_start(hboxconns)
winprefix.show_all()
winprefix.resize(700, 100)
response = winprefix.run()
self.prefix_list = self.prefixbox.get_text().split(',')
self.prefix_list = map(strip, self.prefix_list)
self.prefixbox = None
self.connector_list = self.conbox.get_text().split(',')
self.connector_list = map(strip, self.connector_list)
self.conbox = None
self.connector_list_nonsplit = self.connsbox.get_text().split(',')
self.connector_list_nonsplit = map(strip, self.connector_list_nonsplit)
self.connsbox = None
# Find a prefix in the first_name
self._fn_prefix_re = re.compile("(\S+)\s+(%s)\s*$" % '|'.join(self.prefix_list),
re.IGNORECASE)
# Find a prefix in the surname
self._sn_prefix_re = re.compile("^\s*(%s)\s+(.+)" % '|'.join(self.prefix_list),
re.IGNORECASE)
# Find a connector in the surname
self._sn_con_re = re.compile("^\s*(.+)\s+(%s)\s+(.+)" % '|'.join(self.connector_list),
re.IGNORECASE)
winprefix.destroy()
self.cb = callback
self.title_list = []
self.nick_list = []
self.prefix1_list = []
self.prefix2_list = []
self.handle_to_action = {}
self.progress = ProgressMeter(
_('Extracting Information from Names'), '')
@ -127,6 +177,18 @@ class PatchNames(tool.BatchTool, ManagedWindow.ManagedWindow):
name = person.get_primary_name()
first = name.get_first_name()
sname = name.get_surname()
old_prefix = []
old_surn = []
old_con = []
old_prim = []
old_orig = []
for surn in name.get_surname_list():
old_prefix.append(surn.get_prefix())
old_surn.append(surn.get_surname())
old_con.append(surn.get_connector())
old_prim.append(surn.get_primary())
old_orig.append(surn.get_origintype())
if name.get_title():
old_title = [name.get_title()]
@ -140,46 +202,160 @@ class PatchNames(tool.BatchTool, ManagedWindow.ManagedWindow):
first = groups[1]
new_title.append(groups[0])
match = _title_re.match(first)
matchnick = _nick_re.match(first)
if new_title:
self.title_list.append((key, " ".join(old_title+new_title),
first))
continue
match = _nick_re.match(first)
if match:
groups = match.groups()
self.nick_list.append((key, groups[0], groups[1]))
continue
old_prefix = name.get_surname_prefix()
# First try to find the name prefix in the first_name
match = _fn_prefix_re.match(first)
if match:
groups = match.groups()
if old_prefix:
# Put the found prefix before the old prefix
new_prefix = " ".join([groups[1], old_prefix])
titleval = (" ".join(old_title+new_title), first)
if key in self.handle_to_action:
self.handle_to_action[key][self.titleid] = titleval
else:
new_prefix = groups[1]
self.prefix1_list.append((key, groups[0], new_prefix))
continue
# Next, try to find the name prefix in the surname
match = _sn_prefix_re.match(sname)
if match:
groups = match.groups()
if old_prefix:
# Put the found prefix after the old prefix
new_prefix = " ".join([old_prefix, groups[0]])
self.handle_to_action[key] = {self.titleid: titleval}
elif matchnick:
# we check for nick, which changes given name like title
groups = matchnick.groups()
nickval = (groups[0], groups[1])
if key in self.handle_to_action:
self.handle_to_action[key][self.nickid] = nickval
else:
new_prefix = groups[0]
self.prefix2_list.append((key, groups[1], new_prefix))
self.handle_to_action[key] = {self.nickid: nickval}
else:
# Try to find the name prefix in the given name, also this
# changes given name
match = self._fn_prefix_re.match(first)
if match:
groups = match.groups()
if old_prefix[0]:
# Put the found prefix before the old prefix
new_prefix = " ".join([groups[1], old_prefix[0]])
else:
new_prefix = groups[1]
pref1val = (groups[0], new_prefix, groups[1])
if key in self.handle_to_action:
self.handle_to_action[key][self.pref1id] = pref1val
else:
self.handle_to_action[key] = {self.pref1id: pref1val}
#check for Gedcom import of compound surnames
if len(old_surn) == 1 and old_con[0] == '':
prefixes = old_prefix[0].split(',')
surnames = old_surn[0].split(',')
if len(prefixes) > 1 and len(prefixes) == len(surnames):
#assume a list of prefix and a list of surnames
prefixes = map(strip, prefixes)
surnames = map(strip, surnames)
primaries = [False] * len(prefixes)
primaries[0] = True
origs = []
for ind in range(len(prefixes)):
origs.append(gen.lib.NameOriginType())
origs[0] = old_orig[0]
compoundval = (surnames, prefixes, ['']*len(prefixes),
primaries, origs)
if key in self.handle_to_action:
self.handle_to_action[key][self.compid] = compoundval
else:
self.handle_to_action[key] = {self.compid: compoundval}
#we cannot check compound surnames, so continue the loop
continue
# Next, try to split surname in compounds: prefix surname connector
found = False
new_prefix_list = []
new_surname_list = []
new_connector_list = []
new_prim_list = []
new_orig_list = []
ind = 0
cont = True
for pref, surn, con, prim, orig in zip(old_prefix, old_surn,
old_con, old_prim, old_orig):
surnval = surn.split()
if surnval == []:
new_prefix_list.append(pref)
new_surname_list.append('')
new_connector_list.append(con)
new_prim_list.append(prim)
new_orig_list.append(orig)
cont = False
continue
val = surnval.pop(0)
while cont:
new_prefix_list.append(pref)
new_surname_list.append('')
new_connector_list.append(con)
new_prim_list.append(prim)
new_orig_list.append(orig)
while cont and (val.lower() in self.prefix_list):
found = True
if new_prefix_list[-1]:
new_prefix_list[-1] += ' ' + val
else:
new_prefix_list[-1] = val
try:
val = surnval.pop(0)
except IndexError:
val = ''
cont = False
#after prefix we have a surname
if cont:
new_surname_list[-1] = val
try:
val = surnval.pop(0)
except IndexError:
val = ''
cont = False
#if value after surname indicates continue, then continue
while cont and (val.lower() in self.connector_list_nonsplit):
#add this val to the current surname
new_surname_list[-1] += ' ' + val
try:
val = surnval.pop(0)
except IndexError:
val = ''
cont = False
# if previous is non-splitting connector, then add new val to
# current surname
if cont and (new_surname_list[-1].split()[-1].lower() \
in self.connector_list_nonsplit):
new_surname_list[-1] += ' ' + val
try:
val = surnval.pop(0)
except IndexError:
val = ''
cont = False
#if next is a connector, add it to the surname
if cont and val.lower() in self.connector_list:
found = True
if new_connector_list[-1]:
new_connector_list[-1] = ' ' + val
else:
new_connector_list[-1] = val
try:
val = surnval.pop(0)
except IndexError:
val = ''
cont = False
#initialize for a next surname in case there are still
#val
if cont:
found = True # we split surname
pref=''
con = ''
prim = False
orig = gen.lib.NameOriginType()
ind += 1
if found:
compoundval = (new_surname_list, new_prefix_list,
new_connector_list, new_prim_list, new_orig_list)
if key in self.handle_to_action:
self.handle_to_action[key][self.compid] = compoundval
else:
self.handle_to_action[key] = {self.compid: compoundval}
self.progress.step()
if self.nick_list or self.title_list or self.prefix1_list or self.prefix2_list:
if self.handle_to_action:
self.display()
else:
self.progress.close()
@ -228,7 +404,7 @@ class PatchNames(tool.BatchTool, ManagedWindow.ManagedWindow):
c = gtk.TreeViewColumn(_('Value'), gtk.CellRendererText(), text=3)
self.list.append_column(c)
c = gtk.TreeViewColumn(_('Name'), gtk.CellRendererText(), text=4)
c = gtk.TreeViewColumn(_('Current Name'), gtk.CellRendererText(), text=4)
self.list.append_column(c)
self.list.set_model(self.model)
@ -236,58 +412,65 @@ class PatchNames(tool.BatchTool, ManagedWindow.ManagedWindow):
self.nick_hash = {}
self.title_hash = {}
self.prefix1_hash = {}
self.prefix2_hash = {}
self.compound_hash = {}
self.progress.set_pass(_('Building display'),
len(self.nick_list)+len(self.title_list)
+len(self.prefix1_list)+len(self.prefix2_list))
len(self.handle_to_action.keys()))
for (pid, name, nick) in self.nick_list:
p = self.db.get_person_from_handle(pid)
for key, data in self.handle_to_action.items():
p = self.db.get_person_from_handle(key)
gid = p.get_gramps_id()
handle = self.model.append()
self.model.set_value(handle, 0, 1)
self.model.set_value(handle, 1, gid)
self.model.set_value(handle, 2, _('Nickname'))
self.model.set_value(handle, 3, nick)
self.model.set_value(handle, 4, p.get_primary_name().get_name())
self.nick_hash[pid] = handle
self.progress.step()
for (pid, title, name) in self.title_list:
p = self.db.get_person_from_handle(pid)
gid = p.get_gramps_id()
handle = self.model.append()
self.model.set_value(handle, 0, 1)
self.model.set_value(handle, 1, gid)
self.model.set_value(handle, 2, _('Person|Title'))
self.model.set_value(handle, 3, title)
self.model.set_value(handle, 4, p.get_primary_name().get_name())
self.title_hash[pid] = handle
self.progress.step()
for (pid, fname, prefix) in self.prefix1_list:
p = self.db.get_person_from_handle(pid)
gid = p.get_gramps_id()
handle = self.model.append()
self.model.set_value(handle, 0, 1)
self.model.set_value(handle, 1, gid)
self.model.set_value(handle, 2, _('Prefix'))
self.model.set_value(handle, 3, prefix)
self.model.set_value(handle, 4, p.get_primary_name().get_name())
self.prefix1_hash[pid] = handle
self.progress.step()
for (pid, sname, prefix) in self.prefix2_list:
p = self.db.get_person_from_handle(pid)
gid = p.get_gramps_id()
handle = self.model.append()
self.model.set_value(handle, 0, 1)
self.model.set_value(handle, 1, gid)
self.model.set_value(handle, 2, _('Prefix'))
self.model.set_value(handle, 3, prefix)
self.model.set_value(handle, 4, p.get_primary_name().get_name())
self.prefix2_hash[pid] = handle
if self.nickid in data:
given, nick = data[self.nickid]
handle = self.model.append()
self.model.set_value(handle, 0, 1)
self.model.set_value(handle, 1, gid)
self.model.set_value(handle, 2, _('Nickname'))
self.model.set_value(handle, 3, nick)
self.model.set_value(handle, 4, p.get_primary_name().get_name())
self.nick_hash[key] = handle
if self.titleid in data:
title, given = data[self.titleid]
handle = self.model.append()
self.model.set_value(handle, 0, 1)
self.model.set_value(handle, 1, gid)
self.model.set_value(handle, 2, _('Person|Title'))
self.model.set_value(handle, 3, title)
self.model.set_value(handle, 4, p.get_primary_name().get_name())
self.title_hash[key] = handle
if self.pref1id in data:
given, prefixtotal, new_prefix = data[self.pref1id]
handle = self.model.append()
self.model.set_value(handle, 0, 1)
self.model.set_value(handle, 1, gid)
self.model.set_value(handle, 2, _('Prefix in given name'))
self.model.set_value(handle, 3, prefixtotal)
self.model.set_value(handle, 4, p.get_primary_name().get_name())
self.prefix1_hash[key] = handle
if self.compid in data:
surn_list, pref_list, con_list, prims, origs = data[self.compid]
handle = self.model.append()
self.model.set_value(handle, 0, 1)
self.model.set_value(handle, 1, gid)
self.model.set_value(handle, 2, _('Compound surname'))
newval = ''
for sur, pre, con in zip(surn_list, pref_list, con_list):
if newval:
newval += '-['
else:
newval = '['
newval += pre + ',' + sur
if con:
newval += ',' + con + ']'
else:
newval += ']'
self.model.set_value(handle, 3, newval)
self.model.set_value(handle, 4, p.get_primary_name().get_name())
self.compound_hash[key] = handle
self.progress.step()
self.progress.close()
@ -300,49 +483,58 @@ class PatchNames(tool.BatchTool, ManagedWindow.ManagedWindow):
def on_ok_clicked(self, obj):
trans = self.db.transaction_begin("", batch=True)
self.db.disable_signals()
for grp in self.nick_list:
handle = self.nick_hash[grp[0]]
val = self.model.get_value(handle, 0)
if val:
p = self.db.get_person_from_handle(grp[0])
name = p.get_primary_name()
name.set_first_name(grp[1].strip())
nick_name = grp[2].strip()
attr = gen.lib.Attribute()
attr.set_type(gen.lib.AttributeType.NICKNAME)
attr.set_value(nick_name)
p.add_attribute(attr)
self.db.commit_person(p, trans)
for grp in self.title_list:
handle = self.title_hash[grp[0]]
val = self.model.get_value(handle, 0)
if val:
p = self.db.get_person_from_handle(grp[0])
name = p.get_primary_name()
name.set_first_name(grp[2].strip())
name.set_title(grp[1].strip())
self.db.commit_person(p, trans)
for grp in self.prefix1_list:
handle = self.prefix1_hash[grp[0]]
val = self.model.get_value(handle, 0)
if val:
p = self.db.get_person_from_handle(grp[0])
name = p.get_primary_name()
name.set_first_name(grp[1].strip())
name.set_surname_prefix(grp[2].strip())
self.db.commit_person(p, trans)
for grp in self.prefix2_list:
handle = self.prefix2_hash[grp[0]]
val = self.model.get_value(handle, 0)
if val:
p = self.db.get_person_from_handle(grp[0])
name = p.get_primary_name()
name.set_surname(grp[1].strip())
name.set_surname_prefix(grp[2].strip())
self.db.commit_person(p, trans)
for key, data in self.handle_to_action.items():
p = self.db.get_person_from_handle(key)
if self.nickid in data:
modelhandle = self.nick_hash[key]
val = self.model.get_value(modelhandle, 0)
if val:
given, nick = data[self.nickid]
name = p.get_primary_name()
name.set_first_name(given.strip())
name.set_nick_name(nick.strip())
if self.titleid in data:
modelhandle = self.title_hash[key]
val = self.model.get_value(modelhandle, 0)
if val:
title, given = data[self.titleid]
name = p.get_primary_name()
name.set_first_name(given.strip())
name.set_title(title.strip())
if self.pref1id in data:
modelhandle = self.prefix1_hash[key]
val = self.model.get_value(modelhandle, 0)
if val:
given, prefixtotal, prefix = data[self.pref1id]
name = p.get_primary_name()
name.set_first_name(given.strip())
oldpref = name.get_surname_list()[0].get_prefix().strip()
if oldpref == '' or oldpref == prefix.strip():
name.get_surname_list()[0].set_prefix(prefix)
else:
name.get_surname_list()[0].set_prefix('%s %s' % (prefix, oldpref))
if self.compid in data:
modelhandle = self.compound_hash[key]
val = self.model.get_value(modelhandle, 0)
if val:
surns, prefs, cons, prims, origs = data[self.compid]
name = p.get_primary_name()
new_surn_list = []
for surn, pref, con, prim, orig in zip(surns, prefs, cons,
prims, origs):
new_surn_list.append(gen.lib.Surname())
new_surn_list[-1].set_surname(surn.strip())
new_surn_list[-1].set_prefix(pref.strip())
new_surn_list[-1].set_connector(con.strip())
new_surn_list[-1].set_primary(prim)
new_surn_list[-1].set_origintype(orig)
name.set_surname_list(new_surn_list)
self.db.commit_person(p, trans)
self.db.transaction_commit(trans,
_("Extract information from names"))
@ -351,7 +543,6 @@ class PatchNames(tool.BatchTool, ManagedWindow.ManagedWindow):
self.close()
self.cb()
class PatchNamesOptions(tool.ToolOptions):
"""
Defines options and provides handling interface.
@ -359,3 +550,7 @@ class PatchNamesOptions(tool.ToolOptions):
def __init__(self, name, person_id=None):
tool.ToolOptions.__init__(self, name, person_id)
def strip(arg):
return arg.strip()

View File

@ -12,12 +12,10 @@
<child internal-child="vbox">
<object class="GtkVBox" id="dialog-vbox1">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkVBox" id="vbox2">
<property name="visible">True</property>
<property name="border_width">6</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="title">
<property name="visible">True</property>
@ -32,10 +30,18 @@
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="ypad">10</property>
<property name="label" translatable="yes">Below is a list of the nicknames, titles and family name prefixes that Gramps can extract from the
current database. If you accept the changes, Gramps will modify the entries
that have been selected.</property>
<property name="label" translatable="yes">Below is a list of the nicknames, titles, prefixes and compound surnames that Gramps can extract from the family tree.
If you accept the changes, Gramps will modify the entries that have been selected.
Compound surnames are shown as lists of [prefix, surname, connector].
For example, with the defaults, the name "de Mascarenhas da Silva e Lencastre" shows as:
[de, Mascarenhas]-[da, Silva, e]-[,Lencastre]
Run this tool several times to correct names that have multiple information that can be extracted.</property>
<property name="wrap">True</property>
<property name="max_width_chars">100</property>
</object>
<packing>
<property name="expand">False</property>

View File

@ -158,17 +158,27 @@ class PersonTreeView(BasePersonView):
# attempt to get the current surname
(model, pathlist) = self.selection.get_selected_rows()
name = u""
name = gen.lib.Name()
basepers = None
if len(pathlist) == 1:
path = pathlist[0]
if len(path) == 1:
name = model.on_get_iter(path).name
else:
node = model.on_get_iter(path)
name = model.on_iter_parent(node).name
path = (path[0], 0)
node = model.get_iter(path)
handle = model.get_value(node, self.handle_col)
basepers = self.dbstate.db.get_person_from_handle(handle)
if basepers:
surnlist = []
primname = basepers.get_primary_name()
for surn in primname.get_surname_list():
surnlist.append(gen.lib.Surname(source=surn))
name.set_surname_list(surnlist)
name.set_family_nick_name(primname.get_family_nick_name())
name.set_group_as(primname.get_group_as())
name.set_sort_as(primname.get_sort_as())
try:
person.get_primary_name().set_surname(name)
person.set_primary_name(name)
EditPerson(self.dbstate, self.uistate, [], person)
except Errors.WindowActiveError:
pass