Rework primary object Deletes in views

This commit is contained in:
prculley 2020-08-10 10:27:25 -05:00 committed by Nick Hall
parent c01b81809a
commit 80908fc6f7
23 changed files with 338 additions and 755 deletions

View File

@ -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,

View File

@ -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`

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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):
"""

View File

@ -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():

View 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)

View File

@ -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):
"""

View File

@ -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):
"""

View File

@ -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)

View File

@ -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():

View File

@ -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):
"""

View File

@ -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():

View File

@ -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():

View File

@ -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)