1# 2# Gramps - a GTK+/GNOME based genealogy program 3# 4# Copyright (C) 2000-2007 Donald N. Allingham 5# Copyright (C) 2010 Michiel D. Nauta 6# Copyright (C) 2011 Tim G L Lyons 7# Copyright (C) 2013 Doug Blank <doug.blank@gmail.com> 8# Copyright (C) 2017 Nick Hall 9# 10# This program is free software; you can redistribute it and/or modify 11# it under the terms of the GNU General Public License as published by 12# the Free Software Foundation; either version 2 of the License, or 13# (at your option) any later version. 14# 15# This program is distributed in the hope that it will be useful, 16# but WITHOUT ANY WARRANTY; without even the implied warranty of 17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18# GNU General Public License for more details. 19# 20# You should have received a copy of the GNU General Public License 21# along with this program; if not, write to the Free Software 22# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23# 24 25""" 26Name class for Gramps. 27""" 28 29#------------------------------------------------------------------------- 30# 31# Gramps modules 32# 33#------------------------------------------------------------------------- 34from .secondaryobj import SecondaryObject 35from .privacybase import PrivacyBase 36from .citationbase import CitationBase 37from .notebase import NoteBase 38from .datebase import DateBase 39from .surnamebase import SurnameBase 40from .nametype import NameType 41from .const import IDENTICAL, EQUAL, DIFFERENT 42from .date import Date 43from ..const import GRAMPS_LOCALE as glocale 44_ = glocale.translation.gettext 45 46#------------------------------------------------------------------------- 47# 48# Personal Name 49# 50#------------------------------------------------------------------------- 51class Name(SecondaryObject, PrivacyBase, SurnameBase, CitationBase, NoteBase, 52 DateBase): 53 """ 54 Provide name information about a person. 55 56 A person may have more that one name throughout his or her life. The Name 57 object stores one of them 58 """ 59 60 DEF = 0 # Default format (determined by gramps-wide prefs) 61 LNFN = 1 # last name first name 62 FNLN = 2 # first name last name 63 FN = 4 # first name 64 LNFNP = 5 # primary name primconnector rest, given pa/ma suffix, primprefix 65 66 NAMEFORMATS = (DEF, LNFN, FNLN, FN, LNFNP) 67 #deprecated : 68 PTFN = 3 # patronymic first name 69 70 def __init__(self, source=None, data=None): 71 """Create a new Name instance, copying from the source if provided. 72 We should connect here to 'person-groupname-rebuild' and do something 73 correct when first parameter is the name, and second parameter is 74 different from the group here. However, that would be complicated and 75 no real errors that cannot be ammended can be done if group is 76 saved differently. 77 """ 78 PrivacyBase.__init__(self, source) 79 SurnameBase.__init__(self, source) 80 CitationBase.__init__(self, source) 81 NoteBase.__init__(self, source) 82 DateBase.__init__(self, source) 83 if data: 84 (privacy, citation_list, note, date, 85 self.first_name, surname_list, self.suffix, self.title, name_type, 86 self.group_as, self.sort_as, self.display_as, self.call, 87 self.nick, self.famnick) = data 88 self.type = NameType(name_type) 89 SurnameBase.unserialize(self, surname_list) 90 PrivacyBase.unserialize(self, privacy) 91 CitationBase.unserialize(self, citation_list) 92 NoteBase.unserialize(self, note) 93 DateBase.unserialize(self, date) 94 elif source: 95 self.first_name = source.first_name 96 self.suffix = source.suffix 97 self.title = source.title 98 self.type = NameType(source.type) 99 self.group_as = source.group_as 100 self.sort_as = source.sort_as 101 self.display_as = source.display_as 102 self.call = source.call 103 self.nick = source.nick 104 self.famnick = source.famnick 105 else: 106 self.first_name = "" 107 self.suffix = "" 108 self.title = "" 109 self.type = NameType() 110 self.group_as = "" 111 self.sort_as = self.DEF 112 self.display_as = self.DEF 113 self.call = "" 114 self.nick = "" 115 self.famnick = "" 116 117 def serialize(self): 118 """ 119 Convert the object to a serialized tuple of data. 120 """ 121 return (PrivacyBase.serialize(self), 122 CitationBase.serialize(self), 123 NoteBase.serialize(self), 124 DateBase.serialize(self), 125 self.first_name, 126 SurnameBase.serialize(self), 127 self.suffix, self.title, 128 self.type.serialize(), 129 self.group_as, self.sort_as, self.display_as, self.call, 130 self.nick, self.famnick) 131 132 @classmethod 133 def get_schema(cls): 134 """ 135 Returns the JSON Schema for this class. 136 137 :returns: Returns a dict containing the schema. 138 :rtype: dict 139 """ 140 from .surname import Surname 141 return { 142 "type": "object", 143 "title": _("Name"), 144 "properties": { 145 "_class": {"enum": [cls.__name__]}, 146 "private": {"type": "boolean", 147 "title": _("Private")}, 148 "citation_list": {"type": "array", 149 "items": {"type": "string", 150 "maxLength": 50}, 151 "title": _("Citations")}, 152 "note_list": {"type": "array", 153 "items": {"type": "string", 154 "maxLength": 50}, 155 "title": _("Notes")}, 156 "date": {"oneOf": [{"type": "null"}, Date.get_schema()], 157 "title": _("Date")}, 158 "first_name": {"type": "string", 159 "title": _("Given name")}, 160 "surname_list": {"type": "array", 161 "items": Surname.get_schema(), 162 "title": _("Surnames")}, 163 "suffix": {"type": "string", 164 "title": _("Suffix")}, 165 "title": {"type": "string", 166 "title": _("Title")}, 167 "type": NameType.get_schema(), 168 "group_as": {"type": "string", 169 "title": _("Group as")}, 170 "sort_as": {"type": "integer", 171 "title": _("Sort as")}, 172 "display_as": {"type": "integer", 173 "title": _("Display as")}, 174 "call": {"type": "string", 175 "title": _("Call name")}, 176 "nick": {"type": "string", 177 "title": _("Nick name")}, 178 "famnick": {"type": "string", 179 "title": _("Family nick name")} 180 } 181 } 182 183 def is_empty(self): 184 """ 185 Indicate if the name is empty. 186 """ 187 namefieldsempty = (self.first_name == "" and 188 self.suffix == "" and 189 self.title == "" and 190 self.nick == "" and 191 self.famnick == "") 192 surnamefieldsempty = False not in [surn.is_empty() 193 for surn in self.surname_list] 194 return namefieldsempty and surnamefieldsempty 195 196 def unserialize(self, data): 197 """ 198 Convert a serialized tuple of data to an object. 199 """ 200 (privacy, citation_list, note_list, date, 201 self.first_name, surname_list, self.suffix, self.title, name_type, 202 self.group_as, self.sort_as, self.display_as, self.call, 203 self.nick, self.famnick) = data 204 self.type = NameType(name_type) 205 PrivacyBase.unserialize(self, privacy) 206 SurnameBase.unserialize(self, surname_list) 207 CitationBase.unserialize(self, citation_list) 208 NoteBase.unserialize(self, note_list) 209 DateBase.unserialize(self, date) 210 return self 211 212 def get_text_data_list(self): 213 """ 214 Return the list of all textual attributes of the object. 215 216 :returns: Returns the list of all textual attributes of the object. 217 :rtype: list 218 """ 219 return [self.first_name, self.suffix, self.title, 220 str(self.type), self.call, self.nick, self.famnick] 221 222 def get_text_data_child_list(self): 223 """ 224 Return the list of child objects that may carry textual data. 225 226 :returns: Returns the list of child objects that may carry textual data. 227 :rtype: list 228 """ 229 return self.surname_list 230 231 def get_note_child_list(self): 232 """ 233 Return the list of child secondary objects that may refer notes. 234 235 :returns: Returns the list of child secondary child objects that may 236 refer notes. 237 :rtype: list 238 """ 239 return [] 240 241 def get_handle_referents(self): 242 """ 243 Return the list of child objects which may, directly or through 244 their children, reference primary objects. 245 246 :returns: Returns the list of objects referencing primary objects. 247 :rtype: list 248 """ 249 return [] 250 251 def get_referenced_handles(self): 252 """ 253 Return the list of (classname, handle) tuples for all directly 254 referenced primary objects. 255 256 :returns: List of (classname, handle) tuples for referenced objects. 257 :rtype: list 258 """ 259 return self.get_referenced_note_handles() + \ 260 self.get_referenced_citation_handles() 261 262 def is_equivalent(self, other): 263 """ 264 Return if this name is equivalent, that is agrees in type, first, 265 call, surname_list, suffix, title and date, to other. 266 267 :param other: The name to compare this name to. 268 :type other: Name 269 :returns: Constant indicating degree of equivalence. 270 :rtype: int 271 """ 272 # TODO what to do with sort and display? 273 if self.get_text_data_list() != other.get_text_data_list() or \ 274 self.get_date_object() != other.get_date_object() or \ 275 SurnameBase.serialize(self) != SurnameBase.serialize(other): 276 return DIFFERENT 277 else: 278 if self.is_equal(other): 279 return IDENTICAL 280 else: 281 return EQUAL 282 283 def merge(self, acquisition): 284 """ 285 Merge the content of acquisition into this name. 286 Normally the person merge code should opt for adding an alternate 287 name if names are actually different (like not equal surname list) 288 289 Lost: type, first, call, suffix, title, nick, famnick and date of 290 acquisition. 291 292 :param acquisition: The name to merge with the present name. 293 :type acquisition: Name 294 """ 295 # TODO what to do with sort and display? 296 self._merge_privacy(acquisition) 297 self._merge_surname_list(acquisition) 298 self._merge_note_list(acquisition) 299 self._merge_citation_list(acquisition) 300 301 def set_group_as(self, name): 302 """ 303 Set the grouping name for a person. 304 305 Normally, this is the person's surname. However, some locales group 306 equivalent names (e.g. Ivanova and Ivanov in Russian are usually 307 considered equivalent. 308 309 .. note:: There is also a database wide grouping set_name_group_mapping 310 So one might map a name Smith to SmithNew, and have one person still 311 grouped with name Smith. Hence, group_as can be equal to surname! 312 """ 313 self.group_as = name 314 315 def get_group_as(self): 316 """ 317 Return the grouping name, which is used to group equivalent surnames. 318 """ 319 return self.group_as 320 321 def get_group_name(self): 322 """ 323 Return the grouping name, which is used to group equivalent surnames. 324 """ 325 if self.group_as: 326 return self.group_as 327 else: 328 return self.get_primary_surname().get_surname() 329 330 def set_sort_as(self, value): 331 """ 332 Specifies the sorting method for the specified name. 333 334 Typically the locale's default should be used. However, there may be 335 names where a specific sorting structure is desired for a name. 336 """ 337 self.sort_as = value 338 339 def get_sort_as(self): 340 """ 341 Return the selected sorting method for the name. 342 343 The options are LNFN (last name, first name), FNLN (first name, last 344 name), etc. 345 """ 346 return self.sort_as 347 348 def set_display_as(self, value): 349 """ 350 Specifies the display format for the specified name. 351 352 Typically the locale's default should be used. However, there may be 353 names where a specific display format is desired for a name. 354 """ 355 self.display_as = value 356 357 def get_display_as(self): 358 """ 359 Return the selected display format for the name. 360 361 The options are LNFN (last name, first name), FNLN (first name, last 362 name), etc. 363 """ 364 return self.display_as 365 366 def get_call_name(self): 367 """ 368 Return the call name. 369 370 The call name's exact definition is not predetermined, and may be 371 locale specific. 372 """ 373 return self.call 374 375 def set_call_name(self, val): 376 """ 377 Set the call name. 378 379 The call name's exact definition is not predetermined, and may be 380 locale specific. 381 """ 382 self.call = val 383 384 def get_nick_name(self): 385 """ 386 Return the nick name. 387 388 The nick name of the person, a not official name the person is known 389 with. 390 """ 391 return self.nick 392 393 def set_nick_name(self, val): 394 """ 395 Set the nick name. 396 397 The nick name of the person, a not official name the person is known 398 with. 399 """ 400 self.nick = val 401 402 def get_family_nick_name(self): 403 """ 404 Return the family nick name. 405 406 The family nick name of the family of the person, a not official name 407 use to denote the entire family. 408 """ 409 return self.famnick 410 411 def set_family_nick_name(self, val): 412 """ 413 Set the family nick name. 414 415 The family nick name of the family of the person, a not official name 416 use to denote the entire family. 417 """ 418 self.famnick = val 419 420 def set_type(self, the_type): 421 """Set the type of the Name instance.""" 422 self.type.set(the_type) 423 424 def get_type(self): 425 """Return the type of the Name instance.""" 426 return self.type 427 428 def set_first_name(self, name): 429 """Set the given name for the Name instance.""" 430 self.first_name = name 431 432 def get_first_name(self): 433 """Return the given name for the Name instance.""" 434 return self.first_name 435 436 def set_suffix(self, name): 437 """Set the suffix (such as Jr., III, etc.) for the Name instance.""" 438 self.suffix = name 439 440 def get_suffix(self): 441 """Return the suffix for the Name instance.""" 442 return self.suffix 443 444 def set_title(self, title): 445 """Set the title (Dr., Reverand, Captain) for the Name instance.""" 446 self.title = title 447 448 def get_title(self): 449 """Return the title for the Name instance.""" 450 return self.title 451 452 def get_name(self): 453 """ 454 Return a name string built from the components of the Name instance, 455 in the form of: surname, Firstname. 456 """ 457 first = self.first_name 458 surname = self.get_surname() 459 if self.suffix: 460 # translators: needed for Arabic, ignore otherwise 461 return _("%(surname)s, %(first)s %(suffix)s" 462 ) % {'surname':surname, 'first':first, 'suffix':self.suffix} 463 else: 464 # translators: needed for Arabic, ignore otherwise 465 return _("%(str1)s, %(str2)s") % {'str1':surname, 'str2':first} 466 467 def get_upper_name(self): 468 """ 469 Return a name string built from the components of the Name instance, 470 in the form of SURNAME, Firstname. 471 """ 472 first = self.first_name 473 surname = self.get_surname().upper() 474 if self.suffix: 475 # translators: needed for Arabic, ignore otherwise 476 return _("%(surname)s, %(first)s %(suffix)s" 477 ) % {'surname':surname, 'first':first, 'suffix':self.suffix} 478 else: 479 # translators: needed for Arabic, ignore otherwise 480 return _("%(str1)s, %(str2)s") % {'str1':surname, 'str2':first} 481 482 def get_regular_name(self): 483 """ 484 Return a name string built from the components of the Name instance, 485 in the form of Firstname surname. 486 """ 487 first = self.first_name 488 surname = self.get_surname() 489 if self.suffix == "": 490 return "%s %s" % (first, surname) 491 else: 492 # translators: needed for Arabic, ignore otherwise 493 return _("%(first)s %(surname)s, %(suffix)s" 494 ) % {'surname':surname, 'first':first, 'suffix':self.suffix} 495 496 def get_gedcom_parts(self): 497 """ 498 Returns a GEDCOM-formatted name dictionary. 499 500 .. note:: Fields patronymic and prefix are deprecated, prefix_list and 501 surname list, added. 502 """ 503 retval = {} 504 retval['given'] = self.first_name.strip() 505 retval['surname'] = self.get_surname().replace('/', '?') 506 retval['suffix'] = self.suffix 507 retval['title'] = self.title 508 retval['surnamelist'] = self.get_surnames() 509 retval['prefixes'] = self.get_prefixes() 510 retval['connectors'] = self.get_connectors() 511 retval['nick'] = self.nick 512 retval['famnick'] = self.famnick 513 return retval 514 515 def get_gedcom_name(self): 516 """ 517 Returns a GEDCOM-formatted name. 518 """ 519 firstname = self.first_name.strip() 520 surname = self.get_surname().replace('/', '?') 521 suffix = self.suffix 522 if suffix == "": 523 return '%s /%s/' % (firstname, surname) 524 else: 525 return '%s /%s/ %s' % (firstname, surname, suffix) 526