From 9130c8819e1a318f533183a69c1d29898a0f42f3 Mon Sep 17 00:00:00 2001 From: Martin Hawlisch Date: Sun, 13 Mar 2005 19:49:38 +0000 Subject: [PATCH] * src/GenericFilter.py (Rule,GenericFilter): New methods prepare() and reset(), that are called before/after a filter is applied, to properly support query caches; (IsWitness): new filter; (RelationshipPathBetween,IsDescendantOf,IsLessThanNthGenerationDescendantOf, IsMoreThanNthGenerationDescendantOf,IsChildOfFilterMatch,IsSiblingOfFilterMatch, IsAncestorOf,IsAncestorOfFilterMatch,IsLessThanNthGenerationAncestorOf, IsMoreThanNthGenerationAncestorOf,IsParentOfFilterMatch,HasCommonAncestorWith): use prepare() and reset() to create a proper query cache. Currently the cache was only created once after object creation and never updated. * src/gramps_main.py: Add new filters to the menu. svn: r4171 --- gramps2/ChangeLog | 12 ++ gramps2/src/GenericFilter.py | 335 ++++++++++++++++++++--------------- gramps2/src/gramps_main.py | 5 + 3 files changed, 206 insertions(+), 146 deletions(-) diff --git a/gramps2/ChangeLog b/gramps2/ChangeLog index 8af80ef3f..df6bec983 100644 --- a/gramps2/ChangeLog +++ b/gramps2/ChangeLog @@ -1,3 +1,15 @@ +2005-03-12 Martin Hawlisch + * src/GenericFilter.py (Rule,GenericFilter): New methods prepare() and + reset(), that are called before/after a filter is applied, to properly + support query caches; (IsWitness): new filter; + (RelationshipPathBetween,IsDescendantOf,IsLessThanNthGenerationDescendantOf, + IsMoreThanNthGenerationDescendantOf,IsChildOfFilterMatch,IsSiblingOfFilterMatch, + IsAncestorOf,IsAncestorOfFilterMatch,IsLessThanNthGenerationAncestorOf, + IsMoreThanNthGenerationAncestorOf,IsParentOfFilterMatch,HasCommonAncestorWith): + use prepare() and reset() to create a proper query cache. Currently the + cache was only created once after object creation and never updated. + * src/gramps_main.py: Add new filters to the menu. + 2005-03-11 Alex Roitman * src/RelLib.py (SourceNote): Add methods for detection and removal source references in itself and child objects; (SourceNote,Person, diff --git a/gramps2/src/GenericFilter.py b/gramps2/src/GenericFilter.py index 651509753..03595daf6 100644 --- a/gramps2/src/GenericFilter.py +++ b/gramps2/src/GenericFilter.py @@ -88,6 +88,12 @@ class Rule: def __init__(self,list): self.set_list(list) + + def prepare(self,db): + pass + + def reset(self): + pass def set_list(self,list): assert type(list) == type([]) or list == None, "Argument is not a list" @@ -178,9 +184,14 @@ class RelationshipPathBetween(Rule): labels = [ _('ID:'), _('ID:') ] - def __init__(self,list): - Rule.__init__(self,list) - self.init = 0 + def prepare(self,db): + self.db = db + self.map = {} + root1 = self.list[0] + root2 = self.list[1] + self.init_list(root1,root2) + + def reset(self): self.map = {} def name(self): @@ -205,28 +216,23 @@ class RelationshipPathBetween(Rule): if child_handle: self.desc_list(child_handle,map,0) - def apply_filter(self,rank,person,plist,pmap): + def apply_filter(self,rank,p_id,plist,pmap): + person = self.db.get_person_from_handle(p_id) if person == None: return plist.append(person) pmap[person.get_handle()] = rank - family = person.get_main_parents_family_handle() + fam_id = person.get_main_parents_family_handle() + family = self.db.get_family_from_handle(fam_id) if family != None: self.apply_filter(rank+1,family.get_father_handle(),plist,pmap) self.apply_filter(rank+1,family.get_mother_handle(),plist,pmap) def apply(self,db,p_id): - self.db = db - if not self.init: - self.init = 1 - root1 = self.list[0] - root2 = self.list[1] - self.init_list(root1,root2) return self.map.has_key(p_id) def init_list(self,p1_id,p2_id): - firstMap = {} firstList = [] secondMap = {} @@ -393,22 +399,9 @@ class IsDescendantOf(Rule): labels = [ _('ID:'), _('Inclusive:') ] - def __init__(self,list): - Rule.__init__(self,list) - self.init = 0 + def prepare(self,db): + self.db = db self.map = {} - - def name(self): - return 'Is a descendant of' - - def category(self): - return _('Descendant filters') - - def description(self): - return _('Matches all descendants for the specified person') - - def apply(self,db,p_id): - self.orig_id = p_id self.db = db try: if int(self.list[1]): @@ -422,6 +415,20 @@ class IsDescendantOf(Rule): self.init = 1 root_id = self.list[0] self.init_list(root_id,first) + + def reset(self): + self.map = {} + + def name(self): + return 'Is a descendant of' + + def category(self): + return _('Descendant filters') + + def description(self): + return _('Matches all descendants for the specified person') + + def apply(self,db,p_id): return self.map.has_key(p_id) def init_list(self,p_id,first): @@ -459,22 +466,6 @@ class IsDescendantOfFilterMatch(IsDescendantOf): return _("Matches people that are descendants of someone matched by a filter") def apply(self,db,p_id): - self.orig_id = p_id - self.db = db - try: - if int(self.list[1]): - first = 0 - else: - first = 1 - except IndexError: - first = 1 - - if not self.init: - self.init = 1 - filt = MatchesFilter(self.list) - for person_handle in db.get_person_handles(sort_handles=False): - if filt.apply (db, person_handle): - self.init_list (person_handle, first) return self.map.has_key(p_id) #------------------------------------------------------------------------- @@ -488,9 +479,13 @@ class IsLessThanNthGenerationDescendantOf(Rule): labels = [ _('ID:'), _('Number of generations:') ] - def __init__(self,list): - Rule.__init__(self,list) - self.init = 0 + def prepare(self,db): + self.db = db + self.map = {} + root_id = self.list[0] + self.init_list(root_id,0) + + def reset(self): self.map = {} def name(self): @@ -504,13 +499,6 @@ class IsLessThanNthGenerationDescendantOf(Rule): "not more than N generations away") def apply(self,db,p_id): - self.orig_id = p_id - self.db = db - - if not self.init: - self.init = 1 - root_id = self.list[0] - self.init_list(root_id,0) return self.map.has_key(p_id) def init_list(self,p_id,gen): @@ -536,9 +524,13 @@ class IsMoreThanNthGenerationDescendantOf(Rule): labels = [ _('ID:'), _('Number of generations:') ] - def __init__(self,list): - Rule.__init__(self,list) - self.init = 0 + def prepare(self,db): + self.db = db + self.map = {} + root_id = self.list[0] + self.init_list(root_id,0) + + def reset(self): self.map = {} def name(self): @@ -552,13 +544,6 @@ class IsMoreThanNthGenerationDescendantOf(Rule): return _("Descendant filters") def apply(self,db,p_id): - self.orig_id = p_id - self.db = db - - if not self.init: - self.init = 1 - root_id = self.list[0] - self.init_list(root_id,0) return self.map.has_key(p_id) def init_list(self,p_id,gen): @@ -582,9 +567,15 @@ class IsChildOfFilterMatch(Rule): labels = [ _('Filter name:') ] - def __init__(self,list): - Rule.__init__(self,list) - self.init = 0 + def prepare(self,db): + self.db = db + self.map = {} + filt = MatchesFilter(self.list) + for person_handle in db.get_person_handles(sort_handles=False): + if filt.apply (db, person_handle): + self.init_list (person_handle) + + def reset(self): self.map = {} def name(self): @@ -597,15 +588,6 @@ class IsChildOfFilterMatch(Rule): return _('Family filters') def apply(self,db,p_id): - self.orig_id = p_id - self.db = db - - if not self.init: - self.init = 1 - filt = MatchesFilter(self.list) - for person_handle in db.get_person_handles(sort_handles=False): - if filt.apply (db, person_handle): - self.init_list (person_handle) return self.map.has_key(p_id) def init_list(self,p_id): @@ -626,9 +608,15 @@ class IsSiblingOfFilterMatch(Rule): labels = [ _('Filter name:') ] - def __init__(self,list): - Rule.__init__(self,list) - self.init = 0 + def prepare(self,db): + self.db = db + self.map = {} + filt = MatchesFilter(self.list) + for person_handle in db.get_person_handles(sort_handles=False): + if filt.apply (db, person_handle): + self.init_list (person_handle) + + def reset(self): self.map = {} def name(self): @@ -641,15 +629,6 @@ class IsSiblingOfFilterMatch(Rule): return _('Family filters') def apply(self,db,p_id): - self.orig_id = p_id - self.db = db - - if not self.init: - self.init = 1 - filt = MatchesFilter(self.list) - for person_handle in db.get_person_handles(sort_handles=False): - if filt.apply (db, person_handle): - self.init_list (person_handle) return self.map.has_key(p_id) def init_list(self,p_id): @@ -721,9 +700,21 @@ class IsAncestorOf(Rule): labels = [ _('ID:'), _('Inclusive:') ] - def __init__(self,list): - Rule.__init__(self,list) - self.init = 0 + def prepare(self,db): + """Assume that if 'Inclusive' not defined, assume inclusive""" + self.db = db + self.map = {} + try: + if int(self.list[1]): + first = 0 + else: + first = 1 + except IndexError: + first = 1 + root_id = self.list[0] + self.init_ancestor_list(db,root_id,first) + + def reset(self): self.map = {} def name(self): @@ -736,21 +727,6 @@ class IsAncestorOf(Rule): return _("Ancestral filters") def apply(self,db,p_id): - """Assume that if 'Inclusive' not defined, assume inclusive""" - self.orig_id = p_id - self.db = db - try: - if int(self.list[1]): - first = 0 - else: - first = 1 - except IndexError: - first = 1 - - if not self.init: - self.init = 1 - root_id = self.list[0] - self.init_ancestor_list(db,root_id,first) return self.map.has_key(p_id) def init_ancestor_list(self,db,p_id,first): @@ -783,6 +759,21 @@ class IsAncestorOfFilterMatch(IsAncestorOf): def __init__(self,list): IsAncestorOf.__init__(self,list) + def prepare(self,db): + try: + if int(self.list[1]): + first = 0 + else: + first = 1 + except IndexError: + first = 1 + + self.init = 1 + filt = MatchesFilter(self.list) + for person_handle in db.get_person_handles(sort_handles=False): + if filt.apply (db, person_handle): + self.init_ancestor_list (db,person_handle,first) + def name(self): return 'Is an ancestor of filter match' @@ -794,21 +785,6 @@ class IsAncestorOfFilterMatch(IsAncestorOf): return _("Ancestral filters") def apply(self,db,p_id): - self.orig_id = p_id - try: - if int(self.list[1]): - first = 0 - else: - first = 1 - except IndexError: - first = 1 - - if not self.init: - self.init = 1 - filt = MatchesFilter(self.list) - for person_handle in db.get_person_handles(sort_handles=False): - if filt.apply (db, person_handle): - self.init_ancestor_list (db,person_handle,first) return self.map.has_key(p_id) #------------------------------------------------------------------------- @@ -822,9 +798,12 @@ class IsLessThanNthGenerationAncestorOf(Rule): labels = [ _('ID:'), _('Number of generations:') ] - def __init__(self,list): - Rule.__init__(self,list) - self.init = 0 + def prepare(self,db): + self.db = db + self.map = {} + self.build_witness_list() + + def reset(self): self.map = {} def name(self): @@ -877,10 +856,14 @@ class IsMoreThanNthGenerationAncestorOf(Rule): labels = [ _('ID:'), _('Number of generations:') ] - def __init__(self,list): - Rule.__init__(self,list) - self.init = 0 + def prepare(self,db): + self.db = db self.map = {} + root_id = self.list[0] + self.init_ancestor_list(root_id,0) + + def reset(self): + self.map = [] def name(self): return 'Is an ancestor of person at least N generations away' @@ -893,12 +876,6 @@ class IsMoreThanNthGenerationAncestorOf(Rule): return _("Ancestral filters") def apply(self,db,p_id): - self.orig_id = p_id - self.db = db - if not self.init: - self.init = 1 - root_id = self.list[0] - self.init_ancestor_list(root_id,0) return self.map.has_key(p_id) def init_ancestor_list(self,p_id,gen): @@ -930,9 +907,15 @@ class IsParentOfFilterMatch(Rule): labels = [ _('Filter name:') ] - def __init__(self,list): - Rule.__init__(self,list) - self.init = 0 + def prepare(self,db): + self.db = db + self.map = {} + filt = MatchesFilter(self.list) + for person_handle in db.get_person_handles(sort_handles=False): + if filt.apply (db, person_handle): + self.init_list (person_handle) + + def reset(self): self.map = {} def name(self): @@ -945,15 +928,6 @@ class IsParentOfFilterMatch(Rule): return _('Family filters') def apply(self,db,p_id): - self.orig_id = p_id - self.db = db - - if not self.init: - self.init = 1 - filt = MatchesFilter(self.list) - for person_handle in db.get_person_handles(sort_handles=False): - if filt.apply (db, person_handle): - self.init_list (person_handle) return self.map.has_key(p_id) def init_list(self,p_id): @@ -984,14 +958,17 @@ class HasCommonAncestorWith(Rule): def category(self): return _("Ancestral filters") - def __init__(self,list): - Rule.__init__(self,list) + def prepare(self,db): + self.db = db # Keys in `ancestor_cache' are ancestors of list[0]. # We delay the computation of ancestor_cache until the # first use, because it's not uncommon to instantiate # this class and not use it. self.ancestor_cache = {} + def reset(self): + self.ancestor_cache = {} + def init_ancestor_cache(self,db): # list[0] is an Id, but we need to pass a Person to for_each_ancestor. p_id = self.list[0] @@ -1788,6 +1765,67 @@ class PeoplePrivate(Rule): p = db.get_person_from_handle(p_id) return p.get_privacy() +#------------------------------------------------------------------------- +# "Witnesses" +#------------------------------------------------------------------------- + + +class IsWitness(Rule): + """Witnesses""" + + labels = [_('Personal event:'), _('Family event:')] + + def prepare(self,db): + self.db = db + self.map = [] + self.build_witness_list() + + def reset(self): + self.map = [] + + def name(self): + return 'Witnesses' + + def description(self): + return _("Matches persons who are whitness in an event") + + def category(self): + return _('Event filters') + + def apply(self,db,p_id): + return p_id in self.map + + def build_witness_list(self): + event_type = None + if self.list and self.list[0]: + event_type = self.list[0] + if not self.list or event_type: + for person_handle in self.db.get_person_handles(): + p = self.db.get_person_from_handle(person_handle) + self.get_witness_of_events( event_type, + p.get_event_list()+[p.get_birth_handle(), p.get_death_handle()]) + event_type = None + if self.list and self.list[1]: + event_type = self.list[1] + if not self.list or event_type: + for family_handle in self.db.get_family_handles(): + f = self.db.get_family_from_handle(family_handle) + self.get_witness_of_events(event_type, f.get_event_list()) + + def get_witness_of_events(self, event_type, event_list): + if not event_list: + return + for event_handle in event_list: + event = self.db.get_event_from_handle(event_handle) + if event: + if event_type and not event.get_name() == event_type: + continue + wlist = event.get_witness_list() + if wlist: + for w in wlist: + if w.get_type() == RelLib.Event.ID: + self.map.append(w.get_value()) + #------------------------------------------------------------------------- # # GenericFilter @@ -1910,9 +1948,13 @@ class GenericFilter: def apply(self,db,id_list): m = self.get_check_func() res = [] + for rule in self.flist: + rule.prepare(db) for p_id in id_list: if m(db,p_id): res.append(p_id) + for rule in self.flist: + rule.reset() return res @@ -1971,6 +2013,7 @@ tasks = { unicode(_("Families with incomplete events")) : FamilyWithIncompleteEvent, unicode(_("People probably alive")) : ProbablyAlive, unicode(_("People marked private")) : PeoplePrivate, + unicode(_("Witnesses")) : IsWitness, } #------------------------------------------------------------------------- diff --git a/gramps2/src/gramps_main.py b/gramps2/src/gramps_main.py index f723e487c..1b3608ade 100755 --- a/gramps2/src/gramps_main.py +++ b/gramps2/src/gramps_main.py @@ -942,6 +942,11 @@ class Gramps: all.add_rule(GenericFilter.PeoplePrivate([])) filter_list.append(all) + all = GenericFilter.GenericFilter() + all.set_name(_("Witnesses")) + all.add_rule(GenericFilter.IsWitness([])) + filter_list.append(all) + self.filter_model = GenericFilter.FilterStore(filter_list) self.filter_list.set_model(self.filter_model) self.filter_list.set_active(self.filter_model.default_index())