Improve treebasemodel to allow filtering of secondary object nodes. Fix sorting of secondary object nodes.

svn: r18706
This commit is contained in:
Nick Hall 2012-01-05 19:16:34 +00:00
parent 6ddb6dbcd1
commit 809c3bb833
2 changed files with 98 additions and 62 deletions

View File

@ -68,6 +68,7 @@ class CitationTreeModel(CitationBaseModel, TreeBaseModel):
def __init__(self, db, scol=0, order=gtk.SORT_ASCENDING, search=None, def __init__(self, db, scol=0, order=gtk.SORT_ASCENDING, search=None,
skip=set(), sort_map=None): skip=set(), sort_map=None):
self.db = db self.db = db
self.number_items = self.db.get_number_of_sources
self.map = self.db.get_raw_source_data self.map = self.db.get_raw_source_data
self.gen_cursor = self.db.get_source_cursor self.gen_cursor = self.db.get_source_cursor
# The items here must correspond, in order, with data in # The items here must correspond, in order, with data in
@ -101,7 +102,8 @@ class CitationTreeModel(CitationBaseModel, TreeBaseModel):
tooltip_column=9, tooltip_column=9,
search=search, skip=skip, sort_map=sort_map, search=search, skip=skip, sort_map=sort_map,
nrgroups = 1, nrgroups = 1,
group_can_have_handle = True) group_can_have_handle = True,
has_secondary=True)
def destroy(self): def destroy(self):
""" """
@ -111,18 +113,22 @@ class CitationTreeModel(CitationBaseModel, TreeBaseModel):
self.gen_cursor = None self.gen_cursor = None
self.map = None self.map = None
self.fmap = None self.fmap = None
self.map2 = None
self.fmap2 = None
self.smap = None self.smap = None
self.number_items = 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) TreeBaseModel.destroy(self)
def _set_base_data(self): def _set_base_data(self):
"""See TreeBaseModel, for citations, most have been set in init of """See TreeBaseModel, for citations, most have been set in init of
CitationBaseModel 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.map2 = self.db.get_raw_citation_data
self.gen_cursor2 = self.db.get_citation_cursor
self.fmap2 = [ self.fmap2 = [
self.citation_page, self.citation_page,
self.citation_id, self.citation_id,
@ -135,6 +141,18 @@ class CitationTreeModel(CitationBaseModel, TreeBaseModel):
self.citation_handle, self.citation_handle,
self.citation_tooltip 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): def get_tree_levels(self):
""" """
@ -144,49 +162,24 @@ class CitationTreeModel(CitationBaseModel, TreeBaseModel):
def add_row(self, handle, data): 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. handle The handle of the gramps object.
data The object data. data The object data.
""" """
# first add the source
# source_name = self.source_src_title(data)
sort_key = self.sort_func(data) sort_key = self.sort_func(data)
# add as node: parent, child, sortkey, handle; parent and child are self.add_node(None, handle, sort_key, handle)
# nodes in the treebasemodel, and will be used as iters
if self.get_node(handle) is None: def add_row2(self, handle, data):
self.add_node(None, handle, sort_key, handle) """
# now add all the related citations Add citation nodes to the node map.
source_handle_list = []
for i in get_source_referents(handle, self.db): handle The handle of the gramps object.
for j in i: data The object data.
source_handle_list.append(j) """
for citation_handle in source_handle_list: sort_key = self.sort_func2(data)
if self.get_node(citation_handle) is None: if self.get_node(data[5]):
# # add as node: parent, child, sortkey, handle; parent and child are self.add_node(data[5], handle, sort_key, handle, secondary=True)
# # 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)
def add_secondary_row(self, handle, data): def add_secondary_row(self, handle, data):
""" """

View File

@ -3,9 +3,9 @@
# #
# Copyright (C) 2000-2007 Donald N. Allingham # Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2009 Gary Burton # Copyright (C) 2009 Gary Burton
# Copyright (C) 2009-2010 Nick Hall # Copyright (C) 2009-2011 Nick Hall
# Copyright (C) 2009 Benny Malengier # 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 # 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 # 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 can groups have a handle. If False, this means groups
are only used to group subnodes, not for holding data and are only used to group subnodes, not for holding data and
showing subnodes 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 # LRU cache size
@ -278,7 +281,8 @@ class TreeBaseModel(gtk.GenericTreeModel):
search=None, skip=set(), search=None, skip=set(),
scol=0, order=gtk.SORT_ASCENDING, sort_map=None, scol=0, order=gtk.SORT_ASCENDING, sort_map=None,
nrgroups = 1, nrgroups = 1,
group_can_have_handle = False): group_can_have_handle = False,
has_secondary=False):
cput = time.clock() cput = time.clock()
gtk.GenericTreeModel.__init__(self) gtk.GenericTreeModel.__init__(self)
#two unused attributes pesent to correspond to flatbasemodel #two unused attributes pesent to correspond to flatbasemodel
@ -289,6 +293,7 @@ class TreeBaseModel(gtk.GenericTreeModel):
self.scol = scol self.scol = scol
self.nrgroups = nrgroups self.nrgroups = nrgroups
self.group_can_have_handle = group_can_have_handle self.group_can_have_handle = group_can_have_handle
self.has_secondary = has_secondary
self.db = db self.db = db
self._set_base_data() self._set_base_data()
@ -307,9 +312,13 @@ class TreeBaseModel(gtk.GenericTreeModel):
#we need the model col, that corresponds with scol #we need the model col, that corresponds with scol
col = self.sort_map[scol][1] col = self.sort_map[scol][1]
self.sort_func = self.smap[col] self.sort_func = self.smap[col]
if self.has_secondary:
self.sort_func2 = self.smap2[col]
self.sort_col = col self.sort_col = col
else: else:
self.sort_func = self.smap[scol] self.sort_func = self.smap[scol]
if self.has_secondary:
self.sort_func2 = self.smap2[scol]
self.sort_col = scol self.sort_col = scol
self._in_build = False self._in_build = False
@ -333,6 +342,8 @@ class TreeBaseModel(gtk.GenericTreeModel):
""" """
self.db = None self.db = None
self.sort_func = None self.sort_func = None
if self.has_secondary:
self.sort_func2 = None
if self.nodemap: if self.nodemap:
self.nodemap.destroy() self.nodemap.destroy()
self.nodemap = None self.nodemap = None
@ -354,17 +365,19 @@ class TreeBaseModel(gtk.GenericTreeModel):
map : function to obtain the raw bsddb object datamap map : function to obtain the raw bsddb object datamap
smap : the map with functions to obtain sort value based on sort col 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 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.gen_cursor = None
self.number_items = None # function self.number_items = None # function
self.map = None self.map = None
self.map2 = None
self.smap = None self.smap = None
self.fmap = 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): def displayed(self):
""" """
@ -478,15 +491,28 @@ class TreeBaseModel(gtk.GenericTreeModel):
""" """
self.__total = 0 self.__total = 0
self.__displayed = 0 self.__displayed = 0
items = self.number_items() 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, pmon = progressdlg.ProgressMonitor(progressdlg.GtkProgressDialog,
popup_time=2) popup_time=2)
status = progressdlg.LongOpStatus(msg=_("Building View"), status = progressdlg.LongOpStatus(msg=_("Building View"),
total_steps=items, interval=items//20, total_steps=items, interval=items//20,
can_cancel=True) can_cancel=True)
pmon.add_op(status) pmon.add_op(status)
with self.gen_cursor() as cursor: with gen_cursor() as cursor:
for handle, data in cursor: for handle, data in cursor:
status.heartbeat() status.heartbeat()
if status.should_cancel(): if status.should_cancel():
@ -495,7 +521,7 @@ class TreeBaseModel(gtk.GenericTreeModel):
if not (handle in skip or (dfilter and not if not (handle in skip or (dfilter and not
dfilter.match(handle, self.db))): dfilter.match(handle, self.db))):
self.__displayed += 1 self.__displayed += 1
self.add_row(handle, data) add_func(handle, data)
if not status.was_cancelled(): if not status.was_cancelled():
status.end() status.end()
@ -503,29 +529,46 @@ class TreeBaseModel(gtk.GenericTreeModel):
""" """
Rebuild the data map where a filter is applied. 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, pmon = progressdlg.ProgressMonitor(progressdlg.GtkProgressDialog,
popup_time=2) popup_time=2)
status = progressdlg.LongOpStatus(msg=_("Building People View"), status = progressdlg.LongOpStatus(msg=_("Building View"),
total_steps=3, interval=1) total_steps=3, interval=1)
pmon.add_op(status) pmon.add_op(status)
self.__total = self.number_items() status_ppl = progressdlg.LongOpStatus(msg=_("Obtaining all rows"),
status_ppl = progressdlg.LongOpStatus(msg=_("Obtaining all people"), total_steps=items, interval=items//10)
total_steps=self.__total, interval=self.__total//10)
pmon.add_op(status_ppl) pmon.add_op(status_ppl)
self.__total += items
def beat(key): def beat(key):
status_ppl.heartbeat() status_ppl.heartbeat()
return key return key
with self.gen_cursor() as cursor: with gen_cursor() as cursor:
handle_list = [beat(key) for key, data in cursor] handle_list = [beat(key) for key, data in cursor]
status_ppl.end() status_ppl.end()
self.__displayed = 0
status.heartbeat() status.heartbeat()
if dfilter: if dfilter:
status_filter = progressdlg.LongOpStatus(msg=_("Applying filter"), 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) pmon.add_op(status_filter)
handle_list = dfilter.apply(self.db, handle_list, handle_list = dfilter.apply(self.db, handle_list,
cb_progress=status_filter.heartbeat) cb_progress=status_filter.heartbeat)
@ -538,9 +581,9 @@ class TreeBaseModel(gtk.GenericTreeModel):
pmon.add_op(status_col) pmon.add_op(status_col)
for handle in handle_list: for handle in handle_list:
status_col.heartbeat() status_col.heartbeat()
data = self.map(handle) data = data_map(handle)
if not handle in skip: if not handle in skip:
self.add_row(handle, data) add_func(handle, data)
self.__displayed += 1 self.__displayed += 1
status_col.end() status_col.end()
status.end() status.end()