Version 1 of the recursive descendant routine. More recursive classes to come.
ander882@hotmail.com svn: r23412
This commit is contained in:
parent
c29af0860b
commit
824a9a5134
@ -26,7 +26,7 @@
|
||||
# libcairo
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libcairodoc',
|
||||
name = "Cairodoc lib",
|
||||
description = _("Provides a library for using Cairo to "
|
||||
@ -45,7 +45,7 @@ authors_email = ["http://gramps-project.org"],
|
||||
# libgedcom
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libgedcom',
|
||||
name = "GEDCOM library",
|
||||
description = _("Provides GEDCOM processing functionality"),
|
||||
@ -57,12 +57,29 @@ authors = ["The Gramps project"],
|
||||
authors_email = ["http://gramps-project.org"],
|
||||
)
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# librecurse
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
id='librecurse',
|
||||
name="Recursive lib",
|
||||
description= _("Provides recursive routines for reports"),
|
||||
version='1.0',
|
||||
gramps_target_version='4.1',
|
||||
status=STABLE,
|
||||
fname='librecurse.py',
|
||||
authors=["The Gramps project"],
|
||||
authors_email=["http://gramps-project.org"],
|
||||
)
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# libgrampsxml
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libgrampsxml',
|
||||
name = "Grampsxml lib",
|
||||
description = _("Provides common functionality for Gramps XML "
|
||||
@ -80,7 +97,7 @@ authors_email = ["http://gramps-project.org"],
|
||||
# libholiday
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libholiday',
|
||||
name = "holiday lib",
|
||||
description = _("Provides holiday information for different countries.") ,
|
||||
@ -98,7 +115,7 @@ authors_email = ["http://gramps-project.org"],
|
||||
# llibhtmlbackend
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libhtmlbackend',
|
||||
name = "htmlbackend lib",
|
||||
description = _("Manages a HTML file implementing DocBackend.") ,
|
||||
@ -116,7 +133,7 @@ authors_email = ["http://gramps-project.org"],
|
||||
# libhtmlconst
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libhtmlconst',
|
||||
name = "htmlconst lib",
|
||||
description = _("Common constants for html files.") ,
|
||||
@ -134,7 +151,7 @@ authors_email = ["http://gramps-project.org"],
|
||||
# libhtml
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libhtml',
|
||||
name = "html lib",
|
||||
description = _("Manages an HTML DOM tree.") ,
|
||||
@ -152,7 +169,7 @@ authors_email = ["gerald.britton@gmail.com"],
|
||||
# libmapservice
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libmapservice',
|
||||
name = "mapservice lib",
|
||||
description = _("Provides base functionality for map services.") ,
|
||||
@ -169,7 +186,7 @@ authors_email = ["http://gramps-project.org"],
|
||||
# libnarrate
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libnarrate',
|
||||
name = "narration lib",
|
||||
description = _("Provides Textual Narration.") ,
|
||||
@ -186,7 +203,7 @@ authors_email = ["brian@gramps-project.org"],
|
||||
# libodfbackend
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libodfbackend',
|
||||
name = "odfbackend lib",
|
||||
description = _("Manages an ODF file implementing DocBackend.") ,
|
||||
@ -203,7 +220,7 @@ authors_email = ["http://gramps-project.org"],
|
||||
# libpersonview
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libpersonview',
|
||||
name = "person list lib",
|
||||
description = _("Provides the Base needed for the List People views.") ,
|
||||
@ -220,7 +237,7 @@ authors_email = ["http://gramps-project.org"],
|
||||
# libplaceview
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libplaceview',
|
||||
name = "place list lib",
|
||||
description = _("Provides the Base needed for the List Place views.") ,
|
||||
@ -237,7 +254,7 @@ authors_email = ["http://gramps-project.org"],
|
||||
# libsubstkeyword
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libsubstkeyword',
|
||||
name = "Substitution Values",
|
||||
description = _("Provides variable substitution on display lines.") ,
|
||||
@ -253,7 +270,7 @@ authors_email = ["http://gramps-project.org"],
|
||||
# libtreebase
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
register(GENERAL,
|
||||
id = 'libtreebase',
|
||||
name = "Graphical report lib",
|
||||
description = _("Provides the base needed for the ancestor and "
|
||||
|
307
gramps/plugins/lib/librecurse.py
Normal file
307
gramps/plugins/lib/librecurse.py
Normal file
@ -0,0 +1,307 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2013 Craig Anderson
|
||||
#
|
||||
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
# $Id:
|
||||
|
||||
""" Recursive base classes for reports
|
||||
"""
|
||||
|
||||
from gramps.gen.plug.report import utils as ReportUtils
|
||||
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Class DescendPerson
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
class DescendPerson(object):
|
||||
""" Recursive (down) base class
|
||||
|
||||
The following methods need to be sub-classed as needed:
|
||||
. add_person
|
||||
. add_person_again (called when a person is seen a second more more times)
|
||||
if you don't want to see marriages don't subclass the following two
|
||||
. add_marriage
|
||||
. add_marriage_again (when a marriage is seen a second more more times)
|
||||
|
||||
Public variables:
|
||||
. families_seen a set of all famalies seen.
|
||||
. people_seen, a set of all people seen.
|
||||
. . useful for knowing if a recursion (kid marring a grandparent)
|
||||
. . has happened.
|
||||
These can be edited if needed
|
||||
. appending can be useful for excluding parts of the tree
|
||||
|
||||
Methods (tools):
|
||||
is_direct_descendant - is this person a direct descendant
|
||||
. in the example 'kid 1 of mom and other spouse' is NOT
|
||||
stop_descending - tells the recursion to stop going down
|
||||
. mostly used in add_person_again and add_marriage_again
|
||||
has_children - checks to see if the person:
|
||||
. is NOT already seen and has hildren.
|
||||
|
||||
Methods (informative)
|
||||
. These are the methods that need to be subclassed
|
||||
. all methods are given the:
|
||||
. . level in (Generagion, Spousal level) tuple
|
||||
. . person_handle of the person
|
||||
. . family_handle of the family
|
||||
add_person - The recursion found a new person in the tree
|
||||
add_person_again - found a person again
|
||||
. a prolific person or recursion
|
||||
add_marriage
|
||||
add_marriage_again
|
||||
|
||||
Methods (recursive)
|
||||
recurse - The main recursive routine. needs:
|
||||
. person_handle
|
||||
. g_level - Generation level of this person
|
||||
. . if max_gen is 2 and g_level is 1, only this generation
|
||||
. . will be displayed.
|
||||
. s_level - spousal level - most always 0
|
||||
recurse_parents - Thes same as above except:
|
||||
. mom (the spouse) is still shown even if s_level == 0
|
||||
. . father will have a level of (g_level,0), mother (g_level, 1)
|
||||
"""
|
||||
def __init__(self, dbase, maxgen, maxspouse):
|
||||
""" initalized with the
|
||||
. database
|
||||
. maxgen is the max generations (down) of people to return
|
||||
. maxspouse is the level of spouses to recruse through
|
||||
. . 0 = no spouses, 1 = spouses of a direct descendant
|
||||
. . 2 = spouses of 1, 3 = spouses of 2, etc. See example below
|
||||
|
||||
"""
|
||||
# example: maxgen = 2, maxspouses = 2
|
||||
# (1,0) father
|
||||
# (1,1) Mother
|
||||
# (1,2) Mothers other spouse
|
||||
# (2,0) kid 1 of mom and other spouse
|
||||
# (2,0) Kid 1 of father and mother
|
||||
# (1,1) fathers other spouse
|
||||
# (2,0) Kid 1 of father and fathers other spouse
|
||||
# (2,1) Spouse of Kid 1 of father and fathers other spouse
|
||||
|
||||
self.database = dbase
|
||||
|
||||
self.families_seen = set()
|
||||
self.people_seen = set()
|
||||
|
||||
self.max_generations = maxgen
|
||||
self.max_spouses = maxspouse
|
||||
|
||||
#can we bold direct descendants?
|
||||
#bold_now will have only three values
|
||||
#0 - no bolding
|
||||
#1 - Only bold the first person
|
||||
#2 - Bold all direct descendants
|
||||
self.__bold_now = 1
|
||||
self.__this_slevel = -1
|
||||
self.__stop_descending = False
|
||||
|
||||
def is_direct_descendant(self):
|
||||
return self.__bold_now != 0 and self.__this_slevel == 0
|
||||
|
||||
def stop_descending(self):
|
||||
self.__stop_descending = True
|
||||
|
||||
def has_children(self, person_handle):
|
||||
"""
|
||||
Quickly check to see if this person has children
|
||||
still we want to respect the people_seen list
|
||||
"""
|
||||
|
||||
if not person_handle or person_handle in self.people_seen:
|
||||
return False
|
||||
|
||||
person = self.database.get_person_from_handle(person_handle)
|
||||
|
||||
for family_handle in person.get_family_handle_list():
|
||||
if family_handle not in self.families_seen:
|
||||
|
||||
family = self.database.get_family_from_handle(family_handle)
|
||||
|
||||
if family.get_child_ref_list():
|
||||
return True
|
||||
return False
|
||||
|
||||
def add_person(self, level, person_handle, family_handle):
|
||||
""" Makes a person box """
|
||||
pass
|
||||
|
||||
def add_person_again(self, level, person_handle, family_handle):
|
||||
pass
|
||||
|
||||
def __add_person(self, level, person_handle, family_handle):
|
||||
if person_handle is not None and person_handle in self.people_seen:
|
||||
self.add_person_again(level, person_handle, family_handle)
|
||||
else:
|
||||
self.add_person(level, person_handle, family_handle)
|
||||
if person_handle is not None:
|
||||
self.people_seen.add(person_handle)
|
||||
|
||||
def add_marriage(self, level, person_handle, family_handle):
|
||||
""" Makes a marriage box """
|
||||
pass
|
||||
|
||||
def add_marriage_again(self, level, person_handle, family_handle):
|
||||
""" Makes a marriage box """
|
||||
pass
|
||||
|
||||
def __add_marriage(self, level, person_handle, family_handle):
|
||||
""" Makes a marriage box """
|
||||
if family_handle in self.families_seen:
|
||||
self.add_marriage_again(level, person_handle, family_handle)
|
||||
else:
|
||||
self.add_marriage(level, person_handle, family_handle)
|
||||
self.families_seen.add(family_handle)
|
||||
|
||||
def recurse(self, person_handle, g_level, s_level):
|
||||
"""traverse the descendants recursively
|
||||
until either the end of a line is found,
|
||||
or until we reach the maximum number of generations
|
||||
or we reach the max number of spouses
|
||||
that we want to deal with"""
|
||||
|
||||
if not person_handle:
|
||||
return
|
||||
if g_level > self.max_generations:
|
||||
return
|
||||
if s_level > 0 and s_level == self.max_spouses:
|
||||
return
|
||||
#if person_handle in self.people_seen: return
|
||||
|
||||
person = self.database.get_person_from_handle(person_handle)
|
||||
family_handles = person.get_family_handle_list()
|
||||
if s_level == 0:
|
||||
val = family_handles[0] if family_handles else None
|
||||
self.__this_slevel = s_level
|
||||
self.__add_person((g_level, s_level), person_handle, val)
|
||||
|
||||
if self.__bold_now == 1:
|
||||
self.__bold_now = 0
|
||||
|
||||
if self.__stop_descending:
|
||||
self.__stop_descending = False
|
||||
return
|
||||
|
||||
if s_level == 1:
|
||||
tmp_bold = self.__bold_now
|
||||
self.__bold_now = 0
|
||||
|
||||
for family_handle in family_handles:
|
||||
#Marriage box if the option is there.
|
||||
self.__add_marriage((g_level, s_level + 1),
|
||||
person_handle, family_handle)
|
||||
|
||||
if self.__stop_descending:
|
||||
self.__stop_descending = False
|
||||
continue
|
||||
|
||||
family = self.database.get_family_from_handle(family_handle)
|
||||
|
||||
spouse_handle = ReportUtils.find_spouse(person, family)
|
||||
if self.max_spouses > s_level:
|
||||
self.__this_slevel = s_level + 1
|
||||
self.__add_person((g_level, s_level + 1),
|
||||
spouse_handle, family_handle)
|
||||
|
||||
if self.__stop_descending:
|
||||
self.__stop_descending = False
|
||||
continue
|
||||
|
||||
mykids = [kid.ref for kid in family.get_child_ref_list()]
|
||||
|
||||
if not self.__stop_descending:
|
||||
for child_ref in mykids:
|
||||
self.recurse(child_ref, g_level + 1, 0)
|
||||
else:
|
||||
self.__stop_descending = False
|
||||
|
||||
if self.max_spouses > s_level:
|
||||
#spouse_handle = ReportUtils.find_spouse(person,family)
|
||||
self.recurse(spouse_handle, g_level, s_level + 1)
|
||||
|
||||
if s_level == 1:
|
||||
self.__bold_now = tmp_bold
|
||||
|
||||
def recurse_parents(self, family_handle, g_level):
|
||||
"""
|
||||
Adds a family.
|
||||
ignoring maxspouse, s_level assumed 0 and 1
|
||||
father is (g_level,0) and mother is (g_level,1)
|
||||
children are (g_level+1,0) and respects maxgen
|
||||
"""
|
||||
|
||||
if family_handle is None:
|
||||
return
|
||||
|
||||
family = self.database.get_family_from_handle(family_handle)
|
||||
father_h = family.get_father_handle()
|
||||
mother_h = family.get_mother_handle()
|
||||
|
||||
self.__bold_now = 2
|
||||
self.__this_slevel = 0
|
||||
#if father_h:
|
||||
father_b = self.__add_person((g_level, 0), father_h, family_handle)
|
||||
#else:
|
||||
# #TODO - should send family_h instead of None?
|
||||
# father_b = self.__add_person((g_level, 0), None, family_h)
|
||||
#self.people_seen.add(father_h)
|
||||
|
||||
family_b = self.__add_marriage((g_level, 1), father_h, family_handle)
|
||||
|
||||
self.__bold_now = 0
|
||||
self.__this_slevel = 1
|
||||
mother_b = self.__add_person((g_level, 1), mother_h, family_handle)
|
||||
|
||||
self.__bold_now = 2
|
||||
for child_ref in family.get_child_ref_list():
|
||||
self.recurse(child_ref.ref, g_level + 1, 0)
|
||||
|
||||
self.__bold_now = 0
|
||||
|
||||
return (father_b, family_b, mother_b)
|
||||
|
||||
def recurse_if(self, person_handle, g_level):
|
||||
"""
|
||||
Quickly check to see if we want to continue recursion
|
||||
we still we want to respect the FamiliesSeen list
|
||||
"""
|
||||
|
||||
person = self.database.get_person_from_handle(person_handle)
|
||||
|
||||
show = False
|
||||
myfams = person.get_family_handle_list()
|
||||
if len(myfams) > 1: # and self.max_spouses > 0
|
||||
show = True
|
||||
|
||||
#if self.max_spouses == 0 and not self.has_children(person_handle):
|
||||
# self.people_seen.add(person_handle)
|
||||
# show = False
|
||||
|
||||
if show:
|
||||
self.__bold_now = 1
|
||||
self.recurse(person_handle, g_level, 0)
|
||||
|
||||
#------------
|
||||
# Jer 29:11: "For I know the plans I have for you," declares the LORD,
|
||||
# "plans to prosper you and not to harm you, plans to give you hope
|
||||
# and a future."
|
Loading…
Reference in New Issue
Block a user