#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2007 Thom Sturgill
# 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 Pubilc 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$
"""
Web Calendar generator.
Created 4/22/07 by Thom Sturgill based on Calendar.py (with patches)
by Doug Blank with input dialog based on NarrativeWeb.py by Don Allingham.
"""
#------------------------------------------------------------------------
#
# python modules
#
#------------------------------------------------------------------------
import os
import time
import datetime
import const
import codecs
import locale
import shutil
from gettext import gettext as _
from xml.parsers import expat
try:
set()
except:
from sets import Set as set
#------------------------------------------------------------------------
#
# Set up logging
#
#------------------------------------------------------------------------
import logging
log = logging.getLogger(".WebPage")
#------------------------------------------------------------------------
#
# GNOME/gtk
#
#------------------------------------------------------------------------
import gtk
#------------------------------------------------------------------------
#
# GRAMPS module
#
#------------------------------------------------------------------------
import gen.lib
import const
import BaseDoc
from GrampsCfg import get_researcher
from PluginUtils import register_report
from ReportBase import Report, ReportUtils, ReportOptions, \
CATEGORY_WEB, CATEGORY_TEXT, MODE_GUI
from ReportBase._ReportDialog import ReportDialog
import Errors
import Utils
import GrampsLocale
from QuestionDialog import ErrorDialog, WarningDialog
from Utils import probably_alive
from FontScale import string_trim, string_width
#------------------------------------------------------------------------
#
# constants
#
#------------------------------------------------------------------------
_CALENDAR = "calendar.css"
_character_sets = [
[_('Unicode (recommended)'), 'utf-8'],
['ISO-8859-1', 'iso-8859-1' ],
['ISO-8859-2', 'iso-8859-2' ],
['ISO-8859-3', 'iso-8859-3' ],
['ISO-8859-4', 'iso-8859-4' ],
['ISO-8859-5', 'iso-8859-5' ],
['ISO-8859-6', 'iso-8859-6' ],
['ISO-8859-7', 'iso-8859-7' ],
['ISO-8859-8', 'iso-8859-8' ],
['ISO-8859-9', 'iso-8859-9' ],
['ISO-8859-10', 'iso-8859-10' ],
['ISO-8859-13', 'iso-8859-13' ],
['ISO-8859-14', 'iso-8859-14' ],
['ISO-8859-15', 'iso-8859-15' ],
['koi8_r', 'koi8_r', ],
]
_cc = [
'',
'
',
'
',
'
',
'
',
'
',
]
def make_date(year, month, day):
"""
Returns a Date object of the particular year/month/day.
"""
retval = gen.lib.Date()
retval.set_yr_mon_day(year, month, day)
return retval
#------------------------------------------------------------------------
#
# WebReport
#
#------------------------------------------------------------------------
class WebReport(Report):
def __init__(self,database,person,options):
"""
Creates WebReport object that produces the report.
The arguments are:
database - the GRAMPS database instance
person - currently selected person
options - instance of the Options class for this report
This report needs the following parameters (class variables)
that come in the options class.
filter Surname
od Country
WCext Year
WCencoding Alive
WCod Birthday
WCcopyright Anniv
Month_image Month_repeat
WCtitle
Note_text1
Note_text2
Note_text3
Note_text4
Note_text5
Note_text6
Note_text7
Note_text8
Note_text9
Note_text10
Note_text11
Note_text12
"""
self.database = database
self.start_person = person
self.options = options
filter_num = options.handler.options_dict['WCfilter']
filters = ReportUtils.get_person_filters(person)
self.filter = filters[filter_num]
self.ext = options.handler.options_dict['WCext']
self.html_dir = options.handler.options_dict['WCod']
self.copy = options.handler.options_dict['WCcopyright']
self.encoding = options.handler.options_dict['WCencoding']
self.Title_text = options.handler.options_dict['WCtitle']
self.Note = [options.handler.options_dict['Note_text1'],options.handler.options_dict['Note_text2'],
options.handler.options_dict['Note_text3'], options.handler.options_dict['Note_text4'],
options.handler.options_dict['Note_text5'], options.handler.options_dict['Note_text6'],
options.handler.options_dict['Note_text7'], options.handler.options_dict['Note_text8'],
options.handler.options_dict['Note_text9'], options.handler.options_dict['Note_text10'],
options.handler.options_dict['Note_text11'],options.handler.options_dict['Note_text12']]
self.Month_image = options.handler.options_dict['Month_image']
self.Month_repeat = options.handler.options_dict['Month_repeat']
self.Country = options.handler.options_dict['Country']
self.Year = options.handler.options_dict['Year']
self.Surname = options.handler.options_dict['Surname']
self.Alive = options.handler.options_dict['alive']
self.Birthday = options.handler.options_dict['birthdays']
self.Anniv = options.handler.options_dict['anniversaries']
self.Serif_fonts = options.handler.options_dict['Serif_fonts']
self.SanSerif_fonts = options.handler.options_dict['SanSerif_fonts']
self.Home_link = options.handler.options_dict['Home_link']
def get_short_name(self, person, maiden_name = None):
""" Returns person's name, unless maiden_name given, unless married_name listed. """
# Get all of a person's names:
primary_name = person.get_primary_name()
married_name = None
names = [primary_name] + person.get_alternate_names()
for n in names:
if int(n.get_type()) == gen.lib.NameType.MARRIED:
married_name = n
# Now, decide which to use:
if maiden_name != None:
if married_name != None:
first_name, family_name = married_name.get_first_name(), married_name.get_surname()
call_name = married_name.get_call_name()
else:
first_name, family_name = primary_name.get_first_name(), maiden_name
call_name = primary_name.get_call_name()
else:
first_name, family_name = primary_name.get_first_name(), primary_name.get_surname()
call_name = primary_name.get_call_name()
# If they have a nickname use it
if call_name != None and call_name.strip() != "":
first_name = call_name.strip()
else: # else just get the first name:
first_name = first_name.strip()
if " " in first_name:
first_name, rest = first_name.split(" ", 1) # just one split max
return ("%s %s" % (first_name, family_name)).strip()
def add_day_item(self, text, year, month, day):
month_dict = self.calendar.get(month, {})
day_list = month_dict.get(day, [])
day_list.append(text)
month_dict[day] = day_list
self.calendar[month] = month_dict
def get_holidays(self, year, country = "United States"):
""" Looks in multiple places for holidays.xml files """
locations = [const.PLUGINS_DIR, const.USER_PLUGINS]
holiday_file = 'holidays.xml'
for dir in locations:
holiday_full_path = os.path.join(dir, holiday_file)
if os.path.exists(holiday_full_path):
self.process_holiday_file(holiday_full_path, year, country)
def process_holiday_file(self, filename, year, country):
""" This will process a holiday file """
parser = Xml2Obj()
element = parser.Parse(filename)
calendar = Holidays(element, country)
date = datetime.date(year, 1, 1)
while date.year == year:
holidays = calendar.check_date( date )
for text in holidays:
self.add_day_item(text, date.year, date.month, date.day)
date = date.fromordinal( date.toordinal() + 1)
def write_css(self):
"""
Create the CSS file.
"""
# simplify the style and weight printing
font_style = ['normal','italic']
font_weight = ['normal','bold']
# use user defined font families
font_family = [self.SanSerif_fonts,self.Serif_fonts]
default_style = BaseDoc.StyleSheet()
self.options.make_default_style(default_style)
# Read all style sheets available for this item
style_file = self.options.handler.get_stylesheet_savefile()
self.style_list = BaseDoc.StyleSheetList(style_file,default_style)
# Get the selected stylesheet
style_name = self.options.handler.get_default_stylesheet_name()
self.selected_style = self.style_list.get_style_sheet(style_name)
default_style = BaseDoc.StyleSheet(self.selected_style)
#
# NAVIGATION BLOCK
#
of = self.create_file(_CALENDAR)
of.write('ul#navlist { padding: 0;\n\tmargin: 0;\n\tlist-style-type: none;')
of.write('\n\tfloat: left;\n\twidth: 100%;')
of.write('\n\tcolor: #FFFFFF;\n\tbackground-color: #003366;\n\t}\n')
of.write('ul#navlist li { display: inline; }\n')
of.write('ul#navlist li a { float: left;\n\twidth: 2.8em;')
of.write('\n\tcolor: #FFFFFF;\n\tbackground-color: #003366;')
of.write('\n\tpadding: 0.2em 1em;\n\ttext-decoration: none;')
of.write('\n\tborder-right: 1px solid #FFFFFF;\n\t}\n')
of.write('ul#navlist li a:hover { background-color: #336699;')
of.write('\n\tcolor: #FFFFFF;\n\t}\n')
#
# HEADER / BODY BACKGROUND
#
of.write('h1 {')
style = default_style.get_paragraph_style("WC-Title")
font = style.get_font()
italic = font_style[font.get_italic()]
bold = font_weight[font.get_bold()]
family = font_family[font.get_type_face()]
color = "#%02X%02X%02X" % font.get_color()
of.write('\tfont-family: %s;\n\tfont-size: %dpt;\n'
'\tfont-style: %s;\n\tfont-weight: %s;\n'
'\tcolor: %s;\n\ttext-align: %s;\n\t}\n'
% (family, font.get_size(), italic, bold,
color, style.get_alignment_text()))
of.write('body { background-color: #%02X%02X%02X;\n}\n' % style.get_background_color() )
#
# CALENDAR TABLE
#
of.write('.calendar { ')
style = default_style.get_paragraph_style("WC-Table")
font = style.get_font()
italic = font_style[font.get_italic()]
bold = font_weight[font.get_bold()]
family = font_family[font.get_type_face()]
color = "#%02X%02X%02X" % font.get_color()
of.write('font-family: %s;\n\tfont-size: %dpt;\n'
'\tfont-style: %s;\n\tfont-weight: %s;\n'
'\tcolor: %s;\n\ttext-align: %s;\n'
% (family, font.get_size(), italic, bold,
color, style.get_alignment_text()))
of.write('\tbackground-color: #%02X%02X%02X;\n}\n' % style.get_background_color() )
#
# MONTH NAME
#
style = default_style.get_paragraph_style("WC-Month")
of.write('.cal_month { border-bottom-width: 0;\n')
font = style.get_font()
italic = font_style[font.get_italic()]
bold = font_weight[font.get_bold()]
family = font_family[font.get_type_face()]
color = "#%02X%02X%02X" % font.get_color()
mon_backcolor = "#%02X%02X%02X" % style.get_background_color()
of.write('\tfont-family:%s;\n\tfont-size: %dpt;\n'
'\tfont-style: %s;\n\tfont-weight: %s;\n'
'\tcolor: %s;\n\ttext-align: %s;\n'
% (family, font.get_size(), italic, bold, color, style.get_alignment_text()))
if self.Month_image.strip() != "":
of.write('\tbackground-image: URL( %s );\n' % self.Month_image)
of.write('\tbackground-repeat: %s;\n' % self.options.repeat_options[self.Month_repeat] )
of.write('\tbackground-color: %s;\n}\n' % mon_backcolor )
#
# WEEKDAY NAMES
#
of.write('.cal_sun { border-top-width: 0;\n\tborder-right-width: 0;')
of.write('\n\tborder-style: solid; ')
of.write('background-color: %s }\n' % mon_backcolor )
of.write('.cal_weekday { border-top-width: 0;\n\tborder-left-width: 0;\n\tborder-right-width: 0; ')
of.write('\n\tborder-style: solid;\n\tbackground-color: %s }\n' % mon_backcolor )
of.write('.cal_sat { border-top-width: 0;\n\tborder-left-width: 0;\n')
of.write('\tborder-right-width: 0;\n\tborder-style: solid;')
of.write('\n\tbackground-color: %s }\n' % mon_backcolor )
#of.write('.cal_day_num { text-align: right;\n\tfont-size: x-large;\n\tfont-weight: bold;}\n')
#
# CALENDAR ENTRY TEXT
#
style = default_style.get_paragraph_style("WC-Text")
of.write('.cal_text { vertical-align:bottom;\n')
font = style.get_font()
italic = font_style[font.get_italic()]
bold = font_weight[font.get_bold()]
family = font_family[font.get_type_face()]
color = "#%02X%02X%02X" % font.get_color()
msg_backcolor = "#%02X%02X%02X" % style.get_background_color()
of.write('\tfont-family:%s;\n\tfont-size: %dpt;\n'
'\tfont-style: %s;\n\tfont-weight: %s;\n'
'\tcolor: %s;\n\ttext-align: %s;\n\t}\n'
% (family, font.get_size(), italic, bold, color, style.get_alignment_text()))
of.write('.cal_row { height: 70px;\n\tborder-style: solid;\n\t}\n')
of.write('.cal_cell_hilite {background-color: %s;}\n' % msg_backcolor )
#
# CALENDAR NOTE TEXT
#
style = default_style.get_paragraph_style("WC-Note")
font = style.get_font()
italic = font_style[font.get_italic()]
bold = font_weight[font.get_bold()]
family = font_family[font.get_type_face()]
color = "#%02X%02X%02X" % font.get_color()
backcolor = "#%02X%02X%02X" % style.get_background_color()
of.write('.cal_cell { background-color: %s;}\n' % backcolor )
of.write('.cal_note {\n')
of.write('\tfont-family:%s;\n\tfont-size: %dpt;\n'
'\tfont-style: %s;\n\tfont-weight: %s;\n'
'\tcolor: %s;\n\ttext-align: %s;\n'
'\tbackground-color: %s;\n\t}\n'
% (family, font.get_size(), italic, bold, color, style.get_alignment_text(), backcolor))
#
# FOOTER AND DONE
#
of.write('.footer { text-align: center;\n\tfont-size:small; }\n')
of.write('img { border: 0; }\n')
of.close()
def write_footer(self,of):
author = get_researcher().get_name()
value = unicode(time.strftime('%x',time.localtime(time.time())),
GrampsLocale.codeset)
msg = _('Generated by '
'GRAMPS on %(date)s') % { 'date' : value }
of.write(' \n')
of.write('