From 2359633198ef50072d2bb6ca25f923718fab02d8 Mon Sep 17 00:00:00 2001 From: prculley Date: Wed, 7 Dec 2016 11:52:21 -0600 Subject: [PATCH] bug 8333; fix merge issue with Person Tree View --- gramps/gui/views/listview.py | 21 ++++++++++++---- gramps/gui/views/treemodels/treebasemodel.py | 18 +++++++++++--- gramps/plugins/lib/libpersonview.py | 3 +++ gramps/plugins/view/citationtreeview.py | 26 +++++++++++++++++++- gramps/plugins/view/placetreeview.py | 14 +++++++---- 5 files changed, 67 insertions(+), 15 deletions(-) diff --git a/gramps/gui/views/listview.py b/gramps/gui/views/listview.py index 0d65bd349..b0f480adb 100644 --- a/gramps/gui/views/listview.py +++ b/gramps/gui/views/listview.py @@ -57,7 +57,7 @@ from .navigationview import NavigationView from ..actiongroup import ActionGroup from ..columnorder import ColumnOrder from gramps.gen.config import config -from gramps.gen.errors import WindowActiveError, FilterError +from gramps.gen.errors import WindowActiveError, FilterError, HandleError from ..filters import SearchBar from ..widgets.menuitem import add_menuitem from gramps.gen.const import CUSTOM_FILTERS @@ -707,7 +707,13 @@ class ListView(NavigationView): """ selected_ids = self.selected_handles() if len(selected_ids) > 0: - self.change_active(selected_ids[0]) + # In certain cases the tree models do row updates which result in a + # selection changed signal to a handle in progress of being + # deleted. In these cases we don't want to change the active to + # non-existant handles. + if hasattr(self.model, "dont_change_active"): + if not self.model.dont_change_active: + self.change_active(selected_ids[0]) if len(selected_ids) == 1: if self.drag_info(): @@ -804,10 +810,15 @@ class ListView(NavigationView): lookup_handle = self.dbstate.db.get_table_metadata(nav_type)['handle_func'] for handle in selected_ids: # Still exist? - if lookup_handle(handle): + # should really use db.has_handle(nav_type, handle) but doesn't + # exist for bsddb + try: + lookup_handle(handle) # Select it, and stop selecting: - self.change_active(handle) - break + except HandleError: + continue + self.change_active(handle) + break def _button_press(self, obj, event): """ diff --git a/gramps/gui/views/treemodels/treebasemodel.py b/gramps/gui/views/treemodels/treebasemodel.py index 90a3100d9..7b1c3d2ec 100644 --- a/gramps/gui/views/treemodels/treebasemodel.py +++ b/gramps/gui/views/treemodels/treebasemodel.py @@ -283,6 +283,7 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel, BaseModel): cput = time.clock() GObject.GObject.__init__(self) BaseModel.__init__(self) + #We create a stamp to recognize invalid iterators. From the docs: #Set the stamp to be equal to your model's stamp, to mark the #iterator as valid. When your model's structure changes, you should @@ -300,6 +301,7 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel, BaseModel): self.group_can_have_handle = group_can_have_handle self.has_secondary = has_secondary self.db = db + self.dont_change_active = False self._set_base_data() @@ -796,18 +798,26 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel, BaseModel): def update_row_by_handle(self, handle): """ Update a row in the model. + + We have to do delete/add because sometimes row position changes when + object name changes. + A delete action causes the listview module to set a prior row to + active. In some cases (merge) the prior row may have been already + removed from the db. To avoid invalid handle exceptions in gramplets + at the change active, we tell listview not to change active. + The add_row below changes to current active again so we end up in right + place. """ assert isinstance(handle, str) self.clear_cache(handle) if self._get_node(handle) is None: - return # row not currently displayed + return # row not currently displayed + self.dont_change_active = True self.delete_row_by_handle(handle) + self.dont_change_active = False self.add_row_by_handle(handle) - # If the node hasn't moved, all we need is to call row_changed. - #self.row_changed(path, node) - def _new_iter(self, nodeid): """ Return a new iter containing the nodeid in the nodemap diff --git a/gramps/plugins/lib/libpersonview.py b/gramps/plugins/lib/libpersonview.py index ad6fbc174..30c9f4b04 100644 --- a/gramps/plugins/lib/libpersonview.py +++ b/gramps/plugins/lib/libpersonview.py @@ -139,6 +139,9 @@ class BasePersonView(ListView): 'person-rebuild' : self.object_build, 'person-groupname-rebuild' : self.object_build, 'no-database': self.no_database, + 'family-update' : self.object_build, + 'family-add' : self.object_build, + 'family-delete' : self.object_build, } ListView.__init__( diff --git a/gramps/plugins/view/citationtreeview.py b/gramps/plugins/view/citationtreeview.py index 8b89dd0ed..833d167eb 100644 --- a/gramps/plugins/view/citationtreeview.py +++ b/gramps/plugins/view/citationtreeview.py @@ -212,7 +212,12 @@ class CitationTreeView(ListView): def _source_row_update(self, handle_list): self._print_handles("source row update", handle_list) - self.row_update(handle_list) + # if the source update changes the title or other item being sorted + # then it may change position on tree; it's easier to just rebuild the + # whole tree. row_update cannot fix changes to first level of tree + #self.row_update(handle_list) + self.dirty = True + self.build_tree() def _source_row_delete(self, handle_list): self._print_handles("source row delete", handle_list) @@ -225,6 +230,25 @@ class CitationTreeView(ListView): def navigation_type(self): return 'Citation' + def object_build(self, *args): + """ + Called when the tree must be rebuilt and bookmarks redrawn. + """ + self.dirty = True + if self.active: + # Save the currently selected handles, if any: + selected_ids = self.selected_handles() + self.bookmarks.redraw() + self.build_tree() + # Reselect one, if it still exists after rebuild: + for handle in selected_ids: + # Still exist? It might be either a source or citation handle. + if (self.dbstate.db.has_citation_handle(handle) or + self.dbstate.db.has_source_handle(handle)): + # Select it, and stop selecting: + self.change_active(handle) + break + def drag_info(self): # Since drag only needs to work when just one row is selected, ideally, # this should just return SOURCE_LINK if one source is selected and diff --git a/gramps/plugins/view/placetreeview.py b/gramps/plugins/view/placetreeview.py index 556b90cf5..35d48d917 100644 --- a/gramps/plugins/view/placetreeview.py +++ b/gramps/plugins/view/placetreeview.py @@ -167,14 +167,17 @@ class PlaceTreeView(PlaceBaseView): for handle in handle_list: # Rebuild the model if the primary parent has changed. - if self._parent_changed(handle): + if self._significant_change(handle): self.build_tree() break - def _parent_changed(self, handle): + def _significant_change(self, handle): """ Return True if the primary parent is different from the parent - displayed in the tree, else return False. + displayed in the tree, or if there are children. + The first occurs if a change moves a child to a different parent, + the second if a change to a parent occurs (a rename might shift + position in the tree). """ new_handle = None place = self.dbstate.db.get_place_from_handle(handle) @@ -183,10 +186,11 @@ class PlaceTreeView(PlaceBaseView): new_handle = placeref_list[0].ref old_handle = None + children = False iter_ = self.model.get_iter_from_handle(handle) if iter_: parent_iter = self.model.iter_parent(iter_) if parent_iter: old_handle = self.model.get_handle_from_iter(parent_iter) - - return True if new_handle != old_handle else False + children = self.model.get_node_from_iter(iter_).children + return new_handle != old_handle or children