diff --git a/src/DataViews/EventView.py b/src/DataViews/EventView.py index 36927a9be..b60dc95e8 100644 --- a/src/DataViews/EventView.py +++ b/src/DataViews/EventView.py @@ -109,6 +109,9 @@ class EventView(PageView.ListView): Config.client.notify_add("/apps/gramps/interface/filter", self.filter_toggle) + def column_ord_setfunc(self, clist): + self.dbstate.db.set_event_column_order(clist) + def get_bookmarks(self): """ Return the bookmark object @@ -209,10 +212,6 @@ class EventView(PageView.ListView): EventView.COLUMN_NAMES, self.set_column_order) - def set_column_order(self, clist): - self.dbstate.db.set_event_column_order(clist) - self.build_columns() - def add(self, obj): try: EditEvent(self.dbstate, self.uistate, [], gen.lib.Event()) diff --git a/src/DataViews/FamilyList.py b/src/DataViews/FamilyList.py index af4d3195d..1416abd96 100644 --- a/src/DataViews/FamilyList.py +++ b/src/DataViews/FamilyList.py @@ -93,10 +93,13 @@ class FamilyListView(PageView.ListView): DisplayModels.FamilyModel, signal_map, dbstate.db.get_family_bookmarks(), Bookmarks.FamilyBookmarks, filter_class=FamilySidebarFilter) - + Config.client.notify_add("/apps/gramps/interface/filter", self.filter_toggle) + def column_ord_setfunc(self, clist): + self.dbstate.db.self.dbstate.db.set_family_list_column_order(clist) + def column_order(self): return self.dbstate.db.get_family_list_column_order() @@ -110,10 +113,6 @@ class FamilyListView(PageView.ListView): FamilyListView.COLUMN_NAMES, self.set_column_order) - def set_column_order(self, clist): - self.dbstate.db.set_family_list_column_order(clist) - self.build_columns() - def get_stock(self): return 'gramps-family' diff --git a/src/DataViews/MediaView.py b/src/DataViews/MediaView.py index b1a57ff83..7f4f84b62 100644 --- a/src/DataViews/MediaView.py +++ b/src/DataViews/MediaView.py @@ -118,6 +118,9 @@ class MediaView(PageView.ListView): Config.client.notify_add("/apps/gramps/interface/filter", self.filter_toggle) + def column_ord_setfunc(self, clist): + self.dbstate.db.set_media_column_order(clist) + def _set_dnd(self): """ Set up drag-n-drop. The source and destionation are set by calling .target() @@ -242,13 +245,6 @@ class MediaView(PageView.ListView): MediaView.COLUMN_NAMES, self.set_column_order) - def set_column_order(self, clist): - """ - Saves the column order to the database - """ - self.dbstate.db.set_media_column_order(clist) - self.build_columns() - def column_order(self): """ Get the column order from the database diff --git a/src/DataViews/NoteView.py b/src/DataViews/NoteView.py index 295a225d5..b67470e72 100644 --- a/src/DataViews/NoteView.py +++ b/src/DataViews/NoteView.py @@ -100,6 +100,9 @@ class NoteView(PageView.ListView): Config.client.notify_add("/apps/gramps/interface/filter", self.filter_toggle) + def column_ord_setfunc(self, clist): + self.dbstate.db.self.dbstate.db.set_note_column_order(clist) + def get_bookmarks(self): """ Return the bookmark object @@ -190,10 +193,6 @@ class NoteView(PageView.ListView): NoteView.COLUMN_NAMES, self.set_column_order) - def set_column_order(self, clist): - self.dbstate.db.set_note_column_order(clist) - self.build_columns() - def add(self, obj): try: EditNote(self.dbstate, self.uistate, [], Note()) diff --git a/src/DataViews/PlaceView.py b/src/DataViews/PlaceView.py index bbff7dd35..0eddbf96a 100644 --- a/src/DataViews/PlaceView.py +++ b/src/DataViews/PlaceView.py @@ -120,6 +120,9 @@ class PlaceView(PageView.ListView): Config.client.notify_add("/apps/gramps/interface/filter", self.filter_toggle) + def column_ord_setfunc(self, clist): + self.dbstate.db.set_place_column_order(clist) + def get_bookmarks(self): return self.dbstate.db.get_place_bookmarks() @@ -261,10 +264,6 @@ class PlaceView(PageView.ListView): PlaceView.COLUMN_NAMES, self.set_column_order) - def set_column_order(self, clist): - self.dbstate.db.set_place_column_order(clist) - self.build_columns() - def column_order(self): return self.dbstate.db.get_place_column_order() diff --git a/src/DataViews/RepositoryView.py b/src/DataViews/RepositoryView.py index 008064667..d1b9b275a 100644 --- a/src/DataViews/RepositoryView.py +++ b/src/DataViews/RepositoryView.py @@ -110,6 +110,9 @@ class RepositoryView(PageView.ListView): Config.client.notify_add("/apps/gramps/interface/filter", self.filter_toggle) + def column_ord_setfunc(self, clist): + self.dbstate.db.self.dbstate.db.set_repository_column_order(clist) + def get_bookmarks(self): return self.dbstate.db.get_repo_bookmarks() @@ -137,10 +140,6 @@ class RepositoryView(PageView.ListView): RepositoryView.COLUMN_NAMES, self.set_column_order) - def set_column_order(self, clist): - self.dbstate.db.set_repository_column_order(clist) - self.build_columns() - def column_order(self): return self.dbstate.db.get_repository_column_order() diff --git a/src/DataViews/SourceView.py b/src/DataViews/SourceView.py index cbf552a5a..8355adffd 100644 --- a/src/DataViews/SourceView.py +++ b/src/DataViews/SourceView.py @@ -102,6 +102,9 @@ class SourceView(PageView.ListView): Config.client.notify_add("/apps/gramps/interface/filter", self.filter_toggle) + def column_ord_setfunc(self, clist): + self.dbstate.db.set_source_column_order(clist) + def get_bookmarks(self): return self.dbstate.db.get_source_bookmarks() @@ -127,10 +130,6 @@ class SourceView(PageView.ListView): SourceView.COLUMN_NAMES, self.set_column_order) - def set_column_order(self, clist): - self.dbstate.db.set_source_column_order(clist) - self.build_columns() - def column_order(self): return self.dbstate.db.get_source_column_order() diff --git a/src/Filters/_GenericFilter.py b/src/Filters/_GenericFilter.py index 6e6b484f4..bc22e4af7 100644 --- a/src/Filters/_GenericFilter.py +++ b/src/Filters/_GenericFilter.py @@ -112,7 +112,7 @@ class GenericFilter(object): def find_from_handle(self, db, handle): return db.get_person_from_handle(handle) - def check_func(self, db, id_list, task, progress=None): + def check_func(self, db, id_list, task, progress=None, tupleind=None): final_list = [] if id_list is None: @@ -125,15 +125,19 @@ class GenericFilter(object): if task(db, person) != self.invert: final_list.append(handle) else: - for handle in id_list: + for data in id_list: + if tupleind is None: + handle = data + else: + handle = data[tupleind] person = self.find_from_handle(db, handle) if progress: progress.step() if task(db, person) != self.invert: - final_list.append(handle) + final_list.append(data) return final_list - def check_and(self, db, id_list, progress=None): + def check_and(self, db, id_list, progress=None, tupleind=None): final_list = [] flist = self.flist @@ -148,23 +152,30 @@ class GenericFilter(object): if val != self.invert: final_list.append(handle) else: - for handle in id_list: + for data in id_list: + if tupleind is None: + handle = data + else: + handle = data[tupleind] person = self.find_from_handle(db, handle) if progress: progress.step() val = all(rule.apply(db, person) for rule in flist) if val != self.invert: - final_list.append(handle) + final_list.append(data) return final_list - def check_or(self, db, id_list, progress=None): - return self.check_func(db, id_list, self.or_test, progress) + def check_or(self, db, id_list, progress=None, tupleind=None): + return self.check_func(db, id_list, self.or_test, progress, + tupleind) - def check_one(self, db, id_list, progress=None): - return self.check_func(db, id_list, self.one_test, progress) + def check_one(self, db, id_list, progress=None, tupleind=None): + return self.check_func(db, id_list, self.one_test, progress, + tupleind) - def check_xor(self, db, id_list, progress=None): - return self.check_func(db, id_list, self.xor_test, progress) + def check_xor(self, db, id_list, progress=None, tupleind=None): + return self.check_func(db, id_list, self.xor_test, progress, + tupleind) def xor_test(self, db, person): test = False @@ -199,11 +210,28 @@ class GenericFilter(object): # progress is optional. If present it must be an instance of # gui.utils.ProgressMeter - def apply(self, db, id_list=None, progress=None): + def apply(self, db, id_list=None, progress=None, tupleind=None): + """ + Apply the filter using db. + If id_list given, the handles in id_list are used. If not given + a database cursor will be used over all entries. + + If progress given, it will be used to indicate progress of the + Filtering + + If typleind is given, id_list is supposed to consist of a list of + tuples, with the handle being index tupleind. So + handle_0 = id_list[0][tupleind] + + :Returns: if id_list given, it is returned with the items that + do not match the filter, filtered out. + if id_list not given, all items in the database that + match the filter are returned as a list of handles + """ m = self.get_check_func() for rule in self.flist: rule.prepare(db) - res = m(db, id_list, progress) + res = m(db, id_list, progress, tupleind) for rule in self.flist: rule.reset() return res diff --git a/src/PageView.py b/src/PageView.py index d084b7098..af2e40eca 100644 --- a/src/PageView.py +++ b/src/PageView.py @@ -640,10 +640,12 @@ class ListView(BookMarkView): self.renderer = gtk.CellRendererText() self.renderer.set_property('ellipsize', pango.ELLIPSIZE_END) self.sort_col = 0 + self.sort_order = gtk.SORT_ASCENDING self.columns = [] self.colinfo = columns self.handle_col = handle_col self.make_model = make_model + self.model = None self.signal_map = signal_map self.multiple_selection = multiple self.generic_filter = None @@ -734,7 +736,31 @@ class ListView(BookMarkView): return True def column_order(self): - assert False + """ + Must be set by children. The method that obtains the column order + to be used. Format: see ColumnOrder. + """ + raise NotImplementedError + + def column_ord_setfunc(self, clist): + """ + Must be set by children. The method that stores the column order + given by clist (result of ColumnOrder class). + """ + raise NotImplementedError + + def set_column_order(self, clist): + """ + change the order of the columns to that given in clist + """ + self.column_ord_setfunc(clist) + #now we need to rebuild the model so it contains correct column info + self.dirty = True + #make sure we sort on first column. We have no idea where the + # column that was sorted on before is situated now. + self.sort_col = 0 + self.sort_order = gtk.SORT_ASCENDING + self.build_tree() def build_widget(self): """ @@ -838,6 +864,12 @@ class ListView(BookMarkView): # disable the inactive flag self.inactive = False + def __display_column_sort(self): + for i in xrange(len(self.columns)): + enable_sort_flag = (i==self.sort_col) + self.columns[i].set_sort_indicator(enable_sort_flag) + self.columns[self.sort_col].set_sort_order(self.sort_order) + def column_clicked(self, obj, data): cput = time.clock() same_col = False @@ -852,6 +884,7 @@ class ListView(BookMarkView): order = gtk.SORT_DESCENDING self.sort_col = data + self.sort_order = order handle = self.first_selected() if Config.get(Config.FILTER): @@ -862,18 +895,16 @@ class ListView(BookMarkView): if same_col: self.model.reverse_order() else: - self.model = self.make_model(self.dbstate.db, self.sort_col, order, - search=search, - sort_map=self.column_order()) + self.model = self.make_model(self.dbstate.db, self.sort_col, + self.sort_order, + search=search, + sort_map=self.column_order()) self.list.set_model(self.model) + self.__display_column_sort() if handle: self.goto_handle(handle) - for i in xrange(len(self.columns)): - enable_sort_flag = (i==self.sort_col) - self.columns[i].set_sort_indicator(enable_sort_flag) - self.columns[self.sort_col].set_sort_order(order) # set the search column to be the sorted column search_col = self.column_order()[data][1] @@ -915,18 +946,29 @@ class ListView(BookMarkView): else: filter_info = (False, self.search_bar.get_value()) - self.model = self.make_model(self.dbstate.db, self.sort_col, - search=filter_info) - self.list.set_model(self.model) + if self.dirty or self.model is None \ + or not self.model.node_map.full_srtkey_hndl_map(): + self.model = self.make_model(self.dbstate.db, self.sort_col, + search=filter_info, + sort_map=self.column_order()) + else: + #the entire data to show is already in memory. + #run only the part that determines what to show + self.list.set_model(None) + self.model.set_search(filter_info) + self.model.rebuild_data() + self.build_columns() + self.list.set_model(self.model) + self.__display_column_sort() if const.USE_TIPS and self.model.tooltip_column is not None: self.tooltips = TreeTips.TreeTips( self.list, self.model.tooltip_column, True) self.dirty = False self.uistate.show_filter_results(self.dbstate, - self.model.displayed, - self.model.total) + self.model.displayed(), + self.model.total()) _LOG.debug(self.__class__.__name__ + ' build_tree ' + str(time.clock() - cput) + ' sec') @@ -936,6 +978,7 @@ class ListView(BookMarkView): def object_build(self): """callback, for if tree must be rebuilt and bookmarks redrawn """ + self.dirty = True if self.active: self.bookmarks.redraw() self.build_tree() @@ -966,6 +1009,8 @@ class ListView(BookMarkView): db.connect(sig, self.signal_map[sig]) self.bookmarks.update_bookmarks(self.get_bookmarks()) if self.active: + #force rebuild of the model on build of tree + self.dirty = True self.build_tree() self.bookmarks.redraw() else: @@ -978,6 +1023,9 @@ class ListView(BookMarkView): self.model.add_row_by_handle(handle) _LOG.debug(' ' + self.__class__.__name__ + ' row_add ' + str(time.clock() - cput) + ' sec') + self.uistate.show_filter_results(self.dbstate, + self.model.displayed(), + self.model.total()) else: self.dirty = True @@ -1000,6 +1048,9 @@ class ListView(BookMarkView): self.model.delete_row_by_handle(handle) _LOG.debug(' ' + self.__class__.__name__ + ' row_delete ' + str(time.clock() - cput) + ' sec') + self.uistate.show_filter_results(self.dbstate, + self.model.displayed(), + self.model.total()) else: self.dirty = True @@ -1086,8 +1137,8 @@ class ListView(BookMarkView): def change_page(self): if self.model: self.uistate.show_filter_results(self.dbstate, - self.model.displayed, - self.model.total) + self.model.displayed(), + self.model.total()) self.edit_action.set_sensitive(not self.dbstate.db.readonly) def key_delete(self): diff --git a/src/gui/views/treemodels/flatbasemodel.py b/src/gui/views/treemodels/flatbasemodel.py index 68dc82406..90de9bed5 100644 --- a/src/gui/views/treemodels/flatbasemodel.py +++ b/src/gui/views/treemodels/flatbasemodel.py @@ -56,6 +56,8 @@ from __future__ import with_statement import locale import logging import bisect +import time +import copy _LOG = logging.getLogger(".gui.basetreemodel") @@ -73,7 +75,6 @@ import gtk #------------------------------------------------------------------------- from Filters import SearchFilter import Config -import time #------------------------------------------------------------------------- # @@ -98,7 +99,8 @@ class FlatNodeMap(object): ascending, but will begin at back of list if view shows the entries in reverse. * index2hndl : list of (srtkey, hndl) tuples. The index gives the - (srtkey, hndl) it belongs to + (srtkey, hndl) it belongs to. + This normally is only a part of all possible data * hndl2index : dictionary of *hndl: index* values The implementation provides a list of (srtkey, hndl) of which the index is @@ -114,25 +116,55 @@ class FlatNodeMap(object): Create a new instance. """ self._index2hndl = [] + self._fullhndl = self._index2hndl + self._identical = True self._hndl2index = {} self._reverse = False self.__corr = (0, 1) - def set_path_map(self, index2hndllist, reverse=False): + def set_path_map(self, index2hndllist, fullhndllist, identical=True, + reverse=False): """ This is the core method to set up the FlatNodeMap Input is a list of (srtkey, handle), of which the index is the path Calling this method sets the index2hndllist, and creates the hndl2index - map. + map. + fullhndllist is the entire list of (srtkey, handle) that is possible, + normally index2hndllist is only part of this list as determined by + filtering. To avoid memory, if both lists are the same, pass only one + list twice and set identical to True. + Reverse sets up how the path is determined from the index. If True the + first index is the last path :param index2hndllist: the ascending sorted (sortkey, handle) values - as they will appear in the flat treeview. + as they will appear in the flat treeview. This often is + a subset of all possible data :type index2hndllist: a list of (sortkey, handle) tuples + :param fullhndllist: the list of all possilbe ascending sorted + (sortkey, handle) values as they will appear in the flat + treeview if all data is shown. + :type fullhndllist: a list of (sortkey, handle) tuples + :param identical: identify if index2hndllist and fullhndllist are the + same list, so only one is kept in memory. + :type identical: bool """ self._index2hndl = index2hndllist self._hndl2index = {} + self._identical = identical + if identical: + self._fullhndl = self._index2hndl + else: + self._fullhndl = fullhndllist self._reverse = reverse self.reverse_order() + + def full_srtkey_hndl_map(self): + """ + The list of all possible (sortkey, handle) tuples. + This is stored in FlatNodeMap so that it would not be needed to + reiterate over the database to obtain all posibilities. + """ + return self._fullhndl def reverse_order(self): """ @@ -177,6 +209,8 @@ class FlatNodeMap(object): """ self._index2hndl = [] self._hndl2index = {} + self._fullhndl = self._index2hndl + self._identical = True def get_path(self, handle): """ @@ -241,7 +275,14 @@ class FlatNodeMap(object): """ return len(self._index2hndl) - def insert(self, srtkey_hndl): + def max_rows(self): + """ + Return maximum number of entries that might be present in the + map + """ + return len(self._fullhndl) + + def insert(self, srtkey_hndl, allkeyonly=False): """ Insert a node. Given is a tuple (sortkey, handle), and this is added in the correct place, while the hndl2index map is updated. @@ -250,8 +291,13 @@ class FlatNodeMap(object): :param srtkey_hndl: the (sortkey, handle) tuple that must be inserted :Returns: path of the row inserted in the treeview - :Returns type: integer + :Returns type: integer or None """ + if not self._identical: + bisect.insort_left(self._fullhndl, srtkey_hndl) + if allkeyonly: + #key is not part of the view + return None insert_pos = bisect.bisect_left(self._index2hndl, srtkey_hndl) self._index2hndl.insert(insert_pos, srtkey_hndl) #make sure the index map is updated @@ -264,19 +310,34 @@ class FlatNodeMap(object): self.__corr = (len(self._index2hndl) - 1, -1) return self.real_path(insert_pos) - def delete(self, handle): + def delete(self, srtkey_hndl): """ - Delete the row with handle. + Delete the row with the given (sortkey, handle). This then rebuilds the hndl2index, subtracting one from each item greater than the deleted index. + path of deleted row is returned + If handle is not present, None is returned - :param handle: the handle that must be removed - :type handle: an object handle + :param srtkey_hndl: the (sortkey, handle) tuple that must be inserted :Returns: path of the row deleted from the treeview - :Returns type: integer + :Returns type: integer or None """ - index = self._hndl2index[handle] + #remove it from the full list first + if not self._identical: + del_pos = bisect.bisect_left(self._fullhndl, srtkey_hndl) + #check that indeed this is correct: + if not self._fullhndl[del_pos][1] == srtkey_hndl[1]: + raise KeyError, 'Handle %s not in list of all handles' % \ + srtkey_hndl[1] + del self._fullhndl[del_pos] + #now remove it from the index maps + handle = srtkey_hndl[1] + try: + index = self._hndl2index[handle] + except KeyError: + # key not present in the treeview + return None del self._index2hndl[index] del self._hndl2index[handle] #update self.__corr so it remains correct @@ -318,29 +379,8 @@ class FlatBaseModel(gtk.GenericTreeModel): self.sort_col = scol self.skip = skip - self.total = 0 - self.displayed = 0 - self.node_map = FlatNodeMap() - - if search: - if search[0]: - self.search = search[1] - self.rebuild_data = self._rebuild_filter - else: - if search[1]: - # we have search[1] = (index, text_unicode, inversion) - col = search[1][0] - text = search[1][1] - inv = search[1][2] - func = lambda x: self.on_get_value(x, col) or u"" - self.search = SearchFilter(func, text, inv) - else: - self.search = None - self.rebuild_data = self._rebuild_search - else: - self.search = None - self.rebuild_data = self._rebuild_search + self.set_search(search) self._reverse = (order == gtk.SORT_DESCENDING) self.tooltip_column = tooltip_column @@ -359,6 +399,35 @@ class FlatBaseModel(gtk.GenericTreeModel): _LOG.debug(self.__class__.__name__ + ' __init__ ' + str(time.clock() - cput) + ' sec') + def set_search(self, search): + """ + Change the search function that filters the data in the model. + When this method is called, make sure: + # you call self.rebuild_data() to recalculate what should be seen + in the model + # you reattach the model to the treeview so that the treeview updates + with the new entries + """ + if search: + if search[0]: + #following is None if no data given in filter sidebar + self.search = search[1] + self.rebuild_data = self._rebuild_filter + else: + if search[1]: + # we have search[1] = (index, text_unicode, inversion) + col = search[1][0] + text = search[1][1] + inv = search[1][2] + func = lambda x: self.on_get_value(x, col) or u"" + self.search = SearchFilter(func, text, inv) + else: + self.search = None + self.rebuild_data = self._rebuild_search + else: + self.search = None + self.rebuild_data = self._rebuild_search + def __update_todo(self, client, cnxn_id, entry, data): """ Callback if preferences todo color changes @@ -377,11 +446,17 @@ class FlatBaseModel(gtk.GenericTreeModel): """ self.complete_color = Config.get(Config.COMPLETE_COLOR) - def set_sort_column(self, col): + def total(self): """ - set sort column to column with index col + Total number of items that maximally can be shown """ - self.sort_func = self.smap[col] + return self.node_map.max_rows() + + def displayed(self): + """ + Number of items that are currently displayed + """ + return len(self.node_map) def reverse_order(self): """ @@ -397,7 +472,6 @@ class FlatBaseModel(gtk.GenericTreeModel): This list is sorted ascending (via localized string sort) """ sort_data = [] - self.total = 0 with self.gen_cursor() as cursor: # use cursor as a context manager #loop over database and store the sort field, and the handle @@ -411,45 +485,60 @@ class FlatBaseModel(gtk.GenericTreeModel): #bisect.insort_left(sort_data, # (locale.strxfrm(self.sort_func(data)), key)) sort_data.sort() - self.total = len(sort_data) return sort_data def _rebuild_search(self, ignore=None): """ function called when view must be build, given a search text in the top search bar """ - self.total = 0 if self.db.is_open(): + allkeys = self.node_map.full_srtkey_hndl_map() + if not allkeys: + allkeys = self.sort_keys() if self.search and self.search.text: - dlist = [h for h in self.sort_keys()\ - if self.search.match(h[1],self.db) and \ + dlist = [h for h in allkeys \ + if self.search.match(h[1], self.db) and \ h[1] not in self.skip and h[1] != ignore] + ident = False + elif ignore is None and not self.skip: + #nothing to remove from the keys present + ident = True + dlist = allkeys else: - dlist = [h for h in self.sort_keys() \ + ident = False + dlist = [h for h in allkeys \ if h[1] not in self.skip and h[1] != ignore] - self.displayed = len(dlist) - self.node_map.set_path_map(dlist, reverse=self._reverse) + self.node_map.set_path_map(dlist, allkeys, identical=ident, + reverse=self._reverse) else: - self.displayed = 0 self.node_map.clear_map() def _rebuild_filter(self, ignore=None): """ function called when view must be build, given filter options in the filter sidebar """ - self.total = 0 if self.db.is_open(): + allkeys = self.node_map.full_srtkey_hndl_map() + if not allkeys: + allkeys = self.sort_keys() if self.search: - dlist = self.search.apply(self.db, - [ k for k in self.sort_keys()\ - if k[1] != ignore]) + ident = False + if ignore is None: + tmp = copy.copy(allkeys) + dlist = self.search.apply(self.db, tmp, tupleind=1) + else: + dlist = self.search.apply(self.db, + [ k for k in allkeys if k[1] != ignore], + tupleind=1) + elif ignore is None : + ident = True + dlist = allkeys else: - dlist = [ k for k in self.sort_keys() \ - if k[1] != ignore ] - self.displayed = len(dlist) - self.node_map.set_path_map(dlist, reverse=self._reverse) + ident = False + dlist = [ k for k in allkeys if k[1] != ignore ] + self.node_map.set_path_map(dlist, allkeys, identical=ident, + reverse=self._reverse) else: - self.displayed = 0 self.node_map.clear_map() def add_row_by_handle(self, handle): @@ -457,23 +546,29 @@ class FlatBaseModel(gtk.GenericTreeModel): Add a row. This is called after object with handle is created. Row is only added if search/filter data is such that it must be shown """ + data = self.map(handle) + insert_val = (locale.strxfrm(self.sort_func(data)), handle) if not self.search or \ (self.search and self.search.match(handle, self.db)): #row needs to be added to the model - data = self.map(handle) - insert_val = (locale.strxfrm(self.sort_func(data)), handle) insert_path = self.node_map.insert(insert_val) if insert_path is not None: node = self.get_iter(insert_path) self.row_inserted(insert_path, node) + else: + self.node_map.insert(insert_val, allkeyonly=True) def delete_row_by_handle(self, handle): """ Delete a row, called after the object with handle is deleted """ - delete_path = self.node_map.delete(handle) - self.row_deleted(delete_path) + data = self.map(handle) + delete_val = (locale.strxfrm(self.sort_func(data)), handle) + delete_path = self.node_map.delete(delete_val) + #delete_path is an integer from 0 to n-1 + if delete_path is not None: + self.row_deleted(delete_path) def update_row_by_handle(self, handle): """ @@ -481,8 +576,9 @@ class FlatBaseModel(gtk.GenericTreeModel): """ ## TODO: if sort key changes, this is not updated correctly .... path = self.node_map.get_path(handle) - node = self.get_iter(path) - self.row_changed(path, node) + if path is not None: + node = self.get_iter(path) + self.row_changed(path, node) def on_get_flags(self): """