Merge pull request #1098 from prculley/noteref
This commit is contained in:
commit
1ba1265356
@ -1894,14 +1894,10 @@ class DbWriteBase(DbReadBase):
|
||||
|
||||
handle = person.get_handle()
|
||||
|
||||
person_list = [
|
||||
item[1] for item in
|
||||
self.find_backlink_handles(handle, ['Person'])]
|
||||
|
||||
for phandle in person_list:
|
||||
prsn = self.get_person_from_handle(phandle)
|
||||
prsn.remove_handle_references('Person', [handle])
|
||||
self.commit_person(prsn, trans)
|
||||
for obj_type, ohandle in self.find_backlink_handles(handle):
|
||||
obj = self.method("get_%s_from_handle", obj_type)(ohandle)
|
||||
obj.remove_handle_references('Person', [handle])
|
||||
self.method("commit_%s", obj_type)(obj, trans)
|
||||
self.remove_person(handle, trans)
|
||||
|
||||
def remove_family_relationships(self, family_handle, trans=None):
|
||||
@ -1919,13 +1915,11 @@ class DbWriteBase(DbReadBase):
|
||||
"""
|
||||
Remove a family and all that references it; trans is compulsory.
|
||||
"""
|
||||
person_list = [item[1] for item in
|
||||
self.find_backlink_handles(family_handle, ['Person'])]
|
||||
for phandle in person_list:
|
||||
person = self.get_person_from_handle(phandle)
|
||||
if person:
|
||||
person.remove_handle_references('Family', [family_handle])
|
||||
self.commit_person(person, trans)
|
||||
for obj_type, ohandle in self.find_backlink_handles(family_handle):
|
||||
obj = self.method("get_%s_from_handle", obj_type)(ohandle)
|
||||
if obj:
|
||||
obj.remove_handle_references('Family', [family_handle])
|
||||
self.method("commit_%s", obj_type)(obj, trans)
|
||||
self.remove_family(family_handle, trans)
|
||||
|
||||
def remove_parent_from_family(self, person_handle, family_handle,
|
||||
|
@ -114,7 +114,8 @@ class BaseTest(unittest.TestCase):
|
||||
"""
|
||||
rule = HasReferenceCountOf(['greater than', '1'])
|
||||
self.assertEqual(self.filter_with_rule(rule), set([
|
||||
'238CGQ939HG18SS5MG', 'b39fe1cfc1305ac4a21']))
|
||||
'238CGQ939HG18SS5MG', 'b39fe1cfc1305ac4a21',
|
||||
'Y3ARGQWE088EQRTTDH']))
|
||||
|
||||
def test_hassourcecount(self):
|
||||
"""
|
||||
|
@ -161,7 +161,79 @@ class Note(BasicPrimaryObject):
|
||||
:returns: List of (classname, handle) tuples for referenced objects.
|
||||
:rtype: list
|
||||
"""
|
||||
return self.get_referenced_tag_handles()
|
||||
reflist = []
|
||||
for dom, obj, prop, hndl in self.get_links():
|
||||
if dom != "gramps" or prop != "handle":
|
||||
continue
|
||||
else:
|
||||
reflist.append((obj, hndl))
|
||||
reflist.extend(self.get_referenced_tag_handles())
|
||||
return reflist
|
||||
|
||||
def has_handle_reference(self, classname, handle):
|
||||
"""
|
||||
Return True if the object has reference to a given handle of given
|
||||
primary object type.
|
||||
|
||||
:param classname: The name of the primary object class.
|
||||
:type classname: str
|
||||
:param handle: The handle to be checked.
|
||||
:type handle: str
|
||||
|
||||
:returns:
|
||||
Returns whether the object has reference to this handle of
|
||||
this object type.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
for dom, obj, prop, hndl in self.get_links():
|
||||
if dom == "gramps" and prop == "handle" and \
|
||||
obj == classname and hndl == handle:
|
||||
return True
|
||||
return False
|
||||
|
||||
def remove_handle_references(self, classname, handle_list):
|
||||
"""
|
||||
Remove all references in this object to object handles in the list.
|
||||
|
||||
:param classname: The name of the primary object class.
|
||||
:type classname: str
|
||||
:param handle_list: The list of handles to be removed.
|
||||
:type handle_list: str
|
||||
|
||||
If the link is in the styled text, we just remove the style for that
|
||||
link.
|
||||
"""
|
||||
tags = []
|
||||
for styledtext_tag in self.text.get_tags():
|
||||
if(styledtext_tag.name == StyledTextTagType.LINK and
|
||||
styledtext_tag.value.startswith("gramps://")):
|
||||
obj, prop, value = styledtext_tag.value[9:].split("/", 2)
|
||||
if obj == classname and prop == 'handle' and \
|
||||
value in handle_list:
|
||||
continue
|
||||
tags.append(styledtext_tag)
|
||||
self.text.set_tags(tags)
|
||||
|
||||
def replace_handle_reference(self, classname, old_handle, new_handle):
|
||||
"""
|
||||
Replace all references to old handle with those to the new handle.
|
||||
|
||||
:param classname: The name of the primary object class.
|
||||
:type classname: str
|
||||
:param old_handle: The handle to be replaced.
|
||||
:type old_handle: str
|
||||
:param new_handle: The handle to replace the old one with.
|
||||
:type new_handle: str
|
||||
"""
|
||||
for styledtext_tag in self.text.get_tags():
|
||||
if(styledtext_tag.name == StyledTextTagType.LINK and
|
||||
styledtext_tag.value.startswith("gramps://")):
|
||||
obj, prop, value = styledtext_tag.value[9:].split("/", 2)
|
||||
if(obj == classname and prop == 'handle' and
|
||||
value == old_handle):
|
||||
styledtext_tag.value = styledtext_tag.value.replace(
|
||||
old_handle, new_handle)
|
||||
|
||||
def merge(self, acquisition):
|
||||
"""
|
||||
|
@ -22,6 +22,15 @@
|
||||
"""
|
||||
NoteBase class for Gramps.
|
||||
"""
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import logging
|
||||
|
||||
LOG = logging.getLogger(".note")
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -132,6 +141,25 @@ class NoteBase:
|
||||
|
||||
return False
|
||||
|
||||
def remove_note_references(self, handle_list):
|
||||
"""
|
||||
Remove the specified handles from the list of note handles, and all
|
||||
secondary child objects.
|
||||
|
||||
:param citation_handle_list: The list of note handles to be removed
|
||||
:type handle: list
|
||||
"""
|
||||
LOG.debug('enter remove_note handle: %s self: %s note_list: %s',
|
||||
handle_list, self, self.note_list)
|
||||
for handle in handle_list:
|
||||
if handle in self.note_list:
|
||||
LOG.debug('remove handle %s from note_list %s',
|
||||
handle, self.note_list)
|
||||
self.note_list.remove(handle)
|
||||
LOG.debug('get_note_child_list %s', self.get_note_child_list())
|
||||
for item in self.get_note_child_list():
|
||||
item.remove_note_references(handle_list)
|
||||
|
||||
def set_note_list(self, note_list):
|
||||
"""
|
||||
Assign the passed list to be object's list of :class:`~.note.Note`
|
||||
|
@ -39,8 +39,10 @@ from .tableobj import TableObject
|
||||
from .privacybase import PrivacyBase
|
||||
from .citationbase import CitationBase
|
||||
from .mediabase import MediaBase
|
||||
from .notebase import NoteBase
|
||||
from .tagbase import TagBase
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Basic Primary Object class
|
||||
@ -274,6 +276,8 @@ class PrimaryObject(BasicPrimaryObject):
|
||||
self.remove_citation_references(handle_list)
|
||||
elif classname == 'Media' and isinstance(self, MediaBase):
|
||||
self.remove_media_references(handle_list)
|
||||
elif classname == 'Note' and isinstance(self, NoteBase):
|
||||
self.remove_note_references(handle_list)
|
||||
else:
|
||||
self._remove_handle_references(classname, handle_list)
|
||||
|
||||
|
@ -967,6 +967,49 @@ class NoteCheck(unittest.TestCase, PrivacyBaseTest):
|
||||
self.titanic = Note("hello world")
|
||||
self.ref_obj = Note("hello world")
|
||||
|
||||
def test_note_replace_handle_reference(self):
|
||||
ptag = StyledTextTag(name=StyledTextTagType.LINK,
|
||||
value="gramps://Event/handle/e0000",
|
||||
ranges=[0, 3])
|
||||
self.phoenix.text.set_tags([ptag])
|
||||
rtag = StyledTextTag(name=StyledTextTagType.LINK,
|
||||
value="gramps://Event/handle/e0001",
|
||||
ranges=[0, 3])
|
||||
self.ref_obj.text.set_tags([rtag])
|
||||
self.phoenix.replace_handle_reference('Event', 'e0000', 'e0001')
|
||||
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
|
||||
|
||||
def test_note_has_handle_reference(self):
|
||||
ptag = StyledTextTag(name=StyledTextTagType.LINK,
|
||||
value="gramps://Event/handle/e0000",
|
||||
ranges=[0, 3])
|
||||
self.phoenix.text.set_tags([ptag])
|
||||
self.assertTrue(self.phoenix.has_handle_reference('Event', 'e0000'))
|
||||
self.assertFalse(self.phoenix.has_handle_reference('Event', 'e0001'))
|
||||
|
||||
def test_note_get_referenced_handles(self):
|
||||
tag0 = StyledTextTag(name=StyledTextTagType.LINK,
|
||||
value="gramps://Event/handle/e0000",
|
||||
ranges=[0, 2])
|
||||
tag1 = StyledTextTag(name=StyledTextTagType.LINK,
|
||||
value="gramps://Person/handle/i0001",
|
||||
ranges=[2, 3])
|
||||
self.phoenix.text.set_tags([tag0, tag1])
|
||||
self.phoenix.add_tag("t1234")
|
||||
tag_list = self.phoenix.get_referenced_handles()
|
||||
self.assertEqual(tag_list, [('Event', 'e0000'), ('Person', 'i0001'),
|
||||
('Tag', 't1234')])
|
||||
self.assertFalse(self.phoenix.has_handle_reference('Event', 'e0001'))
|
||||
|
||||
def test_note_remove_handle_references(self):
|
||||
ptag = StyledTextTag(name=StyledTextTagType.LINK,
|
||||
value="gramps://Event/handle/e0000",
|
||||
ranges=[0, 3])
|
||||
self.phoenix.text.set_tags([ptag])
|
||||
self.phoenix.remove_handle_references('Event', ['e0000'])
|
||||
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
|
||||
|
||||
|
||||
class NoteBaseCheck(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.phoenix = NoteBase()
|
||||
@ -984,6 +1027,7 @@ class NoteBaseCheck(unittest.TestCase):
|
||||
def test_different(self):
|
||||
ref_note_list = NoteBase(self.phoenix)
|
||||
note = Note("note other")
|
||||
note.set_handle('654321')
|
||||
self.titanic.add_note(note.get_handle())
|
||||
ref_note_list.add_note(note.get_handle())
|
||||
self.phoenix._merge_note_list(self.titanic)
|
||||
@ -1018,6 +1062,14 @@ class NoteBaseCheck(unittest.TestCase):
|
||||
self.phoenix.replace_note_references('','')
|
||||
self.assertEqual(self.phoenix.serialize(), ref_note_list.serialize())
|
||||
|
||||
def test_remove_note_references(self):
|
||||
note = Note("note other")
|
||||
note.set_handle('654321')
|
||||
self.phoenix.add_note(note.get_handle())
|
||||
self.phoenix.remove_note_references(['123456', '654321'])
|
||||
ref_note_list = NoteBase()
|
||||
self.assertEqual(self.phoenix.serialize(), ref_note_list.serialize())
|
||||
|
||||
class PersonCheck(unittest.TestCase, PrivacyBaseTest, MediaBaseTest,
|
||||
AttrBaseTest, NoteBaseTest, CitationBaseTest):
|
||||
def setUp(self):
|
||||
|
@ -28,8 +28,8 @@ Provide merge capabilities for citations.
|
||||
# Gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from ..lib import (Person, Family, Event, Place,
|
||||
Media, Repository, Citation, Source)
|
||||
from ..lib import (Person, Family, Event, Place, Media, Repository,
|
||||
Citation, Source, Note)
|
||||
from ..db import DbTxn
|
||||
from ..const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.sgettext
|
||||
@ -105,6 +105,12 @@ class MergeCitationQuery:
|
||||
source.replace_citation_references(old_handle,
|
||||
new_handle)
|
||||
self.database.commit_source(source, trans)
|
||||
elif class_name == Note.__name__:
|
||||
note = self.database.get_note_from_handle(handle)
|
||||
assert(note.has_handle_reference('Citation', old_handle))
|
||||
note.replace_handle_reference(
|
||||
'Citation', old_handle, new_handle)
|
||||
self.database.commit_note(note, trans)
|
||||
else:
|
||||
raise MergeError("Encounter an object of type %s that has "
|
||||
"a citation reference." % class_name)
|
||||
|
@ -27,7 +27,7 @@ Provide merge capabilities for events.
|
||||
# Gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from ..lib import Person, Family
|
||||
from ..lib import Person, Family, Note
|
||||
from ..db import DbTxn
|
||||
from ..const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.sgettext
|
||||
@ -88,6 +88,12 @@ class MergeEventQuery:
|
||||
family.replace_handle_reference("Event", old_handle,
|
||||
new_handle)
|
||||
self.database.commit_family(family, trans)
|
||||
elif class_name == Note.__name__:
|
||||
note = self.database.get_note_from_handle(handle)
|
||||
assert(note.has_handle_reference('Event', old_handle))
|
||||
note.replace_handle_reference(
|
||||
'Event', old_handle, new_handle)
|
||||
self.database.commit_note(note, trans)
|
||||
else:
|
||||
raise MergeError("Encounter an object of type %s that has "
|
||||
"an event reference." % class_name)
|
||||
|
@ -194,12 +194,17 @@ class MergeFamilyQuery:
|
||||
if phoenix_mother:
|
||||
phoenix_mother.remove_family_handle(old_handle)
|
||||
self.database.commit_person(phoenix_mother, trans)
|
||||
# replace the family in lds ordinances
|
||||
for (dummy, person_handle) in self.database.find_backlink_handles(
|
||||
old_handle, ['Person']):
|
||||
if person_handle in (self.titanic_fh, self.titanic_mh):
|
||||
# replace the family in lds ordinances and notes
|
||||
for (ref_obj, ref_handle) in self.database.find_backlink_handles(
|
||||
old_handle, ['Person', 'Note']):
|
||||
if ref_handle in (self.titanic_fh, self.titanic_mh):
|
||||
continue
|
||||
person = self.database.get_person_from_handle(person_handle)
|
||||
person.replace_handle_reference('Family', old_handle,new_handle)
|
||||
self.database.commit_person(person, trans)
|
||||
obj = self.database.method(
|
||||
"get_%s_from_handle", ref_obj)(ref_handle)
|
||||
assert obj.has_handle_reference('Family', old_handle)
|
||||
obj.replace_handle_reference(
|
||||
'Family', old_handle, new_handle)
|
||||
if ref_handle != old_handle:
|
||||
self.database.method("commit_%s", ref_obj)(obj, trans)
|
||||
|
||||
self.database.remove_family(old_handle, trans)
|
||||
|
@ -27,7 +27,7 @@ Provide merge capabilities for media objects.
|
||||
# Gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from ..lib import Person, Family, Event, Source, Citation, Place
|
||||
from ..lib import Person, Family, Event, Source, Citation, Place, Note
|
||||
from ..db import DbTxn
|
||||
from ..const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.sgettext
|
||||
@ -90,6 +90,12 @@ class MergeMediaQuery:
|
||||
assert(place.has_media_reference(old_handle))
|
||||
place.replace_media_references(old_handle, new_handle)
|
||||
self.database.commit_place(place, trans)
|
||||
elif class_name == Note.__name__:
|
||||
note = self.database.get_note_from_handle(handle)
|
||||
assert(note.has_handle_reference('Media', old_handle))
|
||||
note.replace_handle_reference(
|
||||
'Media', old_handle, new_handle)
|
||||
self.database.commit_note(note, trans)
|
||||
else:
|
||||
raise MergeError("Encounter an object of type % s that has "
|
||||
"a media object reference." % class_name)
|
||||
|
@ -28,7 +28,7 @@ Provide merge capabilities for notes.
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from ..lib import (Person, Family, Event, Place, Source, Citation, Repository,
|
||||
Media)
|
||||
Media, Note)
|
||||
from ..db import DbTxn
|
||||
from ..const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.sgettext
|
||||
@ -99,6 +99,12 @@ class MergeNoteQuery:
|
||||
assert(repo.has_note_reference(old_handle))
|
||||
repo.replace_note_references(old_handle, new_handle)
|
||||
self.database.commit_repository(repo, trans)
|
||||
elif class_name == Note.__name__:
|
||||
note = self.database.get_note_from_handle(handle)
|
||||
assert(note.has_handle_reference('Note', old_handle))
|
||||
note.replace_handle_reference(
|
||||
'Note', old_handle, new_handle)
|
||||
self.database.commit_note(note, trans)
|
||||
else:
|
||||
raise MergeError("Encounter object of type %s that has "
|
||||
"a note reference." % class_name)
|
||||
|
@ -100,14 +100,16 @@ class MergePersonQuery:
|
||||
spouse.remove_family_handle(family_handle)
|
||||
self.database.commit_person(spouse, trans)
|
||||
# replace the family in lds ordinances
|
||||
for (dummy, person_handle) in self.database.find_backlink_handles(
|
||||
family_handle, ['Person']):
|
||||
if person_handle == old_handle:
|
||||
for (ref_obj, ref_handle) in self.database.find_backlink_handles(
|
||||
family_handle, ['Person', 'Note']):
|
||||
if ref_handle == old_handle:
|
||||
continue
|
||||
person = self.database.get_person_from_handle(person_handle)
|
||||
person.replace_handle_reference('Family', family_handle,
|
||||
main_family_handle)
|
||||
self.database.commit_person(person, trans)
|
||||
obj = self.database.method(
|
||||
"get_%s_from_handle", ref_obj)(ref_handle)
|
||||
assert obj.has_handle_reference('Family', family_handle)
|
||||
obj.replace_handle_reference('Family', family_handle,
|
||||
main_family_handle)
|
||||
self.database.method("commit_%s", ref_obj)(obj, trans)
|
||||
self.database.remove_family(family_handle, trans)
|
||||
self.database.commit_family(main_family, trans)
|
||||
|
||||
@ -133,13 +135,15 @@ class MergePersonQuery:
|
||||
self.phoenix.merge(self.titanic)
|
||||
self.database.commit_person(self.phoenix, trans)
|
||||
|
||||
for (dummy, person_handle) in self.database.find_backlink_handles(
|
||||
old_handle, ['Person']):
|
||||
person = self.database.get_person_from_handle(person_handle)
|
||||
assert person.has_handle_reference('Person', old_handle)
|
||||
person.replace_handle_reference('Person', old_handle, new_handle)
|
||||
if person_handle != old_handle:
|
||||
self.database.commit_person(person, trans)
|
||||
for (ref_obj, handle) in self.database.find_backlink_handles(
|
||||
old_handle, ['Person', 'Note']):
|
||||
obj = self.database.method(
|
||||
"get_%s_from_handle", ref_obj)(handle)
|
||||
assert obj.has_handle_reference('Person', old_handle)
|
||||
obj.replace_handle_reference(
|
||||
'Person', old_handle, new_handle)
|
||||
if handle != old_handle:
|
||||
self.database.method("commit_%s", ref_obj)(obj, trans)
|
||||
|
||||
for family_handle in self.phoenix.get_parent_family_handle_list():
|
||||
family = self.database.get_family_from_handle(family_handle)
|
||||
|
@ -28,7 +28,7 @@ Provide merge capabilities for places.
|
||||
# Gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from ..lib import Person, Family, Event, Place
|
||||
from ..lib import Person, Family, Event, Place, Note
|
||||
from ..db import DbTxn
|
||||
from ..const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.sgettext
|
||||
@ -85,6 +85,12 @@ class MergePlaceQuery:
|
||||
place.replace_handle_reference('Place', old_handle,
|
||||
new_handle)
|
||||
self.database.commit_place(place, trans)
|
||||
elif class_name == Note.__name__:
|
||||
note = self.database.get_note_from_handle(handle)
|
||||
assert(note.has_handle_reference('Place', old_handle))
|
||||
note.replace_handle_reference('Place', old_handle,
|
||||
new_handle)
|
||||
self.database.commit_note(note, trans)
|
||||
else:
|
||||
raise MergeError("Encounter an object of type %s that has "
|
||||
"a place reference." % class_name)
|
||||
|
@ -27,7 +27,7 @@ Provide merge capabilities for repositories.
|
||||
# Gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from ..lib import Source
|
||||
from ..lib import Source, Note
|
||||
from ..db import DbTxn
|
||||
from ..const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.sgettext
|
||||
@ -65,6 +65,12 @@ class MergeRepositoryQuery:
|
||||
assert source.has_handle_reference('Repository', old_handle)
|
||||
source.replace_repo_references(old_handle, new_handle)
|
||||
self.database.commit_source(source, trans)
|
||||
elif class_name == Note.__name__:
|
||||
note = self.database.get_note_from_handle(handle)
|
||||
assert(note.has_handle_reference('Repository', old_handle))
|
||||
note.replace_handle_reference(
|
||||
'Repository', old_handle, new_handle)
|
||||
self.database.commit_note(note, trans)
|
||||
else:
|
||||
raise MergeError("Encounter an object of type %s that has "
|
||||
"a repository reference." % class_name)
|
||||
|
@ -29,8 +29,7 @@ Provide merge capabilities for sources.
|
||||
# Gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from ..lib import (Person, Family, Event, Place, Source, Repository,
|
||||
Media, Citation)
|
||||
from ..lib import (Citation, Note)
|
||||
from ..db import DbTxn
|
||||
from ..const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.sgettext
|
||||
@ -68,6 +67,12 @@ class MergeSourceQuery:
|
||||
assert(citation.get_reference_handle() == old_handle)
|
||||
citation.set_reference_handle(new_handle)
|
||||
self.database.commit_citation(citation, trans)
|
||||
elif class_name == Note.__name__:
|
||||
note = self.database.get_note_from_handle(handle)
|
||||
assert(note.has_handle_reference('Source', old_handle))
|
||||
note.replace_handle_reference(
|
||||
'Source', old_handle, new_handle)
|
||||
self.database.commit_note(note, trans)
|
||||
else:
|
||||
raise MergeError("Encounter an object of type %s that has "
|
||||
"a source reference." % class_name)
|
||||
|
@ -258,6 +258,7 @@ class PersonCheck(BaseMergeCheck):
|
||||
</source>
|
||||
<source handle="_s0001" id="S0001">
|
||||
<stitle>Source 1</stitle>
|
||||
<reporef hlink="_r0001" medium="Electronic"/>
|
||||
</source>
|
||||
</sources>
|
||||
<places>
|
||||
@ -278,9 +279,40 @@ class PersonCheck(BaseMergeCheck):
|
||||
<file src="image1.jpg" mime="image/jpeg" description="Image 1"/>
|
||||
</object>
|
||||
</objects>
|
||||
<repositories>
|
||||
<repository handle="_r0000" id="R0000">
|
||||
<rname>New York Public Library</rname>
|
||||
<type>Library</type>
|
||||
</repository>
|
||||
<repository handle="_r0001" id="R0001">
|
||||
<rname>Aunt Martha's Attic</rname>
|
||||
<type>Collection</type>
|
||||
</repository>
|
||||
</repositories>
|
||||
<notes>
|
||||
<note handle="_n0000" id="N0000" type="Event Note">
|
||||
<text>Note 0</text>
|
||||
<text>Note 0.</text>
|
||||
<style name="link" value="gramps://Citation/handle/c0001">
|
||||
<range start="0" end="1"/>
|
||||
</style>
|
||||
<style name="link" value="gramps://Event/handle/e0001">
|
||||
<range start="1" end="2"/>
|
||||
</style>
|
||||
<style name="link" value="gramps://Media/handle/o0001">
|
||||
<range start="2" end="3"/>
|
||||
</style>
|
||||
<style name="link" value="gramps://Note/handle/n0001">
|
||||
<range start="3" end="4"/>
|
||||
</style>
|
||||
<style name="link" value="gramps://Place/handle/p0001">
|
||||
<range start="4" end="5"/>
|
||||
</style>
|
||||
<style name="link" value="gramps://Repository/handle/r0001">
|
||||
<range start="5" end="6"/>
|
||||
</style>
|
||||
<style name="link" value="gramps://Source/handle/s0001">
|
||||
<range start="6" end="7"/>
|
||||
</style>
|
||||
</note>
|
||||
<note handle="_n0001" id="N0001" type="Event Note">
|
||||
<text>Note 1</text>
|
||||
@ -291,7 +323,8 @@ class PersonCheck(BaseMergeCheck):
|
||||
encoding='utf-8'))
|
||||
|
||||
def test_event_merge(self):
|
||||
"""Merge two events"""
|
||||
"""Merge two events. Also checks that Event link in note is updated.
|
||||
"""
|
||||
expect = ET.fromstring(self.basedoc, parser=self.parser)
|
||||
eventref = expect.xpath("//g:person[@handle='_i0001']/g:eventref",
|
||||
namespaces={"g": NS_G})[0]
|
||||
@ -299,6 +332,8 @@ class PersonCheck(BaseMergeCheck):
|
||||
event = expect.xpath("//g:event[@handle='_e0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
event.getparent().remove(event)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[1]
|
||||
notetag.attrib['value'] = "gramps://Event/handle/e0000"
|
||||
self.do_case('E0000', 'E0001', self.basedoc, expect)
|
||||
#print(str(ET.tostring(expect, pretty_print=True), 'utf-8'))
|
||||
|
||||
@ -313,6 +348,8 @@ class PersonCheck(BaseMergeCheck):
|
||||
placeobj.getparent().remove(placeobj)
|
||||
placeobj = expect.xpath("//g:placeobj[@handle='_p0000']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[4]
|
||||
notetag.attrib['value'] = "gramps://Place/handle/p0000"
|
||||
ET.SubElement(placeobj, NSP + 'pname', value='Place 1')
|
||||
self.do_case('P0000', 'P0001', self.basedoc, expect)
|
||||
|
||||
@ -325,6 +362,8 @@ class PersonCheck(BaseMergeCheck):
|
||||
citation = expect.xpath("//g:citation[@handle='_c0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
citation.getparent().remove(citation)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Citation/handle/c0000"
|
||||
self.do_case('C0000', 'C0001', self.basedoc, expect)
|
||||
|
||||
def test_media_merge(self):
|
||||
@ -336,6 +375,8 @@ class PersonCheck(BaseMergeCheck):
|
||||
object_ = expect.xpath("//g:object[@handle='_o0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
object_.getparent().remove(object_)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[2]
|
||||
notetag.attrib['value'] = "gramps://Media/handle/o0000"
|
||||
self.do_case('O0000', 'O0001', self.basedoc, expect)
|
||||
|
||||
def test_note_merge(self):
|
||||
@ -346,9 +387,24 @@ class PersonCheck(BaseMergeCheck):
|
||||
noteref.attrib['hlink'] = '_n0000'
|
||||
note = expect.xpath("//g:note[@handle='_n0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[3]
|
||||
notetag.attrib['value'] = "gramps://Note/handle/n0000"
|
||||
note.getparent().remove(note)
|
||||
self.do_case('N0000', 'N0001', self.basedoc, expect)
|
||||
|
||||
def test_repository_merge(self):
|
||||
"""Merge two repository objects"""
|
||||
expect = ET.fromstring(self.basedoc, parser=self.parser)
|
||||
reporef = expect.xpath("//g:source[@handle='_s0001']/g:reporef",
|
||||
namespaces={"g": NS_G})[0]
|
||||
reporef.attrib['hlink'] = '_r0000'
|
||||
object_ = expect.xpath("//g:repository[@handle='_r0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
object_.getparent().remove(object_)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[5]
|
||||
notetag.attrib['value'] = "gramps://Repository/handle/r0000"
|
||||
self.do_case('R0000', 'R0001', self.basedoc, expect)
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -1226,6 +1282,14 @@ class PersonPersonCheck(BaseMergeCheck):
|
||||
</name>
|
||||
</person>
|
||||
</people>
|
||||
<notes>
|
||||
<note handle="_n0000" id="N0000" type="Person Note">
|
||||
<text>Note 0.</text>
|
||||
<style name="link" value="gramps://Person/handle/i0001">
|
||||
<range start="0" end="1"/>
|
||||
</style>
|
||||
</note>
|
||||
</notes>
|
||||
</database>"""
|
||||
self.basedoc = bytes(bytearray(self.base_str + base_str,
|
||||
encoding='utf-8'))
|
||||
@ -1256,6 +1320,8 @@ class PersonPersonCheck(BaseMergeCheck):
|
||||
person = expect.xpath("//g:person[@handle='_i0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
person.getparent().remove(person)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0000"
|
||||
input_doc = ET.tostring(input_ctxt)
|
||||
self.do_case('I0000', 'I0001', input_doc, expect)
|
||||
|
||||
@ -1286,6 +1352,8 @@ class PersonPersonCheck(BaseMergeCheck):
|
||||
person = expect.xpath("//g:person[@handle='_i0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
person.getparent().remove(person)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0000"
|
||||
input_doc = ET.tostring(input_ctxt)
|
||||
self.do_case('I0000', 'I0001', input_doc, expect)
|
||||
|
||||
@ -1309,6 +1377,8 @@ class PersonPersonCheck(BaseMergeCheck):
|
||||
person = expect.xpath("//g:person[@handle='_i0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
person.getparent().remove(person)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0000"
|
||||
input_doc = ET.tostring(input_ctxt)
|
||||
self.do_case('I0000', 'I0001', input_doc, expect)
|
||||
|
||||
@ -1422,6 +1492,26 @@ class FamilyPersonCheck(BaseMergeCheck):
|
||||
<rel type="Unknown"/>
|
||||
</family>
|
||||
</families>
|
||||
<notes>
|
||||
<note handle="_n0000" id="N0000" type="Person Note">
|
||||
<text>Note 0</text>
|
||||
<style name="link" value="gramps://Person/handle/i0002">
|
||||
<range start="0" end="2"/>
|
||||
</style>
|
||||
</note>
|
||||
<note handle="_n0001" id="N0001" type="Family Note">
|
||||
<text>Note 1</text>
|
||||
<style name="link" value="gramps://Family/handle/f0001">
|
||||
<range start="0" end="4"/>
|
||||
</style>
|
||||
</note>
|
||||
<note handle="_n0003" id="N0003" type="Person Note">
|
||||
<text>Note 0</text>
|
||||
<style name="link" value="gramps://Person/handle/i0003">
|
||||
<range start="0" end="2"/>
|
||||
</style>
|
||||
</note>
|
||||
</notes>
|
||||
</database>"""
|
||||
self.basedoc = bytes(bytearray(self.base_str + base_str,
|
||||
encoding='utf-8'))
|
||||
@ -1439,6 +1529,9 @@ class FamilyPersonCheck(BaseMergeCheck):
|
||||
parentref = expect.xpath("//g:person[@handle='_i0000']/g:parentin",
|
||||
namespaces={"g": NS_G})[0]
|
||||
attr.addnext(parentref) # restore order of elements
|
||||
notetag = expect.xpath("//g:note[@handle='_n0000']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0000"
|
||||
persons[2].getparent().remove(persons[2])
|
||||
self.do_case('I0000', 'I0002', self.basedoc, expect)
|
||||
|
||||
@ -1467,6 +1560,9 @@ class FamilyPersonCheck(BaseMergeCheck):
|
||||
father = expect.xpath("//g:family[@handle='_f0001']/g:father",
|
||||
namespaces={"g": NS_G})[0]
|
||||
father.attrib['hlink'] = '_i0000'
|
||||
notetag = expect.xpath("//g:note[@handle='_n0000']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0000"
|
||||
persons[2].getparent().remove(persons[2])
|
||||
input_doc = ET.tostring(input_ctxt)
|
||||
self.do_case('I0000', 'I0002', input_doc, expect)
|
||||
@ -1501,6 +1597,9 @@ class FamilyPersonCheck(BaseMergeCheck):
|
||||
ET.SubElement(family, NSP + 'rel', type='Married')
|
||||
ET.SubElement(family, NSP + 'father', hlink='_i0000')
|
||||
ET.SubElement(family, NSP + 'mother', hlink='_i0003')
|
||||
notetag = expect.xpath("//g:note[@handle='_n0000']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0000"
|
||||
persons[2].getparent().remove(persons[2])
|
||||
|
||||
persons = input_ctxt.xpath("//g:person",
|
||||
@ -1547,7 +1646,13 @@ class FamilyPersonCheck(BaseMergeCheck):
|
||||
parentref = expect.xpath("//g:person[@handle='_i0000']/g:parentin",
|
||||
namespaces={"g": NS_G})[0]
|
||||
attr.addnext(parentref) # restore order of elements
|
||||
notetag = expect.xpath("//g:note[@handle='_n0000']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0000"
|
||||
persons[2].getparent().remove(persons[2])
|
||||
notetag = expect.xpath("//g:note[@handle='_n0001']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
family = expect.xpath("//g:family[@handle='_f0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
family.getparent().remove(family)
|
||||
@ -1583,6 +1688,12 @@ class FamilyPersonCheck(BaseMergeCheck):
|
||||
parentref = expect.xpath("//g:person[@handle='_i0000']/g:parentin",
|
||||
namespaces={"g": NS_G})[0]
|
||||
attr.addnext(parentref) # restore order of elements
|
||||
notetag = expect.xpath("//g:note[@handle='_n0000']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0000"
|
||||
notetag = expect.xpath("//g:note[@handle='_n0001']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
persons[2].getparent().remove(persons[2])
|
||||
family = expect.xpath("//g:family[@handle='_f0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
@ -1615,6 +1726,12 @@ class FamilyPersonCheck(BaseMergeCheck):
|
||||
namespaces={"g": NS_G})[0]
|
||||
attr.addnext(parentref) # restore order of elements
|
||||
persons[3].getparent().remove(persons[3])
|
||||
notetag = expect.xpath("//g:note[@handle='_n0001']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
notetag = expect.xpath("//g:note[@handle='_n0003']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0001"
|
||||
family = expect.xpath("//g:family[@handle='_f0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
family.getparent().remove(family)
|
||||
@ -1655,7 +1772,13 @@ class FamilyPersonCheck(BaseMergeCheck):
|
||||
parentref = expect.xpath("//g:person[@handle='_i0000']/g:parentin",
|
||||
namespaces={"g": NS_G})[0]
|
||||
attr.addnext(parentref) # restore order of elements
|
||||
notetag = expect.xpath("//g:note[@handle='_n0000']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0000"
|
||||
persons[2].getparent().remove(persons[2])
|
||||
notetag = expect.xpath("//g:note[@handle='_n0001']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
families = expect.xpath("//g:family",
|
||||
namespaces={"g": NS_G})
|
||||
families[1].getparent().remove(families[1])
|
||||
@ -1695,7 +1818,13 @@ class FamilyPersonCheck(BaseMergeCheck):
|
||||
parentref = expect.xpath("//g:person[@handle='_i0000']/g:parentin",
|
||||
namespaces={"g": NS_G})[0]
|
||||
attr.addnext(parentref) # restore order of elements
|
||||
notetag = expect.xpath("//g:note[@handle='_n0000']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0000"
|
||||
persons[2].getparent().remove(persons[2])
|
||||
notetag = expect.xpath("//g:note[@handle='_n0001']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
families = expect.xpath("//g:family",
|
||||
namespaces={"g": NS_G})
|
||||
families[1].getparent().remove(families[1])
|
||||
@ -1733,7 +1862,13 @@ class FamilyPersonCheck(BaseMergeCheck):
|
||||
parentref = expect.xpath("//g:person[@handle='_i0000']/g:parentin",
|
||||
namespaces={"g": NS_G})[0]
|
||||
attr.addnext(parentref) # restore order of elements
|
||||
notetag = expect.xpath("//g:note[@handle='_n0000']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0000"
|
||||
persons[2].getparent().remove(persons[2])
|
||||
notetag = expect.xpath("//g:note[@handle='_n0001']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
families = expect.xpath("//g:family",
|
||||
namespaces={"g": NS_G})
|
||||
families[1].getparent().remove(families[1])
|
||||
@ -1776,7 +1911,13 @@ class FamilyPersonCheck(BaseMergeCheck):
|
||||
parentref = expect.xpath("//g:person[@handle='_i0000']/g:parentin",
|
||||
namespaces={"g": NS_G})[0]
|
||||
attr.addnext(parentref) # restore order of elements
|
||||
notetag = expect.xpath("//g:note[@handle='_n0000']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0000"
|
||||
persons[2].getparent().remove(persons[2])
|
||||
notetag = expect.xpath("//g:note[@handle='_n0001']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
families = expect.xpath("//g:family",
|
||||
namespaces={"g": NS_G})
|
||||
families[1].getparent().remove(families[1])
|
||||
@ -1817,7 +1958,13 @@ class FamilyPersonCheck(BaseMergeCheck):
|
||||
parentref = expect.xpath("//g:person[@handle='_i0000']/g:parentin",
|
||||
namespaces={"g": NS_G})[0]
|
||||
attr.addnext(parentref) # restore order of elements
|
||||
notetag = expect.xpath("//g:note[@handle='_n0000']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Person/handle/i0000"
|
||||
persons[2].getparent().remove(persons[2])
|
||||
notetag = expect.xpath("//g:note[@handle='_n0001']/g:style",
|
||||
namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
families = expect.xpath("//g:family",
|
||||
namespaces={"g": NS_G})
|
||||
families[1].getparent().remove(families[1])
|
||||
@ -1879,6 +2026,14 @@ class FamilyMergeCheck(BaseMergeCheck):
|
||||
<mother hlink="_i0003"/>
|
||||
</family>
|
||||
</families>
|
||||
<notes>
|
||||
<note handle="_n0000" id="N0000" type="Family Note">
|
||||
<text>Note 0.</text>
|
||||
<style name="link" value="gramps://Family/handle/f0001">
|
||||
<range start="0" end="1"/>
|
||||
</style>
|
||||
</note>
|
||||
</notes>
|
||||
</database>"""
|
||||
self.basedoc = bytes(bytearray(self.base_str + base_str,
|
||||
encoding='utf-8'))
|
||||
@ -1974,6 +2129,8 @@ class FamilyMergeCheck(BaseMergeCheck):
|
||||
family = expect.xpath("//g:family[@handle='_f0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
family.getparent().remove(family)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
self.do_family_case('F0000', 'F0001', 'i0000', 'i0001',
|
||||
self.basedoc, expect)
|
||||
|
||||
@ -2004,6 +2161,8 @@ class FamilyMergeCheck(BaseMergeCheck):
|
||||
family = expect.xpath("//g:family[@handle='_f0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
family.getparent().remove(family)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
father = expect.xpath("//g:family[@handle='_f0000']/g:father",
|
||||
namespaces={"g": NS_G})[0]
|
||||
father.attrib['hlink'] = '_i0002'
|
||||
@ -2036,6 +2195,8 @@ class FamilyMergeCheck(BaseMergeCheck):
|
||||
family = expect.xpath("//g:family[@handle='_f0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
family.getparent().remove(family)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
input_doc = ET.tostring(input_ctxt)
|
||||
self.do_family_case('F0000', 'F0001', 'i0000', 'i0001',
|
||||
input_doc, expect)
|
||||
@ -2068,6 +2229,8 @@ class FamilyMergeCheck(BaseMergeCheck):
|
||||
family = expect.xpath("//g:family[@handle='_f0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
family.getparent().remove(family)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
family = expect.xpath("//g:family[@handle='_f0000']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
mother = ET.SubElement(family, NSP + 'mother', hlink='_i0003')
|
||||
@ -2115,6 +2278,8 @@ class FamilyMergeCheck(BaseMergeCheck):
|
||||
family = expect.xpath("//g:family[@handle='_f0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
family.getparent().remove(family)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
childof = expect.xpath("//g:person[@handle='_i0004']/g:childof",
|
||||
namespaces={"g": NS_G})[0]
|
||||
childof.attrib['hlink'] = '_f0000'
|
||||
@ -2167,6 +2332,8 @@ class FamilyMergeCheck(BaseMergeCheck):
|
||||
family = expect.xpath("//g:family[@handle='_f0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
family.getparent().remove(family)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
childof = expect.xpath("//g:person[@handle='_i0004']/g:childof",
|
||||
namespaces={"g": NS_G})[1]
|
||||
childof.getparent().remove(childof)
|
||||
@ -2214,6 +2381,8 @@ class FamilyMergeCheck(BaseMergeCheck):
|
||||
family = expect.xpath("//g:family[@handle='_f0001']",
|
||||
namespaces={"g": NS_G})[0]
|
||||
family.getparent().remove(family)
|
||||
notetag = expect.xpath("//g:style", namespaces={"g": NS_G})[0]
|
||||
notetag.attrib['value'] = "gramps://Family/handle/f0000"
|
||||
sealedto = expect.xpath("//g:sealed_to",
|
||||
namespaces={"g": NS_G})[0]
|
||||
sealedto.attrib['hlink'] = '_f0000'
|
||||
|
@ -437,11 +437,29 @@ class MissingMediaDialog:
|
||||
parent=self.top)
|
||||
return True
|
||||
|
||||
|
||||
class MultiSelectDialog:
|
||||
"""
|
||||
Allows a Yes, No, Cancel dialog that includes a checkbox
|
||||
with "Use this answer for the rest of the items" that works with 'Yes'
|
||||
"""
|
||||
def __init__(self, msg1_func, msg2_func, items, lookup,
|
||||
cancel_func=None, no_func=None, yes_func=None,
|
||||
multi_yes_func=None, parent=None):
|
||||
"""
|
||||
msg1_func a function to display big bold text at top
|
||||
msg2_func a function to display normal text at center of dialog
|
||||
items a list of objects (often handles) passed to lookup
|
||||
Must be a list, not a generator
|
||||
lookup A function that looks up an object to pass to yes/no/multi_func
|
||||
cancel_func A function or None called on cancel.
|
||||
yes_func A function or None called on Yes.
|
||||
no_func A function or None called on No.
|
||||
multi_yes_func A function or None called on Yes with
|
||||
"use this answer for rest" checked.
|
||||
The above xxx_func calls will have parameters:
|
||||
object from lookup function
|
||||
"parent=" set to this dialog for transient parent purposes.
|
||||
"""
|
||||
self.xml = Glade(toplevel='multiselectdialog')
|
||||
|
||||
@ -468,7 +486,7 @@ class MultiSelectDialog:
|
||||
self.top.connect('delete_event', self.warn)
|
||||
|
||||
default_action = 0
|
||||
for selected in items:
|
||||
for indx, selected in enumerate(items):
|
||||
item = self.lookup(selected)
|
||||
if default_action == 0:
|
||||
msg1 = self.msg1_func(item)
|
||||
@ -491,22 +509,22 @@ class MultiSelectDialog:
|
||||
if check_button.get_active():
|
||||
# run the multiple yes if 'do remainder' is checked
|
||||
if multi_yes_func and response == 3:
|
||||
multi_yes_func(items)
|
||||
multi_yes_func(items[indx:], parent=self.top)
|
||||
break
|
||||
default_action = response
|
||||
else:
|
||||
response = default_action
|
||||
### Now do it
|
||||
if response == 1: # Cancel
|
||||
# Now do it
|
||||
if response == 1: # Cancel
|
||||
if self.cancel_func:
|
||||
self.cancel_func(item)
|
||||
self.cancel_func(item, parent=self.top)
|
||||
break
|
||||
elif response == 2: # No
|
||||
elif response == 2: # No
|
||||
if self.no_func:
|
||||
self.no_func(item)
|
||||
elif response == 3: # Yes
|
||||
self.no_func(item, parent=self.top)
|
||||
elif response == 3: # Yes
|
||||
if self.yes_func:
|
||||
self.yes_func(item)
|
||||
self.yes_func(item, parent=self.top)
|
||||
self.top.destroy()
|
||||
if parent and parent_modal:
|
||||
parent.set_modal(True)
|
||||
|
@ -23,25 +23,25 @@
|
||||
from .editaddress import EditAddress
|
||||
from .editattribute import EditAttribute, EditSrcAttribute
|
||||
from .editchildref import EditChildRef
|
||||
from .editcitation import EditCitation, DeleteCitationQuery
|
||||
from .editcitation import EditCitation
|
||||
from .editdate import EditDate
|
||||
from .editevent import EditEvent, DeleteEventQuery
|
||||
from .editevent import EditEvent
|
||||
from .editeventref import EditEventRef
|
||||
from .editfamily import EditFamily
|
||||
from .editldsord import EditLdsOrd, EditFamilyLdsOrd
|
||||
from .editlocation import EditLocation
|
||||
from .editmedia import EditMedia, DeleteMediaQuery
|
||||
from .editmedia import EditMedia
|
||||
from .editmediaref import EditMediaRef
|
||||
from .editname import EditName
|
||||
from .editnote import EditNote, DeleteNoteQuery
|
||||
from .editnote import EditNote
|
||||
from .editperson import EditPerson
|
||||
from .editpersonref import EditPersonRef
|
||||
from .editplace import EditPlace, DeletePlaceQuery
|
||||
from .editplace import EditPlace
|
||||
from .editplacename import EditPlaceName
|
||||
from .editplaceref import EditPlaceRef
|
||||
from .editrepository import EditRepository, DeleteRepositoryQuery
|
||||
from .editrepository import EditRepository
|
||||
from .editreporef import EditRepoRef
|
||||
from .editsource import EditSource, DeleteSrcQuery
|
||||
from .editsource import EditSource
|
||||
from .edittaglist import EditTagList
|
||||
from .editurl import EditUrl
|
||||
from .editlink import EditLink
|
||||
|
@ -134,6 +134,15 @@ class BackRefModel(Gtk.ListStore):
|
||||
name = p.get_name()
|
||||
gid = p.gramps_id
|
||||
handle = p.handle
|
||||
elif dtype == 'Note':
|
||||
p = self.db.get_note_from_handle(ref[1])
|
||||
if not p:
|
||||
continue
|
||||
name = " ".join(p.get().split())
|
||||
if len(name) > 80:
|
||||
name = name[:80] + "..."
|
||||
gid = p.gramps_id
|
||||
handle = p.handle
|
||||
else:
|
||||
p = self.db.get_media_from_handle(ref[1])
|
||||
if not p:
|
||||
|
@ -364,58 +364,3 @@ class EditCitation(EditPrimary):
|
||||
else:
|
||||
cmp_obj = self.empty_object()
|
||||
return cmp_obj.serialize(True)[1:] != self.obj.serialize()[1:]
|
||||
|
||||
class DeleteCitationQuery:
|
||||
def __init__(self, dbstate, uistate, citation, the_lists):
|
||||
self.citation = citation
|
||||
self.db = dbstate.db
|
||||
self.uistate = uistate
|
||||
self.the_lists = the_lists
|
||||
|
||||
def query_response(self):
|
||||
with DbTxn(_("Delete Citation (%s)") % self.citation.get_page(),
|
||||
self.db) as trans:
|
||||
self.db.disable_signals()
|
||||
|
||||
(person_list, family_list, event_list, place_list, source_list,
|
||||
media_list, repo_list) = self.the_lists
|
||||
|
||||
ctn_handle_list = [self.citation.get_handle()]
|
||||
|
||||
for handle in person_list:
|
||||
person = self.db.get_person_from_handle(handle)
|
||||
person.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_person(person, trans)
|
||||
|
||||
for handle in family_list:
|
||||
family = self.db.get_family_from_handle(handle)
|
||||
family.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_family(family, trans)
|
||||
|
||||
for handle in event_list:
|
||||
event = self.db.get_event_from_handle(handle)
|
||||
event.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_event(event, trans)
|
||||
|
||||
for handle in place_list:
|
||||
place = self.db.get_place_from_handle(handle)
|
||||
place.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_place(place, trans)
|
||||
|
||||
for handle in source_list:
|
||||
source = self.db.get_source_from_handle(handle)
|
||||
source.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_source(source, trans)
|
||||
|
||||
for handle in media_list:
|
||||
media = self.db.get_media_from_handle(handle)
|
||||
media.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_media(media, trans)
|
||||
|
||||
for handle in repo_list:
|
||||
repo = self.db.get_repository_from_handle(handle)
|
||||
repo.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_repository(repo, trans)
|
||||
|
||||
self.db.enable_signals()
|
||||
self.db.remove_citation(self.citation.get_handle(), trans)
|
||||
|
@ -319,37 +319,3 @@ class EditEvent(EditPrimary):
|
||||
self.top.get_object("place").set_markup(
|
||||
self.place_field.EMPTY_TEXT)
|
||||
self.place_field.set_button(False)
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Delete Query class
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class DeleteEventQuery:
|
||||
def __init__(self, dbstate, uistate, event, person_list, family_list):
|
||||
self.event = event
|
||||
self.db = dbstate.db
|
||||
self.uistate = uistate
|
||||
self.person_list = person_list
|
||||
self.family_list = family_list
|
||||
|
||||
def query_response(self):
|
||||
with DbTxn(_("Delete Event (%s)") % self.event.get_gramps_id(),
|
||||
self.db) as trans:
|
||||
self.db.disable_signals()
|
||||
|
||||
ev_handle_list = [self.event.get_handle()]
|
||||
|
||||
for handle in self.person_list:
|
||||
person = self.db.get_person_from_handle(handle)
|
||||
person.remove_handle_references('Event', ev_handle_list)
|
||||
self.db.commit_person(person, trans)
|
||||
|
||||
for handle in self.family_list:
|
||||
family = self.db.get_family_from_handle(handle)
|
||||
family.remove_handle_references('Event', ev_handle_list)
|
||||
self.db.commit_family(family, trans)
|
||||
|
||||
self.db.enable_signals()
|
||||
self.db.remove_event(self.event.get_handle(), trans)
|
||||
|
@ -359,63 +359,3 @@ class EditMedia(EditPrimary):
|
||||
else:
|
||||
cmp_obj = self.empty_object()
|
||||
return cmp_obj.serialize(True)[1:] != self.obj.serialize()[1:]
|
||||
|
||||
class DeleteMediaQuery:
|
||||
|
||||
def __init__(self, dbstate, uistate, media_handle, the_lists):
|
||||
self.db = dbstate.db
|
||||
self.uistate = uistate
|
||||
self.media_handle = media_handle
|
||||
self.the_lists = the_lists
|
||||
|
||||
def query_response(self):
|
||||
with DbTxn(_("Remove Media Object"), self.db) as trans:
|
||||
self.db.disable_signals()
|
||||
|
||||
(person_list, family_list, event_list,
|
||||
place_list, source_list, citation_list) = self.the_lists
|
||||
|
||||
for handle in person_list:
|
||||
person = self.db.get_person_from_handle(handle)
|
||||
new_list = [photo for photo in person.get_media_list()
|
||||
if photo.get_reference_handle() != self.media_handle]
|
||||
person.set_media_list(new_list)
|
||||
self.db.commit_person(person, trans)
|
||||
|
||||
for handle in family_list:
|
||||
family = self.db.get_family_from_handle(handle)
|
||||
new_list = [photo for photo in family.get_media_list()
|
||||
if photo.get_reference_handle() != self.media_handle]
|
||||
family.set_media_list(new_list)
|
||||
self.db.commit_family(family, trans)
|
||||
|
||||
for handle in event_list:
|
||||
event = self.db.get_event_from_handle(handle)
|
||||
new_list = [photo for photo in event.get_media_list()
|
||||
if photo.get_reference_handle() != self.media_handle]
|
||||
event.set_media_list(new_list)
|
||||
self.db.commit_event(event, trans)
|
||||
|
||||
for handle in place_list:
|
||||
place = self.db.get_place_from_handle(handle)
|
||||
new_list = [photo for photo in place.get_media_list()
|
||||
if photo.get_reference_handle() != self.media_handle]
|
||||
place.set_media_list(new_list)
|
||||
self.db.commit_place(place, trans)
|
||||
|
||||
for handle in source_list:
|
||||
source = self.db.get_source_from_handle(handle)
|
||||
new_list = [photo for photo in source.get_media_list()
|
||||
if photo.get_reference_handle() != self.media_handle]
|
||||
source.set_media_list(new_list)
|
||||
self.db.commit_source(source, trans)
|
||||
|
||||
for handle in citation_list:
|
||||
citation = self.db.get_citation_from_handle(handle)
|
||||
new_list = [photo for photo in citation.get_media_list()
|
||||
if photo.get_reference_handle() != self.media_handle]
|
||||
citation.set_media_list(new_list)
|
||||
self.db.commit_citation(citation, trans)
|
||||
|
||||
self.db.enable_signals()
|
||||
self.db.remove_media(self.media_handle, trans)
|
||||
|
@ -349,71 +349,3 @@ class EditNote(EditPrimary):
|
||||
self._do_close()
|
||||
if self.callback:
|
||||
self.callback(self.obj.get_handle())
|
||||
|
||||
class DeleteNoteQuery:
|
||||
def __init__(self, dbstate, uistate, note, the_lists):
|
||||
self.note = note
|
||||
self.db = dbstate.db
|
||||
self.uistate = uistate
|
||||
self.the_lists = the_lists
|
||||
|
||||
def query_response(self):
|
||||
with DbTxn(_("Delete Note (%s)") % self.note.get_gramps_id(),
|
||||
self.db) as trans:
|
||||
self.db.disable_signals()
|
||||
|
||||
(person_list, family_list, event_list, place_list, source_list,
|
||||
citation_list, media_list, repo_list) = self.the_lists
|
||||
|
||||
note_handle = self.note.get_handle()
|
||||
|
||||
for handle in person_list:
|
||||
person = self.db.get_person_from_handle(handle)
|
||||
if person:
|
||||
person.remove_note(note_handle)
|
||||
self.db.commit_person(person, trans)
|
||||
|
||||
for handle in family_list:
|
||||
family = self.db.get_family_from_handle(handle)
|
||||
if family:
|
||||
family.remove_note(note_handle)
|
||||
self.db.commit_family(family, trans)
|
||||
|
||||
for handle in event_list:
|
||||
event = self.db.get_event_from_handle(handle)
|
||||
if event:
|
||||
event.remove_note(note_handle)
|
||||
self.db.commit_event(event, trans)
|
||||
|
||||
for handle in place_list:
|
||||
place = self.db.get_place_from_handle(handle)
|
||||
if place:
|
||||
place.remove_note(note_handle)
|
||||
self.db.commit_place(place, trans)
|
||||
|
||||
for handle in source_list:
|
||||
source = self.db.get_source_from_handle(handle)
|
||||
if source:
|
||||
source.remove_note(note_handle)
|
||||
self.db.commit_source(source, trans)
|
||||
|
||||
for handle in citation_list:
|
||||
citation = self.db.get_citation_from_handle(handle)
|
||||
if citation:
|
||||
citation.remove_note(note_handle)
|
||||
self.db.commit_citation(citation, trans)
|
||||
|
||||
for handle in media_list:
|
||||
media = self.db.get_media_from_handle(handle)
|
||||
if media:
|
||||
media.remove_note(note_handle)
|
||||
self.db.commit_media(media, trans)
|
||||
|
||||
for handle in repo_list:
|
||||
repo = self.db.get_repository_from_handle(handle)
|
||||
if repo:
|
||||
repo.remove_note(note_handle)
|
||||
self.db.commit_repository(repo, trans)
|
||||
|
||||
self.db.enable_signals()
|
||||
self.db.remove_note(note_handle, trans)
|
||||
|
@ -379,44 +379,3 @@ class EditPlace(EditPrimary):
|
||||
self._do_close()
|
||||
if self.callback:
|
||||
self.callback(self.obj)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# DeletePlaceQuery
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class DeletePlaceQuery:
|
||||
|
||||
def __init__(self, dbstate, uistate, place, person_list, family_list,
|
||||
event_list):
|
||||
self.db = dbstate.db
|
||||
self.uistate = uistate
|
||||
self.obj = place
|
||||
self.person_list = person_list
|
||||
self.family_list = family_list
|
||||
self.event_list = event_list
|
||||
|
||||
def query_response(self):
|
||||
place_title = place_displayer.display(self.db, self.obj)
|
||||
with DbTxn(_("Delete Place (%s)") % place_title, self.db) as trans:
|
||||
self.db.disable_signals()
|
||||
|
||||
place_handle = self.obj.get_handle()
|
||||
|
||||
for handle in self.person_list:
|
||||
person = self.db.get_person_from_handle(handle)
|
||||
person.remove_handle_references('Place', place_handle)
|
||||
self.db.commit_person(person, trans)
|
||||
|
||||
for handle in self.family_list:
|
||||
family = self.db.get_family_from_handle(handle)
|
||||
family.remove_handle_references('Place', place_handle)
|
||||
self.db.commit_family(family, trans)
|
||||
|
||||
for handle in self.event_list:
|
||||
event = self.db.get_event_from_handle(handle)
|
||||
event.remove_handle_references('Place', place_handle)
|
||||
self.db.commit_event(event, trans)
|
||||
|
||||
self.db.enable_signals()
|
||||
self.db.remove_place(place_handle, trans)
|
||||
|
@ -210,23 +210,3 @@ class EditRepository(EditPrimary):
|
||||
self._do_close()
|
||||
if self.callback:
|
||||
self.callback(self.obj)
|
||||
|
||||
class DeleteRepositoryQuery:
|
||||
def __init__(self, dbstate, uistate, repository, sources):
|
||||
self.obj = repository
|
||||
self.db = dbstate.db
|
||||
self.uistate = uistate
|
||||
self.sources = sources
|
||||
|
||||
def query_response(self):
|
||||
with DbTxn(_("Delete Repository (%s)") % self.obj.get_name(),
|
||||
self.db) as trans:
|
||||
|
||||
repos_handle_list = [self.obj.get_handle()]
|
||||
|
||||
for handle in self.sources:
|
||||
source = self.db.get_source_from_handle(handle)
|
||||
source.remove_repo_references(repos_handle_list)
|
||||
self.db.commit_source(source, trans)
|
||||
|
||||
self.db.remove_repository(self.obj.get_handle(), trans)
|
||||
|
@ -231,81 +231,3 @@ class EditSource(EditPrimary):
|
||||
self._do_close()
|
||||
if self.callback:
|
||||
self.callback(self.obj)
|
||||
|
||||
class DeleteSrcQuery:
|
||||
def __init__(self, dbstate, uistate, source, the_lists):
|
||||
self.source = source
|
||||
self.db = dbstate.db
|
||||
self.uistate = uistate
|
||||
self.the_lists = the_lists
|
||||
|
||||
def query_response(self):
|
||||
with DbTxn(_("Delete Source (%s)") % self.source.get_title(),
|
||||
self.db) as trans:
|
||||
self.db.disable_signals()
|
||||
|
||||
# we can have:
|
||||
# object(CitationBase) -> Citation(source_handle) -> Source
|
||||
# We first have to remove the CitationBase references to the
|
||||
# Citation. Then we remove the Citations. (We don't need to
|
||||
# remove the source_handle references to the Source, because we are
|
||||
# removing the whole Citation). Then we can remove the Source
|
||||
|
||||
(citation_list, citation_referents_list) = self.the_lists
|
||||
# citation_list is a tuple of lists. Only the first, for Citations,
|
||||
# exists.
|
||||
citation_list = citation_list[0]
|
||||
|
||||
# (1) delete the references to the citation
|
||||
for (citation_handle, refs) in citation_referents_list:
|
||||
LOG.debug('delete citation %s references %s' %
|
||||
(citation_handle, refs))
|
||||
(person_list, family_list, event_list, place_list, source_list,
|
||||
media_list, repo_list) = refs
|
||||
|
||||
ctn_handle_list = [citation_handle]
|
||||
|
||||
for handle in person_list:
|
||||
person = self.db.get_person_from_handle(handle)
|
||||
person.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_person(person, trans)
|
||||
|
||||
for handle in family_list:
|
||||
family = self.db.get_family_from_handle(handle)
|
||||
family.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_family(family, trans)
|
||||
|
||||
for handle in event_list:
|
||||
event = self.db.get_event_from_handle(handle)
|
||||
event.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_event(event, trans)
|
||||
|
||||
for handle in place_list:
|
||||
place = self.db.get_place_from_handle(handle)
|
||||
place.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_place(place, trans)
|
||||
|
||||
for handle in source_list:
|
||||
source = self.db.get_source_from_handle(handle)
|
||||
source.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_source(source, trans)
|
||||
|
||||
for handle in media_list:
|
||||
media = self.db.get_media_from_handle(handle)
|
||||
media.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_media(media, trans)
|
||||
|
||||
for handle in repo_list:
|
||||
repo = self.db.get_repository_from_handle(handle)
|
||||
repo.remove_citation_references(ctn_handle_list)
|
||||
self.db.commit_repository(repo, trans)
|
||||
|
||||
# (2) delete the actual citations
|
||||
LOG.debug('remove the actual citations %s' % citation_list)
|
||||
for citation_handle in citation_list:
|
||||
LOG.debug("remove_citation %s" % citation_handle)
|
||||
self.db.remove_citation(citation_handle, trans)
|
||||
|
||||
# (3) delete the source
|
||||
self.db.enable_signals()
|
||||
self.db.remove_source(self.source.get_handle(), trans)
|
||||
|
@ -569,12 +569,14 @@ def get_link_color(context):
|
||||
|
||||
return rgb_to_hex((col.red, col.green, col.blue))
|
||||
|
||||
|
||||
def edit_object(dbstate, uistate, reftype, ref):
|
||||
"""
|
||||
Invokes the appropriate editor for an object type and given handle.
|
||||
"""
|
||||
from .editors import (EditEvent, EditPerson, EditFamily, EditSource,
|
||||
EditPlace, EditMedia, EditRepository, EditCitation)
|
||||
EditPlace, EditMedia, EditRepository, EditCitation,
|
||||
EditNote)
|
||||
|
||||
if reftype == 'Person':
|
||||
try:
|
||||
@ -642,6 +644,13 @@ def edit_object(dbstate, uistate, reftype, ref):
|
||||
EditRepository(dbstate, uistate, [], repo)
|
||||
except WindowActiveError:
|
||||
pass
|
||||
elif reftype == 'Note':
|
||||
try:
|
||||
note = dbstate.db.get_note_from_handle(ref)
|
||||
EditNote(dbstate, uistate, [], note)
|
||||
except WindowActiveError:
|
||||
pass
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
|
@ -59,6 +59,7 @@ from .navigationview import NavigationView
|
||||
from ..uimanager import ActionGroup
|
||||
from ..columnorder import ColumnOrder
|
||||
from gramps.gen.config import config
|
||||
from gramps.gen.db import DbTxn
|
||||
from gramps.gen.errors import WindowActiveError, FilterError, HandleError
|
||||
from ..filters import SearchBar
|
||||
from ..widgets.menuitem import add_menuitem
|
||||
@ -66,7 +67,8 @@ from gramps.gen.const import CUSTOM_FILTERS
|
||||
from gramps.gen.utils.debug import profile
|
||||
from gramps.gen.utils.string import data_recover_msg
|
||||
from gramps.gen.plug import CATEGORY_QR_PERSON
|
||||
from ..dialog import QuestionDialog, QuestionDialog3, ErrorDialog
|
||||
from ..dialog import (QuestionDialog, QuestionDialog3, ErrorDialog,
|
||||
MultiSelectDialog)
|
||||
from ..editors import FilterEditor
|
||||
from ..ddtargets import DdTargets
|
||||
from ..plug.quick import create_quickreport_menu, create_web_connect_menu
|
||||
@ -532,57 +534,138 @@ class ListView(NavigationView):
|
||||
def get_column_widths(self):
|
||||
return [column.get_width() for column in self.columns]
|
||||
|
||||
def remove_selected_objects(self):
|
||||
####################################################################
|
||||
# Object Delete functions
|
||||
####################################################################
|
||||
# def remove(self): # this is over-ridden in each view
|
||||
# """
|
||||
# must return the tuple of (object type and handle) for each
|
||||
# selected item
|
||||
# """
|
||||
# handles = self.selected_handles()
|
||||
# ht_list = [('Person', hndl) for hndl in handles]
|
||||
# self.remove_selected_objects(ht_list)
|
||||
|
||||
def remove_selected_objects(self, ht_list=None):
|
||||
"""
|
||||
Function to remove selected objects
|
||||
"""
|
||||
prompt = True
|
||||
if len(self.selected_handles()) > 1:
|
||||
ques = QuestionDialog3(
|
||||
_("Multiple Selection Delete"),
|
||||
_("More than one item has been selected for deletion. "
|
||||
"Select the option indicating how to delete the items:"),
|
||||
_("Delete All"),
|
||||
_("Confirm Each Delete"),
|
||||
parent=self.uistate.window)
|
||||
res = ques.run()
|
||||
if res == -1: # Cancel
|
||||
return
|
||||
else:
|
||||
prompt = not res # we prompt on 'Confirm Each Delete'
|
||||
if len(ht_list) == 1:
|
||||
obj = self.dbstate.db.method(
|
||||
"get_%s_from_handle", ht_list[0][0])(ht_list[0][1])
|
||||
msg1 = self._message1_format(obj)
|
||||
msg2 = self._message2_format(obj)
|
||||
msg2 = "%s %s" % (msg2, data_recover_msg)
|
||||
QuestionDialog(msg1,
|
||||
msg2,
|
||||
_('_Delete'),
|
||||
lambda: self.delete_object_response(obj, parent=self.uistate.window),
|
||||
parent=self.uistate.window)
|
||||
else:
|
||||
MultiSelectDialog(self._message1_format,
|
||||
self._message2_format,
|
||||
ht_list,
|
||||
lambda x: self.dbstate.db.method(
|
||||
"get_%s_from_handle", x[0])(x[1]),
|
||||
yes_func=self.delete_object_response,
|
||||
multi_yes_func=self.delete_multi_object_response,
|
||||
parent=self.uistate.window)
|
||||
|
||||
if not prompt:
|
||||
self.uistate.set_busy_cursor(True)
|
||||
def _message1_format(self, obj):
|
||||
"""
|
||||
Header format for remove dialogs.
|
||||
"""
|
||||
return _('Delete {type} [{gid}]?').format(
|
||||
type=_(obj.__class__.__name__), gid=obj.gramps_id)
|
||||
|
||||
for handle in self.selected_handles():
|
||||
(query, is_used, object) = self.remove_object_from_handle(handle)
|
||||
if prompt:
|
||||
if is_used:
|
||||
msg = _('This item is currently being used. '
|
||||
'Deleting it will remove it from the database and '
|
||||
'from all other items that reference it.')
|
||||
else:
|
||||
msg = _('Deleting item will remove it from the database.')
|
||||
def _message2_format(self, _obj):
|
||||
"""
|
||||
Detailed message format for the remove dialogs.
|
||||
"""
|
||||
return _('Deleting item will remove it from the database.')
|
||||
|
||||
msg += ' ' + data_recover_msg
|
||||
#descr = object.get_description()
|
||||
#if descr == "":
|
||||
descr = object.get_gramps_id()
|
||||
ques = QuestionDialog3(_('Delete %s?') % descr, msg,
|
||||
_('_Yes'), _('_No'),
|
||||
parent=self.uistate.window)
|
||||
res = ques.run()
|
||||
if res == -1: # Cancel
|
||||
return
|
||||
elif res: # If true, perfom the delete
|
||||
self.uistate.set_busy_cursor(True)
|
||||
query.query_response()
|
||||
self.uistate.set_busy_cursor(False)
|
||||
else:
|
||||
query.query_response()
|
||||
def _message3_format(self, obj):
|
||||
"""
|
||||
Transaction label format
|
||||
"""
|
||||
return "%s %s [%s]" % (_("Delete"), _(obj.__class__.__name__),
|
||||
obj.get_gramps_id())
|
||||
|
||||
if not prompt:
|
||||
self.uistate.set_busy_cursor(False)
|
||||
def delete_object_response(self, obj, parent=None):
|
||||
"""
|
||||
Delete the object from the database.
|
||||
"""
|
||||
with DbTxn(self._message3_format(obj), self.dbstate.db) as trans:
|
||||
#self.db.disable_signals()
|
||||
self.remove_object_from_handle(
|
||||
obj.__class__.__name__, obj.handle, trans, in_use_prompt=True, parent=parent)
|
||||
#self.dbstate.db.enable_signals()
|
||||
self.uistate.set_busy_cursor(False)
|
||||
|
||||
def delete_multi_object_response(self, ht_list=None, parent=None):
|
||||
"""
|
||||
Deletes multiple objects from the database.
|
||||
"""
|
||||
# set the busy cursor, so the user knows that we are working
|
||||
self.uistate.set_busy_cursor(True)
|
||||
self.uistate.progress.show()
|
||||
self.uistate.push_message(self.dbstate, _("Processing..."))
|
||||
hndl_cnt = len(ht_list) / 100
|
||||
_db = self.dbstate.db
|
||||
_db.disable_signals()
|
||||
|
||||
# create the transaction
|
||||
with DbTxn('', _db) as trans:
|
||||
for (indx, item) in enumerate(ht_list):
|
||||
result = self.remove_object_from_handle(
|
||||
*item, trans, in_use_prompt=False, parent=parent)
|
||||
self.uistate.pulse_progressbar(indx / hndl_cnt)
|
||||
if result == -1:
|
||||
break
|
||||
trans.set_description(_("Multiple Selection Delete"))
|
||||
|
||||
_db.enable_signals()
|
||||
_db.request_rebuild()
|
||||
self.uistate.progress.hide()
|
||||
self.uistate.set_busy_cursor(False)
|
||||
|
||||
def remove_object_from_handle(self, obj_type, handle,
|
||||
trans, in_use_prompt=False, parent=None):
|
||||
"""
|
||||
deletes a single object from database
|
||||
"""
|
||||
obj = self.dbstate.db.method("get_%s_from_handle", obj_type)(handle)
|
||||
bl_list = list(self.dbstate.db.find_backlink_handles(handle))
|
||||
if in_use_prompt:
|
||||
res = self._in_use_prompt(obj, bl_list, parent=parent)
|
||||
if res != 1: # Cancel or No
|
||||
return res
|
||||
# perfom the cleanup
|
||||
for ref_type, ref_hndl in bl_list:
|
||||
ref_obj = self.dbstate.db.method(
|
||||
"get_%s_from_handle", ref_type)(ref_hndl)
|
||||
ref_obj.remove_handle_references(obj_type, [handle])
|
||||
self.dbstate.db.method("commit_%s", ref_type)(ref_obj, trans)
|
||||
self.dbstate.db.method("remove_%s", obj_type)(
|
||||
obj.get_handle(), trans)
|
||||
|
||||
def _in_use_prompt(self, obj, bl_list, parent=None):
|
||||
"""
|
||||
Prompt user if he wants to continue becasue in use
|
||||
"""
|
||||
if bl_list:
|
||||
msg = _('This item is currently being used. '
|
||||
'Deleting it will remove it from the database and '
|
||||
'from all other items that reference it.')
|
||||
else:
|
||||
msg = _('Deleting item will remove it from the database.')
|
||||
|
||||
msg += ' ' + data_recover_msg
|
||||
descr = obj.get_gramps_id()
|
||||
ques = QuestionDialog3(_('Delete %s?') % descr, msg,
|
||||
_('_Yes'), _('_No'),
|
||||
parent=parent)
|
||||
return ques.run()
|
||||
|
||||
def blist(self, store, path, iter_, sel_list):
|
||||
'''GtkTreeSelectionForeachFunc
|
||||
@ -1188,12 +1271,6 @@ class ListView(NavigationView):
|
||||
Template function to allow the merger of two objects.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def remove_object_from_handle(self, handle):
|
||||
"""
|
||||
Template function to allow the removal of an object by its handle
|
||||
"""
|
||||
|
||||
def open_all_nodes(self, *obj):
|
||||
"""
|
||||
Method for Treeviews to open all groups
|
||||
|
@ -46,12 +46,10 @@ _LOG = logging.getLogger(".gui.personview")
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gramps.gen.lib import Person, Surname
|
||||
from gramps.gen.db import DbTxn
|
||||
from gramps.gui.views.listview import ListView, TEXT, MARKUP, ICON
|
||||
from gramps.gui.uimanager import ActionGroup
|
||||
from gramps.gen.utils.string import data_recover_msg
|
||||
from gramps.gen.display.name import displayer as name_displayer
|
||||
from gramps.gui.dialog import ErrorDialog, MultiSelectDialog, QuestionDialog
|
||||
from gramps.gui.dialog import ErrorDialog
|
||||
from gramps.gen.errors import WindowActiveError
|
||||
from gramps.gui.views.bookmarks import PersonBookmarks
|
||||
from gramps.gen.config import config
|
||||
@ -443,27 +441,8 @@ class BasePersonView(ListView):
|
||||
Remove a person from the database.
|
||||
"""
|
||||
handles = self.selected_handles()
|
||||
if len(handles) == 1:
|
||||
person = self._lookup_person(handles[0])
|
||||
msg1 = self._message1_format(person)
|
||||
msg2 = self._message2_format(person)
|
||||
msg2 = "%s %s" % (msg2, data_recover_msg)
|
||||
# This gets person to delete self.active_person:
|
||||
QuestionDialog(msg1,
|
||||
msg2,
|
||||
_('_Delete Person'),
|
||||
self.delete_person_response,
|
||||
parent=self.uistate.window)
|
||||
else:
|
||||
# Ask to delete; option to cancel, delete rest
|
||||
# This gets person to delete from parameter
|
||||
MultiSelectDialog(self._message1_format,
|
||||
self._message2_format,
|
||||
handles,
|
||||
self._lookup_person,
|
||||
yes_func=self.delete_person_response,
|
||||
multi_yes_func=self.delete_multi_person_response,
|
||||
parent=self.uistate.window)
|
||||
ht_list = [('Person', hndl) for hndl in handles]
|
||||
self.remove_selected_objects(ht_list)
|
||||
|
||||
def _message1_format(self, person):
|
||||
return _('Delete %s?') % (name_displayer.display(person) +
|
||||
@ -473,65 +452,19 @@ class BasePersonView(ListView):
|
||||
return _('Deleting the person will remove the person '
|
||||
'from the database.')
|
||||
|
||||
def _lookup_person(self, handle):
|
||||
def _message3_format(self, person):
|
||||
"""
|
||||
Get the next person from handle.
|
||||
Transaction label format
|
||||
"""
|
||||
return _("Delete Person (%s)") % name_displayer.display(person)
|
||||
|
||||
def remove_object_from_handle(self, _obj_type, handle,
|
||||
trans, in_use_prompt=False, parent=None):
|
||||
"""
|
||||
deletes a single object from database
|
||||
"""
|
||||
person = self.dbstate.db.get_person_from_handle(handle)
|
||||
self.active_person = person
|
||||
return person
|
||||
|
||||
def delete_person_response(self, person=None):
|
||||
"""
|
||||
Deletes the person from the database.
|
||||
"""
|
||||
# set the busy cursor, so the user knows that we are working
|
||||
self.uistate.set_busy_cursor(True)
|
||||
|
||||
# create the transaction
|
||||
with DbTxn('', self.dbstate.db) as trans:
|
||||
|
||||
# create name to save
|
||||
person = self.active_person
|
||||
active_name = _("Delete Person (%s)") % name_displayer.display(person)
|
||||
|
||||
# delete the person from the database
|
||||
# Above will emit person-delete, which removes the person via
|
||||
# callback to the model, so row delete is signaled
|
||||
self.dbstate.db.delete_person_from_database(person, trans)
|
||||
trans.set_description(active_name)
|
||||
|
||||
self.uistate.set_busy_cursor(False)
|
||||
|
||||
def delete_multi_person_response(self, handles=None):
|
||||
"""
|
||||
Deletes multiple persons from the database.
|
||||
"""
|
||||
# set the busy cursor, so the user knows that we are working
|
||||
self.uistate.set_busy_cursor(True)
|
||||
self.uistate.progress.show()
|
||||
self.uistate.push_message(self.dbstate, _("Processing..."))
|
||||
hndl_cnt = len(handles) / 100
|
||||
self.dbstate.db.disable_signals()
|
||||
|
||||
# create the transaction
|
||||
with DbTxn('', self.dbstate.db) as trans:
|
||||
for (indx, handle) in enumerate(handles):
|
||||
person = self.dbstate.db.get_person_from_handle(handle)
|
||||
self.dbstate.db.delete_person_from_database(person, trans)
|
||||
self.uistate.pulse_progressbar(indx / hndl_cnt)
|
||||
trans.set_description(_("Multiple Selection Delete"))
|
||||
|
||||
self.dbstate.db.enable_signals()
|
||||
self.dbstate.db.request_rebuild()
|
||||
self.uistate.progress.hide()
|
||||
self.uistate.set_busy_cursor(False)
|
||||
|
||||
def remove_object_from_handle(self, handle):
|
||||
"""
|
||||
The remove_selected_objects method is not called in this view.
|
||||
"""
|
||||
pass
|
||||
self.dbstate.db.delete_person_from_database(person, trans)
|
||||
|
||||
def define_actions(self):
|
||||
"""
|
||||
|
@ -45,7 +45,7 @@ from gramps.gen.config import config
|
||||
from gramps.gui.dialog import ErrorDialog
|
||||
from gramps.gui.pluginmanager import GuiPluginManager
|
||||
from gramps.gui.ddtargets import DdTargets
|
||||
from gramps.gui.editors import EditPlace, DeletePlaceQuery
|
||||
from gramps.gui.editors import EditPlace
|
||||
from gramps.gui.filters.sidebar import PlaceSidebarFilter
|
||||
from gramps.gui.merge import MergePlace
|
||||
from gramps.gen.plug import CATEGORY_QR_PLACE
|
||||
@ -503,34 +503,17 @@ class PlaceBaseView(ListView):
|
||||
pass
|
||||
|
||||
def remove(self, *obj):
|
||||
ht_list = []
|
||||
for handle in self.selected_handles():
|
||||
for link in self.dbstate.db.find_backlink_handles(handle,['Place']):
|
||||
for _link in self.dbstate.db.find_backlink_handles(handle,
|
||||
['Place']):
|
||||
msg = _("Cannot delete place.")
|
||||
msg2 = _("This place is currently referenced by another place. "
|
||||
"First remove the places it contains.")
|
||||
msg2 = _("This place is currently referenced by another place."
|
||||
" First remove the places it contains.")
|
||||
ErrorDialog(msg, msg2, parent=self.uistate.window)
|
||||
return
|
||||
self.remove_selected_objects()
|
||||
|
||||
def remove_object_from_handle(self, handle):
|
||||
person_list = [
|
||||
item[1] for item in
|
||||
self.dbstate.db.find_backlink_handles(handle,['Person'])]
|
||||
|
||||
family_list = [
|
||||
item[1] for item in
|
||||
self.dbstate.db.find_backlink_handles(handle,['Family'])]
|
||||
|
||||
event_list = [
|
||||
item[1] for item in
|
||||
self.dbstate.db.find_backlink_handles(handle,['Event'])]
|
||||
|
||||
object = self.dbstate.db.get_place_from_handle(handle)
|
||||
query = DeletePlaceQuery(self.dbstate, self.uistate, object,
|
||||
person_list, family_list, event_list)
|
||||
|
||||
is_used = len(person_list) + len(family_list) + len(event_list) > 0
|
||||
return (query, is_used, object)
|
||||
ht_list.append(('Place', handle))
|
||||
self.remove_selected_objects(ht_list)
|
||||
|
||||
def edit(self, *obj):
|
||||
for handle in self.selected_handles():
|
||||
|
104
gramps/plugins/lib/libsourceview.py
Normal file
104
gramps/plugins/lib/libsourceview.py
Normal file
@ -0,0 +1,104 @@
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2020 Paul Culley
|
||||
#
|
||||
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
"""
|
||||
Library common to SourceView and CitationTreeView
|
||||
"""
|
||||
from gramps.gen.errors import HandleError
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# SourceLibView
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class LibSourceView():
|
||||
"""
|
||||
This contains the common delete related methods for the views.
|
||||
It was written specifically for CitationTreeView, but works for SourceView
|
||||
as well; there just will never be an citation handles in selection.
|
||||
|
||||
This must be placed before Listview in the MRO to properly override the
|
||||
included methods. For example:
|
||||
class SourceView(LibSourceView, ListView)
|
||||
"""
|
||||
|
||||
def remove(self, *obj):
|
||||
"""
|
||||
Method called when deleting source(s) or citations from the views.
|
||||
"""
|
||||
ht_list = []
|
||||
handles = self.selected_handles()
|
||||
for hndl in handles:
|
||||
if self.dbstate.db.has_source_handle(hndl):
|
||||
ht_list.append(('Source', hndl))
|
||||
else:
|
||||
ht_list.append(('Citation', hndl))
|
||||
self.remove_selected_objects(ht_list)
|
||||
|
||||
def remove_object_from_handle(self, obj_type, handle,
|
||||
trans, in_use_prompt=False, parent=None):
|
||||
"""
|
||||
deletes a single object from database
|
||||
"""
|
||||
try: # need this in case user selects both source and its Citations
|
||||
obj = self.dbstate.db.method(
|
||||
"get_%s_from_handle", obj_type)(handle)
|
||||
except HandleError:
|
||||
return
|
||||
bl_list = list(self.dbstate.db.find_backlink_handles(handle))
|
||||
if in_use_prompt:
|
||||
res = self._in_use_prompt(obj, bl_list, parent=parent)
|
||||
if res != 1: # Cancel or No
|
||||
return res
|
||||
# perfom the cleanup
|
||||
if obj_type == 'Source':
|
||||
# we need to delete all back linked citations, so sort these out
|
||||
cit_list = []
|
||||
nbl_list = []
|
||||
for item in bl_list:
|
||||
if item[0] == 'Citation':
|
||||
cit_list.append(item[1])
|
||||
else: # save any other back links for later.
|
||||
nbl_list.append(item)
|
||||
# now lets go through citations and clean up their back-refs
|
||||
hndl_cnt = len(cit_list) / 100
|
||||
for indx, cit_hndl in enumerate(cit_list):
|
||||
# the following introduces another pass with the progressbar
|
||||
# to keep the user from wondering what is happening if there
|
||||
# are a lot of citations on the source
|
||||
self.uistate.pulse_progressbar(indx / hndl_cnt)
|
||||
cit_bl_list = list(self.dbstate.db.find_backlink_handles(
|
||||
cit_hndl))
|
||||
for ref_type, ref_hndl in cit_bl_list:
|
||||
ref_obj = self.dbstate.db.method(
|
||||
"get_%s_from_handle", ref_type)(ref_hndl)
|
||||
ref_obj.remove_handle_references(obj_type, [cit_hndl])
|
||||
self.dbstate.db.method("commit_%s", ref_type)(
|
||||
ref_obj, trans)
|
||||
# and delete the citation
|
||||
self.dbstate.db.remove_citation(cit_hndl, trans)
|
||||
bl_list = nbl_list # to clean up any other back refs to source
|
||||
for ref_type, ref_hndl in bl_list:
|
||||
ref_obj = self.dbstate.db.method(
|
||||
"get_%s_from_handle", ref_type)(ref_hndl)
|
||||
ref_obj.remove_handle_references(obj_type, [handle])
|
||||
self.dbstate.db.method("commit_%s", ref_type)(ref_obj, trans)
|
||||
# and delete the source
|
||||
self.dbstate.db.remove_source(handle, trans)
|
@ -47,12 +47,11 @@ from gramps.gui.views.treemodels.citationlistmodel import CitationListModel
|
||||
from gramps.gen.plug import CATEGORY_QR_CITATION
|
||||
from gramps.gen.lib import Citation, Source
|
||||
from gramps.gui.views.listview import ListView, TEXT, MARKUP, ICON
|
||||
from gramps.gen.utils.db import get_citation_referents
|
||||
from gramps.gui.views.bookmarks import CitationBookmarks
|
||||
from gramps.gen.errors import WindowActiveError
|
||||
from gramps.gui.ddtargets import DdTargets
|
||||
from gramps.gui.dialog import ErrorDialog
|
||||
from gramps.gui.editors import EditCitation, DeleteCitationQuery
|
||||
from gramps.gui.editors import EditCitation
|
||||
from gramps.gui.filters.sidebar import CitationSidebarFilter
|
||||
from gramps.gui.merge import MergeCitation
|
||||
|
||||
@ -367,15 +366,9 @@ class CitationListView(ListView):
|
||||
pass
|
||||
|
||||
def remove(self, *obj):
|
||||
self.remove_selected_objects()
|
||||
|
||||
def remove_object_from_handle(self, handle):
|
||||
the_lists = get_citation_referents(handle, self.dbstate.db)
|
||||
object = self.dbstate.db.get_citation_from_handle(handle)
|
||||
query = DeleteCitationQuery(self.dbstate, self.uistate, object,
|
||||
the_lists)
|
||||
is_used = any(the_lists)
|
||||
return (query, is_used, object)
|
||||
handles = self.selected_handles()
|
||||
ht_list = [('Citation', hndl) for hndl in handles]
|
||||
self.remove_selected_objects(ht_list)
|
||||
|
||||
def edit(self, *obj):
|
||||
"""
|
||||
|
@ -48,16 +48,14 @@ from gramps.gui.views.treemodels.citationtreemodel import CitationTreeModel
|
||||
from gramps.gen.plug import CATEGORY_QR_SOURCE_OR_CITATION
|
||||
from gramps.gen.lib import Citation, Source
|
||||
from gramps.gui.views.listview import ListView
|
||||
from gramps.gen.utils.db import (get_source_and_citation_referents,
|
||||
get_citation_referents)
|
||||
from gramps.gui.views.bookmarks import CitationBookmarks
|
||||
from gramps.gen.errors import WindowActiveError, HandleError
|
||||
from gramps.gui.ddtargets import DdTargets
|
||||
from gramps.gui.dialog import ErrorDialog
|
||||
from gramps.gui.editors import EditCitation, DeleteCitationQuery, EditSource, \
|
||||
DeleteSrcQuery
|
||||
from gramps.gui.editors import EditCitation, EditSource
|
||||
from gramps.gui.filters.sidebar import SourceSidebarFilter
|
||||
from gramps.gui.merge import MergeCitation, MergeSource
|
||||
from gramps.plugins.lib.libsourceview import LibSourceView
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -67,12 +65,13 @@ from gramps.gui.merge import MergeCitation, MergeSource
|
||||
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.sgettext
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# PlaceTreeView
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class CitationTreeView(ListView):
|
||||
class CitationTreeView(LibSourceView, ListView):
|
||||
"""
|
||||
A hierarchical view of sources with citations below them.
|
||||
"""
|
||||
@ -590,28 +589,6 @@ class CitationTreeView(ListView):
|
||||
WarningDialog(_("Cannot share this reference"),
|
||||
self.__blocked_text(),
|
||||
parent=self.uistate.window)
|
||||
#
|
||||
def remove(self, *obj):
|
||||
self.remove_selected_objects()
|
||||
|
||||
def remove_object_from_handle(self, handle):
|
||||
# The handle will either be a Source handle or a Citation handle
|
||||
source, citation = self.get_source_or_citation(handle)
|
||||
if citation:
|
||||
the_lists = get_citation_referents(handle, self.dbstate.db)
|
||||
query = DeleteCitationQuery(self.dbstate, self.uistate, citation,
|
||||
the_lists)
|
||||
is_used = any(the_lists)
|
||||
return (query, is_used, citation)
|
||||
else:
|
||||
the_lists = get_source_and_citation_referents(handle,
|
||||
self.dbstate.db)
|
||||
LOG.debug('the_lists %s' % [the_lists])
|
||||
|
||||
query = DeleteSrcQuery(self.dbstate, self.uistate, source,
|
||||
the_lists)
|
||||
is_used = any(the_lists)
|
||||
return (query, is_used, source)
|
||||
|
||||
def edit(self, *obj):
|
||||
"""
|
||||
|
@ -40,14 +40,12 @@ _LOG = logging.getLogger(".plugins.eventview")
|
||||
from gramps.gen.const import GRAMPS_LOCALE as glocale
|
||||
_ = glocale.translation.sgettext
|
||||
|
||||
from gramps.gui.dialog import ErrorDialog, MultiSelectDialog, QuestionDialog
|
||||
from gramps.gen.db import DbTxn
|
||||
from gramps.gui.dialog import ErrorDialog
|
||||
from gramps.gen.errors import WindowActiveError
|
||||
from gramps.gen.lib import Event
|
||||
from gramps.gen.utils.string import data_recover_msg
|
||||
|
||||
from gramps.gui.ddtargets import DdTargets
|
||||
from gramps.gui.editors import EditEvent, DeleteEventQuery
|
||||
from gramps.gui.editors import EditEvent
|
||||
from gramps.gui.filters.sidebar import EventSidebarFilter
|
||||
from gramps.gui.merge import MergeEvent
|
||||
from gramps.gen.plug import CATEGORY_QR_EVENT
|
||||
@ -376,24 +374,8 @@ class EventView(ListView):
|
||||
Method called when deleting event(s) from the event view.
|
||||
"""
|
||||
handles = self.selected_handles()
|
||||
if len(handles) == 1:
|
||||
event = self.dbstate.db.get_event_from_handle(handles[0])
|
||||
msg1 = self._message1_format(event)
|
||||
msg2 = self._message2_format(event)
|
||||
msg2 = "%s %s" % (msg2, data_recover_msg)
|
||||
QuestionDialog(msg1,
|
||||
msg2,
|
||||
_('_Delete Event'),
|
||||
lambda: self.delete_event_response(event),
|
||||
parent=self.uistate.window)
|
||||
else:
|
||||
MultiSelectDialog(self._message1_format,
|
||||
self._message2_format,
|
||||
handles,
|
||||
self.dbstate.db.get_event_from_handle,
|
||||
yes_func=self.delete_event_response,
|
||||
multi_yes_func=self.delete_multi_event_response,
|
||||
parent=self.uistate.window)
|
||||
ht_list = [('Event', hndl) for hndl in handles]
|
||||
self.remove_selected_objects(ht_list)
|
||||
|
||||
def _message1_format(self, event):
|
||||
"""
|
||||
@ -402,73 +384,6 @@ class EventView(ListView):
|
||||
return _('Delete {type} [{gid}]?').format(type=str(event.type),
|
||||
gid=event.gramps_id)
|
||||
|
||||
def _message2_format(self, event):
|
||||
"""
|
||||
Detailed message format for the remove dialogs.
|
||||
"""
|
||||
return _('Deleting item will remove it from the database.')
|
||||
|
||||
def delete_event_response(self, event):
|
||||
"""
|
||||
Delete the event from the database.
|
||||
"""
|
||||
person_list = [item[1] for item in
|
||||
self.dbstate.db.find_backlink_handles(event.handle, ['Person'])]
|
||||
family_list = [item[1] for item in
|
||||
self.dbstate.db.find_backlink_handles(event.handle, ['Family'])]
|
||||
|
||||
query = DeleteEventQuery(self.dbstate, self.uistate, event,
|
||||
person_list, family_list)
|
||||
query.query_response()
|
||||
|
||||
def delete_multi_event_response(self, handles=None):
|
||||
"""
|
||||
Deletes multiple events from the database.
|
||||
"""
|
||||
# set the busy cursor, so the user knows that we are working
|
||||
self.uistate.set_busy_cursor(True)
|
||||
self.uistate.progress.show()
|
||||
self.uistate.push_message(self.dbstate, _("Processing..."))
|
||||
hndl_cnt = len(handles) / 100
|
||||
_db = self.dbstate.db
|
||||
_db.disable_signals()
|
||||
|
||||
# create the transaction
|
||||
with DbTxn('', _db) as trans:
|
||||
for (indx, handle) in enumerate(handles):
|
||||
ev_handle_list = [handle]
|
||||
|
||||
person_list = [
|
||||
item[1] for item in
|
||||
_db.find_backlink_handles(handle, ['Person'])]
|
||||
for hndl in person_list:
|
||||
person = _db.get_person_from_handle(hndl)
|
||||
person.remove_handle_references('Event', ev_handle_list)
|
||||
_db.commit_person(person, trans)
|
||||
|
||||
family_list = [
|
||||
item[1] for item in
|
||||
_db.find_backlink_handles(handle, ['Family'])]
|
||||
for hndl in family_list:
|
||||
family = _db.get_family_from_handle(hndl)
|
||||
family.remove_handle_references('Event', ev_handle_list)
|
||||
_db.commit_family(family, trans)
|
||||
|
||||
_db.remove_event(handle, trans)
|
||||
self.uistate.pulse_progressbar(indx / hndl_cnt)
|
||||
trans.set_description(_("Multiple Selection Delete"))
|
||||
|
||||
_db.enable_signals()
|
||||
_db.request_rebuild()
|
||||
self.uistate.progress.hide()
|
||||
self.uistate.set_busy_cursor(False)
|
||||
|
||||
def remove_object_from_handle(self, handle):
|
||||
"""
|
||||
The remove_selected_objects method is not called in this view.
|
||||
"""
|
||||
pass
|
||||
|
||||
def edit(self, *obj):
|
||||
for handle in self.selected_handles():
|
||||
event = self.dbstate.db.get_event_from_handle(handle)
|
||||
|
@ -359,26 +359,9 @@ class FamilyView(ListView):
|
||||
"""
|
||||
Method called when deleting a family from a family view.
|
||||
"""
|
||||
from gramps.gui.dialog import QuestionDialog, MultiSelectDialog
|
||||
from gramps.gen.utils.string import data_recover_msg
|
||||
handles = self.selected_handles()
|
||||
if len(handles) == 1:
|
||||
family = self.dbstate.db.get_family_from_handle(handles[0])
|
||||
msg1 = self._message1_format(family)
|
||||
msg2 = self._message2_format(family)
|
||||
msg2 = "%s %s" % (msg2, data_recover_msg)
|
||||
QuestionDialog(msg1,
|
||||
msg2,
|
||||
_('_Delete Family'),
|
||||
lambda: self.delete_family_response(family),
|
||||
parent=self.uistate.window)
|
||||
else:
|
||||
MultiSelectDialog(self._message1_format,
|
||||
self._message2_format,
|
||||
handles,
|
||||
self.dbstate.db.get_family_from_handle,
|
||||
yes_func=self.delete_family_response,
|
||||
parent=self.uistate.window)
|
||||
ht_list = [('Family', hndl) for hndl in handles]
|
||||
self.remove_selected_objects(ht_list)
|
||||
|
||||
def _message1_format(self, family):
|
||||
"""
|
||||
@ -387,32 +370,13 @@ class FamilyView(ListView):
|
||||
return _('Delete %s?') % (_('family') +
|
||||
(" [%s]" % family.gramps_id))
|
||||
|
||||
def _message2_format(self, family):
|
||||
def remove_object_from_handle(self, _obj_type, handle,
|
||||
trans, in_use_prompt=False, parent=None):
|
||||
"""
|
||||
Detailed message format for the remove dialogs.
|
||||
deletes a single object from database
|
||||
"""
|
||||
return _('Deleting item will remove it from the database.')
|
||||
|
||||
def delete_family_response(self, family):
|
||||
"""
|
||||
Deletes the family from the database. Callback to remove
|
||||
dialogs.
|
||||
"""
|
||||
from gramps.gen.db import DbTxn
|
||||
# set the busy cursor, so the user knows that we are working
|
||||
self.uistate.set_busy_cursor(True)
|
||||
# create the transaction
|
||||
with DbTxn('', self.dbstate.db) as trans:
|
||||
gramps_id = family.gramps_id
|
||||
self.dbstate.db.remove_family_relationships(family.handle, trans)
|
||||
trans.set_description(_("Family [%s]") % gramps_id)
|
||||
self.uistate.set_busy_cursor(False)
|
||||
|
||||
def remove_object_from_handle(self, handle):
|
||||
"""
|
||||
The remove_selected_objects method is not called in this view.
|
||||
"""
|
||||
pass
|
||||
family = self.dbstate.db.get_family_from_handle(handle)
|
||||
self.dbstate.db.remove_family_relationships(handle, trans)
|
||||
|
||||
def edit(self, *obj):
|
||||
for handle in self.selected_handles():
|
||||
|
@ -54,12 +54,11 @@ from gramps.gui.views.treemodels import MediaModel
|
||||
from gramps.gen.config import config
|
||||
from gramps.gen.utils.file import (media_path, relative_path, media_path_full,
|
||||
create_checksum)
|
||||
from gramps.gen.utils.db import get_media_referents
|
||||
from gramps.gui.views.bookmarks import MediaBookmarks
|
||||
from gramps.gen.mime import get_type, is_valid_type
|
||||
from gramps.gen.lib import Media
|
||||
from gramps.gen.db import DbTxn
|
||||
from gramps.gui.editors import EditMedia, DeleteMediaQuery
|
||||
from gramps.gui.editors import EditMedia
|
||||
from gramps.gen.errors import WindowActiveError
|
||||
from gramps.gui.filters.sidebar import MediaSidebarFilter
|
||||
from gramps.gui.merge import MergeMedia
|
||||
@ -456,18 +455,9 @@ class MediaView(ListView):
|
||||
pass
|
||||
|
||||
def remove(self, *obj):
|
||||
self.remove_selected_objects()
|
||||
|
||||
def remove_object_from_handle(self, handle):
|
||||
"""
|
||||
Remove the selected objects from the database after getting
|
||||
user verification.
|
||||
"""
|
||||
the_lists = get_media_referents(handle, self.dbstate.db)
|
||||
object = self.dbstate.db.get_media_from_handle(handle)
|
||||
query = DeleteMediaQuery(self.dbstate, self.uistate, handle, the_lists)
|
||||
is_used = any(the_lists)
|
||||
return (query, is_used, object)
|
||||
handles = self.selected_handles()
|
||||
ht_list = [('Media', hndl) for hndl in handles]
|
||||
self.remove_selected_objects(ht_list)
|
||||
|
||||
def edit(self, *obj):
|
||||
"""
|
||||
|
@ -46,7 +46,6 @@ from gi.repository import Gtk
|
||||
#-------------------------------------------------------------------------
|
||||
from gramps.gui.views.listview import ListView, TEXT, MARKUP, ICON
|
||||
from gramps.gui.views.treemodels import NoteModel
|
||||
from gramps.gen.utils.db import get_note_referents
|
||||
from gramps.gen.errors import WindowActiveError
|
||||
from gramps.gui.views.bookmarks import NoteBookmarks
|
||||
from gramps.gen.config import config
|
||||
@ -54,7 +53,7 @@ from gramps.gen.lib import Note
|
||||
from gramps.gui.ddtargets import DdTargets
|
||||
from gramps.gui.dialog import ErrorDialog
|
||||
from gramps.gui.filters.sidebar import NoteSidebarFilter
|
||||
from gramps.gui.editors import EditNote, DeleteNoteQuery
|
||||
from gramps.gui.editors import EditNote
|
||||
from gramps.gui.merge import MergeNote
|
||||
from gramps.gen.plug import CATEGORY_QR_NOTE
|
||||
|
||||
@ -330,14 +329,9 @@ class NoteView(ListView):
|
||||
pass
|
||||
|
||||
def remove(self, *obj):
|
||||
self.remove_selected_objects()
|
||||
|
||||
def remove_object_from_handle(self, handle):
|
||||
the_lists = get_note_referents(handle, self.dbstate.db)
|
||||
object = self.dbstate.db.get_note_from_handle(handle)
|
||||
query = DeleteNoteQuery(self.dbstate, self.uistate, object, the_lists)
|
||||
is_used = any(the_lists)
|
||||
return (query, is_used, object)
|
||||
handles = self.selected_handles()
|
||||
ht_list = [('Note', hndl) for hndl in handles]
|
||||
self.remove_selected_objects(ht_list)
|
||||
|
||||
def edit(self, *obj):
|
||||
for handle in self.selected_handles():
|
||||
|
@ -40,7 +40,7 @@ from gramps.gui.views.treemodels import RepositoryModel
|
||||
from gramps.gui.views.bookmarks import RepoBookmarks
|
||||
from gramps.gen.errors import WindowActiveError
|
||||
from gramps.gen.config import config
|
||||
from gramps.gui.editors import EditRepository, DeleteRepositoryQuery
|
||||
from gramps.gui.editors import EditRepository
|
||||
from gramps.gui.ddtargets import DdTargets
|
||||
from gramps.gui.dialog import ErrorDialog
|
||||
from gramps.gui.filters.sidebar import RepoSidebarFilter
|
||||
@ -333,17 +333,12 @@ class RepositoryView(ListView):
|
||||
EditRepository(self.dbstate, self.uistate, [], Repository())
|
||||
|
||||
def remove(self, *obj):
|
||||
self.remove_selected_objects()
|
||||
|
||||
def remove_object_from_handle(self, handle):
|
||||
source_list = [
|
||||
item[1] for item in
|
||||
self.dbstate.db.find_backlink_handles(handle, ['Source'])]
|
||||
object = self.dbstate.db.get_repository_from_handle(handle)
|
||||
query = DeleteRepositoryQuery(self.dbstate, self.uistate, object,
|
||||
source_list)
|
||||
is_used = len(source_list) > 0
|
||||
return (query, is_used, object)
|
||||
"""
|
||||
Method called when deleting repo(s) from the repo view.
|
||||
"""
|
||||
handles = self.selected_handles()
|
||||
ht_list = [('Repository', hndl) for hndl in handles]
|
||||
self.remove_selected_objects(ht_list)
|
||||
|
||||
def edit(self, *obj):
|
||||
for handle in self.selected_handles():
|
||||
|
@ -41,15 +41,15 @@ from gramps.gen.lib import Source
|
||||
from gramps.gen.config import config
|
||||
from gramps.gui.views.listview import ListView, TEXT, MARKUP, ICON
|
||||
from gramps.gui.views.treemodels import SourceModel
|
||||
from gramps.gen.utils.db import get_source_and_citation_referents
|
||||
from gramps.gui.views.bookmarks import SourceBookmarks
|
||||
from gramps.gen.errors import WindowActiveError
|
||||
from gramps.gui.ddtargets import DdTargets
|
||||
from gramps.gui.dialog import ErrorDialog
|
||||
from gramps.gui.editors import EditSource, DeleteSrcQuery
|
||||
from gramps.gui.editors import EditSource
|
||||
from gramps.gui.filters.sidebar import SourceSidebarFilter
|
||||
from gramps.gui.merge import MergeSource
|
||||
from gramps.gen.plug import CATEGORY_QR_SOURCE
|
||||
from gramps.plugins.lib.libsourceview import LibSourceView
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -65,7 +65,7 @@ _ = glocale.translation.sgettext
|
||||
# SourceView
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class SourceView(ListView):
|
||||
class SourceView(LibSourceView, ListView):
|
||||
""" sources listview class
|
||||
"""
|
||||
COL_TITLE = 0
|
||||
@ -318,18 +318,6 @@ class SourceView(ListView):
|
||||
def add(self, *obj):
|
||||
EditSource(self.dbstate, self.uistate, [], Source())
|
||||
|
||||
def remove(self, *obj):
|
||||
self.remove_selected_objects()
|
||||
|
||||
def remove_object_from_handle(self, handle):
|
||||
the_lists = get_source_and_citation_referents(handle, self.dbstate.db)
|
||||
LOG.debug('the_lists %s' % [the_lists])
|
||||
|
||||
object = self.dbstate.db.get_source_from_handle(handle)
|
||||
query = DeleteSrcQuery(self.dbstate, self.uistate, object, the_lists)
|
||||
is_used = any(the_lists)
|
||||
return (query, is_used, object)
|
||||
|
||||
def edit(self, *obj):
|
||||
for handle in self.selected_handles():
|
||||
source = self.dbstate.db.get_source_from_handle(handle)
|
||||
|
Loading…
Reference in New Issue
Block a user