0006849: citationtreeview with search bar only searches in sources, not citation data

0006848: citationtreeview corrupts when search bar open and edit occurs
0006829: Searching into source/citation selector disallows to select all related citations, only matching rows

by fixing treebasemodel so it properly deals with secondary objects, and also citationtreemodel so it adds secondary odes even when the parent is not present.

svn: r22941
This commit is contained in:
Tim G L Lyons 2013-08-29 18:06:43 +00:00
parent 9487b3c1b7
commit 3d30663a5c
4 changed files with 86 additions and 34 deletions

View File

@ -64,7 +64,7 @@ class SelectCitation(BaseSelector):
def get_column_titles(self): def get_column_titles(self):
return [ return [
(_('Page'), 350, BaseSelector.TEXT, 0), (_('Source: Title or Citation: Volume/Page'), 350, BaseSelector.TEXT, 0),
(_('ID'), 75, BaseSelector.TEXT, 1) (_('ID'), 75, BaseSelector.TEXT, 1)
] ]

View File

@ -188,8 +188,15 @@ class CitationTreeModel(CitationBaseModel, TreeBaseModel):
data The object data. data The object data.
""" """
sort_key = self.sort_func2(data) sort_key = self.sort_func2(data)
# If the source for this citation already exists (in the tree model) we
# add the citation as a child of the source. Otherwise (if a search has
# found the citation) we add the citation as a child of nothing.
if self._get_node(data[5]): if self._get_node(data[5]):
# parent child sortkey handle
self.add_node(data[5], handle, sort_key, handle, secondary=True) self.add_node(data[5], handle, sort_key, handle, secondary=True)
else:
# parent child sortkey handle
self.add_node(None, handle, sort_key, handle, secondary=True)
def on_get_n_columns(self): def on_get_n_columns(self):
return len(self.fmap)+1 return len(self.fmap)+1

View File

@ -342,7 +342,10 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel):
self.__displayed = 0 self.__displayed = 0
self.set_search(search) self.set_search(search)
self.rebuild_data(self.current_filter, skip) if self.has_secondary:
self.rebuild_data(self.current_filter, self.current_filter2, skip)
else:
self.rebuild_data(self.current_filter, skip=skip)
_LOG.debug(self.__class__.__name__ + ' __init__ ' + _LOG.debug(self.__class__.__name__ + ' __init__ ' +
str(time.clock() - cput) + ' sec') str(time.clock() - cput) + ' sec')
@ -362,7 +365,9 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel):
self.rebuild_data = None self.rebuild_data = None
self._build_data = None self._build_data = None
self.search = None self.search = None
self.search2 = None
self.current_filter = None self.current_filter = None
self.current_filter2 = None
self.clear_cache() self.clear_cache()
self.lru_data = None self.lru_data = None
@ -447,31 +452,56 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel):
if search[0] == 1: # Filter if search[0] == 1: # Filter
#following is None if no data given in filter sidebar #following is None if no data given in filter sidebar
self.search = search[1] self.search = search[1]
if self.has_secondary:
self.search2 = search[1]
_LOG.debug("search2 filter %s %s" % (search[0], search[1]))
self._build_data = self._rebuild_filter self._build_data = self._rebuild_filter
elif search[0] == 0: # Search elif search[0] == 0: # Search
if search[1]: if search[1]:
# we have search[1] = (index, text_unicode, inversion) # we have search[1] = (index, text_unicode, inversion)
col, text, inv = search[1] col, text, inv = search[1]
func = lambda x: self._get_value(x, col, store_cache=False) or "" func = lambda x: self._get_value(x, col, secondary=False) or u""
if self.has_secondary:
func2 = lambda x: self._get_value(x, col, secondary=True) or u""
if search[2]: if search[2]:
self.search = ExactSearchFilter(func, text, inv) self.search = ExactSearchFilter(func, text, inv)
if self.has_secondary:
self.search2 = ExactSearchFilter(func2, text, inv)
else: else:
self.search = SearchFilter(func, text, inv) self.search = SearchFilter(func, text, inv)
if self.has_secondary:
self.search2 = SearchFilter(func2, text, inv)
else: else:
self.search = None self.search = None
if self.has_secondary:
self.search2 = None
_LOG.debug("search2 search with no data")
self._build_data = self._rebuild_search self._build_data = self._rebuild_search
else: # Fast filter else: # Fast filter
self.search = search[1] self.search = search[1]
if self.has_secondary:
self.search2 = search[2]
_LOG.debug("search2 fast filter")
self._build_data = self._rebuild_search self._build_data = self._rebuild_search
else: else:
self.search = None self.search = None
if self.has_secondary:
self.search2 = search[2]
_LOG.debug("search2 no search parameter")
self._build_data = self._rebuild_search self._build_data = self._rebuild_search
self.current_filter = self.search self.current_filter = self.search
if self.has_secondary:
self.current_filter2 = self.search2
def rebuild_data(self, data_filter=None, skip=[]): def rebuild_data(self, data_filter=None, data_filter2=None, skip=[]):
""" """
Rebuild the data map. Rebuild the data map.
When called externally (from listview), data_filter and data_filter2
should be None; set_search will already have been called to establish
the filter functions. When called internally (from __init__) both
data_filter and data_filter2 will have been set from set_search
""" """
cput = time.clock() cput = time.clock()
self.clear_cache() self.clear_cache()
@ -481,16 +511,21 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel):
return return
self.clear() self.clear()
self._build_data(self.current_filter, skip) if self.has_secondary:
self._build_data(self.current_filter, self.current_filter2, skip)
else:
self._build_data(self.current_filter, None, skip)
self._in_build = False self._in_build = False
self.current_filter = data_filter self.current_filter = data_filter
if self.has_secondary:
self.current_filter2 = data_filter2
_LOG.debug(self.__class__.__name__ + ' rebuild_data ' + _LOG.debug(self.__class__.__name__ + ' rebuild_data ' +
str(time.clock() - cput) + ' sec') str(time.clock() - cput) + ' sec')
def _rebuild_search(self, dfilter, skip): def _rebuild_search(self, dfilter, dfilter2, skip):
""" """
Rebuild the data map where a search condition is applied. Rebuild the data map where a search condition is applied.
""" """
@ -498,12 +533,14 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel):
self.__displayed = 0 self.__displayed = 0
items = self.number_items() items = self.number_items()
_LOG.debug("rebuild search primary")
self.__rebuild_search(dfilter, skip, items, self.__rebuild_search(dfilter, skip, items,
self.gen_cursor, self.add_row) self.gen_cursor, self.add_row)
if self.has_secondary: if self.has_secondary:
_LOG.debug("rebuild search secondary")
items = self.number_items2() items = self.number_items2()
self.__rebuild_search(dfilter, skip, items, self.__rebuild_search(dfilter2, skip, items,
self.gen_cursor2, self.add_row2) self.gen_cursor2, self.add_row2)
def __rebuild_search(self, dfilter, skip, items, gen_cursor, add_func): def __rebuild_search(self, dfilter, skip, items, gen_cursor, add_func):
@ -528,12 +565,13 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel):
self.__total += 1 self.__total += 1
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))):
_LOG.debug(" add %s %s" % (handle, data))
self.__displayed += 1 self.__displayed += 1
add_func(handle, data) add_func(handle, data)
if not status.was_cancelled(): if not status.was_cancelled():
status.end() status.end()
def _rebuild_filter(self, dfilter, skip): def _rebuild_filter(self, dfilter, dfilter2, skip):
""" """
Rebuild the data map where a filter is applied. Rebuild the data map where a filter is applied.
""" """
@ -541,11 +579,13 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel):
self.__displayed = 0 self.__displayed = 0
items = self.number_items() items = self.number_items()
_LOG.debug("rebuild filter primary")
self.__rebuild_filter(dfilter, skip, items, self.__rebuild_filter(dfilter, skip, items,
self.gen_cursor, self.map, self.add_row) self.gen_cursor, self.map, self.add_row)
if self.has_secondary: if self.has_secondary:
items = self.number_items2() items = self.number_items2()
self.__rebuild_filter(dfilter, skip, items, _LOG.debug("rebuild filter secondary")
self.__rebuild_filter(dfilter2, skip, items,
self.gen_cursor2, self.map2, self.add_row2) self.gen_cursor2, self.map2, self.add_row2)
def __rebuild_filter(self, dfilter, skip, items, gen_cursor, data_map, def __rebuild_filter(self, dfilter, skip, items, gen_cursor, data_map,
@ -578,11 +618,14 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel):
status.heartbeat() status.heartbeat()
if dfilter: if dfilter:
_LOG.debug("rebuild filter %s" % dfilter)
_LOG.debug(" list before filter %s" % handle_list)
status_filter = progressdlg.LongOpStatus(msg=_("Applying filter"), status_filter = progressdlg.LongOpStatus(msg=_("Applying filter"),
total_steps=items, interval=items//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)
_LOG.debug(" list after filter %s" % handle_list)
status_filter.end() status_filter.end()
status.heartbeat() status.heartbeat()
@ -743,13 +786,14 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel):
if self._get_node(handle) is not None: if self._get_node(handle) is not None:
return # row already exists return # row already exists
cput = time.clock() cput = time.clock()
if not self.search or \ data = self.map(handle)
(self.search and self.search.match(handle, self.db)): if data:
#row needs to be added to the model if not self.search or \
data = self.map(handle) (self.search and self.search.match(handle, self.db)):
if data:
self.add_row(handle, data) self.add_row(handle, data)
else: else:
if not self.search2 or \
(self.search2 and self.search2.match(handle, self.db)):
self.add_row2(handle, self.map2(handle)) self.add_row2(handle, self.map2(handle))
_LOG.debug(self.__class__.__name__ + ' add_row_by_handle ' + _LOG.debug(self.__class__.__name__ + ' add_row_by_handle ' +
@ -916,6 +960,9 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel):
""" """
Returns the contents of a given column of a gramps object Returns the contents of a given column of a gramps object
""" """
if secondary is None:
raise NotImplementedError
if handle in self.lru_data: if handle in self.lru_data:
data = self.lru_data[handle] data = self.lru_data[handle]
else: else:
@ -923,16 +970,20 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel):
data = self.map(handle) data = self.map(handle)
else: else:
data = self.map2(handle) data = self.map2(handle)
if not self._in_build and store_cache: if not self._in_build:
self.lru_data[handle] = data self.lru_data[handle] = data
try: if not secondary:
if not secondary: # None is used to indicate this column has no data
return self.fmap[col](data) if self.fmap[col] is None:
else: return None
return self.fmap2[col](data) value = self.fmap[col](data)
except: else:
return '' if self.fmap2[col] is None:
return ''
value = self.fmap2[col](data)
return value
def do_get_iter(self, path): def do_get_iter(self, path):
""" """

View File

@ -92,7 +92,7 @@ class CitationTreeView(ListView):
COL_SRC_PINFO = 9 COL_SRC_PINFO = 9
# column definitions # column definitions
COLUMNS = [ COLUMNS = [
(_('Title or Page'), TEXT, None), (_('Source: Title or Citation: Volume/Page'), TEXT, None),
(_('ID'), TEXT, None), (_('ID'), TEXT, None),
(_('Date'), MARKUP, None), (_('Date'), MARKUP, None),
(_('Confidence'), TEXT, None), (_('Confidence'), TEXT, None),
@ -170,17 +170,11 @@ class CitationTreeView(ListView):
def setup_filter(self): def setup_filter(self):
""" """
Override the setup of the default Search Bar in listview, so that only Override the setup of the default Search Bar in listview, so that only
the searchable source fields are shown. This includes renaming the the searchable source fields are shown.
'Title or Page' search to 'Title'
""" """
def name(i):
if i == 0:
return _('Title')
else:
return self.COLUMNS[i][0]
self.search_bar.setup_filter( self.search_bar.setup_filter(
[(name(pair[1]), pair[1], pair[1] in self.exact_search()) [(self.COLUMNS[pair[1]][0], pair[1], pair[1] in self.exact_search())
for pair in self.column_order() if pair[0] and for pair in self.column_order() if pair[0] and
pair[1] in self.COLUMN_FILTERABLE]) pair[1] in self.COLUMN_FILTERABLE])