# # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000-2007 Donald N. Allingham # Copyright (C) 2009 Gary Burton # Copyright (C) 2011 Tim G L Lyons # # 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$ """ Make an 'Unknown' primary object """ #------------------------------------------------------------------------- # # Python modules # #------------------------------------------------------------------------- import time #------------------------------------------------------------------------- # # Gramps modules # #------------------------------------------------------------------------- from ..lib import (Person, Surname, Name, NameType, Family, FamilyRelType, Event, EventType, Source, Place, Citation, Repository, RepositoryType, MediaObject, Note, NoteType, StyledText, StyledTextTag, StyledTextTagType, Tag, ChildRef, ChildRefType) from .id import create_id from ..const import IMAGE_DIR from ..ggettext import sgettext as _ #------------------------------------------------------------------------- # # make_unknown # #------------------------------------------------------------------------- def make_unknown(class_arg, explanation, class_func, commit_func, transaction, **argv): """ Make a primary object and set some property so that it qualifies as "Unknown". Some object types need extra parameters: Family: db, Event: type (optional), Citation: methods to create/store source. Some theoretical underpinning This function exploits the fact that all import methods basically do the same thing: Create an object of the right type, fill it with some attributes, store it in the database. This function does the same, so the observation is why not use the creation and storage methods that the import routines use themselves, that makes nice reuse of code. To do this formally correct we would need to specify a interface (in the OOP sence) which the import methods would need to implement. For now, that is deemed too restrictive and here we just slip through because of the similarity in code of both GEDCOM and XML import methods. :param class_arg: The argument the class_func needs, typically a kind of id. :type class_arg: unspecified :param explanation: Handle of a note that explains the origin of primary obj :type explanation: str :param class_func: Method to create primary object. :type class_func: method :param commit_func: Method to store primary object in db. :type commit_func: method :param transactino: Database transaction handle :type transaction: str :param argv: Possible additional parameters :type param: unspecified :returns: List of newly created objects. :rtype: list """ retval = [] obj = class_func(class_arg) if isinstance(obj, Person): surname = Surname() surname.set_surname('Unknown') name = Name() name.add_surname(surname) name.set_type(NameType.UNKNOWN) obj.set_primary_name(name) elif isinstance(obj, Family): obj.set_relationship(FamilyRelType.UNKNOWN) handle = obj.handle if getattr(argv['db'].transaction, 'no_magic', False): backlinks = argv['db'].find_backlink_handles( handle, [Person.__name__]) for dummy, person_handle in backlinks: person = argv['db'].get_person_from_handle(person_handle) add_personref_to_family(obj, person) else: for person in argv['db'].iter_people(): if person._has_handle_reference('Family', handle): add_personref_to_family(obj, person) elif isinstance(obj, Event): if 'type' in argv: obj.set_type(argv['type']) else: obj.set_type(EventType.UNKNOWN) elif isinstance(obj, Place): obj.set_title(_('Unknown')) elif isinstance(obj, Source): obj.set_title(_('Unknown')) elif isinstance(obj, Citation): #TODO create a new source for every citation? obj2 = argv['source_class_func'](argv['source_class_arg']) obj2.set_title(_('Unknown')) obj2.add_note(explanation) argv['source_commit_func'](obj2, transaction, time.time()) retval.append(obj2) obj.set_reference_handle(obj2.handle) elif isinstance(obj, Repository): obj.set_name(_('Unknown')) obj.set_type(RepositoryType.UNKNOWN) elif isinstance(obj, MediaObject): obj.set_path(os.path.join(IMAGE_DIR, "image-missing.png")) obj.set_mime_type('image/png') obj.set_description(_('Unknown')) elif isinstance(obj, Note): obj.set_type(NoteType.UNKNOWN); text = _('Unknown, created to replace a missing note object.') link_start = text.index(',') + 2 link_end = len(text) - 1 tag = StyledTextTag(StyledTextTagType.LINK, 'gramps://Note/handle/%s' % explanation, [(link_start, link_end)]) obj.set_styledtext(StyledText(text, [tag])) elif isinstance(obj, Tag): if not hasattr(make_unknown, 'count'): make_unknown.count = 1 #primitive static variable obj.set_name(_("Unknown, was missing %(time)s (%(count)d)") % { 'time': time.strftime('%x %X', time.localtime()), 'count': make_unknown.count}) make_unknown.count += 1 else: raise TypeError("Object if of unsupported type") if hasattr(obj, 'add_note'): obj.add_note(explanation) commit_func(obj, transaction, time.time()) retval.append(obj) return retval def create_explanation_note(dbase): """ When creating objects to fill missing primary objects in imported files, those objects of type "Unknown" need a explanatory note. This funcion provides such a note for import methods. """ note = Note( _('Objects referenced by this note ' 'were missing in a file imported on %s.') % time.strftime('%x %X', time.localtime())) note.set_handle(create_id()) note.set_gramps_id(dbase.find_next_note_gramps_id()) # Use defaults for privacy, format and type. return note def add_personref_to_family(family, person): """ Given a family and person, set the parent/child references in the family, that match the person. """ handle = family.handle person_handle = person.handle if handle in person.get_family_handle_list(): if ((person.get_gender() == Person.FEMALE) and (family.get_mother_handle() is None)): family.set_mother_handle(person_handle) else: # This includes cases of Person.UNKNOWN if family.get_father_handle() is None: family.set_father_handle(person_handle) else: family.set_mother_handle(person_handle) if handle in person.get_parent_family_handle_list(): childref = ChildRef() childref.set_reference_handle(person_handle) childref.set_mother_relation(ChildRefType.UNKNOWN) childref.set_father_relation(ChildRefType.UNKNOWN) family.add_child_ref(childref)