Merge from 2.0.1

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

View File

@@ -281,26 +281,78 @@ class MergePeople:
else:
one.add_source_reference(xsrc)
def debug_person(self,person, msg=""):
if __debug__:
print "## %s person handle %s" % (msg,person.get_handle())
for h in person.get_family_handle_list():
fam = self.db.get_family_from_handle(h)
print " - family %s has father: %s, mother: %s" % \
(h,fam.get_father_handle(),fam.get_mother_handle())
for h,m1,m2 in person.get_parent_family_handle_list():
print " - parent family %s" % h
def merge(self):
"""
Perform the actual merge. A new person is created to store the
merged data. First, the person information is merged. This is a
very straight forward process. Second, the families associated
with the merged people must be modified to handle the family
information. This process can be tricky.
Finally, the merged person is delete from the database and the
entire transaction is committed.
"""
self.debug_person(self.p1, "P1")
self.debug_person(self.p2, "P2")
new = RelLib.Person()
trans = self.db.transaction_begin()
self.merge_person_information(new,trans)
self.merge_family_information(new,trans)
self.db.commit_person(new,trans)
self.debug_person(new, "NEW")
self.db.remove_person(self.old_handle,trans)
self.db.transaction_commit(trans,"Merge Person")
def merge_person_information(self,new,trans):
"""
Merging the person's individual information is pretty simple. The
person 'new' is a new, empty person. The data is loaded in this
new person. The idea is that all information that can possibly be
preserved is preserved.
"""
self.old_handle = self.p2.get_handle()
self.new_handle = self.p1.get_handle()
# Choose the handle from the target person. Since this is internal
# only information, no user visible information is lost.
new.set_handle(self.new_handle)
# The gender is chosen from the primary person. This is one case
# where data may be lost if you merge the data from two people of
# opposite genders.
new.set_gender(self.p1.get_gender())
# copy the GRAMPS Ids
self.merge_gramps_ids(new)
# copy names
self.merge_names(new)
# copy the birth event
self.merge_birth(new,trans)
# copy the death event
self.merge_death(new,trans)
# merge the event lists
self.merge_event_lists(new)
# copy attributes
new.set_attribute_list(self.p1.get_attribute_list() +
self.p2.get_attribute_list())
# copy names
new.set_alternate_names(self.p1.get_alternate_names() +
self.p2.get_alternate_names())
# copy addresses
new.set_address_list(self.p1.get_address_list() + self.p2.get_address_list())
@@ -320,68 +372,346 @@ class MergePeople:
for photo in self.p2.get_media_list():
new.add_media_reference(photo)
# note
note1 = self.p1.get_note_object()
note2 = self.p2.get_note_object()
new.set_note_object(self.merge_notes(note1,note2))
def merge(self):
def merge_gramps_ids(self,new):
"""
Merges the GRAMPS IDs. The new GRAMPS ID is taken from
destination person. The GRAMPS ID of the other person is added
to the merged person as an attribute.
"""
# copy of GRAMPS ID as an attribute
attr = RelLib.Attribute()
attr.set_type('Merged GRAMPS ID')
attr.set_value(self.p2.get_gramps_id())
new.add_attribute(attr)
new = RelLib.Person()
trans = self.db.transaction_begin()
# store GRAMPS ID of the destination person
new.set_gramps_id(self.p1.get_gramps_id())
self.merge_person_information(new,trans)
self.merge_family_information(new,trans)
self.db.commit_person(new,trans)
self.db.remove_person(self.old_handle,trans)
self.db.transaction_commit(trans,"Merge Person")
def merge_names(self, new):
"""
Merges the names of the two people into the destination. The
primary name of the destination person is kept as the primary
name.
def convert_child_ids(self, family_id, id1, id2, trans):
new_list = []
change = False
family = self.db.get_family_from_handle(family_id)
The other person's name is stored as an alternate name if it is
not entirely identical to the destination person's primary name.
for child_id in family.get_child_handle_list():
if child_id == id2:
new_list.append(id1)
change = True
else:
new_list.append(child_id)
if change:
family.set_child_handle_list(new_list)
In the current implementation, If only one person has a
nickname, it is assigned as the merged person's nickname. If
both people have nicknames, then the nickname of the second
person is lost.
Remaining alternate names are then added to the merged
person's alternate names.
"""
p1_name = self.p1.get_primary_name()
p2_name = self.p2.get_primary_name()
new.set_primary_name(self.p1.get_primary_name())
if not p2_name.is_equal(p1_name):
new.add_alternate_name(p2_name)
if self.p1.get_nick_name() == "":
new.set_nick_name(self.p2.get_nick_name())
else:
new.set_nick_name(self.p1.get_nick_name())
for name in self.p1.get_alternate_names():
new.add_alternate_name(name)
for name in self.p2.get_alternate_names():
new.add_alternate_name(name)
def merge_birth(self, new,trans):
"""
Merges the birth events of the two people. If the primary
person does not have a birth event, then the birth event from
the secodnary person is selected. If the primary person has
a birth date, then the merged person gets the primary person's
birth event, and the secondary person's birth event is added
as a 'Alternate Birth' event.
"""
handle1 = self.p1.get_birth_handle()
handle2 = self.p2.get_birth_handle()
if handle1:
new.set_birth_handle(handle1)
if handle2:
event = self.db.get_event_from_handle(handle2)
event.set_name('Alternate Birth')
self.db.add_event(event,trans)
new.add_event_handle(event.get_handle())
elif not handle1 and handle2:
new.set_birth_handle(handle2)
def merge_death(self, new, trans):
"""
Merges the death events of the two people. If the primary
person does not have a death event, then the death event from
the secodnary person is selected. If the primary person has
a death date, then the merged person gets the primary person's
death event, and the secondary person's death event is added
as a 'Alternate Death' event.
"""
handle1 = self.p1.get_death_handle()
handle2 = self.p2.get_death_handle()
if handle1:
new.set_death_handle(handle1)
if handle2:
event = self.db.get_event_from_handle(handle2)
event.set_handle(Utils.create_id())
event.set_name('Alternate Death')
new.add_event_handle(event.get_handle())
self.db.add_event(event,trans)
elif not handle1 and handle2:
new.set_death_handle(handle2)
def merge_event_lists(self, new):
"""
Merges the events from the two people into the destination
person. Duplicates are not transferred.
"""
data_list = new.get_event_list()
for handle in self.p1.get_event_list():
if handle not in data_list:
data_list.append(handle)
for handle in self.p2.get_event_list():
if handle not in data_list:
data_list.append(handle)
new.set_event_list(data_list)
def merge_family_information(self, new, trans):
"""
Merge the parent families and the relationship families of the
selected people.
"""
self.merge_parents(new, trans)
self.merge_relationships(new, trans)
def merge_parents(self, new, trans):
"""
Merging the parent list is not too difficult. We grab the
parent list of the destination person. We then loop through
the parent list of the secondary person, adding to the parent
list any parents that are not already there. This eliminates
any duplicates.
Once this has been completed, we loop through each family,
converting any child handles referring to the secondary person
to the destination person.
"""
parent_list = self.p1.get_parent_family_handle_list()
# copy handles of families that are not common between the
# two lists
for fid in self.p2.get_parent_family_handle_list():
if fid not in parent_list:
parent_list.append(fid)
# loop through the combined list, converting the child handles
# of the families, and adding the families to the merged
# person
for (family_handle,mrel,frel) in parent_list:
self.convert_child_ids(family_handle, self.new_handle,
self.old_handle, trans)
new.add_parent_family_handle(family_handle, mrel, frel)
def convert_child_ids(self, fhandle, new_handle, old_handle, trans):
"""
Search the family associated with fhandle, and replace all
child handles that match old_handle with new_handle.
"""
family = self.db.get_family_from_handle(fhandle)
new_child_list = []
orig_list = family.get_child_handle_list()
# loop through original child list. If a handle matches the
# old handle, replace it with the new handle if the new handle
# is not already in the list
for child_id in orig_list:
if child_id == old_handle:
if new_handle not in new_child_list:
new_child_list.append(new_handle)
elif child_id not in new_child_list:
new_child_list.append(child_id)
# compare the new list with the original list. If this list
# is different, we need to save the changes to the database.
if new_child_list != orig_list:
family.set_child_handle_list(new_child_list)
self.db.commit_family(family,trans)
def merge_parents(self, new, trans):
f1_list = self.p1.get_parent_family_handle_list()
f2_list = self.p2.get_parent_family_handle_list()
parent_list = f1_list
for fid in f2_list:
self.convert_child_ids(fid[0], self.new_handle, self.old_handle, trans)
parent_list.append(fid)
for fid in parent_list:
new.add_parent_family_handle(fid[0],fid[1],fid[2])
def merge_family_information(self, new, trans):
self.merge_parents(new, trans)
self.merge_families(new, trans)
def merge_relationships(self,new,trans):
"""
Merges the relationships associated with the merged people.
"""
def find_family(self,family):
if self.p1.get_gender() == RelLib.Person.MALE:
mother_handle = family.get_mother_handle()
father_handle = self.p1.get_handle()
else:
father_handle = family.get_father_handle()
mother_handle = self.p1.get_handle()
family_num = 0
family_list = self.p1.get_family_handle_list()
for src_handle in self.p2.get_family_handle_list():
for myfamily_handle in self.db.get_family_handles():
myfamily = self.db.get_family_from_handle(myfamily_handle)
if (myfamily.get_father_handle() == father_handle and
myfamily.get_mother_handle() == mother_handle):
return myfamily
return None
src_family = self.db.get_family_from_handle(src_handle)
family_num += 1
if not src_family or src_family in family_list:
continue
tgt_family = self.find_modified_family(src_family)
# existing family is found
if tgt_family:
# The target family is already a family in the person's
# family list.
if tgt_family.get_handle() in self.p1.get_family_handle_list():
self.merge_existing_family(new, src_family, tgt_family, trans)
continue
# This is the case the family is not already in the person's
# family list.
else:
self.merge_family_pair(tgt_family,src_family,trans)
# change parents of the family to point to the new
# family
self.adjust_family_pointers(tgt_family, src_family, trans)
new.remove_family_handle(src_handle)
self.db.remove_family(src_handle,trans)
if __debug__:
print "Deleted src_family %s" % src_handle
else:
for fid in self.p1.get_family_handle_list():
if fid not in new.get_family_handle_list():
new.add_family_handle(fid)
if src_handle in new.get_family_handle_list():
continue
src_family = self.db.get_family_from_handle(src_handle)
new.add_family_handle(src_handle)
if src_family.get_father_handle() == self.old_handle:
src_family.set_father_handle(self.new_handle)
if __debug__:
print "Family %s now has father %s" % (
src_handle, self.new_handle)
if src_family.get_mother_handle() == self.old_handle:
src_family.set_mother_handle(self.new_handle)
if __debug__:
print "Family %s now has mother %s" % (
src_handle, self.new_handle)
self.db.commit_family(src_family,trans)
# a little debugging here
cursor = self.db.get_family_cursor()
data = cursor.first()
while data:
fam = RelLib.Family()
fam.unserialize(data[1])
if self.p2 in fam.get_child_handle_list():
fam.remove_child_handle(self.p2)
fam.add_child_handle(self.p1)
if self.p2 == fam.get_father_handle():
fam.set_father_handle(self.p1)
if self.p2 == fam.get_mother_handle():
fam.set_mother_handle(self.p1)
if fam.get_father_handle() == None and fam.get_mother_handle() == None:
self.delete_empty_family(fam,trans)
data = cursor.next()
def find_modified_family(self,family):
"""
Look for a existing family that matches the merged person. This means
looking at the current family, and replacing the secondary person's
handle with the merged person's handle. Search the family table for
a family that matches this new mother/father pair.
If no family is found, return None
"""
family_handle = family.get_handle()
if __debug__:
print "SourceFamily: %s" % family_handle
# Determine the mother and father handles for the search.
# This is determined by replacing the secodnary person's
# handle with the primary person's handle in the mother/father
# pair.
mhandle = family.get_mother_handle()
if mhandle == self.old_handle:
mhandle = self.new_handle
fhandle = family.get_father_handle()
if fhandle == self.old_handle:
fhandle = self.new_handle
# loop through the families using a cursor. Check the handles
# for a mother/father match.
cursor = self.db.get_family_cursor()
node = cursor.next()
myfamily = None
while node:
# data[2] == father_handle field, data[2] == mother_handle field
(thandle,data) = node
if data[2] == fhandle and data[3] == mhandle and thandle != family_handle:
myfamily = RelLib.Family()
myfamily.unserialize(data)
break
node = cursor.next()
if __debug__:
if myfamily:
print "TargetFamily: %s" % myfamily.get_handle()
else:
print "TargetFamily: None"
cursor.close()
return myfamily
def merge_existing_family(self, new, src_family, tgt_family, trans):
src_family_handle = src_family.get_handle()
father_id = tgt_family.get_father_handle()
father = self.db.get_person_from_handle(father_id)
mother_id = tgt_family.get_mother_handle()
mother = self.db.get_person_from_handle(mother_id)
if father and src_family_handle in father.get_family_handle_list():
father.remove_family_handle(src_family_handle)
if __debug__:
print "Removed family %s from father %s" % (src_family_handle, father_id)
self.db.commit_person(father,trans)
if mother and src_family_handle in mother.get_family_handle_list():
mother.remove_family_handle(src_family_handle)
if __debug__:
print "Removed family %s from mother %s" % (src_family_handle, mother_id)
self.db.commit_person(mother,trans)
self.merge_family_pair(tgt_family,src_family,trans)
for child_handle in src_family.get_child_handle_list():
if child_handle != self.new_handle:
child = self.db.get_person_from_handle(child_handle)
if child.remove_parent_family_handle(src_family_handle):
self.db.commit_person(child,trans)
# delete the old source family
self.db.remove_family(src_family_handle,trans)
if __debug__:
print "Deleted src_family %s" % src_family_handle
self.db.commit_family(tgt_family,trans)
new.add_family_handle(tgt_family.get_handle())
def merge_family_pair(self,tgt_family,src_family,trans):
@@ -391,13 +721,13 @@ class MergePeople:
if child_handle not in tgt_family.get_child_handle_list():
child = self.db.get_person_from_handle(child_handle)
parents = child.get_parent_family_handle_list()
tgt_family.add_child_handle(child)
if child.get_main_parents_family_handle() == src_family:
child.set_main_parent_family_handle(tgt_family)
tgt_family.add_child_handle(child_handle)
if child.get_main_parents_family_handle() == src_family.get_handle():
child.set_main_parent_family_handle(tgt_family.get_handle())
i = 0
for fam in parents[:]:
if fam[0] == src_family.get_handle():
parents[i] = (tgt_family,fam[1],fam[2])
parents[i] = (tgt_family.get_handle(),fam[1],fam[2])
i += 1
self.db.commit_person(child,trans)
@@ -430,135 +760,48 @@ class MergePeople:
for photo in src_family.get_media_list():
tgt_family.add_media_reference(photo)
def merge_families(self,new,trans):
def adjust_family_pointers(self, tgt_family, src_family, trans):
"""
Remove the people from one family and merge them into the other.
It is not necessary to remove from the src_family, since the
src_family is going to be removed.
"""
src_family_handle = src_family.get_handle()
tgt_family_handle = tgt_family.get_handle()
family_num = 0
family_list = self.p1.get_family_handle_list()
for src_family_handle in self.p2.get_family_handle_list():
father_handle = src_family.get_father_handle()
if father_handle:
father = self.db.get_person_from_handle(father_handle)
src_family = self.db.get_family_from_handle(src_family_handle)
family_num += 1
# add to new family
father.add_family_handle(tgt_family_handle)
if __debug__:
print "Added family %s to father %s" % (
tgt_family_handle, father_handle)
if not src_family or src_family in family_list:
continue
# commit the change
self.db.commit_person(father,trans)
tgt_family = self.find_family(src_family)
mother_handle = src_family.get_mother_handle()
if mother_handle:
mother = self.db.get_person_from_handle(mother_handle)
#
# This is the case where a new family to be added to the
# p1 as a result of the merge already exists as a
# family. In this case, we need to remove the old source
# family (with the pre-merge identity of the p1) from
# both the parents
#
# add to new family
mother.add_family_handle(tgt_family_handle)
if __debug__:
print "Added family %s to mother %s" % (
tgt_family_handle, mother_handle)
if tgt_family:
tgt_family_handle = tgt_family.get_handle()
if tgt_family_handle in self.p1.get_family_handle_list():
father_id = tgt_family.get_father_handle()
father = self.db.get_person_from_handle(father_id)
mother_id = tgt_family.get_mother_handle()
mother = self.db.get_person_from_handle(mother_id)
# commit the change
self.db.commit_person(mother,trans)
if father and src_family_handle in father.get_family_handle_list():
father.remove_family_handle(src_family_handle)
self.db.commit_person(father,trans)
if mother and src_family_handle in mother.get_family_handle_list():
mother.remove_family_handle(src_family_handle)
self.db.commit_person(mother,trans)
self.merge_family_pair(tgt_family,src_family,trans)
for child_handle in src_family.get_child_handle_list():
if child_handle != self.new_handle:
child = self.db.get_person_from_handle(child_handle)
if child.remove_parent_family_handle(src_family_handle):
self.db.commit_person(child,trans)
# remove the children from the old family
for child_handle in src_family.get_child_handle_list():
if child_handle != self.new_handle:
child = self.db.get_person_from_handle(child_handle)
if child.remove_parent_family_handle(src_family_handle):
self.db.commit_person(child,trans)
# delete the old source family
self.db.remove_family(src_family_handle,trans)
self.db.commit_family(tgt_family,trans)
new.add_family_handle(tgt_family_handle)
continue
# This is the case where a new family to be added
# and it is not already in the list.
else:
# tgt_family a duplicate family, transfer children from
# the p2 family, and delete the family. Not sure
# what to do about marriage/divorce date/place yet.
# transfer child to new family, alter children to
# point to the correct family
self.merge_family_pair(tgt_family,src_family,trans)
# change parents of the family to point to the new
# family
father_handle = src_family.get_father_handle()
if father_handle:
father = self.db.get_person_from_handle(father_handle)
father.remove_family_handle(src_family_handle)
father.add_family_handle(tgt_family_handle)
self.db.commit_person(father,trans)
mother_handle = src_family.get_mother_handle()
if mother_handle:
mother = self.db.get_person_from_handle(mother_handle)
mother.remove_family_handle(src_family_handle)
mother.add_family_handle(tgt_family_handle)
self.db.commit_person(mother,trans)
for child_handle in src_family.get_child_handle_list():
if child_handle != self.new_handle:
child = self.db.get_person_from_handle(child_handle)
if child.remove_parent_family_handle(src_family_handle):
self.db.commit_person(child,trans)
new.remove_family_handle(src_family_handle)
self.db.remove_family(src_family_handle,trans)
else:
for fid in self.p1.get_family_handle_list():
new.add_family_handle(fid)
for src_family_handle in self.p2.get_family_handle_list():
if src_family_handle in self.p1.get_family_handle_list():
continue
src_family = self.db.get_family_from_handle(src_family_handle)
new.add_family_handle(src_family_handle)
if src_family.get_father_handle() == self.old_handle:
src_family.set_father_handle(self.new_handle)
if src_family.get_mother_handle() == self.old_handle:
src_family.set_mother_handle(self.new_handle)
self.db.commit_family(src_family,trans)
# a little debugging here
cursor = self.db.get_family_cursor()
data = cursor.first()
while data:
fam = RelLib.Family()
fam.unserialize(data[1])
if self.p2 in fam.get_child_handle_list():
fam.remove_child_handle(self.p2)
fam.add_child_handle(self.p1)
if self.p2 == fam.get_father_handle():
fam.set_father_handle(self.p1)
if self.p2 == fam.get_mother_handle():
fam.set_mother_handle(self.p1)
if fam.get_father_handle() == None and fam.get_mother_handle() == None:
self.delete_empty_family(fam,trans)
data = cursor.next()
def remove_marriage(self,family,person,trans):
if person:
@@ -576,13 +819,8 @@ class MergePeople:
child.remove_parent_family_handle(family_handle)
self.db.commit_person(child,trans)
self.db.remove_family(family_handle,trans)
def merge_gramps_ids(self,new):
new.set_gramps_id(self.p1.get_gramps_id())
attr = RelLib.Attribute()
attr.set_type('Merged GRAMPS ID')
attr.set_value(self.p2.get_gramps_id())
new.add_attribute(attr)
if __debug__:
print "Deleted empty family %s" % family_handle
def merge_notes(self, note1, note2):
if note1 and not note2:
@@ -595,49 +833,3 @@ class MergePeople:
return note1
return None
def merge_names(self, new):
new.set_primary_name(self.p1.get_primary_name())
new.add_alternate_name(self.p2.get_primary_name())
if self.p1.get_nick_name() == "":
new.set_nick_name(self.p2.get_nick_name())
else:
new.set_nick_name(self.p1.get_nick_name())
def merge_death(self, new, trans):
handle1 = self.p1.get_death_handle()
handle2 = self.p2.get_death_handle()
if handle1:
new.set_death_handle(handle1)
if handle2:
event = self.db.get_event_from_handle(handle2)
event.set_handle(Utils.create_id())
event.set_name('Alternate Death')
new.add_event_handle(event.get_handle())
self.db.add_event(event,trans)
elif not handle1 and handle2:
new.set_death_handle(handle2)
def merge_birth(self, new,trans):
handle1 = self.p1.get_birth_handle()
handle2 = self.p2.get_birth_handle()
if handle1:
new.set_birth_handle(handle1)
if handle2:
event = self.db.get_event_from_handle(handle2)
event.set_name('Alternate Birth')
self.db.add_event(event,trans)
new.add_event_handle(event.get_handle())
elif not handle1 and handle2:
new.set_birth_handle(handle2)
def merge_event_lists(self, new):
data_list = new.get_event_list()
for handle in self.p1.get_event_list():
if handle not in data_list:
data_list.append(handle)
for handle in self.p2.get_event_list():
if handle not in data_list:
data_list.append(handle)
new.set_event_list(data_list)