e8f9c8422a
svn: r16422
991 lines
36 KiB
Python
991 lines
36 KiB
Python
#
|
|
# Gramps - a GTK+/GNOME based genealogy program
|
|
#
|
|
# Copyright (C) 2000-2007 Donald N. Allingham
|
|
# Copyright (C) 2007-2008 Brian G. Matherly
|
|
# Copyright (C) 2010 Jakim Friant#
|
|
# Copyright (C) 2010 Craig J. 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: Ancestor2.py
|
|
|
|
"""Reports/Graphical Reports/Ancestor Tree"""
|
|
|
|
#------------------------------------------------------------------------
|
|
#
|
|
# python modules
|
|
#
|
|
#------------------------------------------------------------------------
|
|
import math
|
|
def log2(val):
|
|
"""
|
|
Calculate the log base 2 of a value.
|
|
"""
|
|
return int(math.log(val, 2))
|
|
|
|
X_INDEX = log2
|
|
|
|
from gen.ggettext import sgettext as _
|
|
|
|
#------------------------------------------------------------------------
|
|
#
|
|
# GRAMPS modules
|
|
#
|
|
#------------------------------------------------------------------------
|
|
|
|
#from Errors import ReportError
|
|
|
|
from gen.plug.menu import BooleanOption
|
|
from gen.plug.menu import NumberOption
|
|
from gen.plug.menu import StringOption
|
|
from gen.plug.menu import EnumeratedListOption
|
|
from gen.plug.menu import TextOption
|
|
from gen.plug.menu import PersonOption
|
|
|
|
from gen.plug.report import Report
|
|
from gen.plug.report import utils as ReportUtils
|
|
from gui.plug.report import MenuReportOptions
|
|
|
|
from gen.display.name import displayer as name_displayer
|
|
|
|
PT2CM = ReportUtils.pt2cm
|
|
#cm2pt = ReportUtils.cm2pt
|
|
|
|
#------------------------------------------------------------------------
|
|
#
|
|
# Constants
|
|
#
|
|
#------------------------------------------------------------------------
|
|
_BORN = _('short for born|b.')
|
|
_DIED = _('short for died|d.')
|
|
_MARR = _('short for married|m.')
|
|
|
|
from libtreebase import *
|
|
|
|
#------------------------------------------------------------------------
|
|
#
|
|
# Box classes
|
|
#
|
|
#------------------------------------------------------------------------
|
|
class AncestorBoxBase(BoxBase):
|
|
""" The base class for the two boxes used in this report """
|
|
|
|
def __init__(self, boxstr):
|
|
BoxBase.__init__(self)
|
|
self.boxstr = boxstr
|
|
|
|
def y_index(self, max_gen):
|
|
""" Calculate the column or generation that this person is in. """
|
|
x_level = self.level[0]
|
|
#Calculate which row in the column of people.
|
|
tmp_y = self.level[1] - (2**x_level)
|
|
#Calculate which row in the table (yes table) of people.
|
|
delta = (2**max_gen) // (2**(x_level))
|
|
return int((delta/2) + (tmp_y*delta))
|
|
|
|
class PersonBox(AncestorBoxBase):
|
|
"""
|
|
Calculates information about the box that will print on a page
|
|
"""
|
|
def __init__(self, level):
|
|
AncestorBoxBase.__init__(self, "AC2-box")
|
|
self.level = (X_INDEX(level), level)
|
|
|
|
class FamilyBox(AncestorBoxBase):
|
|
"""
|
|
Calculates information about the box that will print on a page
|
|
"""
|
|
def __init__(self, level):
|
|
AncestorBoxBase.__init__(self, "AC2-fam-box")
|
|
self.level = (X_INDEX(level)+1, level)
|
|
|
|
def y_index(self, max_gen):
|
|
""" Calculate the column or generation that this person is in. """
|
|
x_level = self.level[0] - 1
|
|
#Calculate which row in the column of people.
|
|
tmp_y = self.level[1] - (2**x_level)
|
|
#Calculate which row in the table (yes table) of people.
|
|
delta = (2**max_gen) // (2**(x_level))
|
|
return int((delta/2) + (tmp_y*delta))
|
|
|
|
|
|
#------------------------------------------------------------------------
|
|
#
|
|
# Line class
|
|
#
|
|
#------------------------------------------------------------------------
|
|
class Line(LineBase):
|
|
""" Our line class."""
|
|
def __init__(self, start):
|
|
LineBase.__init__(self, start)
|
|
self.linestr = 'AC2-line'
|
|
|
|
|
|
#------------------------------------------------------------------------
|
|
#
|
|
# Titles Class(es)
|
|
#
|
|
#------------------------------------------------------------------------
|
|
class TitleN(TitleBox):
|
|
"""No Title class for the report """
|
|
def __init__(self, doc):
|
|
TitleBox.__init__(self, doc, "None")
|
|
|
|
def calc_title(self, center):
|
|
"""Calculate the title of the report"""
|
|
return
|
|
|
|
class TitleA(TitleBox):
|
|
"""Title class for the report """
|
|
def __init__(self, doc):
|
|
TitleBox.__init__(self, doc, "AC2-Title")
|
|
|
|
def calc_title(self, center):
|
|
"""Calculate the title of the report"""
|
|
name = ""
|
|
if center is not None:
|
|
name = name_displayer.display(center)
|
|
|
|
self.text = _("Ancestor Graph for %s") % name
|
|
self.set_box_height_width()
|
|
|
|
|
|
#------------------------------------------------------------------------
|
|
#
|
|
# CalcItems (helper class to calculate text)
|
|
# make_ancestor_tree (main recursive functions)
|
|
#
|
|
#------------------------------------------------------------------------
|
|
class CalcItems(object):
|
|
def __init__(self, dbase):
|
|
__gui = GUIConnect()
|
|
|
|
#calculate the printed lines for each box
|
|
#display_repl = [] #Not used in this report
|
|
#str = ""
|
|
#if self.get_val('miss_val'):
|
|
# str = "_____"
|
|
self.__calc_l = CalcLines(dbase, [])
|
|
|
|
self.__blank_father = None
|
|
self.__blank_mother = None
|
|
|
|
main = self.__calc_l.calc_lines( None, None, __gui.get_val('dispf'))
|
|
secn = self.__calc_l.calc_lines( None, None, __gui.get_val('disp_sec'))
|
|
|
|
self.disp_father = __gui.get_val('dispf')
|
|
self.__blank_father = main
|
|
self.disp_mother = __gui.get_val('dispf')
|
|
self.__blank_mother = main
|
|
if __gui.get_val('dif_sec') == 1:
|
|
self.disp_father = __gui.get_val('disp_sec')
|
|
self.__blank_father = secn
|
|
elif __gui.get_val('dif_sec') == 2:
|
|
self.disp_mother = __gui.get_val('disp_sec')
|
|
self.__blank_mother = secn
|
|
|
|
self.disp_marr = [__gui.get_val('dispmarr')]
|
|
self.__blank_marriage = \
|
|
self.__calc_l.calc_lines(None, None, self.disp_marr)
|
|
|
|
def calc_person(self, index, indi_handle, fams_handle):
|
|
working_lines = ""
|
|
if index == 1 or index % 2 == 0: #The center person always uses main
|
|
if indi_handle == fams_handle == None:
|
|
working_lines = self.__blank_father
|
|
else:
|
|
working_lines = self.disp_father
|
|
else:
|
|
if indi_handle == fams_handle == None:
|
|
working_lines = self.__blank_mother
|
|
else:
|
|
working_lines = self.disp_mother
|
|
|
|
if indi_handle == fams_handle == None:
|
|
return working_lines
|
|
else:
|
|
return self.__calc_l.calc_lines(indi_handle, fams_handle,
|
|
working_lines)
|
|
|
|
def calc_marrage(self, indi_handle, fams_handle):
|
|
if indi_handle == fams_handle == None:
|
|
return self.__blank_marriage
|
|
else:
|
|
return self.__calc_l.calc_lines(indi_handle, fams_handle,
|
|
self.disp_marr)
|
|
|
|
|
|
class MakeAncestorTree(object):
|
|
"""
|
|
The main procedure to use recursion to make the tree based off of a person.
|
|
order of people inserted into Persons is important.
|
|
makes sure that order is done correctly.
|
|
"""
|
|
def __init__(self, dbase, canvas, max_gen, inc_marr, fill_out):
|
|
self.database = dbase
|
|
self.canvas = canvas
|
|
self.inlc_marr = inc_marr
|
|
self.max_generations = max_gen
|
|
self.fill_out = fill_out
|
|
|
|
self.calc_items = CalcItems(self.database)
|
|
|
|
def add_person_box(self, index, indi_handle, fams_handle):
|
|
""" Makes a person box and add that person into the Canvas. """
|
|
|
|
|
|
myself = PersonBox(index)
|
|
|
|
myself.text = self.calc_items.calc_person(
|
|
index, indi_handle, fams_handle)
|
|
|
|
self.canvas.add_box(myself)
|
|
|
|
return myself
|
|
|
|
def add_marriage_box(self, index, indi_handle, fams_handle):
|
|
""" Makes a marriage box and add that person into the Canvas. """
|
|
|
|
|
|
myself = FamilyBox(index)
|
|
|
|
#calculate the text.
|
|
myself.text = self.calc_items.calc_marrage(indi_handle, fams_handle)
|
|
|
|
|
|
self.canvas.add_box(myself)
|
|
|
|
def add_line(self, person, father, mother = None):
|
|
""" Adds the line connecting the boxes """
|
|
if father is None and mother is None:
|
|
return
|
|
|
|
line = Line(person)
|
|
if father:
|
|
line.add_to(father)
|
|
if mother:
|
|
line.add_to(mother)
|
|
|
|
self.canvas.add_line(line)
|
|
|
|
return line
|
|
|
|
def recurse(self, person_handle, family_handle, index):
|
|
""" traverse the ancestors recursively until either the end
|
|
of a line is found, or until we reach the maximum number of
|
|
generations that the user wants """
|
|
|
|
if log2(index) == self.max_generations:
|
|
return None
|
|
|
|
person = self.database.get_person_from_handle(person_handle)
|
|
if not person:
|
|
return self.__fill(index, None,
|
|
min(self.fill_out, self.max_generations-X_INDEX(index)-1)
|
|
)
|
|
|
|
parents_handle = person.get_main_parents_family_handle()
|
|
father = marrbox = mother = None
|
|
if parents_handle:
|
|
#note depth first
|
|
family = self.database.get_family_from_handle(parents_handle)
|
|
father = self.recurse(family.get_father_handle(), parents_handle,
|
|
index*2)
|
|
mybox = self.add_person_box(index, person_handle, family_handle)
|
|
if self.inlc_marr and (log2(index) + 2) <= self.max_generations:
|
|
marrbox = self.add_marriage_box(index,
|
|
family.get_father_handle(),
|
|
parents_handle)
|
|
|
|
mother = self.recurse(family.get_mother_handle(), parents_handle,
|
|
(index*2)+1)
|
|
|
|
self.add_line(mybox, father, mother)
|
|
else:
|
|
mybox = self.__fill(index, person_handle,
|
|
min(self.fill_out, self.max_generations-X_INDEX(index)-1)
|
|
)
|
|
#father = self.__fill(index *2, self.fill_out)
|
|
#mybox = self.add_person_box(index, person_handle, family_handle)
|
|
#if self.fill_out and self.inlc_marr and (log2(index) + 2) <
|
|
# self.max_generations:
|
|
# marrbox = self.add_marriage_box(index*2, None, None)
|
|
#mother = self.__fill(index *2+1, self.fill_out)
|
|
|
|
return mybox
|
|
|
|
def __fill(self, index, person_handle, max_fill):
|
|
""" Fills out the Ancestor tree as desired/needed.
|
|
this is an iterative apporach.
|
|
"""
|
|
|
|
if max_fill < 0:
|
|
return
|
|
##if X_INDEX(index) == self.max_generations:
|
|
## return None
|
|
|
|
###########################
|
|
#list of boxes
|
|
#for each generation (max_fill)
|
|
__BOXES = [None] * (max_fill+1)
|
|
__INDEX = [index]
|
|
__LINES = [None] * max_fill
|
|
|
|
#if __INFO[0][__FILL_AMOUNT] == max_fill or \
|
|
# X_INDEX(index) >= self.max_generations-1:
|
|
if max_fill == 0:
|
|
return self.add_person_box(index, None, None)
|
|
|
|
###########################
|
|
#Prime the pump
|
|
cur_gen = 1
|
|
#Cur_gen is the current Generation that we are working with
|
|
#use a bottom up iterative approach
|
|
while cur_gen > 0:
|
|
###########################
|
|
#Step 1. this level is blank. add our father
|
|
#if __INFO[cur_gen][__INDEX] == 0:
|
|
if len(__INDEX) == cur_gen:
|
|
__INDEX.append(__INDEX[cur_gen-1]*2)
|
|
#we will be adding a father here
|
|
|
|
if cur_gen < max_fill:
|
|
#But first, go to this father first if we can
|
|
cur_gen += 1
|
|
else:
|
|
#found our father. add him
|
|
__BOXES[cur_gen] = self.add_person_box(
|
|
__INDEX[cur_gen], None, None)
|
|
|
|
###########################
|
|
#Step 1.5. Dad has already been made.
|
|
elif __INDEX[cur_gen] %2 == 0:
|
|
|
|
###########################
|
|
#Step 2. add our kid
|
|
__BOXES[cur_gen-1] = self.add_person_box(
|
|
__INDEX[cur_gen-1],
|
|
person_handle if cur_gen == 1 else None,
|
|
None)
|
|
|
|
###########################
|
|
#Step 2.3. add our marriage
|
|
if self.inlc_marr and cur_gen <= max_fill+1:
|
|
self.add_marriage_box(__INDEX[cur_gen-1], None, None)
|
|
|
|
###########################
|
|
#Step 2.6. line part 1
|
|
__LINES[cur_gen-1] = self.add_line(__BOXES[cur_gen-1],
|
|
__BOXES[cur_gen])
|
|
|
|
#make sure there is a NEW int.
|
|
__INDEX.pop()
|
|
#not a refernce that will clobber dada info
|
|
__INDEX.append((__INDEX[cur_gen-1] *2) +1)
|
|
#__INDEX[cur_gen] +=1
|
|
|
|
if cur_gen < max_fill:
|
|
cur_gen += 1
|
|
else:
|
|
###########################
|
|
#Step 3. Now we can make Mom
|
|
__BOXES[cur_gen] = self.add_person_box(
|
|
__INDEX[cur_gen], None, None)
|
|
|
|
###########################
|
|
#Step 4. Father and Mother are done but only 1/2 line
|
|
else:
|
|
if cur_gen > 0:
|
|
###########################
|
|
#Step 2.6. line part 2
|
|
__LINES[cur_gen-1].add_to(__BOXES[cur_gen])
|
|
|
|
__INDEX.pop()
|
|
cur_gen -= 1
|
|
|
|
return __BOXES[0]
|
|
|
|
def start(self, person_id):
|
|
""" go ahead and make it happen """
|
|
center = self.database.get_person_from_gramps_id(person_id)
|
|
center_h = center.get_handle()
|
|
|
|
self.recurse(center_h, None, 1)
|
|
|
|
#------------------------------------------------------------------------
|
|
#
|
|
# Transform Classes
|
|
#
|
|
#------------------------------------------------------------------------
|
|
#------------------------------------------------------------------------
|
|
# Class rl_Transform
|
|
#------------------------------------------------------------------------
|
|
class RLTransform():
|
|
"""
|
|
setup all of the boxes on the canvas in for a left/right report
|
|
"""
|
|
def __init__(self, canvas, opts, max_generations, compress_tree):
|
|
self.canvas = canvas
|
|
self.rept_opts = opts
|
|
self.max_generations = max_generations
|
|
self.compress_tree = compress_tree
|
|
self.y_offset = self.rept_opts.littleoffset*2 + self.canvas.title.height
|
|
self.__last_y_level = 0
|
|
self.__y_level = 0
|
|
|
|
def __next_y(self, box):
|
|
""" boxes are already in top down (.y_cm) form so if we
|
|
set the box in the correct y level depending on compress_tree
|
|
"""
|
|
y_index = box.y_index(self.max_generations+1) -1
|
|
|
|
if self.compress_tree:
|
|
current_y = self.__y_level
|
|
if y_index > self.__last_y_level:
|
|
self.__last_y_level = y_index
|
|
self.__y_level += 1
|
|
current_y = self.__y_level
|
|
return current_y
|
|
else:
|
|
return y_index
|
|
|
|
def _place(self, box):
|
|
""" put the box in it's correct spot """
|
|
#1. cm_x
|
|
box.x_cm = self.rept_opts.littleoffset
|
|
box.x_cm += (box.level[0] *
|
|
(self.rept_opts.col_width + self.rept_opts.max_box_width))
|
|
#2. cm_y
|
|
box.y_cm = self.__next_y(box) * self.rept_opts.max_box_height
|
|
box.y_cm += self.y_offset
|
|
#if box.height < self.rept_opts.max_box_height:
|
|
# box.y_cm += ((self.rept_opts.max_box_height - box.height) /2)
|
|
|
|
def place(self):
|
|
""" step through boxes so they can be put in the right spot """
|
|
#prime the pump
|
|
self.__last_y_level = \
|
|
self.canvas.boxes[0].y_index(self.max_generations+1) -1
|
|
#go
|
|
for box in self.canvas.boxes:
|
|
self._place(box)
|
|
|
|
|
|
#------------------------------------------------------------------------
|
|
#
|
|
# class make_report
|
|
#
|
|
#------------------------------------------------------------------------
|
|
class MakeReport():
|
|
|
|
def __init__(self, dbase, doc, canvas,
|
|
font_normal, inlc_marr, compress_tree):
|
|
|
|
self.database = dbase
|
|
self.doc = doc
|
|
self.canvas = canvas
|
|
self.font_normal = font_normal
|
|
self.inlc_marr = inlc_marr
|
|
self.compress_tree = compress_tree
|
|
self.mother_ht = self.father_ht = 0
|
|
|
|
self.max_generations = 0
|
|
|
|
def get_height_width(self, box):
|
|
"""
|
|
obtain width information for each level (x)
|
|
obtain height information for each item
|
|
"""
|
|
|
|
self.canvas.set_box_height_width(box)
|
|
|
|
if box.width > self.doc.report_opts.max_box_width:
|
|
self.doc.report_opts.max_box_width = box.width #+ box.shadow
|
|
|
|
if box.level[1] > 0:
|
|
if box.level[1] % 2 == 0 and box.height > self.father_ht:
|
|
self.father_ht = box.height
|
|
elif box.level[1] % 2 == 1 and box.height > self.mother_ht:
|
|
self.mother_ht = box.height
|
|
|
|
tmp = log2(box.level[1])
|
|
if tmp > self.max_generations:
|
|
self.max_generations = tmp
|
|
|
|
def get_generations(self):
|
|
return self.max_generations
|
|
|
|
def start(self):
|
|
# 1.
|
|
#set the sizes for each box and get the max_generations.
|
|
self.father_ht = 0.0
|
|
self.mother_ht = 0.0
|
|
for box in self.canvas.boxes:
|
|
self.get_height_width(box)
|
|
|
|
if self.compress_tree and not self.inlc_marr:
|
|
self.doc.report_opts.max_box_height = \
|
|
min(self.father_ht, self.mother_ht)
|
|
else:
|
|
self.doc.report_opts.max_box_height = \
|
|
max(self.father_ht, self.mother_ht)
|
|
|
|
#At this point we know everything we need to make the report.
|
|
#Size of each column of people - self.rept_opt.box_width
|
|
#size of each column (or row) of lines - self.rept_opt.col_width
|
|
#size of each row - self.rept_opt.box_height
|
|
#go ahead and set it now.
|
|
for box in self.canvas.boxes:
|
|
box.width = self.doc.report_opts.max_box_width
|
|
|
|
# 2.
|
|
#setup the transform class to move around the boxes on the canvas
|
|
transform = RLTransform(self.canvas, self.doc.report_opts,
|
|
self.max_generations, self.compress_tree)
|
|
transform.place()
|
|
|
|
|
|
class GUIConnect():
|
|
""" This is a BORG object. There is ONLY one.
|
|
This give some common routines that EVERYONE can use like
|
|
get the value from a GUI variable
|
|
"""
|
|
|
|
__shared_state = {}
|
|
def __init__(self): #We are BORG!
|
|
self.__dict__ = self.__shared_state
|
|
|
|
def set__opts(self, options):
|
|
""" Set only once as we are BORG. """
|
|
self.__opts = options
|
|
|
|
def get_val(self, val):
|
|
""" Get a GUI value. """
|
|
return self.__opts.get_option_by_name(val).get_value()
|
|
|
|
def title_class(self, doc):
|
|
""" Return a class that holds the proper title based off of the
|
|
GUI options """
|
|
title_type = self.get_val('report_title')
|
|
return TitleA(doc) if title_type else TitleN(doc)
|
|
|
|
#------------------------------------------------------------------------
|
|
#
|
|
# AncestorTree
|
|
#
|
|
#------------------------------------------------------------------------
|
|
class AncestorTree2(Report):
|
|
|
|
def __init__(self, database, options_class):
|
|
"""
|
|
Create AncestorTree object that produces the report.
|
|
|
|
The arguments are:
|
|
|
|
database - the GRAMPS database instance
|
|
person - currently selected person
|
|
options_class - instance of the Options class for this report
|
|
|
|
This report needs the following parameters (class variables)
|
|
that come in the options class.
|
|
|
|
max_generations - Maximum number of generations to include.
|
|
pagebbg - Whether to include page breaks between generations.
|
|
dispf - Display format for the output box.
|
|
scale_report - Whether to scale the report to fit the width or all.
|
|
indblank - Whether to include blank pages.
|
|
compress - Whether to compress chart.
|
|
"""
|
|
Report.__init__(self, database, options_class)
|
|
|
|
self.connect = GUIConnect()
|
|
self.connect.set__opts(options_class.menu)
|
|
|
|
style_sheet = self.doc.get_style_sheet()
|
|
font_normal = style_sheet.get_paragraph_style("AC2-Normal").get_font()
|
|
self.doc.report_opts = ReportOptions(self.doc, font_normal)
|
|
|
|
self.canvas = Canvas(self.doc)
|
|
|
|
#make the tree into self.canvas
|
|
inlc_marr = self.connect.get_val('incmarr')
|
|
self.max_generations = self.connect.get_val('maxgen')
|
|
fillout = self.connect.get_val('fillout')
|
|
tree = MakeAncestorTree(database, self.canvas, self.max_generations,
|
|
inlc_marr, fillout)
|
|
tree.start(self.connect.get_val('pid'))
|
|
tree = None
|
|
|
|
#Title
|
|
title = self.connect.title_class(self.doc)
|
|
center = self.database.get_person_from_gramps_id(
|
|
self.connect.get_val('pid')
|
|
)
|
|
title.calc_title(center)
|
|
self.canvas.add_title(title)
|
|
|
|
#make the report as big as it wants to be.
|
|
compress = self.connect.get_val('compress')
|
|
report = MakeReport(database, self.doc, self.canvas, font_normal,
|
|
inlc_marr, compress)
|
|
report.start()
|
|
self.max_generations = report.get_generations() #already know
|
|
report = None
|
|
|
|
def begin_report(self):
|
|
"""
|
|
We have
|
|
1. a canvas in its full one-page size
|
|
2. a page that we wish to print on
|
|
scale up/down either or both of the above as needed/desired.
|
|
almost all of this should be moved into Canvas!
|
|
"""
|
|
|
|
if self.connect.get_val('use_note'):
|
|
note_box = NoteBox(self.doc, "AC2-fam-box",
|
|
self.connect.get_val('note_local'))
|
|
subst = SubstKeywords(self.database, None, None)
|
|
note_box.text = subst.replace_and_clean(
|
|
self.connect.get_val('note_disp'))
|
|
self.canvas.add_note(note_box)
|
|
|
|
one_page = self.connect.get_val('onepage')
|
|
scale_report = self.connect.get_val('scale_report')
|
|
|
|
scale = self.canvas.scale_report(one_page,
|
|
scale_report != 0, scale_report == 2)
|
|
if scale != 1:
|
|
self.scale_styles(scale)
|
|
|
|
def write_report(self):
|
|
|
|
one_page = self.connect.get_val('onepage')
|
|
#scale_report = self.connect.get_val('scale_report')
|
|
|
|
#inlc_marr = self.connect.get_val('incmarr')
|
|
inc_border = self.connect.get_val('inc_border')
|
|
incblank = self.connect.get_val('incblank')
|
|
prnnum = self.connect.get_val('prnnum')
|
|
|
|
#####################
|
|
#Setup page infomation
|
|
|
|
colsperpage = self.doc.get_usable_width()
|
|
colsperpage += self.doc.report_opts.col_width
|
|
colsperpage = int(colsperpage / (self.doc.report_opts.max_box_width +
|
|
self.doc.report_opts.col_width))
|
|
colsperpage = colsperpage or 1
|
|
|
|
#####################
|
|
#Vars
|
|
if prnnum:
|
|
page_num_box = PageNumberBox(self.doc, 'AC2-box')
|
|
|
|
#####################
|
|
#ok, everyone is now ready to print on the canvas. Paginate?
|
|
self.canvas.paginate(colsperpage, one_page)
|
|
|
|
#####################
|
|
#Yeah!!!
|
|
#lets finally make some pages!!!
|
|
#####################
|
|
for page in self.canvas.page_iter_gen(incblank):
|
|
|
|
self.doc.start_page()
|
|
|
|
#do we need to print a border?
|
|
if inc_border:
|
|
page.draw_border('AC2-line')
|
|
|
|
#Do we need to print the page number?
|
|
if prnnum:
|
|
page_num_box.display(page)
|
|
|
|
#Print the individual people and lines
|
|
page.display()
|
|
|
|
self.doc.end_page()
|
|
|
|
|
|
def scale_styles(self, scale):
|
|
"""
|
|
Scale the styles for this report.
|
|
"""
|
|
style_sheet = self.doc.get_style_sheet()
|
|
|
|
from gen.plug.docgen import GraphicsStyle
|
|
|
|
graph_style = style_sheet.get_draw_style("AC2-box")
|
|
graph_style.set_shadow(graph_style.get_shadow(),
|
|
graph_style.get_shadow_space() * scale)
|
|
graph_style.set_line_width(graph_style.get_line_width() * scale)
|
|
style_sheet.add_draw_style("AC2-box", graph_style)
|
|
|
|
graph_style = style_sheet.get_draw_style("AC2-fam-box")
|
|
graph_style.set_shadow(graph_style.get_shadow(),
|
|
graph_style.get_shadow_space() * scale)
|
|
graph_style.set_line_width(graph_style.get_line_width() * scale)
|
|
style_sheet.add_draw_style("AC2-fam-box", graph_style)
|
|
|
|
para_style = style_sheet.get_paragraph_style("AC2-Normal")
|
|
font = para_style.get_font()
|
|
font.set_size(font.get_size() * scale)
|
|
para_style.set_font(font)
|
|
style_sheet.add_paragraph_style("AC2-Normal", para_style)
|
|
|
|
para_style = style_sheet.get_paragraph_style("AC2-Title")
|
|
font = para_style.get_font()
|
|
font.set_size(font.get_size() * scale)
|
|
para_style.set_font(font)
|
|
style_sheet.add_paragraph_style("AC2-Title", para_style)
|
|
|
|
graph_style = GraphicsStyle()
|
|
width = graph_style.get_line_width()
|
|
width = width * scale
|
|
graph_style.set_line_width(width)
|
|
style_sheet.add_draw_style("AC2-line", graph_style)
|
|
|
|
self.doc.set_style_sheet(style_sheet)
|
|
|
|
#------------------------------------------------------------------------
|
|
#
|
|
# AncestorTreeOptions
|
|
#
|
|
#------------------------------------------------------------------------
|
|
class AncestorTree2Options(MenuReportOptions):
|
|
|
|
"""
|
|
Defines options and provides handling interface.
|
|
"""
|
|
|
|
def __init__(self, name, dbase):
|
|
MenuReportOptions.__init__(self, name, dbase)
|
|
|
|
def add_menu_options(self, menu):
|
|
|
|
category_name = _("Tree Options")
|
|
|
|
pid = PersonOption(_("Center Person"))
|
|
pid.set_help(_("The center person for the tree"))
|
|
menu.add_option(category_name, "pid", pid)
|
|
|
|
self.max_gen = NumberOption(_("Generations"), 10, 1, 50)
|
|
self.max_gen.set_help(_("The number of generations to include "
|
|
"in the tree"))
|
|
menu.add_option(category_name, "maxgen", self.max_gen)
|
|
|
|
self.fillout = EnumeratedListOption(_("Display unknown\ngenerations"),
|
|
0)
|
|
menu.add_option(category_name, "fillout", self.fillout)
|
|
|
|
self.max_gen.connect('value-changed', self.__fillout_vals)
|
|
self.__fillout_vals()
|
|
|
|
compress = BooleanOption(_('Co_mpress tree'), True)
|
|
compress.set_help(_("Whether to compress the tree."))
|
|
menu.add_option(category_name, "compress", compress)
|
|
|
|
#better to 'Show siblings of\nthe center person
|
|
#Spouse_disp = EnumeratedListOption(_("Show spouses of\nthe center "
|
|
# "person"), 0)
|
|
#Spouse_disp.add_item( 0, _("No. Do not show Spouses"))
|
|
#Spouse_disp.add_item( 1, _("Yes, and use the the Main Display Format"))
|
|
#Spouse_disp.add_item( 2, _("Yes, and use the the Secondary "
|
|
# "Display Format"))
|
|
#Spouse_disp.set_help(_("Show spouses of the center person?"))
|
|
#menu.add_option(category_name, "Spouse_disp", Spouse_disp)
|
|
|
|
category_name = _("Display")
|
|
|
|
disp = TextOption(_("Main\nDisplay Format"),
|
|
["$n","%s $b" % _BORN,"%s $d" %_DIED] )
|
|
disp.set_help(_("Display format for the output box."))
|
|
menu.add_option(category_name, "dispf", disp)
|
|
|
|
difMom = EnumeratedListOption(_("Use Main/Secondary\nDisplay "
|
|
"Format for"), 0)
|
|
difMom.add_item( 0, _("Everyone uses the Main Display format"))
|
|
difMom.add_item( 1, _("Mothers use Main, and Fathers use the "
|
|
"Secondary"))
|
|
difMom.add_item( 2, _("Fathers use Main, and Mothers use the "
|
|
"Secondary"))
|
|
difMom.set_help(_("Which Display format to use for Fathers and "
|
|
"Mothers"))
|
|
menu.add_option(category_name, "dif_sec", difMom)
|
|
|
|
#Will add when libsubstkeyword supports it.
|
|
#missing = EnumeratedListOption(_("Replace missing\nplaces\\dates \
|
|
# with"), 0)
|
|
#missing.add_item( 0, _("Does not display anything"))
|
|
#missing.add_item( 1, _("Displays '_____'"))
|
|
#missing.set_help(_("What will print when information is not known"))
|
|
#menu.add_option(category_name, "miss_val", missing)
|
|
|
|
category_name = _("Secondary")
|
|
|
|
dispMom = TextOption(_("Secondary\nDisplay Format"),
|
|
["$n","%s $b" % _BORN,
|
|
"%s $m" %_MARR,
|
|
"%s $d" %_DIED]
|
|
)
|
|
dispMom.set_help(_("Display format for the output box."))
|
|
menu.add_option(category_name, "disp_sec", dispMom)
|
|
|
|
incmarr = BooleanOption(_('Include Marriage information'), False)
|
|
incmarr.set_help(_("Whether to include marriage information in the "
|
|
"report."))
|
|
menu.add_option(category_name, "incmarr", incmarr)
|
|
|
|
marrdisp = StringOption(_("Marriage\nDisplay Format"), "%s $m" % _MARR)
|
|
marrdisp.set_help(_("Display format for the output box."))
|
|
menu.add_option(category_name, "dispmarr", marrdisp)
|
|
|
|
category_name = _("Print")
|
|
|
|
self.scale = EnumeratedListOption(_("Scale report to fit"), 0)
|
|
self.scale.add_item( 0, _("Do not scale report"))
|
|
self.scale.add_item( 1, _("Scale report to fit page width only"))
|
|
self.scale.add_item( 2, _("Scale report to fit the size of the page"))
|
|
self.scale.set_help(_("Whether to scale the report to fit a "
|
|
"specific size"))
|
|
menu.add_option(category_name, "scale_report", self.scale)
|
|
self.scale.connect('value-changed', self.__check_blank)
|
|
|
|
self.__onepage = BooleanOption(_('One page report'), True)
|
|
self.__onepage.set_help(_("Whether to scale the size of the page to "
|
|
"the size of the report."))
|
|
menu.add_option(category_name, "onepage", self.__onepage)
|
|
self.__onepage.connect('value-changed', self.__check_blank)
|
|
|
|
self.title = EnumeratedListOption(_("Report Title"), 0)
|
|
self.title.add_item( 0, "Do not print a Title")
|
|
self.title.add_item( 1, "Include Report Title")
|
|
menu.add_option(category_name, "report_title", self.title)
|
|
|
|
border = BooleanOption(_('Print a border'), True)
|
|
border.set_help(_("Whether to make a border around the report."))
|
|
menu.add_option(category_name, "inc_border", border)
|
|
|
|
prnnum = BooleanOption(_('Print Page Numbers'), False)
|
|
prnnum.set_help(_("Whether to print page numbers on each page."))
|
|
menu.add_option(category_name, "prnnum", prnnum)
|
|
|
|
self.__blank = BooleanOption(_('Include Blank Pages'), True)
|
|
self.__blank.set_help(_("Whether to include pages that are blank."))
|
|
menu.add_option(category_name, "incblank", self.__blank)
|
|
|
|
self.__check_blank()
|
|
|
|
category_name = _("Notes")
|
|
|
|
self.usenote = BooleanOption(_('Include a personal note'), False)
|
|
self.usenote.set_help(_("Whether to include a personalized note on "
|
|
"the report."))
|
|
menu.add_option(category_name, "use_note", self.usenote)
|
|
|
|
self.notedisp = TextOption(_("Note to add\nto the graph\n\n$T "
|
|
"inserts today's date"), [])
|
|
self.notedisp.set_help(_("Add a personal note"))
|
|
menu.add_option(category_name, "note_disp", self.notedisp)
|
|
|
|
locals = NoteType(0, 1)
|
|
notelocal = EnumeratedListOption(_("Note Location"), 0)
|
|
for num, text in locals.note_locals():
|
|
notelocal.add_item( num, text )
|
|
notelocal.set_help(_("Where to place a personal note."))
|
|
menu.add_option(category_name, "note_local", notelocal)
|
|
|
|
def __check_blank(self):
|
|
off = not self.__onepage.get_value() and (self.scale.get_value() != 2)
|
|
self.__blank.set_available( off )
|
|
|
|
def __fillout_vals(self):
|
|
max_gen = self.max_gen.get_value()
|
|
old_val = self.fillout.get_value()
|
|
item_list = []
|
|
item_list.append([0, _("No generations of empty boxes "
|
|
"for unknown ancestors") ])
|
|
if max_gen > 1:
|
|
item_list.append([1, _("One Generation of empty boxes "
|
|
"for unknown ancestors") ])
|
|
|
|
item_list.extend([itr, str(itr) +
|
|
_(" Generations of empty boxes for unknown ancestors")]
|
|
for itr in range(2, max_gen)
|
|
)
|
|
|
|
self.fillout.set_items(item_list)
|
|
if old_val+2 > len(item_list):
|
|
self.fillout.set_value(len(item_list) -2)
|
|
|
|
|
|
def make_default_style(self, default_style):
|
|
"""Make the default output style for the Ancestor Tree."""
|
|
|
|
from gen.plug.docgen import (FontStyle, ParagraphStyle, GraphicsStyle,
|
|
FONT_SANS_SERIF, PARA_ALIGN_CENTER)
|
|
|
|
## Paragraph Styles:
|
|
font = FontStyle()
|
|
font.set_size(9)
|
|
font.set_type_face(FONT_SANS_SERIF)
|
|
para_style = ParagraphStyle()
|
|
para_style.set_font(font)
|
|
para_style.set_description(_('The basic style used for the '
|
|
'text display.'))
|
|
default_style.add_paragraph_style("AC2-Normal", para_style)
|
|
box_shadow = PT2CM(font.get_size()) * .6
|
|
|
|
font = FontStyle()
|
|
font.set_size(16)
|
|
font.set_type_face(FONT_SANS_SERIF)
|
|
para_style = ParagraphStyle()
|
|
para_style.set_font(font)
|
|
para_style.set_alignment(PARA_ALIGN_CENTER)
|
|
para_style.set_description(_('The basic style used for the '
|
|
'title display.'))
|
|
default_style.add_paragraph_style("AC2-Title", para_style)
|
|
|
|
## Draw styles
|
|
graph_style = GraphicsStyle()
|
|
graph_style.set_paragraph_style("AC2-Normal")
|
|
graph_style.set_shadow(1, box_shadow) #shadow set by text size
|
|
graph_style.set_fill_color((255, 255, 255))
|
|
default_style.add_draw_style("AC2-box", graph_style)
|
|
|
|
graph_style = GraphicsStyle()
|
|
graph_style.set_paragraph_style("AC2-Normal")
|
|
#graph_style.set_shadow(0, PT2CM(9)) #shadow set by text size
|
|
graph_style.set_fill_color((255, 255, 255))
|
|
default_style.add_draw_style("AC2-fam-box", graph_style)
|
|
|
|
graph_style = GraphicsStyle()
|
|
graph_style.set_paragraph_style("AC2-Title")
|
|
graph_style.set_color((0, 0, 0))
|
|
graph_style.set_fill_color((255, 255, 255))
|
|
graph_style.set_line_width(0)
|
|
default_style.add_draw_style("AC2-Title", graph_style)
|
|
|
|
graph_style = GraphicsStyle()
|
|
default_style.add_draw_style("AC2-line", graph_style)
|
|
|
|
#=====================================
|
|
#But even if you should suffer for what is right, you are blessed.
|
|
#"Do not fear what they fear ; do not be frightened."
|
|
#Take Courage
|
|
#1 Peter 3:14
|