increase pylint score of fanchart report from 4.47 to 9.40

This commit is contained in:
Paul Franklin
2016-05-25 12:29:44 -07:00
parent 7ea7850331
commit ffd58ccd9f

View File

@ -23,6 +23,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# #
""" fanchart report """
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
# python modules # python modules
@ -76,9 +78,6 @@ RADIAL_ROUNDABOUT = 1
# to not a bit offset between the text and the polygon # to not a bit offset between the text and the polygon
# this can be considered as a bad hack # this can be considered as a bad hack
WEDGE_TEXT_BARRE_OFFSET = 0.0016 WEDGE_TEXT_BARRE_OFFSET = 0.0016
pt2cm = utils.pt2cm
cal = config.get('preferences.calendar-format-report')
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -93,7 +92,7 @@ def draw_wedge(doc, style, centerx, centery, radius, start_angle,
while end_angle < start_angle: while end_angle < start_angle:
end_angle += 360 end_angle += 360
p = [] path = []
degreestoradians = pi / 180.0 degreestoradians = pi / 180.0
radiansdelta = degreestoradians / 2 radiansdelta = degreestoradians / 2
@ -105,39 +104,39 @@ def draw_wedge(doc, style, centerx, centery, radius, start_angle,
if short_radius == 0: if short_radius == 0:
if (end_angle - start_angle) != 360: if (end_angle - start_angle) != 360:
p.append((centerx, centery)) path.append((centerx, centery))
else: else:
origx = (centerx + cos(angle) * short_radius) origx = (centerx + cos(angle) * short_radius)
origy = (centery + sin(angle) * short_radius) origy = (centery + sin(angle) * short_radius)
p.append((origx, origy)) path.append((origx, origy))
while angle < eangle: while angle < eangle:
x = centerx + cos(angle) * radius _x_ = centerx + cos(angle) * radius
y = centery + sin(angle) * radius _y_ = centery + sin(angle) * radius
p.append((x, y)) path.append((_x_, _y_))
angle = angle + radiansdelta angle = angle + radiansdelta
x = centerx + cos(eangle) * radius _x_ = centerx + cos(eangle) * radius
y = centery + sin(eangle) * radius _y_ = centery + sin(eangle) * radius
p.append((x, y)) path.append((_x_, _y_))
if short_radius: if short_radius:
x = centerx + cos(eangle) * short_radius _x_ = centerx + cos(eangle) * short_radius
y = centery + sin(eangle) * short_radius _y_ = centery + sin(eangle) * short_radius
p.append((x, y)) path.append((_x_, _y_))
angle = eangle angle = eangle
while angle >= sangle: while angle >= sangle:
x = centerx + cos(angle) * short_radius _x_ = centerx + cos(angle) * short_radius
y = centery + sin(angle) * short_radius _y_ = centery + sin(angle) * short_radius
p.append((x, y)) path.append((_x_, _y_))
angle -= radiansdelta angle -= radiansdelta
if do_rendering: if do_rendering:
doc.draw_path(style, p) doc.draw_path(style, path)
delta = (eangle - sangle) / 2.0 delta = (eangle - sangle) / 2.0
rad = short_radius + (radius - short_radius) / 2.0 rad = short_radius + (radius - short_radius) / 2.0
return ( (centerx + cos(sangle + delta + WEDGE_TEXT_BARRE_OFFSET) * rad), return ((centerx + cos(sangle + delta + WEDGE_TEXT_BARRE_OFFSET) * rad),
(centery + sin(sangle + delta + WEDGE_TEXT_BARRE_OFFSET) * rad)) (centery + sin(sangle + delta + WEDGE_TEXT_BARRE_OFFSET) * rad))
#------------------------------------------------------------------------ #------------------------------------------------------------------------
@ -190,11 +189,11 @@ class FanChart(Report):
self.same_style = menu.get_option_by_name('same_style').get_value() self.same_style = menu.get_option_by_name('same_style').get_value()
self.center_person = self.database.get_person_from_gramps_id(pid) self.center_person = self.database.get_person_from_gramps_id(pid)
if self.center_person is None: if self.center_person is None:
raise ReportError(_("Person %s is not in the Database") % pid ) raise ReportError(_("Person %s is not in the Database") % pid)
self.graphic_style = [] self.graphic_style = []
self.text_style = [] self.text_style = []
for i in range (0, self.max_generations): for i in range(0, self.max_generations):
self.graphic_style.append('FC-Graphic' + '%02d' % i) self.graphic_style.append('FC-Graphic' + '%02d' % i)
self.text_style.append('FC-Text' + '%02d' % i) self.text_style.append('FC-Text' + '%02d' % i)
@ -204,7 +203,7 @@ class FanChart(Report):
self.map = [None] * 2**self.max_generations self.map = [None] * 2**self.max_generations
self.text = {} self.text = {}
def apply_filter(self,person_handle,index): def apply_filter(self, person_handle, index):
"""traverse the ancestors recursively until either the end """traverse the ancestors recursively until either the end
of a line is found, or until we reach the maximum number of of a line is found, or until we reach the maximum number of
generations that we want to deal with""" generations that we want to deal with"""
@ -218,57 +217,59 @@ class FanChart(Report):
family_handle = person.get_main_parents_family_handle() family_handle = person.get_main_parents_family_handle()
if family_handle: if family_handle:
family = self.database.get_family_from_handle(family_handle) family = self.database.get_family_from_handle(family_handle)
self.apply_filter(family.get_father_handle(),index*2) self.apply_filter(family.get_father_handle(), index*2)
self.apply_filter(family.get_mother_handle(),(index*2)+1) self.apply_filter(family.get_mother_handle(), (index*2)+1)
def write_report(self): def write_report(self):
self.doc.start_page() self.doc.start_page()
self.apply_filter(self.center_person.get_handle(),1) self.apply_filter(self.center_person.get_handle(), 1)
n = self.center_person.get_primary_name().get_regular_name() p_rn = self.center_person.get_primary_name().get_regular_name()
if self.circle == FULL_CIRCLE: if self.circle == FULL_CIRCLE:
max_angle = 360.0 max_angle = 360.0
start_angle = 90 start_angle = 90
max_circular = 5 max_circular = 5
x = self.doc.get_usable_width() / 2.0 _x_ = self.doc.get_usable_width() / 2.0
y = self.doc.get_usable_height() / 2.0 _y_ = self.doc.get_usable_height() / 2.0
min_xy = min (x, y) min_xy = min(_x_, _y_)
elif self.circle == HALF_CIRCLE: elif self.circle == HALF_CIRCLE:
max_angle = 180.0 max_angle = 180.0
start_angle = 180 start_angle = 180
max_circular = 3 max_circular = 3
x = (self.doc.get_usable_width()/2.0) _x_ = (self.doc.get_usable_width()/2.0)
y = self.doc.get_usable_height() _y_ = self.doc.get_usable_height()
min_xy = min (x, y) min_xy = min(_x_, _y_)
else: # quarter circle else: # quarter circle
max_angle = 90.0 max_angle = 90.0
start_angle = 270 start_angle = 270
max_circular = 2 max_circular = 2
x = 0 _x_ = 0
y = self.doc.get_usable_height() _y_ = self.doc.get_usable_height()
min_xy = min (self.doc.get_usable_width(), y) min_xy = min(self.doc.get_usable_width(), _y_)
# choose one line or two lines translation according to the width # choose one line or two lines translation according to the width
title = self._("%(generations)d Generation Fan Chart " title = self._("%(generations)d Generation Fan Chart "
"for %(person)s" ) % { "for %(person)s") % {
'generations' : self.max_generations, 'generations' : self.max_generations,
'person' : n } 'person' : p_rn}
title_nb_lines = 1 title_nb_lines = 1
style_sheet = self.doc.get_style_sheet() style_sheet = self.doc.get_style_sheet()
if style_sheet: if style_sheet:
paragraph_style = style_sheet.get_paragraph_style('FC-Title') p_style = style_sheet.get_paragraph_style('FC-Title')
if paragraph_style: if p_style:
font = paragraph_style.get_font() font = p_style.get_font()
if font: if font:
title_width = pt2cm(self.doc.string_width(font, title)) title_width = utils.pt2cm(self.doc.string_width(font,
title))
if title_width > self.doc.get_usable_width(): if title_width > self.doc.get_usable_width():
title = self._("%(generations)d Generation Fan Chart " title = self._(
"for\n%(person)s" ) % { "%(generations)d Generation Fan Chart "
"for\n%(person)s") % {
'generations' : self.max_generations, 'generations' : self.max_generations,
'person' : n } 'person' : p_rn}
title_nb_lines = 2 title_nb_lines = 2
if self.circle == FULL_CIRCLE or self.circle == QUAR_CIRCLE: if self.circle == FULL_CIRCLE or self.circle == QUAR_CIRCLE:
@ -276,24 +277,26 @@ class FanChart(Report):
if self.doc.get_usable_height() <= self.doc.get_usable_width(): if self.doc.get_usable_height() <= self.doc.get_usable_width():
# Should be in Landscape now # Should be in Landscape now
style_sheet = self.doc.get_style_sheet() style_sheet = self.doc.get_style_sheet()
paragraph_style = style_sheet.get_paragraph_style('FC-Title') p_style = style_sheet.get_paragraph_style('FC-Title')
if paragraph_style: if p_style:
font = paragraph_style.get_font() font = p_style.get_font()
if font: if font:
fontsize = pt2cm(font.get_size()) fontsize = utils.pt2cm(font.get_size())
# y is vertical distance to center of circle, move center down 1 fontsize # _y_ is vertical distance to center of circle,
y += fontsize*title_nb_lines # move center down 1 fontsize
# min_XY is the diameter of the circle, subtract two fontsize _y_ += fontsize*title_nb_lines
# min_XY is the diameter of the circle,
# subtract two fontsize
# so we dont draw outside bottom of the paper # so we dont draw outside bottom of the paper
min_xy = min(min_xy, y - 2*fontsize*title_nb_lines) min_xy = min(min_xy, _y_ - 2*fontsize*title_nb_lines)
if self.max_generations > max_circular: if self.max_generations > max_circular:
block_size = min_xy / (self.max_generations * 2 - max_circular) block_size = min_xy / (self.max_generations * 2 - max_circular)
else: else:
block_size = min_xy / self.max_generations block_size = min_xy / self.max_generations
# adaptation of the fonts (title and others) # adaptation of the fonts (title and others)
optimized_style_sheet = self.get_optimized_style_sheet(title, optimized_style_sheet = self.get_optimized_style_sheet(
max_circular, block_size, self.same_style, title, max_circular, block_size, self.same_style,
not self.same_style, not self.same_style,
# if same_style, use default generated colors # if same_style, use default generated colors
self.background == BACKGROUND_WHITE) self.background == BACKGROUND_WHITE)
@ -303,66 +306,71 @@ class FanChart(Report):
# title # title
mark = IndexMark(title, INDEX_TYPE_TOC, 1) mark = IndexMark(title, INDEX_TYPE_TOC, 1)
self.doc.center_text ('FC-Graphic-title', title, self.doc.center_text('FC-Graphic-title', title,
self.doc.get_usable_width() / 2, 0, mark) self.doc.get_usable_width() / 2, 0, mark)
#wheel # wheel
for generation in range (0, min (max_circular, self.max_generations)): for generation in range(0, min(max_circular, self.max_generations)):
self.draw_circular (x, y, start_angle, max_angle, block_size, generation) self.draw_circular(_x_, _y_,
for generation in range (max_circular, self.max_generations): start_angle, max_angle, block_size, generation)
self.draw_radial (x, y, start_angle, max_angle, block_size, generation) for generation in range(max_circular, self.max_generations):
self.draw_radial(_x_, _y_,
start_angle, max_angle, block_size, generation)
self.doc.end_page() self.doc.end_page()
def get_info(self,person_handle,generation): def get_info(self, person_handle, generation):
""" get info about a person """
person = self.database.get_person_from_handle(person_handle) person = self.database.get_person_from_handle(person_handle)
pn = person.get_primary_name() p_pn = person.get_primary_name()
self.calendar = config.get('preferences.calendar-format-report') self.calendar = config.get('preferences.calendar-format-report')
birth = get_birth_or_fallback(self.database, person) birth = get_birth_or_fallback(self.database, person)
b = "" bth = ""
if birth: if birth:
b = str(birth.get_date_object().to_calendar(self.calendar).get_year()) bth = birth.get_date_object()
if b == 0: bth = str(bth.to_calendar(self.calendar).get_year())
b = "" if bth == 0:
bth = ""
elif birth.get_type() != EventType.BIRTH: elif birth.get_type() != EventType.BIRTH:
b += '*' bth += '*'
death = get_death_or_fallback(self.database, person) death = get_death_or_fallback(self.database, person)
d = "" dth = ""
if death: if death:
d = str(death.get_date_object().to_calendar(self.calendar).get_year()) dth = death.get_date_object()
if d == 0: dth = str(dth.to_calendar(self.calendar).get_year())
d = "" if dth == 0:
dth = ""
elif death.get_type() != EventType.DEATH: elif death.get_type() != EventType.DEATH:
d += '*' dth += '*'
if b and d: if bth and dth:
val = "%s - %s" % (str(b),str(d)) val = "%s - %s" % (str(bth), str(dth))
elif b: elif bth:
val = "* %s" % (str(b)) val = "* %s" % (str(bth))
elif d: elif dth:
val = "+ %s" % (str(d)) val = "+ %s" % (str(dth))
else: else:
val = "" val = ""
if generation > 7: if generation > 7:
if (pn.get_first_name() != "") and (pn.get_surname() != ""): if (p_pn.get_first_name() != "") and (p_pn.get_surname() != ""):
name = pn.get_first_name() + " " + pn.get_surname() name = p_pn.get_first_name() + " " + p_pn.get_surname()
else: else:
name = pn.get_first_name() + pn.get_surname() name = p_pn.get_first_name() + p_pn.get_surname()
if (name != "") and (val != ""): if (name != "") and (val != ""):
string = name + ", " + val string = name + ", " + val
else: else:
string = name + val string = name + val
return [ string ] return [string]
elif generation == 7: elif generation == 7:
if (pn.get_first_name() != "") and (pn.get_surname() != ""): if (p_pn.get_first_name() != "") and (p_pn.get_surname() != ""):
name = pn.get_first_name() + " " + pn.get_surname() name = p_pn.get_first_name() + " " + p_pn.get_surname()
else: else:
name = pn.get_first_name() + pn.get_surname() name = p_pn.get_first_name() + p_pn.get_surname()
if self.circle == FULL_CIRCLE: if self.circle == FULL_CIRCLE:
return [ name, val ] return [name, val]
elif self.circle == HALF_CIRCLE: elif self.circle == HALF_CIRCLE:
return [ name, val ] return [name, val]
else: else:
if (name != "") and (val != ""): if (name != "") and (val != ""):
string = name + ", " + val string = name + ", " + val
@ -371,20 +379,21 @@ class FanChart(Report):
return [string] return [string]
elif generation == 6: elif generation == 6:
if self.circle == FULL_CIRCLE: if self.circle == FULL_CIRCLE:
return [ pn.get_first_name(), pn.get_surname(), val ] return [p_pn.get_first_name(), p_pn.get_surname(), val]
elif self.circle == HALF_CIRCLE: elif self.circle == HALF_CIRCLE:
return [ pn.get_first_name(), pn.get_surname(), val ] return [p_pn.get_first_name(), p_pn.get_surname(), val]
else: else:
if (pn.get_first_name() != "") and (pn.get_surname() != ""): if (p_pn.get_first_name() != "") and (p_pn.get_surname() != ""):
name = pn.get_first_name() + " " + pn.get_surname() name = p_pn.get_first_name() + " " + p_pn.get_surname()
else: else:
name = pn.get_first_name() + pn.get_surname() name = p_pn.get_first_name() + p_pn.get_surname()
return [ name, val ] return [name, val]
else: else:
return [ pn.get_first_name(), pn.get_surname(), val ] return [p_pn.get_first_name(), p_pn.get_surname(), val]
def get_max_width_for_circles(self, rad1, rad2, max_centering_proportion): def get_max_width_for_circles(self, rad1, rad2, max_centering_proportion):
""" r"""
(the "r" in the above line is to keep pylint happy)
__ __
/__\ <- compute the line width which is drawable between 2 circles. /__\ <- compute the line width which is drawable between 2 circles.
/ _ \ max_centering_proportion : 0, touching the circle1, 1, / _ \ max_centering_proportion : 0, touching the circle1, 1,
@ -400,13 +409,14 @@ class FanChart(Report):
return sin(acos(rmid/rad2)) * rad2 * 2 return sin(acos(rmid/rad2)) * rad2 * 2
def get_max_width_for_circles_line(self, rad1, rad2, line, nb_lines, def get_max_width_for_circles_line(self, rad1, rad2, line, nb_lines,
centering = False): centering=False):
""" r"""
(the "r" in the above line is to keep pylint happy)
__ __
/__\ <- compute the line width which is drawable between 2 circles. /__\ <- compute the line width which is drawable between 2 circles.
/ _ \ instead of a max_centering_proportion, you get a line/nb_lines position. / _ \ instead of a max_centering_proportion, you get a
| |_| | (we suppose that lines have the same heights) | |_| | line/nb_lines position. (we suppose that lines have the
| | for example, if you've 2 lines to draw, | | same heights.) for example, if you've 2 lines to draw,
\ / line 2 max width is at the 2/3 between the 2 circles \ / line 2 max width is at the 2/3 between the 2 circles
\__/ \__/
""" """
@ -417,7 +427,7 @@ class FanChart(Report):
line/float(nb_lines+1)) line/float(nb_lines+1))
def get_optimized_font_size_for_text(self, rad1, rad2, text, font, def get_optimized_font_size_for_text(self, rad1, rad2, text, font,
centering = False): centering=False):
""" """
a text can be several lines a text can be several lines
find the font size equals or lower than font.get_size() which fit find the font size equals or lower than font.get_size() which fit
@ -429,7 +439,8 @@ class FanChart(Report):
i = 1 i = 1
nb_lines = len(text) nb_lines = len(text)
for line in text: for line in text:
font_size = self.get_optimized_font_size(line, font, font_size = self.get_optimized_font_size(
line, font,
self.get_max_width_for_circles_line(rad1, rad2, i, nb_lines, self.get_max_width_for_circles_line(rad1, rad2, i, nb_lines,
centering)) centering))
i += 1 i += 1
@ -443,10 +454,10 @@ class FanChart(Report):
or smaller than font which make line fit into max_width or smaller than font which make line fit into max_width
""" """
test_font = FontStyle(font) test_font = FontStyle(font)
w = pt2cm(self.doc.string_width(test_font, line)) width = utils.pt2cm(self.doc.string_width(test_font, line))
while w > max_width and test_font.get_size() > 1: while width > max_width and test_font.get_size() > 1:
test_font.set_size(test_font.get_size() -1) test_font.set_size(test_font.get_size() -1)
w = pt2cm(self.doc.string_width(test_font, line)) width = utils.pt2cm(self.doc.string_width(test_font, line))
return test_font.get_size() return test_font.get_size()
def get_optimized_style_sheet(self, title, max_circular, block_size, def get_optimized_style_sheet(self, title, max_circular, block_size,
@ -457,66 +468,69 @@ class FanChart(Report):
returns an optimized (modified) style sheet which make fanchart returns an optimized (modified) style sheet which make fanchart
look nicer look nicer
""" """
redefined_style_sheet = self.doc.get_style_sheet() new_style_sheet = self.doc.get_style_sheet()
if not redefined_style_sheet: if not new_style_sheet:
return self.doc.get_style_sheet() return self.doc.get_style_sheet()
# update title font size # update title font size
pstyle_name = 'FC-Title' pstyle_name = 'FC-Title'
paragraph_style = redefined_style_sheet.get_paragraph_style(pstyle_name) p_style = new_style_sheet.get_paragraph_style(pstyle_name)
if paragraph_style: if p_style:
title_font = paragraph_style.get_font() title_font = p_style.get_font()
if title_font: if title_font:
title_width = pt2cm(self.doc.string_multiline_width(title_font, title_width = utils.pt2cm(
title)) self.doc.string_multiline_width(title_font, title))
while (title_width > self.doc.get_usable_width() and while (title_width > self.doc.get_usable_width() and
title_font.get_size() > 1): title_font.get_size() > 1):
title_font.set_size(title_font.get_size()-1) title_font.set_size(title_font.get_size()-1)
title_width = pt2cm(self.doc.string_multiline_width( title_width = utils.pt2cm(
title_font, title)) self.doc.string_multiline_width(title_font, title))
redefined_style_sheet.add_paragraph_style(pstyle_name, new_style_sheet.add_paragraph_style(pstyle_name, p_style)
paragraph_style)
# biggest font allowed is the one of the fist generation, after, # biggest font allowed is the one of the fist generation, after,
# always lower than the previous one # always lower than the previous one
paragraph_style = redefined_style_sheet.get_paragraph_style(self.text_style[0]) p_style = new_style_sheet.get_paragraph_style(self.text_style[0])
font = None font = None
if paragraph_style: if p_style:
font = paragraph_style.get_font() font = p_style.get_font()
if font: if font:
previous_generation_font_size = font.get_size() previous_generation_font_size = font.get_size()
for generation in range (0, self.max_generations): for generation in range(0, self.max_generations):
gstyle_name = self.graphic_style[generation] gstyle_name = self.graphic_style[generation]
pstyle_name = self.text_style [generation] pstyle_name = self.text_style[generation]
g = redefined_style_sheet.get_draw_style(gstyle_name) g_style = new_style_sheet.get_draw_style(gstyle_name)
# paragraph_style is a copy of 'FC-Text' - use different style # p_style is a copy of 'FC-Text' - use different style
# to be able to auto change some fonts for some generations # to be able to auto change some fonts for some generations
if map_style_from_single: if map_style_from_single:
paragraph_style = redefined_style_sheet.get_paragraph_style('FC-Text') p_style = new_style_sheet.get_paragraph_style('FC-Text')
else: else:
paragraph_style = redefined_style_sheet.get_paragraph_style(pstyle_name) p_style = new_style_sheet.get_paragraph_style(pstyle_name)
if g and paragraph_style: if g_style and p_style:
# set graphic colors to paragraph colors, while it's fonctionnaly # set graphic colors to paragraph colors,
# while it's functionnaly
# the same for fanchart or make backgrounds white # the same for fanchart or make backgrounds white
if make_background_white: if make_background_white:
g.set_fill_color((255,255,255)) g_style.set_fill_color((255, 255, 255))
redefined_style_sheet.add_draw_style(gstyle_name, g) new_style_sheet.add_draw_style(gstyle_name, g_style)
elif map_paragraphs_colors_to_graphics: elif map_paragraphs_colors_to_graphics:
pstyle = redefined_style_sheet.get_paragraph_style(pstyle_name) pstyle = new_style_sheet.get_paragraph_style(
pstyle_name)
if pstyle: if pstyle:
g.set_fill_color(pstyle.get_background_color()) g_style.set_fill_color(
redefined_style_sheet.add_draw_style(gstyle_name, g) pstyle.get_background_color())
new_style_sheet.add_draw_style(gstyle_name,
g_style)
# adapt font size if too big # adapt font size if too big
segments = 2**generation segments = 2**generation
if generation < min (max_circular, self.max_generations): if generation < min(max_circular, self.max_generations):
# adpatation for circular fonts # adpatation for circular fonts
rad1, rad2 = self.get_circular_radius(block_size, rad1, rad2 = self.get_circular_radius(
generation, self.circle) block_size, generation, self.circle)
font = paragraph_style.get_font() font = p_style.get_font()
if font: if font:
min_font_size = font.get_size() min_font_size = font.get_size()
# find the smallest font required # find the smallest font required
@ -525,7 +539,7 @@ class FanChart(Report):
font_size = \ font_size = \
self.get_optimized_font_size_for_text( self.get_optimized_font_size_for_text(
rad1, rad2, self.text[index], rad1, rad2, self.text[index],
paragraph_style.get_font(), p_style.get_font(),
(self.circle == FULL_CIRCLE and (self.circle == FULL_CIRCLE and
generation == 0) generation == 0)
) )
@ -542,37 +556,39 @@ class FanChart(Report):
for index in range(segments - 1, 2*segments - 1): for index in range(segments - 1, 2*segments - 1):
if self.map[index]: if self.map[index]:
for line in self.text[index]: for line in self.text[index]:
width = pt2cm(self.doc.string_multiline_width( width = utils.pt2cm(
paragraph_style.get_font(), line)) self.doc.string_multiline_width(
p_style.get_font(), line))
if width > longest_width: if width > longest_width:
longest_line = line longest_line = line
longest_width = width longest_width = width
# determine maximum width allowed for this generation # determine maximum width allowed for this generation
rad1, rad2 = self.get_radial_radius(block_size, rad1, rad2 = self.get_radial_radius(
generation, self.circle) block_size, generation, self.circle)
max_width = rad2 - rad1 max_width = rad2 - rad1
# reduce the font so that longest_width fit into max_width # reduce the font so that longest_width
font = paragraph_style.get_font() # fit into max_width
font = p_style.get_font()
if font: if font:
font.set_size(min(previous_generation_font_size, font.set_size(min(previous_generation_font_size,
self.get_optimized_font_size(longest_line, self.get_optimized_font_size(
paragraph_style.get_font(), longest_line,
max_width)) p_style.get_font(),
) max_width)))
# redefine the style # redefine the style
redefined_style_sheet.add_paragraph_style(pstyle_name, new_style_sheet.add_paragraph_style(pstyle_name, p_style)
paragraph_style) font = p_style.get_font()
font = paragraph_style.get_font()
if font: if font:
previous_generation_font_size = font.get_size() previous_generation_font_size = font.get_size()
# finished # finished
return redefined_style_sheet return new_style_sheet
def draw_circular(self, x, y, start_angle, max_angle, size, generation): def draw_circular(self, _x_, _y_,
start_angle, max_angle, size, generation):
segments = 2**generation segments = 2**generation
delta = max_angle / segments delta = max_angle / segments
end_angle = start_angle end_angle = start_angle
@ -583,19 +599,20 @@ class FanChart(Report):
for index in range(segments - 1, 2*segments - 1): for index in range(segments - 1, 2*segments - 1):
start_angle = end_angle start_angle = end_angle
end_angle = start_angle + delta end_angle = start_angle + delta
(xc,yc) = draw_wedge(self.doc, graphic_style, x, y, rad2, (_xc, _yc) = draw_wedge(self.doc, graphic_style, _x_, _y_, rad2,
start_angle, end_angle, start_angle, end_angle,
self.map[index] or self.draw_empty, rad1) self.map[index] or self.draw_empty, rad1)
if self.map[index]: if self.map[index]:
if (generation == 0) and self.circle == FULL_CIRCLE: if (generation == 0) and self.circle == FULL_CIRCLE:
yc = y _yc = _y_
person = self.database.get_person_from_handle(self.map[index]) person = self.database.get_person_from_handle(self.map[index])
mark = utils.get_person_mark(self.database, person) mark = utils.get_person_mark(self.database, person)
self.doc.rotate_text(graphic_style, self.text[index], self.doc.rotate_text(graphic_style, self.text[index],
xc, yc, text_angle, mark) _xc, _yc, text_angle, mark)
text_angle += delta text_angle += delta
def get_radial_radius(self, size, generation, circle): def get_radial_radius(self, size, generation, circle):
""" determine the radius """
if circle == FULL_CIRCLE: if circle == FULL_CIRCLE:
rad1 = size * ((generation * 2) - 5) rad1 = size * ((generation * 2) - 5)
rad2 = size * ((generation * 2) - 3) rad2 = size * ((generation * 2) - 3)
@ -608,9 +625,11 @@ class FanChart(Report):
return rad1, rad2 return rad1, rad2
def get_circular_radius(self, size, generation, circle): def get_circular_radius(self, size, generation, circle):
""" determine the radius """
return size * generation, size * (generation + 1) return size * generation, size * (generation + 1)
def draw_radial(self, x, y, start_angle, max_angle, size, generation): def draw_radial(self, _x_, _y_,
start_angle, max_angle, size, generation):
segments = 2**generation segments = 2**generation
delta = max_angle / segments delta = max_angle / segments
end_angle = start_angle end_angle = start_angle
@ -621,19 +640,21 @@ class FanChart(Report):
for index in range(segments - 1, 2*segments - 1): for index in range(segments - 1, 2*segments - 1):
start_angle = end_angle start_angle = end_angle
end_angle = start_angle + delta end_angle = start_angle + delta
(xc,yc) = draw_wedge(self.doc, graphic_style, x, y, rad2, (_xc, _yc) = draw_wedge(self.doc, graphic_style, _x_, _y_, rad2,
start_angle, end_angle, start_angle, end_angle,
self.map[index] or self.draw_empty, rad1) self.map[index] or self.draw_empty, rad1)
text_angle += delta text_angle += delta
if self.map[index]: if self.map[index]:
person = self.database.get_person_from_handle(self.map[index]) person = self.database.get_person_from_handle(self.map[index])
mark = utils.get_person_mark(self.database, person) mark = utils.get_person_mark(self.database, person)
if self.radial == RADIAL_UPRIGHT and (start_angle >= 90) and (start_angle < 270): if (self.radial == RADIAL_UPRIGHT
and (start_angle >= 90)
and (start_angle < 270)):
self.doc.rotate_text(graphic_style, self.text[index], self.doc.rotate_text(graphic_style, self.text[index],
xc, yc, text_angle + 180, mark) _xc, _yc, text_angle + 180, mark)
else: else:
self.doc.rotate_text(graphic_style, self.text[index], self.doc.rotate_text(graphic_style, self.text[index],
xc, yc, text_angle, mark) _xc, _yc, text_angle, mark)
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -641,9 +662,10 @@ class FanChart(Report):
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
class FanChartOptions(MenuReportOptions): class FanChartOptions(MenuReportOptions):
""" options for fanchart report """
def __init__(self, name, dbase): def __init__(self, name, dbase):
self.MAX_GENERATIONS = 11 self.max_generations = 11
MenuReportOptions.__init__(self, name, dbase) MenuReportOptions.__init__(self, name, dbase)
@ -661,7 +683,7 @@ class FanChartOptions(MenuReportOptions):
stdoptions.add_living_people_option(menu, category_name) stdoptions.add_living_people_option(menu, category_name)
max_gen = NumberOption(_("Generations"), 5, 1, self.MAX_GENERATIONS) max_gen = NumberOption(_("Generations"), 5, 1, self.max_generations)
max_gen.set_help(_("The number of generations " max_gen.set_help(_("The number of generations "
"to include in the report")) "to include in the report"))
menu.add_option(category_name, "maxgen", max_gen) menu.add_option(category_name, "maxgen", max_gen)
@ -670,7 +692,7 @@ class FanChartOptions(MenuReportOptions):
circle.add_item(FULL_CIRCLE, _('full circle')) circle.add_item(FULL_CIRCLE, _('full circle'))
circle.add_item(HALF_CIRCLE, _('half circle')) circle.add_item(HALF_CIRCLE, _('half circle'))
circle.add_item(QUAR_CIRCLE, _('quarter circle')) circle.add_item(QUAR_CIRCLE, _('quarter circle'))
circle.set_help( _("The form of the graph: full circle, half circle," circle.set_help(_("The form of the graph: full circle, half circle,"
" or quarter circle.")) " or quarter circle."))
menu.add_option(category_name, "circle", circle) menu.add_option(category_name, "circle", circle)
@ -681,8 +703,8 @@ class FanChartOptions(MenuReportOptions):
" dependent")) " dependent"))
menu.add_option(category_name, "background", background) menu.add_option(category_name, "background", background)
radial = EnumeratedListOption( _('Orientation of radial texts'), radial = EnumeratedListOption(_('Orientation of radial texts'),
RADIAL_UPRIGHT ) RADIAL_UPRIGHT)
radial.add_item(RADIAL_UPRIGHT, _('upright')) radial.add_item(RADIAL_UPRIGHT, _('upright'))
radial.add_item(RADIAL_ROUNDABOUT, _('roundabout')) radial.add_item(RADIAL_ROUNDABOUT, _('roundabout'))
radial.set_help(_("Print radial texts upright or roundabout")) radial.set_help(_("Print radial texts upright or roundabout"))
@ -700,59 +722,60 @@ class FanChartOptions(MenuReportOptions):
stdoptions.add_localization_option(menu, category_name) stdoptions.add_localization_option(menu, category_name)
def make_default_style(self,default_style): def make_default_style(self, default_style):
"""Make the default output style for the Fan Chart report.""" """Make the default output style for the Fan Chart report."""
BACKGROUND_COLORS = [ background_colors = [(255, 63, 0),
(255, 63, 0), (255, 175, 15),
(255,175, 15), (255, 223, 87),
(255,223, 87), (255, 255, 111),
(255,255,111), (159, 255, 159),
(159,255,159), (111, 215, 255),
(111,215,255), (79, 151, 255),
( 79,151,255), (231, 23, 255),
(231, 23,255), (231, 23, 221),
(231, 23,221), (210, 170, 124),
(210,170,124), (189, 153, 112)
(189,153,112)
] ]
#Paragraph Styles #Paragraph Styles
f = FontStyle() f_style = FontStyle()
f.set_size(18) f_style.set_size(18)
f.set_bold(1) f_style.set_bold(1)
f.set_type_face(FONT_SANS_SERIF) f_style.set_type_face(FONT_SANS_SERIF)
p = ParagraphStyle() p_style = ParagraphStyle()
p.set_font(f) p_style.set_font(f_style)
p.set_alignment(PARA_ALIGN_CENTER) p_style.set_alignment(PARA_ALIGN_CENTER)
p.set_description(_('The style used for the title.')) p_style.set_description(_('The style used for the title.'))
default_style.add_paragraph_style("FC-Title",p) default_style.add_paragraph_style("FC-Title", p_style)
f = FontStyle() f_style = FontStyle()
f.set_size(9) f_style.set_size(9)
f.set_type_face(FONT_SANS_SERIF) f_style.set_type_face(FONT_SANS_SERIF)
p = ParagraphStyle() p_style = ParagraphStyle()
p.set_font(f) p_style.set_font(f_style)
p.set_alignment(PARA_ALIGN_CENTER) p_style.set_alignment(PARA_ALIGN_CENTER)
p.set_description(_('The basic style used for the default text display.')) p_style.set_description(
default_style.add_paragraph_style("FC-Text", p) _('The basic style used for the default text display.'))
default_style.add_paragraph_style("FC-Text", p_style)
for i in range (0, self.MAX_GENERATIONS): for i in range(0, self.max_generations):
f = FontStyle() f_style = FontStyle()
f.set_size(9) f_style.set_size(9)
f.set_type_face(FONT_SANS_SERIF) f_style.set_type_face(FONT_SANS_SERIF)
p = ParagraphStyle() p_style = ParagraphStyle()
p.set_font(f) p_style.set_font(f_style)
p.set_alignment(PARA_ALIGN_CENTER) p_style.set_alignment(PARA_ALIGN_CENTER)
p.set_description(_('The style used for the text display of generation "%d"') % i) p_style.set_description(
default_style.add_paragraph_style("FC-Text" + "%02d" % i, p) _('The style used for the text display of generation "%d"') % i)
default_style.add_paragraph_style("FC-Text" + "%02d" % i, p_style)
# GraphicsStyles # GraphicsStyles
g = GraphicsStyle() g_style = GraphicsStyle()
g.set_paragraph_style('FC-Title') g_style.set_paragraph_style('FC-Title')
default_style.add_draw_style('FC-Graphic-title', g) default_style.add_draw_style('FC-Graphic-title', g_style)
for i in range (0, self.MAX_GENERATIONS): for i in range(0, self.max_generations):
g = GraphicsStyle() g_style = GraphicsStyle()
g.set_paragraph_style('FC-Text' + '%02d' % i) g_style.set_paragraph_style('FC-Text' + '%02d' % i)
g.set_fill_color(BACKGROUND_COLORS[i]) g_style.set_fill_color(background_colors[i])
default_style.add_draw_style('FC-Graphic' + '%02d' % i, g) default_style.add_draw_style('FC-Graphic' + '%02d' % i, g_style)