Add MenuOptions class for report options.

svn: r8926
This commit is contained in:
Brian Matherly 2007-09-05 03:02:50 +00:00
parent af618d3079
commit febd6e9ed5
8 changed files with 681 additions and 271 deletions

View File

@ -1,3 +1,12 @@
2007-09-04 Brian Matherly <brian@gramps-project.org>
* src/ReportBase/__init__.py: Add MenuOptions
* src/ReportBase/_MenuOptions.py: Added
* src/ReportBase/Makefile.am: Add MenuOptions
* src/plugins/DescendChart.py: Use MenuOptions
* src/plugins/AncestorChart.py: Use MenuOptions
* src/plugins/FanChart.py: Use MenuOptions
* src/Utils.py (get_type_converter): Handle boolean types.
2007-09-03 Don Allingham <don@gramps-project.org>
* plugins/WritePkg.py: fix package export
* GrampsDbUtils/_WriteXML.py: fix package export

View File

@ -12,6 +12,7 @@ pkgdata_PYTHON = \
_DrawReportDialog.py\
_Endnotes.py\
_FileEntry.py\
_MenuOptions.py\
__init__.py\
_PaperMenu.py\
_PrintTools.py\

View File

@ -0,0 +1,533 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2007 Brian G. Matherly
#
# 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: $
"""
Abstracted option handling.
"""
#------------------------------------------------------------------------
#
# gtk
#
#------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from _ReportOptions import ReportOptions
#-------------------------------------------------------------------------
#
# Option class
#
#-------------------------------------------------------------------------
class Option:
"""
This class serves as a base class for all options. All Options must
minimally provide the services provided by this class. Options are allowed
to add additional functionality.
"""
def __init__(self,label,value):
"""
@param label: A friendly label to be applied to this option.
Example: "Exclude living people"
@type label: string
@param value: An initial value for this option.
Example: True
@type value: The type will depend on the type of option.
@return: nothing
"""
self.__value = value
self.__label = label
self.__help_str = ""
def get_label(self):
"""
Get the friendly label for this option.
@return: string
"""
return self.__label
def set_label(self,label):
"""
Set the friendly label for this option.
@param label: A friendly label to be applied to this option.
Example: "Exclude living people"
@type label: string
@return: nothing
"""
self.__label = label
def get_value(self):
"""
Get the value of this option.
@return: The option value.
"""
return self.__value
def set_value(self,value):
"""
Set the value of this option.
@param value: A value for this option.
Example: True
@type value: The type will depend on the type of option.
@return: nothing
"""
self.__value = value
def get_help(self):
"""
Get the help information for this option.
@return: A string that provides additional help beyond the label.
"""
return self.__help_str
def set_help(self,help):
"""
Set the help information for this option.
@param help: A string that provides additional help beyond the label.
Example: "Whether to include or exclude people who are calculated
to be alive at the time of the generation of this report"
@type value: string
@return: nothing
"""
self.__help_str = help
#-------------------------------------------------------------------------
#
# StringOption class
#
#-------------------------------------------------------------------------
class StringOption(Option):
"""
This class describes an option that is a simple one-line string.
"""
def __init__(self,label,value):
"""
@param label: A friendly label to be applied to this option.
Example: "Page header"
@type label: string
@param value: An initial value for this option.
Example: "Generated by GRAMPS"
@type value: string
@return: nothing
"""
Option.__init__(self,label,value)
#-------------------------------------------------------------------------
#
# NumberOption class
#
#-------------------------------------------------------------------------
class NumberOption(Option):
"""
This class describes an option that is a simple number with defined maximum
and minimum values.
"""
def __init__(self,label,value,min,max):
"""
@param label: A friendly label to be applied to this option.
Example: "Number of generations to include"
@type label: string
@param value: An initial value for this option.
Example: 5
@type value: int
@param min: The minimum value for this option.
Example: 1
@type min: int
@param max: The maximum value for this option.
Example: 10
@type value: int
@return: nothing
"""
Option.__init__(self,label,value)
self.__min = min
self.__max = max
def get_min(self):
"""
Get the minimum value for this option.
@return: an int that represents the minimum value for this option.
"""
return self.__min
def get_max(self):
"""
Get the maximum value for this option.
@return: an int that represents the maximum value for this option.
"""
return self.__max
#-------------------------------------------------------------------------
#
# TextOption class
#
#-------------------------------------------------------------------------
class TextOption(Option):
"""
This class describes an option that is a multi-line string.
"""
def __init__(self,label,value):
"""
@param label: A friendly label to be applied to this option.
Example: "Page header"
@type label: string
@param value: An initial value for this option.
Example: "Generated by GRAMPS\nCopyright 2007"
@type value: string
@return: nothing
"""
Option.__init__(self,label,value)
#-------------------------------------------------------------------------
#
# BooleanOption class
#
#-------------------------------------------------------------------------
class BooleanOption(Option):
"""
This class describes an option that is a boolean (True or False).
"""
def __init__(self,label,value):
"""
@param label: A friendly label to be applied to this option.
Example: "Exclude living people"
@type label: string
@param value: An initial value for this option.
Example: True
@type value: boolean
@return: nothing
"""
Option.__init__(self,label,value)
#-------------------------------------------------------------------------
#
# EnumeratedListOption class
#
#-------------------------------------------------------------------------
class EnumeratedListOption(Option):
"""
This class describes an option that provides a finite number of values.
Each possible value is assigned a value and a description.
"""
def __init__(self,label,value):
"""
@param label: A friendly label to be applied to this option.
Example: "Paper Size"
@type label: string
@param value: An initial value for this option.
Example: 5
@type value: int
@return: nothing
"""
Option.__init__(self,label,value)
self.__items = []
def add_item(self,value,description):
"""
Add an item to the list of possible values.
@param value: The value that corresponds to this item.
Example: 5
@type value: int
@param description: A description of this value.
Example: "8.5 x 11"
@type description: string
@return: nothing
"""
self.__items.append((value, description))
def get_items(self):
"""
Get all the possible values for this option.
@return: an array of tuples containing (value,description) pairs.
"""
return self.__items
#-------------------------------------------------------------------------
#
# Menu class
#
#-------------------------------------------------------------------------
class Menu:
"""
Introduction
============
A Menu is used to maintain a collection of options that need to be
represented to the user in a non-implementation specific way. The options
can be described using the various option classes. A menu contains many
options and associates them with a unique name and category.
Usage
=====
Menus are used in the following way.
1. Create a option object and configure all the attributes of the option.
2. Add the option to the menu by specifying the option, name and category.
3. Add as many options as necessary.
4. When all the options are added, the menu can be stored and passed to
the part of the system that will actually represent the menu to
the user.
"""
def __init__(self):
self.__options = {}
def add_option(self,category,name,option):
"""
Add an option to the menu.
@param category: A label that describes the category that the option
belongs to.
Example: "Report Options"
@type category: string
@param name: A name that is unique to this option.
Example: "generations"
@type name: string
@param option: The option instance to be added to this menu.
@type option: Option
@return: nothing
"""
if not self.__options.has_key(category):
self.__options[category] = []
self.__options[category].append((name,option))
def get_categories(self):
"""
Get a list of categories in this menu.
@return: a list of strings
"""
categories = []
for category in self.__options:
categories.append(category)
return categories
def get_option_names(self,category):
"""
Get a list of option names for the specified category.
@return: a list of strings
"""
names = []
for (name,option) in self.__options[category]:
names.append(name)
return names
def get_option(self,category,name):
"""
Get an option with the specified category and name.
@return: an Option instance or None on failure.
"""
for (oname,option) in self.__options[category]:
if oname == name:
return option
return None
def get_all_option_names(self):
"""
Get a list of all the option names in this menu.
@return: a list of strings
"""
names = []
for category in self.__options:
for (name,option) in self.__options[category]:
names.append(name)
return names
def get_option_by_name(self,name):
"""
Get an option with the specified name.
@return: an Option instance or None on failure.
"""
for category in self.__options.keys():
for (oname,option) in self.__options[category]:
if oname == name:
return option
return None
#------------------------------------------------------------------------
#
# MenuOptions class
#
#------------------------------------------------------------------------
class MenuOptions(ReportOptions):
"""
The MenuOptions class implementes the ReportOptions functionality in a
generic way so that the user does not need to be concerned with the
graphical representation of the options.
The user should inherit the MenuOptions class and override the
add_menu_options function. The user can add options to the menu and the
MenuOptions class will worry about setting up the GUI.
"""
def __init__(self,name,person_id=None):
self.menu = Menu()
ReportOptions.__init__(self,name, person_id)
def make_default_style(self,default_style):
pass
def set_new_options(self):
self.options_dict = {}
self.options_help = {}
self.add_menu_options(self.menu)
for name in self.menu.get_all_option_names():
option = self.menu.get_option_by_name(name)
self.options_dict[name] = option.get_value()
self.options_help[name] = option.get_help()
def add_menu_options(self,menu):
"""
Add the user defined options to the menu.
@param menu: A menu class for the options to belong to.
@type menu: Menu
@return: nothing
"""
raise NotImplementedError
def add_user_options(self,dialog):
self.gui = {}
self.tooltips = gtk.Tooltips()
for category in self.menu.get_categories():
for name in self.menu.get_option_names(category):
option = self.menu.get_option(category,name)
otype = option.__class__
if otype == NumberOption:
self.__add_number_option(category,name,option,dialog)
elif otype == TextOption:
self.__add_text_option(category,name,option,dialog)
elif otype == BooleanOption:
self.__add_boolean_option(category,name,option,dialog)
elif otype == EnumeratedListOption:
self.__add_enumerated_list_option(category,name,option,
dialog)
else:
raise NotImplementedError
def parse_user_options(self,dialog):
for name in self.menu.get_all_option_names():
option = self.menu.get_option_by_name(name)
otype = option.__class__
if otype == NumberOption:
self.__parse_number_option(name,option)
elif otype == TextOption:
self.__parse_text_option(name,option)
elif otype == BooleanOption:
self.__parse_boolean_option(name,option)
elif otype == EnumeratedListOption:
self.__parse_enumerated_list_option(name,option)
else:
raise NotImplementedError
def __add_number_option(self,category,name,option,dialog):
"""
Add a NumberOption to the dialog.
"""
adj = gtk.Adjustment(1,option.get_min(),option.get_max(),1)
self.gui[name] = gtk.SpinButton(adj)
self.gui[name].set_value(self.options_dict[name])
dialog.add_frame_option(category,option.get_label(),self.gui[name])
self.tooltips.set_tip(self.gui[name],option.get_help())
def __parse_number_option(self,name,option):
self.options_dict[name] = int(self.gui[name].get_value_as_int())
def __add_text_option(self,category,name,option,dialog):
"""
Add a TextOption to the dialog.
"""
self.gui[name] = gtk.TextView()
self.gui[name].get_buffer().set_text("\n".join(self.options_dict[name]))
self.gui[name].set_editable(1)
swin = gtk.ScrolledWindow()
swin.set_shadow_type(gtk.SHADOW_IN)
swin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
swin.add(self.gui[name])
dialog.add_frame_option(category,option.get_label(),swin)
# Required for tooltip
self.gui[name].add_events(gtk.gdk.ENTER_NOTIFY_MASK)
self.gui[name].add_events(gtk.gdk.LEAVE_NOTIFY_MASK)
self.tooltips.set_tip(self.gui[name],option.get_help())
def __parse_text_option(self,name,option):
b = self.gui[name].get_buffer()
text_val = unicode( b.get_text( b.get_start_iter(),
b.get_end_iter(),
False) )
self.options_dict[name] = text_val.split('\n')
def __add_boolean_option(self,category,name,option,dialog):
"""
Add a BooleanOption to the dialog.
"""
self.gui[name] = gtk.CheckButton(option.get_label())
self.gui[name].set_active(self.options_dict[name])
dialog.add_frame_option(category,"",self.gui[name])
self.tooltips.set_tip(self.gui[name],option.get_help())
def __parse_boolean_option(self,name,option):
self.options_dict[name] = self.gui[name].get_active()
def __add_enumerated_list_option(self,category,name,option,dialog):
"""
Add an EnumeratedListOption to the dialog.
"""
active_index = 0
current_index = 0
self.gui[name] = gtk.combo_box_new_text()
for (value,description) in option.get_items():
self.gui[name].append_text(description)
if value == self.options_dict[name]:
active_index = current_index
current_index += 1
self.gui[name].set_active( active_index )
dialog.add_frame_option(category,option.get_label(),self.gui[name])
self.tooltips.set_tip(self.gui[name],option.get_help())
def __parse_enumerated_list_option(self,name,option):
index = self.gui[name].get_active()
items = option.get_items()
(value,description) = items[index]
self.options_dict[name] = value

View File

@ -37,6 +37,8 @@ from _DrawReportDialog import DrawReportDialog
from _TextReportDialog import TextReportDialog
from _ReportOptions import ReportOptions
from _MenuOptions import MenuOptions, NumberOption, BooleanOption, TextOption, \
EnumeratedListOption
import _ReportUtils as ReportUtils
from _Bibliography import Bibliography, Citation

View File

@ -831,6 +831,11 @@ def get_new_filename(ext,folder='~/'):
ix = ix + 1
return os.path.expanduser(_NEW_NAME_PATTERN % (folder,os.path.sep,ix,ext))
def cast_to_bool(val):
if val == str(True):
return True
return False
def get_type_converter(val):
"""
Returns function that converts strings into the type of val.
@ -842,6 +847,8 @@ def get_type_converter(val):
return int
elif val_type == float:
return float
elif val_type == bool:
return cast_to_bool
elif val_type in (list,tuple):
return list

View File

@ -31,13 +31,6 @@
import math
from gettext import gettext as _
#------------------------------------------------------------------------
#
# gtk
#
#------------------------------------------------------------------------
import gtk
#------------------------------------------------------------------------
#
# GRAMPS modules
@ -46,7 +39,8 @@ import gtk
import BaseDoc
from SubstKeywords import SubstKeywords
from PluginUtils import register_report
from ReportBase import Report, ReportUtils, ReportOptions, \
from ReportBase import Report, ReportUtils, \
MenuOptions, NumberOption, BooleanOption, TextOption, \
CATEGORY_DRAW, MODE_GUI, MODE_BKI, MODE_CLI
from BasicUtils import name_displayer
pt2cm = ReportUtils.pt2cm
@ -235,7 +229,7 @@ class AncestorChart(Report):
em = self.doc.string_width(font,"m")
subst = SubstKeywords(self.database,person_handle)
self.text[index] = subst.replace_and_clean(self.display.split('\n'))
self.text[index] = subst.replace_and_clean(self.display)
for line in self.text[index]:
this_box_width = self.doc.string_width(font,line)
@ -440,83 +434,38 @@ class AncestorChart(Report):
#
#
#------------------------------------------------------------------------
class AncestorChartOptions(ReportOptions):
class AncestorChartOptions(MenuOptions):
"""
Defines options and provides handling interface.
"""
def __init__(self,name,person_id=None):
ReportOptions.__init__(self,name,person_id)
def set_new_options(self):
# Options specific for this report
self.options_dict = {
'dispf' : "$n\n%s $b\n%s $d" % (_BORN,_DIED),
'maxgen' : 10,
'singlep' : 1,
'incblank' : 1,
'compress' : 1,
}
self.options_help = {
'dispf' : ("=str","Display format for the outputbox.",
"Allows you to customize the data in the boxes in the report",
True),
'maxgen' : ("=int","Generations",
"The number of generations to include in the report",
True),
'singlep' : ("=0/1","Whether to scale to fit on a single page.",
["Do not scale to fit","Scale to fit"],
True),
'incblank' : ("=0/1","Whether to include pages that are blank.",
["Do not include blank pages","Include blank pages"],
True),
'compress' : ("=0/1","Whether to compress chart.",
["Do not compress chart","Compress chart"],
True),
}
def add_user_options(self,dialog):
"""
Override the base class add_user_options task to add a menu that allows
the user to select the sort method.
"""
self.max_gen = gtk.SpinButton(gtk.Adjustment(1,1,100,1))
self.max_gen.set_value(self.options_dict['maxgen'])
dialog.add_option(_('Generations'),self.max_gen)
MenuOptions.__init__(self,name,person_id)
self.extra_textbox = gtk.TextView()
self.extra_textbox.get_buffer().set_text(self.options_dict['dispf'])
self.extra_textbox.set_editable(1)
swin = gtk.ScrolledWindow()
swin.set_shadow_type(gtk.SHADOW_IN)
swin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
swin.add(self.extra_textbox)
dialog.add_option(_("Display Format"),swin)
self.scale = gtk.CheckButton(_('Sc_ale to fit on a single page'))
self.scale.set_active(self.options_dict['singlep'])
dialog.add_option('',self.scale)
self.blank = gtk.CheckButton(_('Include Blank Pages'))
self.blank.set_active(self.options_dict['incblank'])
dialog.add_option('',self.blank)
self.compress = gtk.CheckButton(_('Co_mpress chart'))
self.compress.set_active(self.options_dict['compress'])
dialog.add_option('',self.compress)
def parse_user_options(self,dialog):
"""
Parses the custom options that we have added.
"""
b = self.extra_textbox.get_buffer()
text_val = unicode(b.get_text(b.get_start_iter(),b.get_end_iter(),False))
self.options_dict['dispf'] = text_val
self.options_dict['maxgen'] = int(self.max_gen.get_value_as_int())
self.options_dict['singlep'] = int(self.scale.get_active ())
self.options_dict['incblank'] = int(self.blank.get_active())
self.options_dict['compress'] = int(self.compress.get_active ())
def add_menu_options(self,menu):
category_name = _("Report Options")
max_gen = NumberOption(_("Generations"),10,1,50)
max_gen.set_help(_("The number of generations to include in the report"))
menu.add_option(category_name,"maxgen",max_gen)
disp = TextOption(_("Display Format"),
["$n","%s $b" % _BORN,"%s $d" %_DIED] )
disp.set_help(_("Display format for the outputbox."))
menu.add_option(category_name,"dispf",disp)
scale = BooleanOption(_('Sc_ale to fit on a single page'),True)
scale.set_help(_("Whether to scale to fit on a single page."))
menu.add_option(category_name,"singlep",scale)
blank = BooleanOption(_('Include Blank Pages'),True)
blank.set_help(_("Whether to include pages that are blank."))
menu.add_option(category_name,"incblank",blank)
compress = BooleanOption(_('Co_mpress chart'),True)
compress.set_help(_("Whether to compress chart."))
menu.add_option(category_name,"compress",compress)
def make_default_style(self,default_style):
"""Make the default output style for the Ancestor Chart report."""

View File

@ -28,29 +28,23 @@
# python modules
#
#------------------------------------------------------------------------
import math
from BasicUtils import name_displayer
from PluginUtils import register_report
from ReportBase import Report, ReportOptions, ReportUtils, \
MenuOptions, NumberOption, BooleanOption, TextOption, \
CATEGORY_DRAW, MODE_GUI, MODE_BKI, MODE_CLI
from SubstKeywords import SubstKeywords
from gettext import gettext as _
#------------------------------------------------------------------------
#
# gtk
#
#------------------------------------------------------------------------
import gtk
import BaseDoc
import math
#------------------------------------------------------------------------
#
# GRAMPS modules
#
#------------------------------------------------------------------------
import BaseDoc
from PluginUtils import register_report
from ReportBase import Report, ReportOptions, ReportUtils, \
CATEGORY_DRAW, MODE_GUI, MODE_BKI, MODE_CLI
pt2cm = ReportUtils.pt2cm
cm2pt = ReportUtils.cm2pt
from SubstKeywords import SubstKeywords
from BasicUtils import name_displayer
#------------------------------------------------------------------------
#
@ -174,7 +168,7 @@ class DescendChart(Report):
em = self.doc.string_width(font,"m")
subst = SubstKeywords(self.database,person_handle)
self.text[(x,y)] = subst.replace_and_clean(self.display.split('\n'))
self.text[(x,y)] = subst.replace_and_clean(self.display)
for line in self.text[(x,y)]:
this_box_width = self.doc.string_width(font,line) + 2*em
self.box_width = max(self.box_width,this_box_width)
@ -394,76 +388,39 @@ class DescendChart(Report):
#
#
#------------------------------------------------------------------------
class DescendChartOptions(ReportOptions):
class DescendChartOptions(MenuOptions):
"""
Defines options and provides handling interface.
"""
def __init__(self,name,person_id=None):
ReportOptions.__init__(self,name,person_id)
def set_new_options(self):
# Options specific for this report
self.options_dict = {
'dispf' : "$n\n%s $b\n%s $d" % (_BORN,_DIED),
'maxgen' : 32,
'singlep' : 1,
'incblank' : 1,
'incblank' : 1,
}
self.options_help = {
'dispf' : ("=str","Display format for the outputbox.",
"Allows you to customize the data in the boxes in the report",
True),
'maxgen' : ("=int","Generations",
"The number of generations to include in the report",
True),
'singlep' : ("=0/1","Whether to scale to fit on a single page.",
["Do not scale to fit","Scale to fit"],
True),
'incblank' : ("=0/1","Whether to include pages that are blank.",
["Do not include blank pages","Include blank pages"],
True),
}
def add_user_options(self,dialog):
"""
Override the base class add_user_options task to add a menu that allows
the user to select the sort method.
"""
self.max_gen = gtk.SpinButton(gtk.Adjustment(1,1,100,1))
self.max_gen.set_value(self.options_dict['maxgen'])
dialog.add_option(_('Generations'),self.max_gen)
MenuOptions.__init__(self,name,person_id)
self.extra_textbox = gtk.TextView()
self.extra_textbox.get_buffer().set_text(self.options_dict['dispf'])
self.extra_textbox.set_editable(1)
swin = gtk.ScrolledWindow()
swin.set_shadow_type(gtk.SHADOW_IN)
swin.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
swin.add(self.extra_textbox)
dialog.add_option(_("Display Format"),swin)
self.scale = gtk.CheckButton(_('Sc_ale to fit on a single page'))
self.scale.set_active(self.options_dict['singlep'])
dialog.add_option('',self.scale)
def add_menu_options(self,menu):
category_name = _("Report Options")
max_gen = NumberOption(_("Generations"),10,1,50)
max_gen.set_help(_("The number of generations to include in the report"))
menu.add_option(category_name,"maxgen",max_gen)
disp = TextOption( _("Display Format"),
["$n","%s $b" % _BORN,"%s $d" %_DIED] )
disp.set_help(_("Display format for the outputbox."))
menu.add_option(category_name,"dispf",disp)
scale = BooleanOption(_('Sc_ale to fit on a single page'),True)
scale.set_help(_("Whether to scale to fit on a single page."))
menu.add_option(category_name,"singlep",scale)
blank = BooleanOption(_('Include Blank Pages'),True)
blank.set_help(_("Whether to include pages that are blank."))
menu.add_option(category_name,"incblank",blank)
compress = BooleanOption(_('Co_mpress chart'),True)
compress.set_help(_("Whether to compress chart."))
menu.add_option(category_name,"compress",compress)
self.blank = gtk.CheckButton(_('Include Blank Pages'))
self.blank.set_active(self.options_dict['incblank'])
dialog.add_option('',self.blank)
def parse_user_options(self,dialog):
"""
Parses the custom options that we have added.
"""
b = self.extra_textbox.get_buffer()
text_val = unicode(b.get_text(b.get_start_iter(),b.get_end_iter(),False))
self.options_dict['dispf'] = text_val
self.options_dict['maxgen'] = int(self.max_gen.get_value_as_int())
self.options_dict['singlep'] = int(self.scale.get_active ())
self.options_dict['incblank'] = int(self.blank.get_active())
def make_default_style(self,default_style):
"""Make the default output style for the Ancestor Chart report."""
## Paragraph Styles:
@ -507,7 +464,7 @@ class DescendChartOptions(ReportOptions):
#
#------------------------------------------------------------------------
register_report(
name = 'descend_chart2',
name = 'descend_chart',
category = CATEGORY_DRAW,
report_class = DescendChart,
options_class = DescendChartOptions,

View File

@ -28,13 +28,6 @@
#------------------------------------------------------------------------
from gettext import gettext as _
#------------------------------------------------------------------------
#
# gnome/gtk
#
#------------------------------------------------------------------------
import gtk
#------------------------------------------------------------------------
#
# gramps modules
@ -43,8 +36,25 @@ import gtk
import BaseDoc
from PluginUtils import register_report
from ReportBase import Report, ReportUtils, ReportOptions, \
MenuOptions, NumberOption, EnumeratedListOption, \
CATEGORY_DRAW, MODE_GUI, MODE_BKI, MODE_CLI
from SubstKeywords import SubstKeywords
#------------------------------------------------------------------------
#
# private constants
#
#------------------------------------------------------------------------
FULL_CIRCLE = 0
HALF_CIRCLE = 1
QUAR_CIRCLE = 2
BACKGROUND_WHITE = 0
BACKGROUND_GEN = 1
RADIAL_UPRIGHT = 0
RADIAL_ROUNDABOUT = 1
pt2cm = ReportUtils.pt2cm
#------------------------------------------------------------------------
@ -68,24 +78,20 @@ class FanChart(Report):
that come in the options class.
maxgen - Maximum number of generations to include.
full_circle - != 0: draw a full circle; half_circle and quar_circle should be 0.
half_circle - != 0: draw a half circle; full_circle and quar_circle should be 0.
quar_circle - != 0: draw a quarter circle; full_circle and half_circle should be 0.
backgr_white - 0: Background color is generation dependent; 1: Background color is white.
radial_upright - 0: Print radial texts roundabout; 1: Print radial texts as upright as possible.
circle - Draw a full circle, half circle, or quarter circle.
background - Background color is generation dependent or white.
radial - Print radial texts roundabout or as upright as possible.
"""
self.max_generations = options_class.handler.options_dict['maxgen']
self.full_circle = options_class.handler.options_dict['full_circle']
self.half_circle = options_class.handler.options_dict['half_circle']
self.quar_circle = options_class.handler.options_dict['quar_circle']
self.backgr_white = options_class.handler.options_dict['backgr_white']
self.radial_upright = options_class.handler.options_dict['radial_upright']
self.circle = options_class.handler.options_dict['circle']
self.background = options_class.handler.options_dict['background']
self.radial = options_class.handler.options_dict['radial']
self.background_style = []
self.text_style = []
for i in range (0, self.max_generations):
if self.backgr_white:
if self.background == BACKGROUND_WHITE:
background_style_name = 'background_style_white'
else:
background_style_name = 'background_style' + '%d' % i
@ -140,7 +146,7 @@ class FanChart(Report):
self.apply_filter(self.start_person.get_handle(),1)
n = self.start_person.get_primary_name().get_regular_name()
if self.full_circle:
if self.circle == FULL_CIRCLE:
max_angle = 360.0
start_angle = 90
max_circular = 5
@ -148,7 +154,7 @@ class FanChart(Report):
y = self.doc.get_usable_height() / 2.0
min_xy = min (x, y)
elif self.half_circle:
elif self.circle == HALF_CIRCLE:
max_angle = 180.0
start_angle = 180
max_circular = 3
@ -216,9 +222,9 @@ class FanChart(Report):
else:
name = pn.get_first_name() + pn.get_surname()
if self.full_circle:
if self.circle == FULL_CIRCLE:
return [ name, val ]
elif self.half_circle:
elif self.circle == HALF_CIRCLE:
return [ name, val ]
else:
if (name != "") and (val != ""):
@ -227,9 +233,9 @@ class FanChart(Report):
string = name + val
return [string]
elif generation == 6:
if self.full_circle:
if self.circle == FULL_CIRCLE:
return [ pn.get_first_name(), pn.get_surname(), val ]
elif self.half_circle:
elif self.circle == HALF_CIRCLE:
return [ pn.get_first_name(), pn.get_surname(), val ]
else:
if (pn.get_first_name() != "") and (pn.get_surname() != ""):
@ -257,7 +263,7 @@ class FanChart(Report):
(xc,yc) = ReportUtils.draw_wedge(self.doc,background_style, x, y, rad2,
start_angle, end_angle, rad1)
if self.map[index]:
if (generation == 0) and self.full_circle:
if (generation == 0) and self.circle == FULL_CIRCLE:
yc = y
self.doc.rotate_text(text_style,
self.get_info(self.map[index],
@ -273,10 +279,10 @@ class FanChart(Report):
text_angle = start_angle - delta / 2.0
background_style = self.background_style[generation]
text_style = self.text_style[generation]
if self.full_circle:
if self.circle == FULL_CIRCLE:
rad1 = size * ((generation * 2) - 5)
rad2 = size * ((generation * 2) - 3)
elif self.half_circle:
elif self.circle == HALF_CIRCLE:
rad1 = size * ((generation * 2) - 3)
rad2 = size * ((generation * 2) - 1)
else: # quarter circle
@ -290,7 +296,7 @@ class FanChart(Report):
start_angle, end_angle, rad1)
text_angle += delta
if self.map[index]:
if self.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(text_style,
self.get_info(self.map[index],
generation),
@ -306,95 +312,41 @@ class FanChart(Report):
#
#
#------------------------------------------------------------------------
class FanChartOptions(ReportOptions):
"""
Defines options and provides handling interface for Fan Chart.
"""
class FanChartOptions(MenuOptions):
def __init__(self,name,person_id=None):
ReportOptions.__init__(self,name,person_id)
self.MAX_GENERATIONS = 8
def set_new_options(self):
# Options specific for this report
self.options_dict = {
'maxgen' : 5,
'full_circle' : 0,
'half_circle' : 1,
'quar_circle' : 0,
'backgr_white' : 0,
'backgr_generation' : 1,
'radial_upright' : 1,
'radial_roundabout' : 0,
}
self.options_help = {
'maxgen' : ("=num","Number of generations to print.",
[],
True),
'full_circle': ("=0/1","The form of the diagram shall be a full circle.",
["half or quarter circle","full circle"],
True),
'half_circle': ("=0/1","The form of the diagram shall be a half circle.",
["full or quarter circle","half circle"],
True),
'quar_circle': ("=0/1","The form of the diagram shall be a quarter circle.",
["full or half circle","quarter circle"],
True),
'backgr_white': ("=0/1","Background color is white.",
["generation dependent","white"],
True),
'backgr_generation': ("=0/1","Background color is generation dependent.",
["white","generation dependent"],
True),
'radial_upright': ("=0/1","Print radial texts as upright as possible.",
["roundabout","upright"],
True),
'radial_roundabout': ("=0/1","Print radial texts roundabout.",
["upright","roundabout"],
True),
}
def add_user_options(self,dialog):
"""
Override the base class add_user_options task to add a menu that allows
the user to select the number of generations to print, ....
"""
self.max_gen = gtk.SpinButton(gtk.Adjustment(5,2,self.MAX_GENERATIONS,1))
self.max_gen.set_value(self.options_dict['maxgen'])
self.max_gen.set_wrap(True)
dialog.add_option(_('Generations'),self.max_gen)
self.type_box = gtk.combo_box_new_text ()
self.type_box.append_text (_('full circle'))
self.type_box.append_text (_('half circle'))
self.type_box.append_text (_('quarter circle'))
self.type_box.set_active(self.options_dict['half_circle'] + 2 * self.options_dict['quar_circle'])
dialog.add_option(_('Type of graph'),self.type_box)
self.backgr_box = gtk.combo_box_new_text ()
self.backgr_box.append_text (_('white'))
self.backgr_box.append_text (_('generation dependent'))
self.backgr_box.set_active(self.options_dict['backgr_generation'])
dialog.add_option(_('Background color'),self.backgr_box)
self.radial_box = gtk.combo_box_new_text ()
self.radial_box.append_text (_('upright'))
self.radial_box.append_text (_('roundabout'))
self.radial_box.set_active(self.options_dict['radial_roundabout'])
dialog.add_option(_('Orientation of radial texts'),self.radial_box)
def parse_user_options(self,dialog):
"""
Parses the custom options that we have added.
"""
self.options_dict['maxgen'] = int(self.max_gen.get_value_as_int())
self.options_dict['full_circle'] = int(self.type_box.get_active() == 0)
self.options_dict['half_circle'] = int(self.type_box.get_active() == 1)
self.options_dict['quar_circle'] = int(self.type_box.get_active() == 2)
self.options_dict['backgr_white'] = int(self.backgr_box.get_active() == 0)
self.options_dict['backgr_generation'] = int(self.backgr_box.get_active() == 1)
self.options_dict['radial_upright'] = int(self.radial_box.get_active() == 0)
self.options_dict['radial_roundabout'] = int(self.radial_box.get_active() == 1)
MenuOptions.__init__(self,name,person_id)
def add_menu_options(self,menu):
category_name = _("Report Options")
max_gen = NumberOption(_("Generations"),5,1,self.MAX_GENERATIONS)
max_gen.set_help(_("The number of generations to include in the report"))
menu.add_option(category_name,"maxgen",max_gen)
circle = EnumeratedListOption(_('Type of graph'),HALF_CIRCLE)
circle.add_item(FULL_CIRCLE,_('full circle'))
circle.add_item(HALF_CIRCLE,_('half circle'))
circle.add_item(QUAR_CIRCLE,_('quarter circle'))
circle.set_help( _("The form of the graph: full circle, half circle,"
" or quarter circle."))
menu.add_option(category_name,"circle",circle)
background = EnumeratedListOption(_('Background color'),BACKGROUND_GEN)
background.add_item(BACKGROUND_WHITE,_('white'))
background.add_item(BACKGROUND_GEN,_('generation dependent'))
background.set_help(_("Background color is either white or generation"
" dependent"))
menu.add_option(category_name,"background",background)
radial = EnumeratedListOption( _('Orientation of radial texts'),
RADIAL_UPRIGHT )
radial.add_item(RADIAL_UPRIGHT,_('upright'))
radial.add_item(RADIAL_ROUNDABOUT,_('roundabout'))
radial.set_help(_("Print raidal texts upright or roundabout"))
menu.add_option(category_name,"radial",radial)
def make_default_style(self,default_style):
"""Make the default output style for the Fan Chart report."""