2007-08-27 09:22:06 +05:30
|
|
|
#
|
|
|
|
# Gramps - a GTK+/GNOME based genealogy program
|
|
|
|
#
|
2008-02-10 09:39:09 +05:30
|
|
|
# Copyright (C) 2007 Thom Sturgill
|
|
|
|
# Copyright (C) 2007-2008 Brian G. Matherly
|
2007-08-27 09:22:06 +05:30
|
|
|
#
|
|
|
|
# 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.
|
2008-01-29 13:10:35 +05:30
|
|
|
|
2007-08-27 09:22:06 +05:30
|
|
|
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.
|
2008-01-29 13:10:35 +05:30
|
|
|
|
2008-03-02 04:17:48 +05:30
|
|
|
Reports/Web Page/Web Calendar
|
2007-08-27 09:22:06 +05:30
|
|
|
"""
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# python modules
|
|
|
|
#
|
|
|
|
#------------------------------------------------------------------------
|
|
|
|
import os
|
|
|
|
import time
|
|
|
|
import datetime
|
2008-01-29 13:10:35 +05:30
|
|
|
#import const
|
2007-08-27 09:22:06 +05:30
|
|
|
import codecs
|
|
|
|
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")
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# GRAMPS module
|
|
|
|
#
|
|
|
|
#------------------------------------------------------------------------
|
2007-10-08 22:11:39 +05:30
|
|
|
import gen.lib
|
2007-08-27 09:22:06 +05:30
|
|
|
import const
|
|
|
|
import BaseDoc
|
|
|
|
from GrampsCfg import get_researcher
|
|
|
|
from PluginUtils import register_report
|
2008-02-10 09:39:09 +05:30
|
|
|
from ReportBase import (Report, ReportUtils, MenuReportOptions, CATEGORY_WEB,
|
2008-01-29 13:10:35 +05:30
|
|
|
MODE_GUI)
|
2008-02-10 09:39:09 +05:30
|
|
|
from PluginUtils import FilterOption, EnumeratedListOption, PersonOption, \
|
|
|
|
BooleanOption, NumberOption, StringOption, DestinationOption
|
2007-08-27 09:22:06 +05:30
|
|
|
import Utils
|
|
|
|
import GrampsLocale
|
2008-01-29 13:10:35 +05:30
|
|
|
from QuestionDialog import ErrorDialog
|
2007-08-27 09:22:06 +05:30
|
|
|
from Utils import probably_alive
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
# constants
|
|
|
|
#
|
|
|
|
#------------------------------------------------------------------------
|
|
|
|
_CALENDAR = "calendar.css"
|
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
_CHARACTER_SETS = [
|
2007-08-27 09:22:06 +05:30
|
|
|
[_('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', ],
|
|
|
|
]
|
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
_CC = [
|
|
|
|
'<a rel="license" href="http://creativecommons.org/licenses/by/2.5/">'
|
|
|
|
'<img alt="Creative Commons License - By attribution" title="Creative '
|
|
|
|
'Commons License - By attribution" src="somerights20.gif" /></a>',
|
|
|
|
|
|
|
|
'<a rel="license" href="http://creativecommons.org/licenses/by-nd/2.5/">'
|
|
|
|
'<img alt="Creative Commons License - By attribution, No derivations" '
|
|
|
|
'title="Creative Commons License - By attribution, No derivations" '
|
|
|
|
'src="somerights20.gif" /></a>',
|
|
|
|
|
|
|
|
'<a rel="license" href="http://creativecommons.org/licenses/by-sa/2.5/">'
|
|
|
|
'<img alt="Creative Commons License - By attribution, Share-alike" '
|
|
|
|
'title="Creative Commons License - By attribution, Share-alike" '
|
|
|
|
'src="somerights20.gif" /></a>',
|
|
|
|
|
|
|
|
'<a rel="license" href="http://creativecommons.org/licenses/by-nc/2.5/">'
|
|
|
|
'<img alt="Creative Commons License - By attribution, Non-commercial" '
|
|
|
|
'title="Creative Commons License - By attribution, Non-commercial" '
|
|
|
|
'src="somerights20.gif" /></a>',
|
|
|
|
|
|
|
|
'<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/2.5/">'
|
|
|
|
'<img alt="Creative Commons License - By attribution, Non-commercial, No '
|
|
|
|
'derivations" title="Creative Commons License - By attribution, '
|
|
|
|
'Non-commercial, No derivations" src="somerights20.gif" /></a>',
|
|
|
|
|
|
|
|
'<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.5/">'
|
|
|
|
'<img alt="Creative Commons License - By attribution, Non-commerical, '
|
|
|
|
'Share-alike" title="Creative Commons License - By attribution, '
|
|
|
|
'Non-commerical, Share-alike" src="somerights20.gif" /></a>'
|
2007-08-27 09:22:06 +05:30
|
|
|
]
|
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
_COPY_OPTIONS = [
|
|
|
|
_('Standard copyright'),
|
|
|
|
_('Creative Commons - By attribution'),
|
|
|
|
_('Creative Commons - By attribution, No derivations'),
|
|
|
|
_('Creative Commons - By attribution, Share-alike'),
|
|
|
|
_('Creative Commons - By attribution, Non-commercial'),
|
|
|
|
_('Creative Commons - By attribution, Non-commercial, No derivations'),
|
|
|
|
_('Creative Commons - By attribution, Non-commercial, Share-alike'),
|
|
|
|
_('No copyright notice'),
|
|
|
|
]
|
|
|
|
|
2007-12-15 21:19:53 +05:30
|
|
|
def make_date(year, month, day):
|
|
|
|
"""
|
2008-02-24 19:25:55 +05:30
|
|
|
Return a Date object of the particular year/month/day.
|
2007-12-15 21:19:53 +05:30
|
|
|
"""
|
|
|
|
retval = gen.lib.Date()
|
|
|
|
retval.set_yr_mon_day(year, month, day)
|
|
|
|
return retval
|
|
|
|
|
2007-08-27 09:22:06 +05:30
|
|
|
#------------------------------------------------------------------------
|
|
|
|
#
|
2008-02-10 09:39:09 +05:30
|
|
|
# WebCalReport
|
2007-08-27 09:22:06 +05:30
|
|
|
#
|
|
|
|
#------------------------------------------------------------------------
|
2008-02-10 09:39:09 +05:30
|
|
|
class WebCalReport(Report):
|
|
|
|
"""
|
2008-02-24 19:25:55 +05:30
|
|
|
Create WebCalReport object that produces the report.
|
2008-02-10 09:39:09 +05:30
|
|
|
"""
|
2008-02-20 10:22:10 +05:30
|
|
|
def __init__(self, database, options):
|
|
|
|
Report.__init__(self, database, options)
|
2008-02-10 09:39:09 +05:30
|
|
|
menu = options.menu
|
2007-08-27 09:22:06 +05:30
|
|
|
|
|
|
|
self.database = database
|
|
|
|
self.options = options
|
2008-02-10 09:39:09 +05:30
|
|
|
|
|
|
|
self.html_dir = menu.get_option_by_name('target').get_value()
|
|
|
|
filter_option = menu.get_option_by_name('filter')
|
|
|
|
self.filter = filter_option.get_filter()
|
|
|
|
self.ext = menu.get_option_by_name('ext').get_value()
|
|
|
|
self.copy = menu.get_option_by_name('cright').get_value()
|
|
|
|
self.encoding = menu.get_option_by_name('encoding').get_value()
|
|
|
|
self.Country = menu.get_option_by_name('country').get_value()
|
|
|
|
self.Year = menu.get_option_by_name('year').get_value()
|
|
|
|
self.Surname = menu.get_option_by_name('surname').get_value()
|
|
|
|
self.Alive = menu.get_option_by_name('alive').get_value()
|
|
|
|
self.Birthday = menu.get_option_by_name('birthdays').get_value()
|
|
|
|
self.Anniv = menu.get_option_by_name('anniversaries').get_value()
|
|
|
|
self.Title_text = menu.get_option_by_name('title').get_value()
|
|
|
|
self.Month_image = menu.get_option_by_name('background').get_value()
|
|
|
|
self.Month_repeat = menu.get_option_by_name('repeat').get_value()
|
|
|
|
self.Serif_fonts = menu.get_option_by_name('serif_fonts').get_value()
|
|
|
|
self.SanSerif_fonts = \
|
|
|
|
menu.get_option_by_name('sanserif_fonts').get_value()
|
|
|
|
self.Home_link = menu.get_option_by_name('home_link').get_value()
|
|
|
|
|
|
|
|
self.Note = [ menu.get_option_by_name('note_jan').get_value(),
|
|
|
|
menu.get_option_by_name('note_feb').get_value(),
|
|
|
|
menu.get_option_by_name('note_mar').get_value(),
|
|
|
|
menu.get_option_by_name('note_apr').get_value(),
|
|
|
|
menu.get_option_by_name('note_may').get_value(),
|
|
|
|
menu.get_option_by_name('note_jun').get_value(),
|
|
|
|
menu.get_option_by_name('note_jul').get_value(),
|
|
|
|
menu.get_option_by_name('note_aug').get_value(),
|
|
|
|
menu.get_option_by_name('note_sep').get_value(),
|
|
|
|
menu.get_option_by_name('note_oct').get_value(),
|
|
|
|
menu.get_option_by_name('note_nov').get_value(),
|
|
|
|
menu.get_option_by_name('note_dec').get_value()]
|
2007-08-27 09:22:06 +05:30
|
|
|
|
|
|
|
def get_short_name(self, person, maiden_name = None):
|
2008-02-24 19:25:55 +05:30
|
|
|
""" Return person's name, unless maiden_name given, unless married_name listed. """
|
2007-08-27 09:22:06 +05:30
|
|
|
# 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:
|
2007-10-08 22:11:39 +05:30
|
|
|
if int(n.get_type()) == gen.lib.NameType.MARRIED:
|
2007-08-27 09:22:06 +05:30
|
|
|
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 """
|
2007-11-26 10:41:19 +05:30
|
|
|
locations = [const.PLUGINS_DIR, const.USER_PLUGINS]
|
2007-08-27 09:22:06 +05:30
|
|
|
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()
|
|
|
|
|
|
|
|
|
2008-02-24 19:25:55 +05:30
|
|
|
def write_footer(self, of):
|
2007-08-27 09:22:06 +05:30
|
|
|
author = get_researcher().get_name()
|
|
|
|
value = unicode(time.strftime('%x',time.localtime(time.time())),
|
|
|
|
GrampsLocale.codeset)
|
|
|
|
msg = _('Generated by <a href="http://gramps-project.org">'
|
|
|
|
'GRAMPS</a> on %(date)s') % { 'date' : value }
|
|
|
|
of.write(' </table>\n')
|
|
|
|
of.write(' <div class="footer">')
|
|
|
|
of.write(msg)
|
|
|
|
of.write('<p><a href="http://validator.w3.org/check?uri=referer"><img ')
|
|
|
|
of.write('src="http://www.w3.org/Icons/valid-xhtml10" ')
|
|
|
|
of.write('alt="Valid XHTML 1.0 Transitional" height="31" width="88" /></a></p>\n')
|
|
|
|
if self.copy > 0 and self.copy <= 6:
|
2008-02-10 09:39:09 +05:30
|
|
|
text = _CC[self.copy-1]
|
2007-09-23 22:48:47 +05:30
|
|
|
from_path = os.path.join(const.IMAGE_DIR,"somerights20.gif")
|
2008-02-24 19:25:55 +05:30
|
|
|
shutil.copyfile(from_path, os.path.join(self.html_dir,"somerights20.gif"))
|
2007-08-27 09:22:06 +05:30
|
|
|
else:
|
|
|
|
text = "© %s %s" % (time.localtime()[0], author)
|
|
|
|
of.write(text)
|
|
|
|
of.write('</div>\n')
|
|
|
|
of.write(' </body>\n')
|
|
|
|
of.write('</html>\n')
|
|
|
|
|
2008-02-24 19:25:55 +05:30
|
|
|
def write_header(self, of):
|
2007-08-27 09:22:06 +05:30
|
|
|
author = get_researcher().get_name()
|
|
|
|
of.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\n')
|
|
|
|
of.write(' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-loose.dtd">\n')
|
|
|
|
#xmllang = Utils.xml_lang()
|
|
|
|
of.write('<html>\n')
|
|
|
|
of.write('<head>\n <title>%s</title>\n' % self.Title_text)
|
|
|
|
of.write(' <meta http-equiv="Content-Type" content="text/html;charset=%s" />\n' % self.encoding)
|
|
|
|
of.write(' <meta name="robots" content="noindex" />\n')
|
|
|
|
of.write(' <meta name="generator" content="GRAMPS 2.26" />\n')
|
|
|
|
of.write(' <meta name="author" content="%s" />\n' % author)
|
|
|
|
of.write(' <link href="%s" ' % _CALENDAR)
|
|
|
|
of.write('rel="stylesheet" type="text/css" media="screen" />\n')
|
|
|
|
of.write(' <link href="/favicon.ico" rel="Shortcut Icon" />\n')
|
|
|
|
#of.write('<!-- %sId%s -->\n' % ('$','$'))
|
|
|
|
of.write('</head>\n')
|
|
|
|
of.write('<body>\n')
|
|
|
|
of.write(' <ul id="navlist">\n')
|
|
|
|
if self.Home_link.strip() != "":
|
|
|
|
of.write(' <li><a href="%s">HOME</a></li>\n' % self.Home_link)
|
|
|
|
for month in range(1, 13):
|
|
|
|
of.write(' <li><a href="Calendar_%s%d.html">%s</a></li>\n' % (GrampsLocale.short_months[month],self.Year,GrampsLocale.short_months[month]))
|
|
|
|
of.write(' </ul>\n')
|
|
|
|
|
2008-02-24 19:25:55 +05:30
|
|
|
def create_file(self, name):
|
|
|
|
page_name = os.path.join(self.html_dir, name)
|
2007-08-27 09:22:06 +05:30
|
|
|
of = codecs.EncodedFile(open(page_name, "w"),'utf-8',self.encoding,'xmlcharrefreplace')
|
|
|
|
return of
|
|
|
|
|
2008-02-24 19:25:55 +05:30
|
|
|
def close_file(self, of):
|
2007-08-27 09:22:06 +05:30
|
|
|
of.close()
|
|
|
|
|
|
|
|
def write_report(self):
|
|
|
|
""" The short method that runs through each month and creates a page. """
|
2007-10-15 17:56:31 +05:30
|
|
|
if not os.path.isdir(self.html_dir):
|
|
|
|
parent_dir = os.path.dirname(self.html_dir)
|
|
|
|
if not os.path.isdir(parent_dir):
|
|
|
|
ErrorDialog(_("Neither %s nor %s are directories") % \
|
|
|
|
(self.html_dir,parent_dir))
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
os.mkdir(self.html_dir)
|
|
|
|
except IOError, value:
|
|
|
|
ErrorDialog(_("Could not create the directory: %s") % \
|
|
|
|
self.html_dir + "\n" + value[1])
|
|
|
|
return
|
|
|
|
except:
|
|
|
|
ErrorDialog(_("Could not create the directory: %s") % \
|
|
|
|
self.html_dir)
|
|
|
|
return
|
|
|
|
|
2007-08-27 09:22:06 +05:30
|
|
|
# initialize the dict to fill:
|
|
|
|
self.calendar = {}
|
2008-01-29 02:52:06 +05:30
|
|
|
self.progress = Utils.ProgressMeter(_("Generate HTML Calendars"),'')
|
2007-08-27 09:22:06 +05:30
|
|
|
|
|
|
|
# Generate the CSS file
|
|
|
|
self.write_css()
|
|
|
|
|
|
|
|
# get the information, first from holidays:
|
|
|
|
if self.Country != 0: # Don't include holidays
|
2008-02-10 09:39:09 +05:30
|
|
|
self.get_holidays(self.Year, _COUNTRIES[self.Country]) # _country is currently global
|
2007-08-27 09:22:06 +05:30
|
|
|
# get data from database:
|
|
|
|
self.collect_data()
|
|
|
|
# generate the report:
|
|
|
|
self.progress.set_pass(_("Creating Calendar pages"),12)
|
|
|
|
|
|
|
|
for month in range(1, 13):
|
|
|
|
self.progress.step()
|
|
|
|
self.print_page(month)
|
|
|
|
self.progress.close()
|
|
|
|
|
|
|
|
def print_page(self, month):
|
|
|
|
"""
|
|
|
|
This method actually writes the calendar page.
|
|
|
|
"""
|
|
|
|
year = self.Year
|
|
|
|
title = "%s %d" % (GrampsLocale.long_months[month], year)
|
|
|
|
cal_file = "Calendar_%s%d.html" % (GrampsLocale.short_months[month], year)
|
|
|
|
of = self.create_file(cal_file)
|
|
|
|
self.write_header(of)
|
|
|
|
of.write(' <h1>%s</h1>\n' % self.Title_text)
|
|
|
|
of.write('<table border="1px" cellspacing="0" cellpadding="1" width="100%" class="calendar">\n')
|
|
|
|
of.write(' <tr>\n <td colspan="7" align="center" class="cal_month">\n')
|
|
|
|
of.write(' %s</td></tr>\n <tr>\n' % title)
|
|
|
|
|
|
|
|
current_date = datetime.date(year, month, 1)
|
|
|
|
if current_date.isoweekday() != 7: # start dow here is 7, sunday
|
|
|
|
current_ord = current_date.toordinal() - current_date.isoweekday()
|
|
|
|
else:
|
|
|
|
current_ord = current_date.toordinal()
|
|
|
|
of.write(' <td width="14%" align="center" class="cal_sun">')
|
|
|
|
of.write(GrampsLocale.short_days[1])
|
|
|
|
of.write('</td>\n')
|
|
|
|
for day_col in range(5):
|
|
|
|
of.write(' <td width="14%" align="center" class="cal_weekday">')
|
|
|
|
of.write(GrampsLocale.short_days[day_col+2])
|
|
|
|
of.write('</td>\n')
|
|
|
|
of.write(' <td width="14%" align="center" class="cal_sat">')
|
|
|
|
of.write(GrampsLocale.short_days[7])
|
|
|
|
of.write('</td>\n </tr>\n')
|
|
|
|
|
|
|
|
for week_row in range(6):
|
|
|
|
first = True
|
|
|
|
last = True
|
|
|
|
of.write(' <tr valign="top" class="cal_row">\n')
|
|
|
|
something_this_week = 0
|
|
|
|
colspan = 0
|
|
|
|
for day_col in range(7):
|
|
|
|
colspan += 1
|
|
|
|
thisday = current_date.fromordinal(current_ord)
|
|
|
|
if thisday.month == month:
|
|
|
|
list = self.calendar.get(month, {}).get(thisday.day, [])
|
|
|
|
if list > []:
|
|
|
|
cellclass = "cal_cell_hilite"
|
|
|
|
else:
|
|
|
|
cellclass = "cal_cell"
|
|
|
|
if first:
|
|
|
|
first = False
|
|
|
|
if day_col > 1:
|
2008-01-06 01:40:26 +05:30
|
|
|
of.write(' <td colspan="%s" class="cal_cell"> </td>\n' % str(day_col))
|
2007-08-27 09:22:06 +05:30
|
|
|
elif day_col == 1:
|
2008-01-06 01:40:26 +05:30
|
|
|
of.write(' <td class="cal_cell"> </td>\n')
|
2007-08-27 09:22:06 +05:30
|
|
|
of.write(' <td class="%s">%s' % (cellclass,str(thisday.day)))
|
|
|
|
something_this_week = 1
|
|
|
|
if list > []:
|
|
|
|
of.write('<div class="cal_text">')
|
|
|
|
for p in list:
|
|
|
|
lines = p.count("\n") + 1 # lines in the text
|
|
|
|
current = 0
|
|
|
|
for line in p.split("\n"):
|
|
|
|
of.write(line)
|
|
|
|
of.write('<br />')
|
|
|
|
current += 1
|
|
|
|
of.write('</div>')
|
|
|
|
of.write('</td>\n')
|
|
|
|
else:
|
|
|
|
# at bottom of calendar
|
|
|
|
if thisday.month > month and thisday.year >= year:
|
|
|
|
# only do it once per row
|
2008-02-05 06:01:57 +05:30
|
|
|
if last:
|
2007-08-27 09:22:06 +05:30
|
|
|
last = False
|
|
|
|
of.write(' <td colspan="')
|
|
|
|
of.write(str(7 - day_col))
|
|
|
|
of.write('"')
|
|
|
|
if week_row == 4:
|
|
|
|
of.write(' class="cal_cell"> </td>\n')
|
|
|
|
continue
|
|
|
|
if week_row == 5:
|
|
|
|
of.write(' class="cal_note">')
|
|
|
|
if self.Note[month-1].strip() != '':
|
2008-01-06 01:40:26 +05:30
|
|
|
of.write(self.Note[month-1])
|
2007-08-27 09:22:06 +05:30
|
|
|
else:
|
|
|
|
of.write(" ")
|
|
|
|
of.write('</td>\n')
|
|
|
|
continue
|
|
|
|
of.write('</div></td>\n')
|
|
|
|
continue
|
|
|
|
#of.write('\n')
|
|
|
|
current_ord += 1
|
|
|
|
if week_row == 5 and month == 12:
|
|
|
|
of.write(' <td colspan="%s" class="cal_note">' % str(colspan))
|
|
|
|
if self.Note[month-1].strip() != '':
|
|
|
|
of.write(self.Note[month-1])
|
|
|
|
else:
|
|
|
|
of.write(" ")
|
|
|
|
of.write('</td>\n')
|
|
|
|
of.write(' </tr>\n')
|
|
|
|
self.write_footer(of)
|
|
|
|
self.close_file(of)
|
|
|
|
|
|
|
|
def collect_data(self):
|
|
|
|
"""
|
|
|
|
This method runs through the data, and collects the relevant dates
|
|
|
|
and text.
|
|
|
|
"""
|
|
|
|
people = self.filter.apply(self.database,
|
|
|
|
self.database.get_person_handles(sort_handles=False))
|
|
|
|
for person_handle in people:
|
|
|
|
person = self.database.get_person_from_handle(person_handle)
|
|
|
|
birth_ref = person.get_birth_ref()
|
|
|
|
birth_date = None
|
|
|
|
if birth_ref:
|
|
|
|
birth_event = self.database.get_event_from_handle(birth_ref.ref)
|
|
|
|
birth_date = birth_event.get_date_object()
|
2007-12-15 21:19:53 +05:30
|
|
|
living = probably_alive(person, self.database, make_date(self.Year, 1, 1), 0)
|
2007-08-27 09:22:06 +05:30
|
|
|
if self.Birthday and birth_date != None and ((self.Alive and living) or not self.Alive):
|
|
|
|
year = birth_date.get_year()
|
|
|
|
month = birth_date.get_month()
|
|
|
|
day = birth_date.get_day()
|
|
|
|
age = self.Year - year
|
|
|
|
# add some things to handle maiden name:
|
|
|
|
father_lastname = None # husband, actually
|
|
|
|
if self.Surname == 0: # get husband's last name:
|
2007-10-08 22:11:39 +05:30
|
|
|
if person.get_gender() == gen.lib.Person.FEMALE:
|
2007-08-27 09:22:06 +05:30
|
|
|
family_list = person.get_family_handle_list()
|
|
|
|
if len(family_list) > 0:
|
|
|
|
fhandle = family_list[0] # first is primary
|
|
|
|
fam = self.database.get_family_from_handle(fhandle)
|
|
|
|
father_handle = fam.get_father_handle()
|
|
|
|
mother_handle = fam.get_mother_handle()
|
|
|
|
if mother_handle == person_handle:
|
|
|
|
if father_handle:
|
|
|
|
father = self.database.get_person_from_handle(father_handle)
|
|
|
|
if father != None:
|
|
|
|
father_lastname = father.get_primary_name().get_surname()
|
|
|
|
short_name = self.get_short_name(person, father_lastname)
|
|
|
|
self.add_day_item("%s, %d" % (short_name, age), year, month, day)
|
|
|
|
if self.Anniv and ((self.Alive and living) or not self.Alive):
|
|
|
|
family_list = person.get_family_handle_list()
|
|
|
|
for fhandle in family_list:
|
|
|
|
fam = self.database.get_family_from_handle(fhandle)
|
|
|
|
father_handle = fam.get_father_handle()
|
|
|
|
mother_handle = fam.get_mother_handle()
|
|
|
|
if father_handle == person.get_handle():
|
|
|
|
spouse_handle = mother_handle
|
|
|
|
else:
|
|
|
|
continue # with next person if this was the marriage event
|
|
|
|
if spouse_handle:
|
|
|
|
spouse = self.database.get_person_from_handle(spouse_handle)
|
|
|
|
if spouse:
|
|
|
|
spouse_name = self.get_short_name(spouse)
|
|
|
|
short_name = self.get_short_name(person)
|
|
|
|
if self.Alive:
|
2007-12-15 21:19:53 +05:30
|
|
|
if not probably_alive(spouse, self.database, make_date(self.Year, 1, 1), 0):
|
2007-08-27 09:22:06 +05:30
|
|
|
continue
|
|
|
|
married = True
|
|
|
|
for event_ref in fam.get_event_ref_list():
|
|
|
|
event = self.database.get_event_from_handle(event_ref.ref)
|
2007-10-16 07:56:38 +05:30
|
|
|
if event and int(event.get_type()) in [gen.lib.EventType.DIVORCE,
|
|
|
|
gen.lib.EventType.ANNULMENT,
|
|
|
|
gen.lib.EventType.DIV_FILING]:
|
|
|
|
married = False
|
2007-08-27 09:22:06 +05:30
|
|
|
if married:
|
|
|
|
for event_ref in fam.get_event_ref_list():
|
|
|
|
event = self.database.get_event_from_handle(event_ref.ref)
|
|
|
|
event_obj = event.get_date_object()
|
|
|
|
year = event_obj.get_year()
|
|
|
|
month = event_obj.get_month()
|
|
|
|
day = event_obj.get_day()
|
|
|
|
years = self.Year - year
|
|
|
|
text = _("%(spouse)s and\n %(person)s, %(nyears)d") % {
|
|
|
|
'spouse' : spouse_name,
|
|
|
|
'person' : short_name,
|
|
|
|
'nyears' : years,
|
|
|
|
}
|
|
|
|
self.add_day_item(text, year, month, day)
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------
|
|
|
|
#
|
2008-02-10 09:39:09 +05:30
|
|
|
# WebCalOptions
|
2007-08-27 09:22:06 +05:30
|
|
|
#
|
|
|
|
#------------------------------------------------------------------------
|
2008-02-10 09:39:09 +05:30
|
|
|
class WebCalOptions(MenuReportOptions):
|
2007-08-27 09:22:06 +05:30
|
|
|
"""
|
|
|
|
Defines options and provides handling interface.
|
|
|
|
"""
|
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
def __init__(self, name, dbase):
|
|
|
|
self.__db = dbase
|
|
|
|
self.__pid = None
|
|
|
|
self.__filter = None
|
|
|
|
MenuReportOptions.__init__(self, name, dbase)
|
2007-08-27 09:22:06 +05:30
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
def add_menu_options(self, menu):
|
|
|
|
"""
|
|
|
|
Add options to the menu for the web calendar.
|
|
|
|
"""
|
|
|
|
self.__add_report_options(menu)
|
|
|
|
self.__add_content_options(menu)
|
|
|
|
self.__add_misc_options(menu)
|
|
|
|
self.__add_notes_options(menu)
|
|
|
|
|
|
|
|
def __add_report_options(self, menu):
|
|
|
|
"""
|
|
|
|
Options on the "Report Options" tab.
|
|
|
|
"""
|
|
|
|
category_name = _("Report Options")
|
|
|
|
|
|
|
|
target = DestinationOption( _("Destination"),
|
|
|
|
os.path.join(const.USER_HOME,"WEBCAL"))
|
|
|
|
target.set_help( _("The destination directory for the web files"))
|
|
|
|
target.set_directory_entry(True)
|
|
|
|
menu.add_option(category_name, "target", target)
|
|
|
|
|
|
|
|
ext = EnumeratedListOption(_("File extension"), ".html" )
|
|
|
|
for etype in ['.html', '.htm', '.shtml', '.php', '.php3', '.cgi']:
|
|
|
|
ext.add_item(etype, etype)
|
|
|
|
ext.set_help( _("The extension to be used for the web files"))
|
|
|
|
menu.add_option(category_name, "ext", ext)
|
|
|
|
|
|
|
|
cright = EnumeratedListOption(_('Copyright'), 0 )
|
|
|
|
index = 0
|
|
|
|
for copt in _COPY_OPTIONS:
|
|
|
|
cright.add_item(index, copt)
|
|
|
|
index += 1
|
|
|
|
cright.set_help( _("The copyright to be used for the web files"))
|
|
|
|
menu.add_option(category_name, "cright", cright)
|
|
|
|
|
|
|
|
encoding = EnumeratedListOption(_('Character set encoding'), 'utf-8' )
|
|
|
|
for eopt in _CHARACTER_SETS:
|
|
|
|
encoding.add_item(eopt[1], eopt[0])
|
|
|
|
encoding.set_help( _("The encoding to be used for the web files"))
|
|
|
|
menu.add_option(category_name, "encoding", encoding)
|
|
|
|
|
|
|
|
def __add_content_options(self, menu):
|
|
|
|
"""
|
|
|
|
Options on the "Content Options" tab.
|
|
|
|
"""
|
|
|
|
category_name = _("Content Options")
|
|
|
|
|
|
|
|
year = NumberOption(_("Year of calendar"), time.localtime()[0],
|
|
|
|
1000, 3000)
|
|
|
|
year.set_help(_("Year of calendar"))
|
|
|
|
menu.add_option(category_name, "year", year)
|
|
|
|
|
|
|
|
self.__filter = FilterOption(_("Filter"), 0)
|
|
|
|
self.__filter.set_help(
|
|
|
|
_("Select filter to restrict people that appear on calendar"))
|
|
|
|
menu.add_option(category_name, "filter", self.__filter)
|
|
|
|
self.__filter.connect('value-changed', self.__filter_changed)
|
|
|
|
|
|
|
|
self.__pid = PersonOption(_("Filter Person"))
|
|
|
|
self.__pid.set_help(_("The center person for the filter"))
|
|
|
|
menu.add_option(category_name, "pid", self.__pid)
|
|
|
|
self.__pid.connect('value-changed', self.__update_filters)
|
|
|
|
|
|
|
|
self.__update_filters()
|
|
|
|
|
|
|
|
country = EnumeratedListOption(_('Country for holidays'), 0 )
|
|
|
|
index = 0
|
|
|
|
for item in _COUNTRIES:
|
|
|
|
country.add_item(index, item)
|
|
|
|
index += 1
|
|
|
|
country.set_help( _("Holidays will be included for the selected "
|
|
|
|
"country"))
|
|
|
|
menu.add_option(category_name, "country", country)
|
|
|
|
|
|
|
|
alive = BooleanOption(_("Include only living people"), True)
|
|
|
|
alive.set_help(_("Include only living people in the calendar"))
|
|
|
|
menu.add_option(category_name, "alive", alive)
|
|
|
|
|
|
|
|
birthdays = BooleanOption(_("Include birthdays"), True)
|
|
|
|
birthdays.set_help(_("Include birthdays in the calendar"))
|
|
|
|
menu.add_option(category_name, "birthdays", birthdays)
|
|
|
|
|
|
|
|
anniversaries = BooleanOption(_("Include anniversaries"), True)
|
|
|
|
anniversaries.set_help(_("Include anniversaries in the calendar"))
|
|
|
|
menu.add_option(category_name, "anniversaries", anniversaries)
|
|
|
|
|
|
|
|
surname = BooleanOption(_('Check for wives to use maiden name'), True)
|
|
|
|
surname.set_help(_("Attempt to use maiden names of women"))
|
|
|
|
menu.add_option(category_name, "surname", surname)
|
2007-08-27 09:22:06 +05:30
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
def __add_misc_options(self, menu):
|
|
|
|
"""
|
|
|
|
Options on the "Misc Options" tab.
|
|
|
|
"""
|
|
|
|
category_name = _("Misc Options")
|
|
|
|
|
|
|
|
title = StringOption(_('Calendar Title'), _('My Family Calendar'))
|
|
|
|
title.set_help(_("The title of the calendar"))
|
|
|
|
menu.add_option(category_name, "title", title)
|
|
|
|
|
|
|
|
home_link = StringOption(_('Home link'), '../index.html')
|
|
|
|
home_link.set_help(_("The link to be included to direct the user to "
|
|
|
|
"the main page of the web site"))
|
|
|
|
menu.add_option(category_name, "home_link", home_link)
|
|
|
|
|
|
|
|
serif_fonts = StringOption(_('Serif font family'),
|
|
|
|
'"Georgia","Times New Roman","Times",serif')
|
|
|
|
serif_fonts.set_help(_("Serif font family"))
|
|
|
|
menu.add_option(category_name, "serif_fonts", serif_fonts)
|
2007-08-27 09:22:06 +05:30
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
sanserif_fonts = StringOption(_('San-Serif font family'),
|
|
|
|
'"Verdana","Helvetica","Arial",sans-serif')
|
|
|
|
sanserif_fonts.set_help(_('San-Serif font family'))
|
|
|
|
menu.add_option(category_name, "sanserif_fonts", sanserif_fonts)
|
|
|
|
|
|
|
|
background = StringOption(_('Background Image'), "")
|
|
|
|
background.set_help(_('The image to be used as the page background'))
|
|
|
|
menu.add_option(category_name, "background", background)
|
|
|
|
|
|
|
|
repeat = EnumeratedListOption(_('Image Repeat'), 1 )
|
|
|
|
repeat.add_item(0, _('no-repeat'))
|
|
|
|
repeat.add_item(1, _('repeat'))
|
|
|
|
repeat.add_item(2, _('repeat-x'))
|
|
|
|
repeat.add_item(3, _('repeat-y'))
|
|
|
|
repeat.set_help( _("Whether to repeat the background image"))
|
|
|
|
menu.add_option(category_name, "repeat", repeat)
|
|
|
|
|
|
|
|
def __add_notes_options(self, menu):
|
|
|
|
"""
|
|
|
|
Options on the "Months Notes" tabs.
|
|
|
|
"""
|
|
|
|
category_name = _("Months 1-6 Notes")
|
2007-08-27 09:22:06 +05:30
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
note_jan = StringOption(_('Jan Note'), _('This prints in January'))
|
|
|
|
note_jan.set_help(_("The note for the month of January"))
|
|
|
|
menu.add_option(category_name, "note_jan", note_jan)
|
|
|
|
|
|
|
|
note_feb = StringOption(_('Feb Note'), _('This prints in February'))
|
|
|
|
note_feb.set_help(_("The note for the month of February"))
|
|
|
|
menu.add_option(category_name, "note_feb", note_feb)
|
|
|
|
|
|
|
|
note_mar = StringOption(_('Mar Note'), _('This prints in March'))
|
|
|
|
note_mar.set_help(_("The note for the month of March"))
|
|
|
|
menu.add_option(category_name, "note_mar", note_mar)
|
|
|
|
|
|
|
|
note_apr = StringOption(_('Apr Note'), _('This prints in April'))
|
|
|
|
note_apr.set_help(_("The note for the month of April"))
|
|
|
|
menu.add_option(category_name, "note_apr", note_apr)
|
|
|
|
|
|
|
|
note_may = StringOption(_('May Note'), _('This prints in May'))
|
|
|
|
note_may.set_help(_("The note for the month of May"))
|
|
|
|
menu.add_option(category_name, "note_may", note_may)
|
|
|
|
|
|
|
|
note_jun = StringOption(_('Jun Note'), _('This prints in June'))
|
|
|
|
note_jun.set_help(_("The note for the month of June"))
|
|
|
|
menu.add_option(category_name, "note_jun", note_jun)
|
|
|
|
|
|
|
|
category_name = _("Months 7-12 Notes")
|
2007-08-27 09:22:06 +05:30
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
note_jul = StringOption(_('Jul Note'), _('This prints in July'))
|
|
|
|
note_jul.set_help(_("The note for the month of July"))
|
|
|
|
menu.add_option(category_name, "note_jul", note_jul)
|
|
|
|
|
|
|
|
note_aug = StringOption(_('Aug Note'), _('This prints in August'))
|
|
|
|
note_aug.set_help(_("The note for the month of August"))
|
|
|
|
menu.add_option(category_name, "note_aug", note_aug)
|
|
|
|
|
|
|
|
note_sep = StringOption(_('Sep Note'), _('This prints in September'))
|
|
|
|
note_sep.set_help(_("The note for the month of September"))
|
|
|
|
menu.add_option(category_name, "note_sep", note_sep)
|
|
|
|
|
|
|
|
note_oct = StringOption(_('Oct Note'), _('This prints in October'))
|
|
|
|
note_oct.set_help(_("The note for the month of October"))
|
|
|
|
menu.add_option(category_name, "note_oct", note_oct)
|
|
|
|
|
|
|
|
note_nov = StringOption(_('Nov Note'), _('This prints in November'))
|
|
|
|
note_nov.set_help(_("The note for the month of November"))
|
|
|
|
menu.add_option(category_name, "note_nov", note_nov)
|
|
|
|
|
|
|
|
note_dec = StringOption(_('Dec Note'), _('This prints in December'))
|
|
|
|
note_dec.set_help(_("The note for the month of December"))
|
|
|
|
menu.add_option(category_name, "note_dec", note_dec)
|
2007-08-27 09:22:06 +05:30
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
def __update_filters(self):
|
|
|
|
"""
|
|
|
|
Update the filter list based on the selected person
|
|
|
|
"""
|
|
|
|
gid = self.__pid.get_value()
|
|
|
|
person = self.__db.get_person_from_gramps_id(gid)
|
|
|
|
filter_list = ReportUtils.get_person_filters(person, False)
|
|
|
|
self.__filter.set_filters(filter_list)
|
2007-08-27 09:22:06 +05:30
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
def __filter_changed(self):
|
|
|
|
"""
|
|
|
|
Handle filter change. If the filter is not specific to a person,
|
|
|
|
disable the person option
|
|
|
|
"""
|
|
|
|
filter_value = self.__filter.get_value()
|
|
|
|
if filter_value in [1, 2, 3, 4]:
|
|
|
|
# Filters 1, 2, 3 and 4 rely on the center person
|
|
|
|
self.__pid.set_available(True)
|
2007-08-27 09:22:06 +05:30
|
|
|
else:
|
2008-02-10 09:39:09 +05:30
|
|
|
# The rest don't
|
|
|
|
self.__pid.set_available(False)
|
|
|
|
|
|
|
|
def make_default_style(self, default_style):
|
2007-08-27 09:22:06 +05:30
|
|
|
"""Make the default output style for the Web Calendar
|
|
|
|
There are 5 named styles for this report.
|
|
|
|
|
|
|
|
WC-Title - The header for the page.
|
|
|
|
WC-Month - The Month name block for the calendar.
|
|
|
|
WC-Text - The text format for the body of the calendar.
|
|
|
|
WC-Note - The text placed at the bottom of each calendar.
|
|
|
|
WC-Table - controls the overall appearance of the calendar table.
|
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
"""
|
2007-08-27 09:22:06 +05:30
|
|
|
#
|
|
|
|
# WC-Title
|
|
|
|
#
|
|
|
|
font = BaseDoc.FontStyle()
|
2008-02-10 09:39:09 +05:30
|
|
|
font.set(face=BaseDoc.FONT_SERIF, size=24, bold=1,
|
|
|
|
italic=1, color=(0x80, 0x0, 0x0))
|
2007-08-27 09:22:06 +05:30
|
|
|
para = BaseDoc.ParagraphStyle()
|
|
|
|
para.set_font(font)
|
2008-02-10 09:39:09 +05:30
|
|
|
para.set(bgcolor=((0xb0, 0xc4, 0xde)))
|
2007-08-27 09:22:06 +05:30
|
|
|
para.set_alignment(BaseDoc.PARA_ALIGN_CENTER)
|
2008-02-10 09:39:09 +05:30
|
|
|
para.set_description(_('The style used for the title ("My Family '
|
|
|
|
'Calendar") of the page. The background color '
|
|
|
|
'sets the PAGE background. Borders DO NOT '
|
|
|
|
'work.'))
|
|
|
|
default_style.add_paragraph_style("WC-Title", para)
|
2007-08-27 09:22:06 +05:30
|
|
|
#
|
|
|
|
# WC-Month
|
|
|
|
#
|
|
|
|
font = BaseDoc.FontStyle()
|
2008-02-10 09:39:09 +05:30
|
|
|
font.set(face=BaseDoc.FONT_SERIF, size=48, bold=1,
|
|
|
|
italic=1, color=((0x80, 0x0, 0x0)))
|
2007-08-27 09:22:06 +05:30
|
|
|
para = BaseDoc.ParagraphStyle()
|
|
|
|
para.set_font(font)
|
2008-02-10 09:39:09 +05:30
|
|
|
para.set(bgcolor=((0xf0, 0xe6, 0x8c)))
|
2007-08-27 09:22:06 +05:30
|
|
|
para.set_alignment(BaseDoc.PARA_ALIGN_CENTER)
|
2008-02-10 09:39:09 +05:30
|
|
|
para.set_description(_('The style used for the month name and year, it'
|
|
|
|
' controls the font face, size, style, color '
|
|
|
|
'and the background color of the block, '
|
|
|
|
'including the day-name area. Inclusion of a '
|
|
|
|
'graphic does not cover the day-name area.'))
|
|
|
|
default_style.add_paragraph_style("WC-Month", para)
|
2007-08-27 09:22:06 +05:30
|
|
|
#
|
|
|
|
# WC-Text
|
|
|
|
#
|
|
|
|
font = BaseDoc.FontStyle()
|
2008-02-10 09:39:09 +05:30
|
|
|
font.set(face=BaseDoc.FONT_SERIF, size=16,
|
|
|
|
italic=1, color=((0x80, 0x0, 0x0)))
|
2007-08-27 09:22:06 +05:30
|
|
|
para = BaseDoc.ParagraphStyle()
|
|
|
|
para.set_font(font)
|
2008-02-10 09:39:09 +05:30
|
|
|
para.set(bgcolor=((0xf0, 0xf8, 0xff)))
|
2007-08-27 09:22:06 +05:30
|
|
|
para.set_alignment(BaseDoc.PARA_ALIGN_LEFT)
|
2008-02-10 09:39:09 +05:30
|
|
|
para.set_description(_('The style used for text in the body of the '
|
|
|
|
'calendar, it controls font size, face, style, '
|
|
|
|
'color, and alignment. The background color is '
|
|
|
|
'used ONLY for cells containing text, allowing '
|
|
|
|
'for high-lighting of dates.'))
|
|
|
|
default_style.add_paragraph_style("WC-Text", para)
|
2007-08-27 09:22:06 +05:30
|
|
|
#
|
|
|
|
# WC-Note
|
|
|
|
#
|
|
|
|
font = BaseDoc.FontStyle()
|
2008-02-10 09:39:09 +05:30
|
|
|
font.set(face=BaseDoc.FONT_SANS_SERIF, size=16, color=((0x0, 0x0, 0x0)))
|
2007-08-27 09:22:06 +05:30
|
|
|
para = BaseDoc.ParagraphStyle()
|
|
|
|
para.set_font(font)
|
2008-02-10 09:39:09 +05:30
|
|
|
para.set(bgcolor=((0xff, 0xff, 0xff)))
|
2007-08-27 09:22:06 +05:30
|
|
|
para.set_alignment(BaseDoc.PARA_ALIGN_LEFT)
|
2008-02-10 09:39:09 +05:30
|
|
|
para.set_description(_('The style used for notes at the bottom of the '
|
|
|
|
'calendar, it controls font size, face, style, '
|
|
|
|
'color and positioning. The background color '
|
|
|
|
'setting affect all EMPTY calendar cells.'))
|
|
|
|
default_style.add_paragraph_style("WC-Note", para)
|
2007-08-27 09:22:06 +05:30
|
|
|
#
|
|
|
|
# WC-Table
|
|
|
|
#
|
|
|
|
font = BaseDoc.FontStyle()
|
2008-02-10 09:39:09 +05:30
|
|
|
font.set(face=BaseDoc.FONT_SERIF, size=24, color=((0x80, 0x0, 0x0)))
|
2007-08-27 09:22:06 +05:30
|
|
|
para = BaseDoc.ParagraphStyle()
|
|
|
|
para.set_font(font)
|
2008-02-10 09:39:09 +05:30
|
|
|
para.set(bgcolor=((0xff, 0xff, 0xff)))
|
2007-08-27 09:22:06 +05:30
|
|
|
para.set_alignment(BaseDoc.PARA_ALIGN_RIGHT)
|
2008-02-10 09:39:09 +05:30
|
|
|
para.set_description(_('The style used for the table itself. This '
|
|
|
|
'affects the color of the table lines and the '
|
|
|
|
'color, font, size, and positioning of the '
|
|
|
|
'calendar date numbers. It also controls the '
|
|
|
|
'color of the day names.'))
|
|
|
|
default_style.add_paragraph_style("WC-Table", para)
|
2007-08-27 09:22:06 +05:30
|
|
|
|
|
|
|
#------------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
#
|
|
|
|
#
|
|
|
|
#------------------------------------------------------------------------
|
|
|
|
class Element:
|
|
|
|
""" A parsed XML element """
|
2008-02-24 19:25:55 +05:30
|
|
|
def __init__(self, name,attributes):
|
2007-08-27 09:22:06 +05:30
|
|
|
'Element constructor'
|
|
|
|
# The element's tag name
|
|
|
|
self.name = name
|
|
|
|
# The element's attribute dictionary
|
|
|
|
self.attributes = attributes
|
|
|
|
# The element's cdata
|
|
|
|
self.cdata = ''
|
|
|
|
# The element's child element list (sequence)
|
|
|
|
self.children = []
|
|
|
|
|
|
|
|
def AddChild(self,element):
|
|
|
|
'Add a reference to a child element'
|
|
|
|
self.children.append(element)
|
|
|
|
|
|
|
|
def getAttribute(self,key):
|
|
|
|
'Get an attribute value'
|
|
|
|
return self.attributes.get(key)
|
|
|
|
|
|
|
|
def getData(self):
|
|
|
|
'Get the cdata'
|
|
|
|
return self.cdata
|
|
|
|
|
2008-02-24 19:25:55 +05:30
|
|
|
def getElements(self, name=''):
|
2007-08-27 09:22:06 +05:30
|
|
|
'Get a list of child elements'
|
|
|
|
#If no tag name is specified, return the all children
|
|
|
|
if not name:
|
|
|
|
return self.children
|
|
|
|
else:
|
|
|
|
# else return only those children with a matching tag name
|
|
|
|
elements = []
|
|
|
|
for element in self.children:
|
|
|
|
if element.name == name:
|
|
|
|
elements.append(element)
|
|
|
|
return elements
|
|
|
|
|
|
|
|
def toString(self, level=0):
|
|
|
|
retval = " " * level
|
|
|
|
retval += "<%s" % self.name
|
|
|
|
for attribute in self.attributes:
|
|
|
|
retval += " %s=\"%s\"" % (attribute, self.attributes[attribute])
|
|
|
|
c = ""
|
|
|
|
for child in self.children:
|
|
|
|
c += child.toString(level+1)
|
|
|
|
if c == "":
|
|
|
|
retval += "/>\n"
|
|
|
|
else:
|
|
|
|
retval += ">\n" + c + ("</%s>\n" % self.name)
|
|
|
|
return retval
|
|
|
|
|
|
|
|
|
|
|
|
class Xml2Obj:
|
|
|
|
""" XML to Object """
|
|
|
|
def __init__(self):
|
|
|
|
self.root = None
|
|
|
|
self.nodeStack = []
|
|
|
|
|
2008-02-24 19:25:55 +05:30
|
|
|
def StartElement(self, name,attributes):
|
2007-08-27 09:22:06 +05:30
|
|
|
'SAX start element even handler'
|
|
|
|
# Instantiate an Element object
|
|
|
|
element = Element(name.encode(),attributes)
|
|
|
|
# Push element onto the stack and make it a child of parent
|
|
|
|
if len(self.nodeStack) > 0:
|
|
|
|
parent = self.nodeStack[-1]
|
|
|
|
parent.AddChild(element)
|
|
|
|
else:
|
|
|
|
self.root = element
|
|
|
|
self.nodeStack.append(element)
|
|
|
|
|
2008-02-24 19:25:55 +05:30
|
|
|
def EndElement(self, name):
|
2007-08-27 09:22:06 +05:30
|
|
|
'SAX end element event handler'
|
|
|
|
self.nodeStack = self.nodeStack[:-1]
|
|
|
|
|
|
|
|
def CharacterData(self,data):
|
|
|
|
'SAX character data event handler'
|
|
|
|
if data.strip():
|
|
|
|
data = data.encode()
|
|
|
|
element = self.nodeStack[-1]
|
|
|
|
element.cdata += data
|
|
|
|
return
|
|
|
|
|
|
|
|
def Parse(self,filename):
|
|
|
|
# Create a SAX parser
|
|
|
|
Parser = expat.ParserCreate()
|
|
|
|
# SAX event handlers
|
|
|
|
Parser.StartElementHandler = self.StartElement
|
|
|
|
Parser.EndElementHandler = self.EndElement
|
|
|
|
Parser.CharacterDataHandler = self.CharacterData
|
|
|
|
# Parse the XML File
|
|
|
|
ParserStatus = Parser.Parse(open(filename,'r').read(), 1)
|
|
|
|
return self.root
|
|
|
|
|
|
|
|
class Holidays:
|
|
|
|
""" Class used to read XML holidays to add to calendar. """
|
|
|
|
def __init__(self, elements, country="US"):
|
|
|
|
self.debug = 0
|
|
|
|
self.elements = elements
|
|
|
|
self.Country = country
|
|
|
|
self.dates = []
|
|
|
|
self.initialize()
|
|
|
|
def set_country(self, country):
|
|
|
|
self.Country = country
|
|
|
|
self.dates = []
|
|
|
|
self.initialize()
|
|
|
|
def initialize(self):
|
|
|
|
# parse the date objects
|
|
|
|
for country_set in self.elements.children:
|
|
|
|
if country_set.name == "country" and country_set.attributes["name"] == self.Country:
|
|
|
|
for date in country_set.children:
|
|
|
|
if date.name == "date":
|
|
|
|
data = {"value" : "",
|
|
|
|
"name" : "",
|
|
|
|
"offset": "",
|
|
|
|
"type": "",
|
|
|
|
"if": "",
|
|
|
|
} # defaults
|
|
|
|
for attr in date.attributes:
|
|
|
|
data[attr] = date.attributes[attr]
|
|
|
|
self.dates.append(data)
|
|
|
|
def get_daynames(self, y, m, dayname):
|
|
|
|
if self.debug: print "%s's in %d %d..." % (dayname, m, y)
|
|
|
|
retval = [0]
|
|
|
|
dow = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'].index(dayname)
|
|
|
|
for d in range(1, 32):
|
|
|
|
try:
|
|
|
|
date = datetime.date(y, m, d)
|
|
|
|
except ValueError:
|
|
|
|
continue
|
|
|
|
if date.weekday() == dow:
|
|
|
|
retval.append( d )
|
|
|
|
if self.debug: print "dow=", dow, "days=", retval
|
|
|
|
return retval
|
|
|
|
def check_date(self, date):
|
|
|
|
retval = []
|
|
|
|
for rule in self.dates:
|
|
|
|
if self.debug: print "Checking ", rule["name"], "..."
|
|
|
|
offset = 0
|
|
|
|
if rule["offset"] != "":
|
|
|
|
if rule["offset"].isdigit():
|
|
|
|
offset = int(rule["offset"])
|
|
|
|
elif rule["offset"][0] in ["-","+"] and rule["offset"][1:].isdigit():
|
|
|
|
offset = int(rule["offset"])
|
|
|
|
else:
|
|
|
|
# must be a dayname
|
|
|
|
offset = rule["offset"]
|
|
|
|
if rule["value"].count("/") == 3: # year/num/day/month, "3rd wednesday in april"
|
|
|
|
y, num, dayname, mon = rule["value"].split("/")
|
|
|
|
if y == "*":
|
|
|
|
y = date.year
|
|
|
|
else:
|
|
|
|
y = int(y)
|
|
|
|
if mon.isdigit():
|
|
|
|
m = int(mon)
|
|
|
|
elif mon == "*":
|
|
|
|
m = date.month
|
|
|
|
else:
|
|
|
|
m = ['jan', 'feb', 'mar', 'apr', 'may', 'jun',
|
|
|
|
'jul', 'aug', 'sep', 'oct', 'nov', 'dec'].index(mon) + 1
|
|
|
|
dates_of_dayname = self.get_daynames(y, m, dayname)
|
|
|
|
if self.debug: print "num =", num
|
|
|
|
d = dates_of_dayname[int(num)]
|
|
|
|
elif rule["value"].count("/") == 2: # year/month/day
|
|
|
|
y, m, d = rule["value"].split("/")
|
|
|
|
if y == "*":
|
|
|
|
y = date.year
|
|
|
|
else:
|
|
|
|
y = int(y)
|
|
|
|
if m == "*":
|
|
|
|
m = date.month
|
|
|
|
else:
|
|
|
|
m = int(m)
|
|
|
|
if d == "*":
|
|
|
|
d = date.day
|
|
|
|
else:
|
|
|
|
d = int(d)
|
|
|
|
ndate = datetime.date(y, m, d)
|
|
|
|
if self.debug: print ndate, offset, type(offset)
|
|
|
|
if type(offset) == int:
|
|
|
|
if offset != 0:
|
|
|
|
ndate = ndate.fromordinal(ndate.toordinal() + offset)
|
|
|
|
elif type(offset) in [type(u''), str]:
|
|
|
|
dir = 1
|
|
|
|
if offset[0] == "-":
|
|
|
|
dir = -1
|
|
|
|
offset = offset[1:]
|
|
|
|
if offset in ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']:
|
|
|
|
# next tuesday you come to, including this one
|
|
|
|
dow = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'].index(offset)
|
|
|
|
ord = ndate.toordinal()
|
|
|
|
while ndate.fromordinal(ord).weekday() != dow:
|
|
|
|
ord += dir
|
|
|
|
ndate = ndate.fromordinal(ord)
|
|
|
|
if self.debug: print "ndate:", ndate, "date:", date
|
|
|
|
if ndate == date:
|
|
|
|
if rule["if"] != "":
|
|
|
|
if not eval(rule["if"]):
|
|
|
|
continue
|
|
|
|
retval.append(rule["name"])
|
|
|
|
return retval
|
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
def process_holiday_file(filename):
|
|
|
|
""" This will process a holiday file for country names """
|
|
|
|
parser = Xml2Obj()
|
|
|
|
element = parser.Parse(filename)
|
|
|
|
country_list = []
|
|
|
|
for country_set in element.children:
|
|
|
|
if country_set.name == "country":
|
|
|
|
if country_set.attributes["name"] not in country_list:
|
|
|
|
country_list.append(country_set.attributes["name"])
|
|
|
|
return country_list
|
|
|
|
|
|
|
|
def _get_countries():
|
2007-08-27 09:22:06 +05:30
|
|
|
""" Looks in multiple places for holidays.xml files """
|
2007-11-26 10:41:19 +05:30
|
|
|
locations = [const.PLUGINS_DIR, const.USER_PLUGINS]
|
2007-08-27 09:22:06 +05:30
|
|
|
holiday_file = 'holidays.xml'
|
|
|
|
country_list = []
|
|
|
|
for dir in locations:
|
|
|
|
holiday_full_path = os.path.join(dir, holiday_file)
|
|
|
|
if os.path.exists(holiday_full_path):
|
|
|
|
cs = process_holiday_file(holiday_full_path)
|
|
|
|
for c in cs:
|
|
|
|
if c not in country_list:
|
|
|
|
country_list.append(c)
|
|
|
|
country_list.sort()
|
|
|
|
country_list.insert(0, _("Don't include holidays"))
|
|
|
|
return country_list
|
|
|
|
|
2008-02-10 09:39:09 +05:30
|
|
|
# TODO: Only load this once the first time it is actually needed so Gramps
|
|
|
|
# doesn't take so long to start up.
|
|
|
|
_COUNTRIES = _get_countries()
|
2007-08-27 09:22:06 +05:30
|
|
|
|
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
#
|
|
|
|
#
|
|
|
|
#
|
|
|
|
#-------------------------------------------------------------------------
|
|
|
|
register_report(
|
|
|
|
name = 'WebCal',
|
|
|
|
category = CATEGORY_WEB,
|
2008-02-10 09:39:09 +05:30
|
|
|
report_class = WebCalReport,
|
|
|
|
options_class = WebCalOptions,
|
2007-08-27 09:22:06 +05:30
|
|
|
modes = MODE_GUI,
|
2008-03-02 04:17:48 +05:30
|
|
|
translated_name = _("Web Calendar"),
|
2007-08-27 09:22:06 +05:30
|
|
|
status = _("Beta"),
|
2008-03-02 04:17:48 +05:30
|
|
|
author_name = "Thom Sturgill",
|
|
|
|
author_email = "thsturgill@yahoo.com",
|
|
|
|
description = _("Produces web (HTML) calendars."),
|
2007-08-27 09:22:06 +05:30
|
|
|
)
|