diff --git a/data/grampsxml.dtd b/data/grampsxml.dtd
index 8c0759e3e..35e286ee6 100644
--- a/data/grampsxml.dtd
+++ b/data/grampsxml.dtd
@@ -59,6 +59,7 @@ DATABASE
bookmarks?, namemaps?)>
+
-
-
-
-
-
+
+
+
+
-
@@ -235,13 +234,13 @@
-
-
-
-
-
+
+
+
+
+
+
-
@@ -252,6 +251,24 @@
+
+
+
+
+
+ 1
+ 0
+
+
+ inherited
+ patronymic
+ matronymic
+ other
+
+
+
+
+
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 232b0cd99..44acc682c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -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
diff --git a/src/DdTargets.py b/src/DdTargets.py
index fd759ff38..3f588be27 100644
--- a/src/DdTargets.py
+++ b/src/DdTargets.py
@@ -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')
diff --git a/src/Filters/Rules/Person/_HasNameOf.py b/src/Filters/Rules/Person/_HasNameOf.py
index 02308fd5a..bc4d79a3b 100644
--- a/src/Filters/Rules/Person/_HasNameOf.py
+++ b/src/Filters/Rules/Person/_HasNameOf.py
@@ -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 ')
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
diff --git a/src/Filters/Rules/Person/_IncompleteNames.py b/src/Filters/Rules/Person/_IncompleteNames.py
index 7fed919e3..a0912fcbd 100644
--- a/src/Filters/Rules/Person/_IncompleteNames.py
+++ b/src/Filters/Rules/Person/_IncompleteNames.py
@@ -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
diff --git a/src/Filters/Rules/Person/_RegExpName.py b/src/Filters/Rules/Person/_RegExpName.py
index 5a0cde75a..226c61e5b 100644
--- a/src/Filters/Rules/Person/_RegExpName.py
+++ b/src/Filters/Rules/Person/_RegExpName.py
@@ -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:
diff --git a/src/Filters/Rules/Person/_SearchName.py b/src/Filters/Rules/Person/_SearchName.py
index 99e7b74eb..6d84a3186 100644
--- a/src/Filters/Rules/Person/_SearchName.py
+++ b/src/Filters/Rules/Person/_SearchName.py
@@ -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:
diff --git a/src/ScratchPad.py b/src/ScratchPad.py
index 181a6734d..48ec0eb63 100644
--- a/src/ScratchPad.py
+++ b/src/ScratchPad.py
@@ -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()
diff --git a/src/Utils.py b/src/Utils.py
index 0fd5bd9d4..cdaef4f0f 100644
--- a/src/Utils.py
+++ b/src/Utils.py
@@ -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 = {}
diff --git a/src/config.py b/src/config.py
index 15b8e7238..6d6002def 100644
--- a/src/config.py
+++ b/src/config.py
@@ -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)
diff --git a/src/gen/db/base.py b/src/gen/db/base.py
index f007e7165..6a128727c 100644
--- a/src/gen/db/base.py
+++ b/src/gen/db/base.py
@@ -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.
diff --git a/src/gen/db/read.py b/src/gen/db/read.py
index b7bb8614e..0c1df20ad 100644
--- a/src/gen/db/read.py
+++ b/src/gen/db/read.py
@@ -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],
diff --git a/src/gen/db/upgrade.py b/src/gen/db/upgrade.py
index 2cfb3e863..13538c358 100644
--- a/src/gen/db/upgrade.py
+++ b/src/gen/db/upgrade.py
@@ -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
diff --git a/src/gen/db/write.py b/src/gen/db/write.py
index 7752ea5d4..1a4e4ba83 100644
--- a/src/gen/db/write.py
+++ b/src/gen/db/write.py
@@ -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()])
diff --git a/src/gen/display/name.py b/src/gen/display/name.py
index f5d5b40e7..7de772d96 100644
--- a/src/gen/display/name.py
+++ b/src/gen/display/name.py
@@ -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()
diff --git a/src/gen/lib/Makefile.am b/src/gen/lib/Makefile.am
index 66e21b371..a8fc70c6c 100644
--- a/src/gen/lib/Makefile.am
+++ b/src/gen/lib/Makefile.am
@@ -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 \
diff --git a/src/gen/lib/__init__.py b/src/gen/lib/__init__.py
index 3a283c841..a5d487b9a 100644
--- a/src/gen/lib/__init__.py
+++ b/src/gen/lib/__init__.py
@@ -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
diff --git a/src/gen/lib/name.py b/src/gen/lib/name.py
index e138adf7c..bfa1884c0 100644
--- a/src/gen/lib/name.py
+++ b/src/gen/lib/name.py
@@ -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)
diff --git a/src/gen/lib/nameorigintype.py b/src/gen/lib/nameorigintype.py
new file mode 100644
index 000000000..00089a607
--- /dev/null
+++ b/src/gen/lib/nameorigintype.py
@@ -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)
+
diff --git a/src/gen/lib/surname.py b/src/gen/lib/surname.py
new file mode 100644
index 000000000..8b7232a92
--- /dev/null
+++ b/src/gen/lib/surname.py
@@ -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
diff --git a/src/gen/lib/surnamebase.py b/src/gen/lib/surnamebase.py
new file mode 100644
index 000000000..82186e9be
--- /dev/null
+++ b/src/gen/lib/surnamebase.py
@@ -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)
diff --git a/src/gen/proxy/proxybase.py b/src/gen/proxy/proxybase.py
index 7fd83f350..1b46a0d1f 100644
--- a/src/gen/proxy/proxybase.py
+++ b/src/gen/proxy/proxybase.py
@@ -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"""
diff --git a/src/glade/editname.glade b/src/glade/editname.glade
index aefc9a1c3..24c8ed810 100644
--- a/src/glade/editname.glade
+++ b/src/glade/editname.glade
@@ -12,275 +12,331 @@