In this commit:

Update Ancestor report
Updated Descendant report
new Family Descendant report

new docs for these reports are found at
http://www.gramps-project.org/wiki/index.php?title=User:Ander882

included into trunk for hopeful inclusion into 3.3



svn: r16348
This commit is contained in:
Craig J. Anderson 2011-01-07 16:11:17 +00:00
parent fa90e31ac2
commit df9825821b
6 changed files with 3252 additions and 821 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -36,11 +36,11 @@ plg.gramps_target_version = '3.3'
plg.status = STABLE plg.status = STABLE
plg.fname = 'AncestorTree.py' plg.fname = 'AncestorTree.py'
plg.ptype = REPORT plg.ptype = REPORT
plg.authors = ["Donald N. Allingham"] plg.authors = ["Craig J. Anderson"]
plg.authors_email = ["don@gramps-project.org"] plg.authors_email = ["ander882@gramps-project.org"]
plg.category = CATEGORY_DRAW plg.category = CATEGORY_DRAW
plg.reportclass = 'AncestorTree' plg.reportclass = 'AncestorTree2'
plg.optionclass = 'AncestorTreeOptions' plg.optionclass = 'AncestorTree2Options'
plg.report_modes = [REPORT_MODE_GUI, REPORT_MODE_BKI, REPORT_MODE_CLI] plg.report_modes = [REPORT_MODE_GUI, REPORT_MODE_BKI, REPORT_MODE_CLI]
#------------------------------------------------------------------------ #------------------------------------------------------------------------
@ -80,11 +80,34 @@ plg.gramps_target_version = '3.3'
plg.status = STABLE plg.status = STABLE
plg.fname = 'DescendTree.py' plg.fname = 'DescendTree.py'
plg.ptype = REPORT plg.ptype = REPORT
plg.authors = ["Donald N. Allingham"] plg.authors = ["Craig J. Anderson"]
plg.authors_email = ["don@gramps-project.org"] plg.authors_email = ["ander882@gramps-project.org"]
plg.category = CATEGORY_DRAW plg.category = CATEGORY_DRAW
plg.reportclass = 'DescendTree' plg.reportclass = 'Descend2Tree'
plg.optionclass = 'DescendTreeOptions' plg.optionclass = 'Descend2TreeOptions'
plg.report_modes = [REPORT_MODE_GUI, REPORT_MODE_BKI, REPORT_MODE_CLI]
#------------------------------------------------------------------------
#
# Family Descendant Tree
#
#------------------------------------------------------------------------
plg = newplugin()
plg.id = 'family_descend_chart'
plg.name = _("Family Descendant Tree")
plg.description = _("Produces a graphical descendant tree around a family")
plg.version = '1.0'
plg.status = STABLE
plg.fname = 'DescendTree.py'
plg.ptype = REPORT
plg.category = CATEGORY_DRAW
plg.gramps_target_version = '3.3'
plg.authors = ["Craig J. Anderson"]
plg.authors_email = ["ander882@gramps-project.org"]
plg.require_active = True
plg.reportclass = 'Descend2Tree'
plg.optionclass = 'Descend2TreeOptions'
plg.report_modes = [REPORT_MODE_GUI, REPORT_MODE_BKI, REPORT_MODE_CLI] plg.report_modes = [REPORT_MODE_GUI, REPORT_MODE_BKI, REPORT_MODE_CLI]
#------------------------------------------------------------------------ #------------------------------------------------------------------------

View File

@ -26,13 +26,14 @@ pkgdata_PYTHON = \
libholiday.py\ libholiday.py\
libmapservice.py\ libmapservice.py\
libmixin.py\ libmixin.py\
libnarrate.py\ libnarrate.py\
libodfbackend.py\ libodfbackend.py\
libpersonview.py\ libpersonview.py\
libplaceview.py\ libplaceview.py\
libplugins.gpr.py\ libplugins.gpr.py\
libsubstkeyword.py\ libsubstkeyword.py\
libtranslate.py libtranslate.py\
libtreebase.py
pkgpyexecdir = @pkgpyexecdir@/plugins/lib pkgpyexecdir = @pkgpyexecdir@/plugins/lib
pkgpythondir = @pkgpythondir@/plugins/lib pkgpythondir = @pkgpythondir@/plugins/lib

View File

@ -302,4 +302,21 @@ fname = 'libsubstkeyword.py',
authors = ["The Gramps project"], authors = ["The Gramps project"],
authors_email = ["http://gramps-project.org"], authors_email = ["http://gramps-project.org"],
) )
#------------------------------------------------------------------------
#
# libtreebase
#
#------------------------------------------------------------------------
register(GENERAL,
id = 'libtreebase',
name = "Graphical report lib",
description = _("Provides the base needed for the ancestor and " +
"descendant graphical reports.") ,
version = '1.0',
gramps_target_version = '3.3',
status = STABLE,
fname = 'libtreebase.py',
authors = ["The Gramps project"],
authors_email = ["http://gramps-project.org"],
)

View File

@ -0,0 +1,874 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2008-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: Descendant.py .... ander882 $
"""Reports/Graphical Reports/Tree_Base"""
#------------------------------------------------------------------------
#
# python modules
#
#------------------------------------------------------------------------
from gen.ggettext import sgettext as _
from gen.plug.report import utils as ReportUtils
from gen.display.name import displayer as name_displayer
from libsubstkeyword import SubstKeywords
PT2CM = ReportUtils.pt2cm
#------------------------------------------------------------------------
#
# Class Calc_Lines
#
#------------------------------------------------------------------------
class CalcLines(object):
""" wrapper for libsubstkeyword and added functionality for
replacements.
Receive: Individual and family handle, and display format [string]
return: [Text] ready for a box.
"""
def __init__(self, dbase, repl):
self.database = dbase
self.display_repl = repl
#self.default_string = default_str
def calc_lines(self, _indi_handle, _fams_handle, workinglines):
"""
In this pass we will:
1. make our text and do our replacements
2. remove any extra (unwanted) lines with the compres option
"""
####################
#1.1 Get our line information here
subst = SubstKeywords(self.database, _indi_handle, _fams_handle)
lines = subst.replace_and_clean(workinglines)
####################
#1.2 do our replacements
lns = []
for line in lines:
for pair in self.display_repl:
if pair.count("/") == 1:
repl = pair.split("/", 1)
line = line.replace(repl[0], repl[1])
lns.append(line)
return lns
#------------------------------------------------------------------------
#
# Class Canvas/Pages
#
#------------------------------------------------------------------------
class Page(object):
""" This class is a printable page.
Offsets from the canvas, Page numbers
boxes and lines
"""
def __init__(self, doc, canvas):
#parts from canvas
self.doc = doc
self.canvas = canvas
#parts about the page
self.page_x_offset = 0
self.page_y_offset = 0
self.x_page_num = 0
self.y_page_num = 0
self.boxes = [] #All object must derive from BoxBase
self.lines = [] #All must derive form Linebase
self.note = None
def is_blank(self):
""" Am I a blank page? Notes and Titles are boxes too """
return self.boxes == [] and self.lines == []
def add_box(self, box):
""" The box must derive from class Box_Base(Object): """
self.boxes.append(box)
box.doc = self.doc
box.page = self
def add_line(self, line):
""" Add a line onto this page """
self.lines.append(line)
def draw_border(self, line_name):
if self.y_page_num == 0:
self.doc.draw_line(line_name, 0, 0,
self.doc.get_usable_width(), 0)
if self.x_page_num == 0:
self.doc.draw_line(line_name, 0, 0, 0,
self.doc.get_usable_height())
if self.y_page_num == self.canvas.y_pages-1:
self.doc.draw_line(line_name, 0,
self.doc.get_usable_height(),
self.doc.get_usable_width(),
self.doc.get_usable_height())
if self.x_page_num == self.canvas.x_pages-1:
self.doc.draw_line(line_name, self.doc.get_usable_width(),
0, self.doc.get_usable_width(),
self.doc.get_usable_height())
def display(self):
""" Display all boxes and lines that are on this page """
for box in self.boxes:
box.display()
for line in self.lines:
line.display(self)
class Canvas(Page):
""" The Canvas is two things.
The all in one canvas. a canvas is a page of unlimited size
a group of pages. each page is set is size and shows only a
part of what is on the entire canvas
"""
def __init__(self, doc):
Page.__init__(self, doc, self)
self.doc = doc
self.report_opts = None
#How many pages are there in the report. one more than real.
self.x_pages = 1
self.y_pages = 1
self.__pages = {(0, 0): self} #set page 0,0 to me.
self.__fonts = {} #keep a list of fonts so we don't have to lookup.
self.title = None
self.note = None
def __new_page(self, x_page, y_page, x_offset, y_offset):
""" Make a new page. This will only happen if we are
paginating (making new pages to hold parts of the canvas) """
if x_page >= self.x_pages:
self.x_pages = x_page + 1
new_page = Page(self.doc, self)
new_page.x_page_num = x_page
new_page.y_page_num = y_page
new_page.page_x_offset = x_offset
new_page.page_y_offset = y_offset
self.__pages[x_page, y_page] = new_page
return new_page
def sort_boxes_on_y_cm(self):
""" sorts the list of boxes on the canvas by .y_cm (top down) """
self.boxes.sort( key=lambda box: box.y_cm)
def add_title(self, title):
""" The title must derive from class TitleBox(BoxBase): """
self.title = title
def add_note(self, note):
""" The note must derive from class NoteBox(BoxBase, NoteType) """
self.note = note
self.set_box_height_width(self.note)
def __get_font(self, box):
""" returns the font used by a box. makes a list of all seen fonts
to be faster. If a new is found, run through the process to get it """
if not self.__fonts.has_key(box.boxstr):
style_sheet = self.doc.get_style_sheet()
style_name = style_sheet.get_draw_style(box.boxstr)
style_name = style_name.get_paragraph_style()
self.__fonts[box.boxstr] = \
style_sheet.get_paragraph_style(style_name).get_font()
return self.__fonts[box.boxstr]
def get_report_height_width(self):
""" returns the (max width, max height) of the report
This does not take into account any shadows """
max_width = 0
max_height = 0
for box in self.boxes:
tmp = box.x_cm + box.width + box.shadow
if tmp > max_width:
max_width = tmp
tmp = box.y_cm + box.height + box.shadow
if tmp > max_height:
max_height = tmp
return (max_width, max_height)
def __scale_canvas(self, scale_amount):
""" scales everything up/down depending upon scale_amount """
self.doc.report_opts.scale_everything(scale_amount)
self.title.scale(scale_amount)
if self.note is not None:
self.note.scale(scale_amount)
#scale down everyone!
for box in self.boxes:
box.scale(scale_amount)
def set_box_height_width(self, box):
""" Sets the .width .height and .shadow of a box. """
if box.boxstr == "None":
box.height = box.width = 0
return
font = self.__get_font(box)
#####################
#Get the width
for line in box.text:
width = self.doc.string_width(font, line)
width = PT2CM(width)
if width > box.width:
box.width = width
#####################
#Get the height
height = len(box.text) * font.get_size() * 1.5
height += 1.0/2.0 * font.get_size() #funny number(s) based upon font.
box.height = PT2CM(height)
style_sheet = self.doc.get_style_sheet()
style = style_sheet.get_draw_style(box.boxstr)
if style.get_shadow():
box.shadow = style.get_shadow_space()
def page_iter_gen(self, incblank):
""" generate the pages of the report. do so in a left to right
up down approach. incblank asks to include blank pages """
blank = Page(self.doc, self)
for y_p in range(self.y_pages):
for x_p in range(self.x_pages):
if self.__pages.has_key((x_p, y_p)):
yield self.__pages[(x_p, y_p)]
else:
if incblank:
blank.x_page_num = x_p
blank.y_page_num = y_p
yield blank
def __add_box_to_page(self, x_page, y_page, x_offset, y_offset, box):
""" adds a box to a page. If the page is not there, make it first """
if not self.__pages.has_key((x_page, y_page)):
#Add the new page into the dictionary
self.__new_page(x_page, y_page, x_offset, y_offset)
#Add the box into the page
self.__pages[x_page, self.y_pages-1].add_box(box)
def scale_report(self, one_page, scale_to_width, scale_to_height):
""" We have a report in its full size (on the canvas
and pages to print on. scale one or both as needed/desired.
- one_page, boolean. Whether to make the page(or parts of) the size
of the report
- scale_to_width, boolean. Scale the report width to the page size?
- scale_to_height, boolean. Scale the report height to page size?
"""
if scale_to_width or scale_to_height:
max_width, max_height = self.canvas.get_report_height_width()
max_width += self.doc.report_opts.littleoffset
max_height += self.doc.report_opts.littleoffset
"""
calc - Calculate the scale amount (if any).
<1 everything is smaller to fit on the page
1 == no scaling
>1 make everything bigger to fill out the page
"""
scale = 1
scaled_report_to = None
#####################
#scale the report option - width
if scale_to_width:
#Check the width of the title
title_width = self.title.width
title_width += self.doc.report_opts.littleoffset * 2
max_width = max(title_width, max_width)
#This will be our base amount and
#then we will decrease only as needed from here.
scale = self.doc.get_usable_width() / max_width
scaled_report_to = "width"
#####################
#scale the report option - height
if scale_to_height:
tmp = self.doc.get_usable_height() / max_height
if not scale_to_width or tmp < scale:
scale = tmp
scaled_report_to = "height"
#Now I have the scale amount
if scale != 1: #scale everything on the canvas
self.__scale_canvas(scale)
#####################
#Scale the page option
if one_page:
#user wants PAGE to be the size of the report.
size = self.doc.paper.get_size()
max_width, max_height = \
self.canvas.get_report_height_width()
if scaled_report_to != "width":
#calculate the width of the report
max_width += self.doc.report_opts.littleoffset
max_width += self.doc.paper.get_left_margin()
max_width += self.doc.paper.get_right_margin()
#calculate the width of the title
title_width = self.canvas.title.width
title_width += self.doc.paper.get_left_margin()
title_width += self.doc.paper.get_right_margin()
title_width += self.doc.report_opts.littleoffset
max_width = max(title_width, max_width)
size.set_width(max_width)
if scaled_report_to != "height":
#calculate the height of the report
max_height += self.doc.paper.get_top_margin()
max_height += self.doc.paper.get_bottom_margin()
max_height += self.doc.report_opts.littleoffset
size.set_height(max_height)
return scale
def __paginate_x_offsets(self, colsperpage):
""" Go through the boxes and get the x page offsets """
#fix soon. should not use .level
liloffset = self.doc.report_opts.littleoffset
x_page_offsets = {0:0} #change me to [] ???
for box in self.boxes:
x_index = box.level[0]
x_page = x_index / colsperpage
if x_page not in x_page_offsets and x_index % colsperpage == 0:
x_page_offsets[x_page] = box.x_cm - liloffset
if x_page >= self.x_pages:
self.x_pages = x_page+1
return x_page_offsets
def __paginate_y_pages(self, colsperpage, x_page_offsets):
""" Go through the boxes and put each one in a page
note that the self.boxes needs to be sorted by .y_cm """
page_y_top = [0]
page_y_height = [self.doc.get_usable_height()]
liloffset = self.doc.report_opts.littleoffset
for box in self.boxes:
#check to see if this box cross over to the next (y) page
height = box.y_cm + liloffset + box.height + box.shadow/2
if height > page_y_height[-1]:
#we went off the end
page_y_height.append(box.y_cm - liloffset + page_y_height[0])
page_y_top.append(box.y_cm - liloffset)
self.y_pages = len(page_y_height)
#Calculate my (x) page
#fix soon. should not use .level
x_page = box.level[0] / colsperpage
self.__add_box_to_page(x_page, self.y_pages-1,
x_page_offsets[x_page],
page_y_top[self.y_pages-1],
box)
#if not self.__pages.has_key((x_page, self.y_pages-1)):
# #Add the new page into the dictionary
# self.__new_page(x_page, self.y_pages-1,
# )
#
##Add the box into the page
#self.__pages[x_page, self.y_pages-1].add_box(box)
return page_y_top
def __paginate_note(self, x_page_offsets, page_y_top):
""" Put the note on first. it can be overwritten by other
boxes but it CAN NOT overwrite a box. """
x_page, y_page = self.note.set_on_page(self)
if not self.__pages.has_key((x_page, y_page)):
#Add the new page into the dictionary
self.__new_page(x_page, y_page,
x_page_offsets[x_page], page_y_top[y_page])
#Add the box into the page
self.__pages[x_page, y_page].boxes.insert(0, self.note)
self.note.doc = self.doc
self.note.page = self
def __paginate_lines(self, x_page_offsets, page_y_top):
""" Step three go through the lines and put each in page(s) """
for line in self.lines:
pages = []
#if type(line.start) == type([]):
pages = []
end = line.start + line.end
#else:
# end = [line.start] + line.end
# pages = []
start_x_page = end[0].page.x_page_num
start_y_page = end[0].page.y_page_num
end_y_page = end[0].page.y_page_num
for box in end:
x_page = box.page.x_page_num
y_page = box.page.y_page_num
if (x_page, y_page) not in pages:
if not self.__pages.has_key((x_page, y_page)):
#Add the new page into the dictionary
self.__new_page(x_page, y_page,
x_page_offsets[x_page],
page_y_top[y_page])
self.__pages[x_page, y_page].add_line(line)
pages.append((x_page, y_page))
if y_page < start_y_page:
start_y_page = y_page
if y_page > end_y_page:
end_y_page = y_page
#if len(end) = 2 & end[0].y_page = 0 & end[1].y_page = 4
#the line will not print on y_pages 1,2,3. Fix that here.
x_page = start_x_page
for y_page in range(start_y_page, end_y_page+1):
if (x_page, y_page) not in pages:
if not self.__pages.has_key((x_page, y_page)):
#Add the new page into the dictionary
self.__new_page(x_page, y_page,
x_page_offsets[x_page],
page_y_top[y_page])
self.__pages[x_page, y_page].add_line(line)
def __paginate_title(self, x_page_offsets):
#step four work with the title
if self.title.boxstr == "None":
return
#x_page_offsets[page] tells me the widths I can use
if len(x_page_offsets) > 1:
title_list = self.title.text.split(" ")
title_font = self.__get_font(self.title)
#space_width = PT2CM(self.doc.string_width(title_font," "))
list_title = [title_list.pop(0)]
while len(title_list):
tmp = list_title[-1] + " " + title_list[0]
if PT2CM(self.doc.string_width(title_font, tmp)) > \
x_page_offsets[1]:
list_title.append("")
if list_title[-1] != "":
list_title[-1] += " "
list_title[-1] += title_list.pop(0)
start_page = (len(x_page_offsets) - len(list_title)) / 2
for tmp in range(start_page):
list_title.insert(0, "")
list_title.append("")
list_title.append("") #one extra for security. doesn't hurt.
x_page = 0
for title in list_title:
if title == "":
x_page += 1
continue
if not self.__pages.has_key((x_page, 0)):
#Add the new page into the dictionary
self.__new_page(x_page, 0, x_page_offsets[1], 0)
title_part = TitleBox(self.doc, self.title.boxstr)
title_part.text = list_title[x_page]
title_part.width = x_page_offsets[1]
#Add the box into the page
self.__pages[x_page, 0].add_box(title_part)
x_page = x_page + 1
else:
self.title.width = self.doc.get_usable_width()
self.__pages[0, 0].add_box(self.title)
def __paginate(self, colsperpage):
""" take the boxes on the canvas and put them into separate pages.
The boxes need to be sorted by y_cm """
liloffset = self.doc.report_opts.littleoffset
self.__pages = {}
x_page_offsets = self.__paginate_x_offsets(colsperpage)
page_y_top = self.__paginate_y_pages(colsperpage, x_page_offsets)
if self.note is not None:
self.__paginate_note(x_page_offsets, page_y_top)
self.__paginate_lines(x_page_offsets, page_y_top)
self.__paginate_title(x_page_offsets)
def paginate(self, colsperpage, one_page_report):
""" self.boxes must be sorted by box.y_cm for this to work. """
if one_page_report:
#self.canvas.add_box(self.canvas.title)
title_part = TitleBox(self.doc, self.title.boxstr)
title_part.text = self.title.text
title_part.width = self.doc.get_usable_width()
self.add_box(title_part)
if self.note is not None:
self.note.set_on_page(self)
self.boxes.insert(0, self.note)
self.note.doc = self.doc
self.note.page = self
else:
self.__paginate(colsperpage)
#------------------------------------------------------------------------
#
# Class Box_Base
#
#------------------------------------------------------------------------
class BoxBase(object):
""" boxes are always in/on a Page
Needed to print are: boxstr, text, x_cm, y_cm, width, height
"""
def __init__(self):
self.page = None
#'None' will cause an error. Sub-classes will init
self.boxstr = "None"
self.text = ""
self.level = (0,) #which column/level am I in? int zero based.
self.x_cm = 0.0
self.y_cm = 0.0
self.width = 0.0
self.height = 0.0
self.shadow = 0.0
def scale(self, scale_amount):
""" Scale the amounts """
self.x_cm *= scale_amount
self.y_cm *= scale_amount
self.width *= scale_amount
self.height *= scale_amount
self.shadow *= scale_amount
def display(self):
""" display the box accounting for page x, y offsets
Ignore any box with 'None' is boxstr """
if self.boxstr != "None":
text = '\n'.join(self.text)
xbegin = self.x_cm - self.page.page_x_offset
ybegin = self.y_cm - self.page.page_y_offset
self.page.doc.draw_box(self.boxstr,
text,
xbegin, ybegin,
self.width, self.height)
class TitleBox(BoxBase):
"""
Holds information about the Title that will print on a page
"""
def __init__(self, doc, boxstr):
""" initalize the title box """
BoxBase.__init__(self)
self.doc = doc
self.boxstr = boxstr
if boxstr == "None":
return
self.cm_y = self.doc.report_opts.littleoffset
style_sheet = self.doc.get_style_sheet()
style_name = style_sheet.get_draw_style(self.boxstr)
style_name = style_name.get_paragraph_style()
self.font = style_sheet.get_paragraph_style(style_name).get_font()
def set_box_height_width(self):
if self.boxstr == "None":
return
#fix me. width should be the printable area
self.width = PT2CM(self.doc.string_width(self.font, self.text))
self.height = PT2CM(self.font.get_size() * 1.2)
def _get_names(self, persons):
""" A helper function that receives a list of persons and
returns their names in a list """
tmp = []
for person in persons:
tmp.append(name_displayer.display(person))
return tmp
def display(self):
""" display the title box. """
if self.page.y_page_num != 0 or self.boxstr == "None":
return
if self.text != "":
self.doc.center_text(self.boxstr, self.text,
self.width/2, self.y_cm)
class PageNumberBox(BoxBase):
"""
Calculates information about the page numbers that will print on a page
do not put in a value for PageNumberBox.text. this will be calculated for
each page """
def __init__(self, doc, boxstr):
""" initalize the page number box """
BoxBase.__init__(self)
self.doc = doc
self.boxstr = boxstr
def __calc_position(self, page):
""" calculate where I am to print on the page(s) """
self.text = "(%d,%d)"
style_sheet = self.doc.get_style_sheet()
style_name = style_sheet.get_draw_style(self.boxstr)
style_name = style_name.get_paragraph_style()
font = style_sheet.get_paragraph_style(style_name).get_font()
#calcualate how much space is needed
if page.canvas.x_pages > 10:
tmp = "00"
else:
tmp = "0"
if page.canvas.y_pages > 10:
tmp += "00"
else:
tmp += "0"
width = self.doc.string_width(font, '(,)'+tmp)
width = PT2CM(width)
self.width = width
height = font.get_size() * 1.4
height += 0.5/2.0 * font.get_size() #funny number(s) based upon font.
self.height = PT2CM(height)
self.x_cm = self.doc.get_usable_width() - self.width
self.y_cm = self.doc.get_usable_height() - self.height
def display(self, page):
""" If this is the first time I am ran, get my position
then display the page number """
if self.text == "":
self.__calc_position(page)
self.doc.draw_text(self.boxstr,
self.text % (page.x_page_num+1,page.y_page_num+1),
self.x_cm, self.y_cm)
class NoteType(object):
""" Provide the different options (corners) to place the note """
TOPLEFT = 0
TOPRIGHT = 1
BOTTOMLEFT = 2
BOTTOMRIGHT = 3
_DEFAULT = BOTTOMRIGHT
_DATAMAP = [
(TOPLEFT, _("Top Left"), "Top Left"),
(TOPRIGHT, _("Top Right"), "Top Right"),
(BOTTOMLEFT, _("Bottom Left"), "Bottom Left"),
(BOTTOMRIGHT, _("Bottom Right"), "Bottom Right"),
]
def __init__(self, value, exclude=None):
""" initalize GrampsType """
self.value = value
self.exclude = exclude
#GrampsType.__init__(self, value)
def note_locals(self, start=0):
""" generates an int of all the options """
for tuple in self._DATAMAP:
if tuple[0] != self.exclude:
yield tuple[0], tuple[1]
class NoteBox(BoxBase, NoteType):
""" Box that will hold the note to display on the page """
def __init__(self, doc, boxstr, locale, exclude=None):
""" initalize the NoteBox """
BoxBase.__init__(self)
NoteType.__init__(self, locale, exclude)
self.doc = doc
self.boxstr = boxstr
def set_on_page(self, canvas):
""" set the x_cm and y_cm given
self.doc, leloffset, and title_height """
liloffset = self.doc.report_opts.littleoffset
#left or right side
if self.value == NoteType.BOTTOMLEFT or \
self.value == NoteType.TOPLEFT:
self.x_cm = liloffset
else:
self.x_cm = self.doc.get_usable_width() - self.width - liloffset
#top or bottom
if self.value == NoteType.TOPRIGHT or \
self.value == NoteType.TOPLEFT:
self.y_cm = canvas.title.height + liloffset*2
else:
self.y_cm = self.doc.get_usable_height() - self.height - liloffset
""" helper function for canvas.paginate().
return the (x, y) page I want to print on """
if self.value == NoteType.TOPLEFT:
return (0, 0)
elif self.value == NoteType.TOPRIGHT:
return (canvas.x_pages-1, 0)
elif self.value == NoteType.BOTTOMLEFT:
return (0, canvas.y_pages-1)
elif self.value == NoteType.BOTTOMRIGHT:
return (canvas.x_pages-1, canvas.y_pages-1)
def display(self):
""" position the box and display """
title = self.page.canvas.title
title_height = 0
if title is not None:
title_height = title.height
text = '\n'.join(self.text)
self.doc.draw_box(self.boxstr, text,
self.x_cm, self.y_cm,
self.width, self.height)
#------------------------------------------------------------------------
#
# Class Line_base
#
#------------------------------------------------------------------------
class LineBase(object):
""" A simple line class.
self.start is the box that we are drawing a line from
self.end are the boxes that we are drawing lines to.
"""
def __init__(self, start):
self.linestr = "None"
self.start = [start]
self.end = []
def add_to(self, person):
""" add destination boxes to draw this line to """
self.end.append(person)
def display(self, page):
""" display the line. left to right line. one start, multiple end.
page will tell us what parts of the line we can print """
if self.end == []:
return
# y_cm and x_cm start points - take into account page offsets
#yme = self.start.y_cm + self.start.height/2 - page.page_y_offset
#if type(self.start) != type([]):
# self.start = [self.start]
start = self.start[0]
xbegin = start.x_cm + start.width - page.page_x_offset
# out 3/4 of the way and x_cm end point(s)
x34 = xbegin + (start.doc.report_opts.col_width * 3/4)
xend = xbegin + start.doc.report_opts.col_width
if x34 > 0: # > 0 tell us we are printing on this page.
usable_height = start.doc.get_usable_height()
#1 - Line from start box out
for box in self.start:
yme = box.y_cm + box.height/2 - page.page_y_offset
if box.page.y_page_num == page.y_page_num:
# and 0 < yme < usable_height and \
start.doc.draw_line(self.linestr, xbegin, yme, x34, yme)
#2 - veritcal line
mid = []
for box in self.start + self.end:
tmp = box.y_cm + box.height/2
mid.append(tmp)
mid.sort()
mid = [mid[0]-page.page_y_offset, mid[-1]-page.page_y_offset]
if mid[0] < 0:
mid[0] = 0
if mid[1] > usable_height:
mid[1] = usable_height
#draw the connecting vertical line.
start.doc.draw_line(self.linestr, x34, mid[0], x34, mid[1])
else:
x34 = 0
#3 - horizontal line(s)
for box in self.end:
if box.page.y_page_num == page.y_page_num:
yme = box.y_cm + box.height/2 - box.page.page_y_offset
start.doc.draw_line(self.linestr, x34, yme, xend, yme)
#------------------------------------------------------------------------
#
# Class report_options
#
#------------------------------------------------------------------------
class ReportOptions(object):
"""
A simple class to hold various report information
Calculates
the gap between persons,
the column width, for lines,
the left hand spacing for spouses (Descendant report only)
"""
def __init__(self, doc, normal_font):
""" initalize various report variables that are used """
self.box_pgap = PT2CM(1.25*normal_font.get_size()) #gap between persons
self.box_mgap = self.box_pgap /2 #gap between marriage information
self.box_shadow = PT2CM(9) #size of normal text
self.spouse_offset = PT2CM(doc.string_width(normal_font, "0"))
self.col_width = PT2CM(doc.string_width(normal_font, "(000,0)"))
self.littleoffset = PT2CM(1)
#Things that will get added later
self.max_box_width = 0
self.max_box_height = 0
self.scale = 1
def scale_everything(self, amount):
""" Scale the amounts that are needed to generate a report """
self.scale = amount
self.col_width *= amount
self.littleoffset *= amount
self.max_box_width *= amount #box_width
self.spouse_offset *= amount
self.box_shadow *= amount
#=====================================
#"And Jesus said unto them ... , "If ye have faith as a grain of mustard
#seed, ye shall say unto this mountain, Remove hence to younder place; and
#it shall remove; and nothing shall be impossible to you."
#Romans 1:17