From 809c3bb833e6e94687c72a4aa82e3dbe5ebae19a Mon Sep 17 00:00:00 2001 From: Nick Hall Date: Thu, 5 Jan 2012 19:16:34 +0000 Subject: [PATCH] Improve treebasemodel to allow filtering of secondary object nodes. Fix sorting of secondary object nodes. svn: r18706 --- src/gui/views/treemodels/citationtreemodel.py | 77 ++++++++--------- src/gui/views/treemodels/treebasemodel.py | 83 ++++++++++++++----- 2 files changed, 98 insertions(+), 62 deletions(-) diff --git a/src/gui/views/treemodels/citationtreemodel.py b/src/gui/views/treemodels/citationtreemodel.py index 818940083..b4283622d 100644 --- a/src/gui/views/treemodels/citationtreemodel.py +++ b/src/gui/views/treemodels/citationtreemodel.py @@ -68,6 +68,7 @@ class CitationTreeModel(CitationBaseModel, TreeBaseModel): def __init__(self, db, scol=0, order=gtk.SORT_ASCENDING, search=None, skip=set(), sort_map=None): self.db = db + self.number_items = self.db.get_number_of_sources self.map = self.db.get_raw_source_data self.gen_cursor = self.db.get_source_cursor # The items here must correspond, in order, with data in @@ -101,7 +102,8 @@ class CitationTreeModel(CitationBaseModel, TreeBaseModel): tooltip_column=9, search=search, skip=skip, sort_map=sort_map, nrgroups = 1, - group_can_have_handle = True) + group_can_have_handle = True, + has_secondary=True) def destroy(self): """ @@ -111,18 +113,22 @@ class CitationTreeModel(CitationBaseModel, TreeBaseModel): self.gen_cursor = None self.map = None self.fmap = None - self.map2 = None - self.fmap2 = None self.smap = None self.number_items = None + self.gen_cursor2 = None + self.map2 = None + self.fmap2 = None + self.smap2 = None + self.number_items2 = None TreeBaseModel.destroy(self) def _set_base_data(self): """See TreeBaseModel, for citations, most have been set in init of CitationBaseModel """ - self.number_items = self.db.get_number_of_citations + self.number_items2 = self.db.get_number_of_citations self.map2 = self.db.get_raw_citation_data + self.gen_cursor2 = self.db.get_citation_cursor self.fmap2 = [ self.citation_page, self.citation_id, @@ -135,6 +141,18 @@ class CitationTreeModel(CitationBaseModel, TreeBaseModel): self.citation_handle, self.citation_tooltip ] + self.smap2 = [ + self.citation_page, + self.citation_id, + self.citation_sort_date, + self.citation_confidence, + self.citation_sort_change, + self.dummy_sort_key, + self.dummy_sort_key, + self.dummy_sort_key, + self.citation_handle, + self.citation_tooltip + ] def get_tree_levels(self): """ @@ -144,49 +162,24 @@ class CitationTreeModel(CitationBaseModel, TreeBaseModel): def add_row(self, handle, data): """ - Add nodes to the node map for a single citation. + Add source nodes to the node map. handle The handle of the gramps object. data The object data. """ - # first add the source -# source_name = self.source_src_title(data) sort_key = self.sort_func(data) - # add as node: parent, child, sortkey, handle; parent and child are - # nodes in the treebasemodel, and will be used as iters - if self.get_node(handle) is None: - self.add_node(None, handle, sort_key, handle) - # now add all the related citations - source_handle_list = [] - for i in get_source_referents(handle, self.db): - for j in i: - source_handle_list.append(j) - for citation_handle in source_handle_list: - if self.get_node(citation_handle) is None: - # # add as node: parent, child, sortkey, handle; parent and child are - # # nodes in the treebasemodel, and will be used as iters - citation = self.db.get_citation_from_handle(citation_handle) - citation_page = citation.get_page() - self.add_node(handle, citation_handle, citation_page, - citation_handle, secondary=True) -# try: -# source_handle = data[COLUMN_SOURCE] -# except: -# LOG.debug("add_row: data %s is empty, handle %s citation %s data %s" % -# (data, handle, self.db.get_citation_from_handle(handle), -# self.db.get_citation_from_handle(handle).serialize())) -# source = self.db.get_source_from_handle(source_handle) -# if source is not None: -# source_name = source.get_title() -# sort_key = self.sort_func(data) -# if self.get_node(source_handle) is None: -# self.add_node(None, source_handle, source_name, source_handle, -# secondary=True) -# self.add_node(source_handle, handle, sort_key, handle) -# else: -# log.warn("Citation %s does not have a source" % -# unicode(data[COLUMN_PAGE]), -# exc_info=True) + self.add_node(None, handle, sort_key, handle) + + def add_row2(self, handle, data): + """ + Add citation nodes to the node map. + + handle The handle of the gramps object. + data The object data. + """ + sort_key = self.sort_func2(data) + if self.get_node(data[5]): + self.add_node(data[5], handle, sort_key, handle, secondary=True) def add_secondary_row(self, handle, data): """ diff --git a/src/gui/views/treemodels/treebasemodel.py b/src/gui/views/treemodels/treebasemodel.py index 428f88266..09446af5c 100644 --- a/src/gui/views/treemodels/treebasemodel.py +++ b/src/gui/views/treemodels/treebasemodel.py @@ -3,9 +3,9 @@ # # Copyright (C) 2000-2007 Donald N. Allingham # Copyright (C) 2009 Gary Burton -# Copyright (C) 2009-2010 Nick Hall +# Copyright (C) 2009-2011 Nick Hall # Copyright (C) 2009 Benny Malengier -# Copyright (C) 2011 Nick Hall, Tim G L lyons +# Copyright (C) 2011 Tim G L lyons # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -269,6 +269,9 @@ class TreeBaseModel(gtk.GenericTreeModel): can groups have a handle. If False, this means groups are only used to group subnodes, not for holding data and showing subnodes + has_secondary : If True, the model contains two Gramps object types. + The suffix '2' is appended to variables relating to the + secondary object type. """ # LRU cache size @@ -278,7 +281,8 @@ class TreeBaseModel(gtk.GenericTreeModel): search=None, skip=set(), scol=0, order=gtk.SORT_ASCENDING, sort_map=None, nrgroups = 1, - group_can_have_handle = False): + group_can_have_handle = False, + has_secondary=False): cput = time.clock() gtk.GenericTreeModel.__init__(self) #two unused attributes pesent to correspond to flatbasemodel @@ -289,6 +293,7 @@ class TreeBaseModel(gtk.GenericTreeModel): self.scol = scol self.nrgroups = nrgroups self.group_can_have_handle = group_can_have_handle + self.has_secondary = has_secondary self.db = db self._set_base_data() @@ -307,9 +312,13 @@ class TreeBaseModel(gtk.GenericTreeModel): #we need the model col, that corresponds with scol col = self.sort_map[scol][1] self.sort_func = self.smap[col] + if self.has_secondary: + self.sort_func2 = self.smap2[col] self.sort_col = col else: self.sort_func = self.smap[scol] + if self.has_secondary: + self.sort_func2 = self.smap2[scol] self.sort_col = scol self._in_build = False @@ -333,6 +342,8 @@ class TreeBaseModel(gtk.GenericTreeModel): """ self.db = None self.sort_func = None + if self.has_secondary: + self.sort_func2 = None if self.nodemap: self.nodemap.destroy() self.nodemap = None @@ -354,17 +365,19 @@ class TreeBaseModel(gtk.GenericTreeModel): map : function to obtain the raw bsddb object datamap smap : the map with functions to obtain sort value based on sort col fmap : the map with functions to obtain value of a row with handle - hmap : the map with functions to obtain value of a row without handle """ self.gen_cursor = None self.number_items = None # function self.map = None - self.map2 = None - self.smap = None self.fmap = None - self.smap2 = None - self.fmap2 = None + + if self.has_secondary: + self.gen_cursor2 = None + self.number_items2 = None # function + self.map2 = None + self.smap2 = None + self.fmap2 = None def displayed(self): """ @@ -478,15 +491,28 @@ class TreeBaseModel(gtk.GenericTreeModel): """ self.__total = 0 self.__displayed = 0 - + items = self.number_items() + self.__rebuild_search(dfilter, skip, items, + self.gen_cursor, self.add_row) + + if self.has_secondary: + items = self.number_items2() + self.__rebuild_search(dfilter, skip, items, + self.gen_cursor2, self.add_row2) + + def __rebuild_search(self, dfilter, skip, items, gen_cursor, add_func): + """ + Rebuild the data map for a single Gramps object type, where a search + condition is applied. + """ pmon = progressdlg.ProgressMonitor(progressdlg.GtkProgressDialog, popup_time=2) status = progressdlg.LongOpStatus(msg=_("Building View"), total_steps=items, interval=items//20, can_cancel=True) pmon.add_op(status) - with self.gen_cursor() as cursor: + with gen_cursor() as cursor: for handle, data in cursor: status.heartbeat() if status.should_cancel(): @@ -495,7 +521,7 @@ class TreeBaseModel(gtk.GenericTreeModel): if not (handle in skip or (dfilter and not dfilter.match(handle, self.db))): self.__displayed += 1 - self.add_row(handle, data) + add_func(handle, data) if not status.was_cancelled(): status.end() @@ -503,29 +529,46 @@ class TreeBaseModel(gtk.GenericTreeModel): """ Rebuild the data map where a filter is applied. """ + self.__total = 0 + self.__displayed = 0 + + items = self.number_items() + self.__rebuild_filter(dfilter, skip, items, + self.gen_cursor, self.map, self.add_row) + if self.has_secondary: + items = self.number_items2() + self.__rebuild_filter(dfilter, skip, items, + self.gen_cursor2, self.map2, self.add_row2) + + def __rebuild_filter(self, dfilter, skip, items, gen_cursor, data_map, + add_func): + """ + Rebuild the data map for a single Gramps object type, where a filter + is applied. + """ pmon = progressdlg.ProgressMonitor(progressdlg.GtkProgressDialog, popup_time=2) - status = progressdlg.LongOpStatus(msg=_("Building People View"), + status = progressdlg.LongOpStatus(msg=_("Building View"), total_steps=3, interval=1) pmon.add_op(status) - self.__total = self.number_items() - status_ppl = progressdlg.LongOpStatus(msg=_("Obtaining all people"), - total_steps=self.__total, interval=self.__total//10) + status_ppl = progressdlg.LongOpStatus(msg=_("Obtaining all rows"), + total_steps=items, interval=items//10) pmon.add_op(status_ppl) + self.__total += items + def beat(key): status_ppl.heartbeat() return key - with self.gen_cursor() as cursor: + with gen_cursor() as cursor: handle_list = [beat(key) for key, data in cursor] status_ppl.end() - self.__displayed = 0 status.heartbeat() if dfilter: status_filter = progressdlg.LongOpStatus(msg=_("Applying filter"), - total_steps=self.__total, interval=self.__total//10) + total_steps=items, interval=items//10) pmon.add_op(status_filter) handle_list = dfilter.apply(self.db, handle_list, cb_progress=status_filter.heartbeat) @@ -538,9 +581,9 @@ class TreeBaseModel(gtk.GenericTreeModel): pmon.add_op(status_col) for handle in handle_list: status_col.heartbeat() - data = self.map(handle) + data = data_map(handle) if not handle in skip: - self.add_row(handle, data) + add_func(handle, data) self.__displayed += 1 status_col.end() status.end()