From 9bd507d626fe0341df8bb4fa292124a1248687b1 Mon Sep 17 00:00:00 2001 From: Nick Hall Date: Wed, 6 Apr 2016 20:41:07 +0100 Subject: [PATCH] Add new family ancestor and descendant rules --- gramps/gen/filters/rules/family/__init__.py | 4 ++ .../gen/filters/rules/family/_isancestorof.py | 72 +++++++++++++++++++ .../filters/rules/family/_isdescendantof.py | 68 ++++++++++++++++++ .../filters/rules/test/family_rules_test.py | 67 +++++++++++++++++ gramps/gui/editors/filtereditor.py | 2 +- po/POTFILES.in | 2 + po/POTFILES.skip | 2 + 7 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 gramps/gen/filters/rules/family/_isancestorof.py create mode 100644 gramps/gen/filters/rules/family/_isdescendantof.py create mode 100644 gramps/gen/filters/rules/test/family_rules_test.py diff --git a/gramps/gen/filters/rules/family/__init__.py b/gramps/gen/filters/rules/family/__init__.py index 8b7fd2425..8fac878ae 100644 --- a/gramps/gen/filters/rules/family/__init__.py +++ b/gramps/gen/filters/rules/family/__init__.py @@ -59,6 +59,8 @@ from ._childhasidof import ChildHasIdOf from ._changedsince import ChangedSince from ._hastag import HasTag from ._hastwins import HasTwins +from ._isancestorof import IsAncestorOf +from ._isdescendantof import IsDescendantOf editor_rule_list = [ AllFamilies, @@ -88,4 +90,6 @@ editor_rule_list = [ ChangedSince, HasTag, HasTwins, + IsAncestorOf, + IsDescendantOf, ] diff --git a/gramps/gen/filters/rules/family/_isancestorof.py b/gramps/gen/filters/rules/family/_isancestorof.py new file mode 100644 index 000000000..aad5fc808 --- /dev/null +++ b/gramps/gen/filters/rules/family/_isancestorof.py @@ -0,0 +1,72 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2002-2006 Donald N. Allingham +# Copyright (C) 2016 Nick Hall +# +# 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from .. import Rule +from ....const import GRAMPS_LOCALE as glocale +_ = glocale.translation.gettext + +#------------------------------------------------------------------------- +# +# IsAncestorOf +# +#------------------------------------------------------------------------- +class IsAncestorOf(Rule): + """ + Rule that checks for a family that is an ancestor of a specified family. + """ + labels = [ _('ID:'), _('Inclusive:') ] + name = _('Ancestor families of ') + category = _('General filters') + description = _('Matches ancestor families of the specified family') + + def prepare(self, db): + self.map = set() + first = False if int(self.list[1]) else True + root_family = db.get_family_from_gramps_id(self.list[0]) + self.init_list(db, root_family, first) + + def reset(self): + self.map.clear() + + def apply(self, db, family): + return family.handle in self.map + + def init_list(self, db, family, first): + if not family: + return + if family.handle in self.map: + return + if not first: + self.map.add(family.handle) + + for parent_handle in [family.get_father_handle(), + family.get_mother_handle()]: + if parent_handle: + parent = db.get_person_from_handle(parent_handle) + family_handle = parent.get_main_parents_family_handle() + if family_handle: + parent_family = db.get_family_from_handle(family_handle) + self.init_list(db, parent_family, 0) diff --git a/gramps/gen/filters/rules/family/_isdescendantof.py b/gramps/gen/filters/rules/family/_isdescendantof.py new file mode 100644 index 000000000..16a7f1138 --- /dev/null +++ b/gramps/gen/filters/rules/family/_isdescendantof.py @@ -0,0 +1,68 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2002-2006 Donald N. Allingham +# Copyright (C) 2016 Nick Hall +# +# 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from .. import Rule +from ....const import GRAMPS_LOCALE as glocale +_ = glocale.translation.gettext + +#------------------------------------------------------------------------- +# +# IsDescendantOf +# +#------------------------------------------------------------------------- +class IsDescendantOf(Rule): + """ + Rule that checks for a family that is a descendant of a specified family. + """ + labels = [ _('ID:'), _('Inclusive:') ] + name = _('Descendant families of ') + category = _('General filters') + description = _('Matches descendant families of the specified family') + + def prepare(self, db): + self.map = set() + first = False if int(self.list[1]) else True + root_family = db.get_family_from_gramps_id(self.list[0]) + self.init_list(db, root_family, first) + + def reset(self): + self.map.clear() + + def apply(self, db, family): + return family.handle in self.map + + def init_list(self, db, family, first): + if not family: + return + if not first: + self.map.add(family.handle) + + for child_ref in family.get_child_ref_list(): + child = db.get_person_from_handle(child_ref.ref) + if child: + for family_handle in child.get_family_handle_list(): + child_family = db.get_family_from_handle(family_handle) + self.init_list(db, child_family, 0) diff --git a/gramps/gen/filters/rules/test/family_rules_test.py b/gramps/gen/filters/rules/test/family_rules_test.py new file mode 100644 index 000000000..3f9e44af9 --- /dev/null +++ b/gramps/gen/filters/rules/test/family_rules_test.py @@ -0,0 +1,67 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2016 Tom Samstag +# +# 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 +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +""" +Unittest that tests family-specific filter rules +""" +import unittest + +from gramps.gen.merge.diff import import_as_dict +from gramps.cli.user import User +from gramps.gen.filters import GenericFilterFactory + +from gramps.gen.filters.rules.family import * + +GenericFamilyFilter = GenericFilterFactory('Family') + +class BaseTest(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls.db = import_as_dict("example/gramps/example.gramps", User()) + + def filter_with_rule(self, rule): + filter_ = GenericFamilyFilter() + filter_.add_rule(rule) + results = filter_.apply(self.db) + return set(results) + + def test_IsAncestorOf(self): + rule = IsAncestorOf(['F0031', '0']) + self.assertEqual(self.filter_with_rule(rule), set([ + b'4AXJQC96KTN3WGPTVE', b'1RUJQCYX9QL1V45YLD', b'5GTJQCXVYVAIQTBVKA', + b'X3WJQCSF48F6809142', b'NSVJQC89IHEEBIPDP2', b'9OUJQCBOHW9UEK9CNV', + b'1RUJQCCL9MVRYLMTBO', b'RRVJQC5A8DDHQFPRDL', b'0SUJQCOS78AXGWP8QR', + b'57WJQCTBJKR5QYPS6K', b'8OUJQCUVZ0XML7BQLF', b'7PUJQC4PPS4EDIVMYE' + ])) + + def test_IsDescendantOf(self): + rule = IsDescendantOf(['F0031', '0']) + self.assertEqual(self.filter_with_rule(rule), set([ + b'SFXJQCLE8PIG7PH38J', b'UCXJQCC5HS8VXDKWBM', b'IIEKQCRX89WYBHKB7R', + b'XDXJQCMWU5EIV8XCRF', b'7BXJQCU22OCA4HN38A', b'3FXJQCR749H2H7G321', + b'IEXJQCFUN95VENI6BO', b'4FXJQC7656WDQ3HJGW', b'FLEKQCRVG3O1UA9YUB', + b'BCXJQC9AQ0DBXCVLEQ', b'9SEKQCAAWRUCIO7A0M', b'DDXJQCVT5X72TOXP0C', + b'CGXJQC515QL9RLPQTU', b'XGXJQCNVZH2PWRMVAH', b'RBXJQCUYMQR2KRMDFY' + ])) + + +if __name__ == "__main__": + unittest.main() diff --git a/gramps/gui/editors/filtereditor.py b/gramps/gui/editors/filtereditor.py index aca96fed5..f1223e345 100644 --- a/gramps/gui/editors/filtereditor.py +++ b/gramps/gui/editors/filtereditor.py @@ -560,7 +560,7 @@ class EditRule(ManagedWindow): key=lambda s: s.lower()) t = MySelect(_name2typeclass[v], additional) elif v == _('Inclusive:'): - t = MyBoolean(_('Include original person')) + t = MyBoolean(_('Include selected Gramps ID')) elif v == _('Case sensitive:'): t = MyBoolean(_('Use exact case of letters')) elif v == _('Regular-Expression matching:'): diff --git a/po/POTFILES.in b/po/POTFILES.in index 97b74b47a..1d8f51c27 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -108,6 +108,8 @@ gramps/gen/filters/rules/family/_hassourceof.py gramps/gen/filters/rules/family/_hastag.py gramps/gen/filters/rules/family/_hastwins.py gramps/gen/filters/rules/family/_isbookmarked.py +gramps/gen/filters/rules/family/_isancestorof.py +gramps/gen/filters/rules/family/_isdescendantof.py gramps/gen/filters/rules/family/_matchesfilter.py gramps/gen/filters/rules/family/_matchessourceconfidence.py gramps/gen/filters/rules/family/_motherhasidof.py diff --git a/po/POTFILES.skip b/po/POTFILES.skip index 41c2649e2..5e249ccc5 100644 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -78,6 +78,8 @@ gramps/gen/filters/_searchfilter.py # gramps/gen/filters/rules/_hastextmatchingregexpof.py gramps/gen/filters/rules/__init__.py +gramps/gen/filters/rules/test/person_rules_test.py +gramps/gen/filters/rules/test/family_rules_test.py # # gen.filters.rules.person package #