Reorganization of the narrative web report. (#445)

* Reorganization of the narrative web report.

Resolves  #010151, #07740

* Add empty role to person and family backref lists
This commit is contained in:
Serge Noiraud 2017-08-19 19:54:15 +02:00 committed by GitHub
parent 1d51fa4f61
commit 8a648e7e22
22 changed files with 10019 additions and 8674 deletions

View File

@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
AddressBookPage
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.plug.report import Bibliography
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import FULLCLEAR
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
class AddressBookPage(BasePage):
"""
Create one page for one Address
"""
def __init__(self, report, title, person_handle, has_add, has_res, has_url):
"""
@param: report -- The instance of the main report class
for this report
@param: title -- Is the title of the web page
@param: person_handle -- the url, address and residence to use
for the report
@param: has_add -- the address to use for the report
@param: has_res -- the residence to use for the report
@param: has_url -- the url to use for the report
"""
person = report.database.get_person_from_handle(person_handle)
BasePage.__init__(self, report, title, person.gramps_id)
self.bibli = Bibliography()
self.uplink = True
# set the file name and open file
output_file, sio = self.report.create_file(person_handle, "addr")
addressbookpage, head, body = self.write_header(_("Address Book"))
# begin address book page division and section title
with Html("div", class_="content",
id="AddressBookDetail") as addressbookdetail:
body += addressbookdetail
link = self.new_person_link(person_handle, uplink=True,
person=person)
addressbookdetail += Html("h3", link)
# individual has an address
if has_add:
addressbookdetail += self.display_addr_list(has_add, None)
# individual has a residence
if has_res:
addressbookdetail.extend(
self.dump_residence(res)
for res in has_res
)
# individual has a url
if has_url:
addressbookdetail += self.display_url_list(has_url)
# add fullclear for proper styling
# and footer section to page
footer = self.write_footer(None)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(addressbookpage, output_file, sio, 0)

View File

@ -0,0 +1,170 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
AddressBookListPage
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import FULLCLEAR
LOG = logging.getLogger(".NarrativeWeb")
_ = glocale.translation.sgettext
getcontext().prec = 8
class AddressBookListPage(BasePage):
"""
Create the index for addresses.
"""
def __init__(self, report, title, has_url_addr_res):
"""
@param: report -- The instance of the main report class
for this report
@param: title -- Is the title of the web page
@param: has_url_addr_res -- The url, address and residence to use
for the report
"""
BasePage.__init__(self, report, title)
# Name the file, and create it
output_file, sio = self.report.create_file("addressbook")
# Add xml, doctype, meta and stylesheets
addressbooklistpage, head, body = self.write_header(_("Address Book"))
# begin AddressBookList division
with Html("div", class_="content",
id="AddressBookList") as addressbooklist:
body += addressbooklist
# Address Book Page message
msg = _("This page contains an index of all the individuals in "
"the database, sorted by their surname, with one of the "
"following: Address, Residence, or Web Links. "
"Selecting the person&#8217;s name will take you "
"to their individual Address Book page.")
addressbooklist += Html("p", msg, id="description")
# begin Address Book table
with Html("table",
class_="infolist primobjlist addressbook") as table:
addressbooklist += table
thead = Html("thead")
table += thead
trow = Html("tr")
thead += trow
trow.extend(
Html("th", label, class_=colclass, inline=True)
for (label, colclass) in [
["&nbsp;", "ColumnRowLabel"],
[_("Full Name"), "ColumnName"],
[_("Address"), "ColumnAddress"],
[_("Residence"), "ColumnResidence"],
[_("Web Links"), "ColumnWebLinks"]
]
)
tbody = Html("tbody")
table += tbody
index = 1
for (sort_name, person_handle,
has_add, has_res,
has_url) in has_url_addr_res:
address = None
residence = None
weblinks = None
# has address but no residence event
if has_add and not has_res:
address = "X"
# has residence, but no addresses
elif has_res and not has_add:
residence = "X"
# has residence and addresses too
elif has_add and has_res:
address = "X"
residence = "X"
# has Web Links
if has_url:
weblinks = "X"
trow = Html("tr")
tbody += trow
trow.extend(
Html("td", data or "&nbsp;", class_=colclass,
inline=True)
for (colclass, data) in [
["ColumnRowLabel", index],
["ColumnName",
self.addressbook_link(person_handle)],
["ColumnAddress", address],
["ColumnResidence", residence],
["ColumnWebLinks", weblinks]
]
)
index += 1
# Add footer and clearline
footer = self.write_footer(None)
body += (FULLCLEAR, footer)
# send the page out for processing
# and close the file
self.xhtml_writer(addressbooklistpage, output_file, sio, 0)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
CitationPages - dummy
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
#################################################
#
# Passes citations through to the Sources page
#
#################################################
class CitationPages(BasePage):
"""
This class is responsible for displaying information about the 'Citation'
database objects. It passes this information to the 'Sources' tab. It is
told by the 'add_instances' call which 'Citation's to display.
"""
def __init__(self, report):
"""
@param: report -- The instance of the main report class for
this report
"""
BasePage.__init__(self, report, title="")
def display_pages(self, title):
pass

View File

@ -0,0 +1,863 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2010-2017 Serge Noiraud
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
This module is used to share variables, enums and functions between all modules
"""
from unicodedata import normalize
from collections import defaultdict
from hashlib import md5
import re
import logging
from xml.sax.saxutils import escape
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.display.name import displayer as _nd
from gramps.gen.display.place import displayer as _pd
from gramps.gen.utils.db import get_death_or_fallback
from gramps.gen.lib import (EventType, Date)
from gramps.gen.plug import BasePluginManager
from gramps.plugins.lib.libgedcom import make_gedcom_date, DATE_QUALITY
from gramps.gen.plug.report import utils
from gramps.plugins.lib.libhtml import Html
LOG = logging.getLogger(".NarrativeWeb")
# define clear blank line for proper styling
FULLCLEAR = Html("div", class_="fullclear", inline=True)
# define all possible web page filename extensions
_WEB_EXT = ['.html', '.htm', '.shtml', '.php', '.php3', '.cgi']
# used to select secured web site or not
HTTP = "http://"
HTTPS = "https://"
GOOGLE_MAPS = 'https://maps.googleapis.com/maps/'
# javascript code for marker path
MARKER_PATH = """
var marker_png = '%s'
"""
# javascript code for Google's FamilyLinks...
FAMILYLINKS = """
var tracelife = %s
function initialize() {
var myLatLng = new google.maps.LatLng(%s, %s);
var mapOptions = {
scaleControl: true,
panControl: true,
backgroundColor: '#000000',
zoom: %d,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"),
mapOptions);
var flightPath = new google.maps.Polyline({
path: tracelife,
strokeColor: "#FF0000",
strokeOpacity: 1.0,
strokeWeight: 2
});
flightPath.setMap(map);
}"""
# javascript for Google's Drop Markers...
DROPMASTERS = """
var markers = [];
var iterator = 0;
var tracelife = %s
var map;
var myLatLng = new google.maps.LatLng(%s, %s);
function initialize() {
var mapOptions = {
scaleControl: true,
zoomControl: true,
zoom: %d,
mapTypeId: google.maps.MapTypeId.ROADMAP,
center: myLatLng,
};
map = new google.maps.Map(document.getElementById("map_canvas"),
mapOptions);
};
function drop() {
for (var i = 0; i < tracelife.length; i++) {
setTimeout(function() {
addMarker();
}, i * 1000);
}
}
function addMarker() {
var location = tracelife[iterator];
var myLatLng = new google.maps.LatLng(location[1], location[2]);
markers.push(new google.maps.Marker({
position: myLatLng,
map: map,
draggable: true,
title: location[0],
animation: google.maps.Animation.DROP
}));
iterator++;
}"""
# javascript for Google's Markers...
MARKERS = """
var tracelife = %s
var map;
var myLatLng = new google.maps.LatLng(%s, %s);
function initialize() {
var mapOptions = {
scaleControl: true,
panControl: true,
backgroundColor: '#000000',
zoom: %d,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"),
mapOptions);
addMarkers();
}
function addMarkers() {
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < tracelife.length; i++) {
var location = tracelife[i];
var myLatLng = new google.maps.LatLng(location[1], location[2]);
var marker = new google.maps.Marker({
position: myLatLng,
draggable: true,
title: location[0],
map: map,
zIndex: location[3]
});
bounds.extend(myLatLng);
if ( i > 1 ) { map.fitBounds(bounds); };
}
}"""
# javascript for OpenStreetMap's markers...
OSM_MARKERS = """
function initialize(){
var map;
var tracelife = %s;
var iconStyle = new ol.style.Style({
image: new ol.style.Icon(({
opacity: 1.0,
src: marker_png
}))
});
var markerSource = new ol.source.Vector({
});
for (var i = 0; i < tracelife.length; i++) {
var loc = tracelife[i];
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.transform([loc[0], loc[1]],
'EPSG:4326', 'EPSG:3857')),
name: loc[2],
});
iconFeature.setStyle(iconStyle);
markerSource.addFeature(iconFeature);
}
markerLayer = new ol.layer.Vector({
source: markerSource,
style: iconStyle
});
var centerCoord = new ol.proj.transform([%s, %s], 'EPSG:4326', 'EPSG:3857');
map= new ol.Map({
target: 'map_canvas',
layers: [new ol.layer.Tile({ source: new ol.source.OSM() }),
markerLayer],
view: new ol.View({ center: centerCoord, zoom: %d })
});
var element = document.getElementById('popup');
var tooltip = new ol.Overlay({
element: element,
positioning: 'bottom-center',
stopEvent: false
});
map.addOverlay(tooltip);
var displayFeatureInfo = function(pixel) {
var feature = map.forEachFeatureAtPixel(pixel, function(feature, layer) {
return feature;
});
var info = document.getElementById('popup');
if (feature) {
var geometry = feature.getGeometry();
var coord = geometry.getCoordinates();
tooltip.setPosition(coord);
$(element).siblings('.popover').css({ width: '250px' });
$(element).siblings('.popover').css({ background: '#aaa' });
$(info).popover({
'placement': 'auto',
'html': true,
'content': feature.get('name')
});
$(info).popover('show');
} else {
// TODO : some warning with firebug here
$(info).popover('destroy');
$('.popover').remove();
}
};
map.on('pointermove', function(evt) {
if (evt.dragging) {
return;
}
var pixel = map.getEventPixel(evt.originalEvent);
displayFeatureInfo(pixel);
});
map.on('click', function(evt) {
displayFeatureInfo(evt.pixel);
});
};
"""
# variables for alphabet_navigation()
_KEYPERSON, _KEYPLACE, _KEYEVENT, _ALPHAEVENT = 0, 1, 2, 3
COLLATE_LANG = glocale.collation
_NAME_STYLE_SHORT = 2
_NAME_STYLE_DEFAULT = 1
_NAME_STYLE_FIRST = 0
_NAME_STYLE_SPECIAL = None
PLUGMAN = BasePluginManager.get_instance()
CSS = PLUGMAN.process_plugin_data('WEBSTUFF')
#_NAME_COL = 3
_WRONGMEDIAPATH = []
_HTML_DBL_QUOTES = re.compile(r'([^"]*) " ([^"]*) " (.*)', re.VERBOSE)
_HTML_SNG_QUOTES = re.compile(r"([^']*) ' ([^']*) ' (.*)", re.VERBOSE)
# Events that are usually a family event
_EVENTMAP = set([EventType.MARRIAGE, EventType.MARR_ALT,
EventType.MARR_SETTL, EventType.MARR_LIC,
EventType.MARR_CONTR, EventType.MARR_BANNS,
EventType.ENGAGEMENT, EventType.DIVORCE,
EventType.DIV_FILING])
# Names for stylesheets
_NARRATIVESCREEN = "narrative-screen.css"
_NARRATIVEPRINT = "narrative-print.css"
def sort_people(dbase, handle_list, rlocale=glocale):
"""
will sort the database people by surname
"""
sname_sub = defaultdict(list)
sortnames = {}
for person_handle in handle_list:
person = dbase.get_person_from_handle(person_handle)
primary_name = person.get_primary_name()
if primary_name.group_as:
surname = primary_name.group_as.encode('utf-8')
else:
group_map = _nd.primary_surname(primary_name)
surname = dbase.get_name_group_mapping(group_map)
if isinstance(surname, bytes):
surname = surname.decode('utf-8')
# Treat people who have no name with those whose name is just
# 'whitespace'
if surname is None or surname.isspace():
surname = ''
sortnames[person_handle] = _nd.sort_string(primary_name)
sname_sub[surname].append(person_handle)
sorted_lists = []
temp_list = sorted(sname_sub, key=rlocale.sort_key)
for name in temp_list:
if isinstance(name, bytes):
name = name.decode('utf-8')
slist = sorted(((sortnames[x], x) for x in sname_sub[name]),
key=lambda x: rlocale.sort_key(x[0]))
entries = [x[1] for x in slist]
sorted_lists.append((name, entries))
return sorted_lists
def sort_event_types(dbase, event_types, event_handle_list, rlocale):
"""
sort a list of event types and their associated event handles
@param: dbase -- report database
@param: event_types -- a dict of event types
@param: event_handle_list -- all event handles in this database
"""
event_dict = dict((evt_type, list()) for evt_type in event_types)
for event_handle in event_handle_list:
event = dbase.get_event_from_handle(event_handle)
event_type = rlocale.translation.sgettext(event.get_type().xml_str())
# add (gramps_id, date, handle) from this event
if event_type in event_dict:
sort_value = event.get_date_object().get_sort_value()
event_dict[event_type].append((sort_value, event_handle))
for tup_list in event_dict.values():
tup_list.sort()
# return a list of sorted tuples, one per event
retval = [(event_type, event_list) for (event_type,
event_list) in event_dict.items()]
retval.sort(key=lambda item: str(item[0]))
return retval
# Modified _get_regular_surname from WebCal.py to get prefix, first name,
# and suffix
def _get_short_name(gender, name):
""" Will get suffix for all people passed through it """
short_name = name.get_first_name()
suffix = name.get_suffix()
if suffix:
short_name = short_name + ", " + suffix
return short_name
def __get_person_keyname(dbase, handle):
""" .... """
person = dbase.get_person_from_handle(handle)
return _nd.sort_string(person.get_primary_name())
def __get_place_keyname(dbase, handle):
""" ... """
return utils.place_name(dbase, handle)
# See : http://www.gramps-project.org/bugs/view.php?id = 4423
# Contraction data taken from CLDR 22.1. Only the default variant is considered.
# The languages included below are, by no means, all the langauges that have
# contractions - just a sample of langauges that have been supported
# At the time of writing (Feb 2013), the following langauges have greater that
# 50% coverage of translation of Gramps: bg Bulgarian, ca Catalan, cs Czech, da
# Danish, de German, el Greek, en_GB, es Spanish, fi Finish, fr French, he
# Hebrew, hr Croation, hu Hungarian, it Italian, ja Japanese, lt Lithuanian, nb
# Noregian Bokmål, nn Norwegian Nynorsk, nl Dutch, pl Polish, pt_BR Portuguese
# (Brazil), pt_P Portugeuse (Portugal), ru Russian, sk Slovak, sl Slovenian, sv
# Swedish, vi Vietnamese, zh_CN Chinese.
# Key is the language (or language and country), Value is a list of
# contractions. Each contraction consists of a tuple. First element of the
# tuple is the list of characters, second element is the string to use as the
# index entry.
# The DUCET contractions (e.g. LATIN CAPIAL LETTER L, MIDDLE DOT) are ignored,
# as are the supresscontractions in some locales.
CONTRACTIONS_DICT = {
# bg Bulgarian validSubLocales="bg_BG" no contractions
# ca Catalan validSubLocales="ca_AD ca_ES"
"ca" : [(("", ""), "L")],
# Czech, validSubLocales="cs_CZ" Czech_Czech Republic
"cs" : [(("ch", "cH", "Ch", "CH"), "CH")],
# Danish validSubLocales="da_DK" Danish_Denmark
"da" : [(("aa", "Aa", "AA"), "Å")],
# de German validSubLocales="de_AT de_BE de_CH de_DE de_LI de_LU" no
# contractions in standard collation.
# el Greek validSubLocales="el_CY el_GR" no contractions.
# es Spanish validSubLocales="es_419 es_AR es_BO es_CL es_CO es_CR es_CU
# es_DO es_EA es_EC es_ES es_GQ es_GT es_HN es_IC es_MX es_NI es_PA es_PE
# es_PH es_PR es_PY es_SV es_US es_UY es_VE" no contractions in standard
# collation.
# fi Finish validSubLocales="fi_FI" no contractions in default (phonebook)
# collation.
# fr French no collation data.
# he Hebrew validSubLocales="he_IL" no contractions
# hr Croation validSubLocales="hr_BA hr_HR"
"hr" : [(("", ""), ""),
(("lj", "Lj", 'LJ'), "LJ"),
(("Nj", "NJ", "nj"), "NJ")],
# Hungarian hu_HU for two and three character contractions.
"hu" : [(("cs", "Cs", "CS"), "CS"),
(("dzs", "Dzs", "DZS"), "DZS"), # order is important
(("dz", "Dz", "DZ"), "DZ"),
(("gy", "Gy", "GY"), "GY"),
(("ly", "Ly", "LY"), "LY"),
(("ny", "Ny", "NY"), "NY"),
(("sz", "Sz", "SZ"), "SZ"),
(("ty", "Ty", "TY"), "TY"),
(("zs", "Zs", "ZS"), "ZS")
],
# it Italian no collation data.
# ja Japanese unable to process the data as it is too complex.
# lt Lithuanian no contractions.
# Norwegian Bokmål
"nb" : [(("aa", "Aa", "AA"), "Å")],
# nn Norwegian Nynorsk validSubLocales="nn_NO"
"nn" : [(("aa", "Aa", "AA"), "Å")],
# nl Dutch no collation data.
# pl Polish validSubLocales="pl_PL" no contractions
# pt Portuguese no collation data.
# ru Russian validSubLocales="ru_BY ru_KG ru_KZ ru_MD ru_RU ru_UA" no
# contractions
# Slovak, validSubLocales="sk_SK" Slovak_Slovakia
# having DZ in Slovak as a contraction was rejected in
# http://unicode.org/cldr/trac/ticket/2968
"sk" : [(("ch", "cH", "Ch", "CH"), "Ch")],
# sl Slovenian validSubLocales="sl_SI" no contractions
# sv Swedish validSubLocales="sv_AX sv_FI sv_SE" default collation is
# "reformed" no contractions.
# vi Vietnamese validSubLocales="vi_VN" no contractions.
# zh Chinese validSubLocales="zh_Hans zh_Hans_CN zh_Hans_SG" no contractions
# in Latin characters the others are too complex.
}
# The comment below from the glibc locale sv_SE in
# localedata/locales/sv_SE :
#
# % The letter w is normally not present in the Swedish alphabet. It
# % exists in some names in Swedish and foreign words, but is accounted
# % for as a variant of 'v'. Words and names with 'w' are in Swedish
# % ordered alphabetically among the words and names with 'v'. If two
# % words or names are only to be distinguished by 'v' or % 'w', 'v' is
# % placed before 'w'.
#
# See : http://www.gramps-project.org/bugs/view.php?id = 2933
#
# HOWEVER: the characters V and W in Swedish are not considered as a special
# case for several reasons. (1) The default collation for Swedish (called the
# 'reformed' collation type) regards the difference between 'v' and 'w' as a
# primary difference. (2) 'v' and 'w' in the 'standard' (non-default) collation
# type are not a contraction, just a case where the difference is secondary
# rather than primary. (3) There are plenty of other languages where a
# difference that is primary in other languages is secondary, and those are not
# specially handled.
def first_letter(string, rlocale=glocale):
"""
Receives a string and returns the first letter
"""
if string is None or len(string) < 1:
return ' '
norm_unicode = normalize('NFKC', str(string))
contractions = CONTRACTIONS_DICT.get(COLLATE_LANG)
if contractions is None:
contractions = CONTRACTIONS_DICT.get(COLLATE_LANG.split("_")[0])
if contractions is not None:
for contraction in contractions:
count = len(contraction[0][0])
if (len(norm_unicode) >= count and
norm_unicode[:count] in contraction[0]):
return contraction[1]
# no special case
return norm_unicode[0].upper()
try:
import PyICU # pylint : disable=wrong-import-position
PRIM_COLL = PyICU.Collator.createInstance(PyICU.Locale(COLLATE_LANG))
PRIM_COLL.setStrength(PRIM_COLL.PRIMARY)
def primary_difference(prev_key, new_key, rlocale=glocale):
"""
Try to use the PyICU collation.
"""
return PRIM_COLL.compare(prev_key, new_key) != 0
except:
def primary_difference(prev_key, new_key, rlocale=glocale):
"""
The PyICU collation is not available.
Returns true if there is a primary difference between the two parameters
See http://www.gramps-project.org/bugs/view.php?id=2933#c9317 if
letter[i]+'a' < letter[i+1]+'b' and letter[i+1]+'a' < letter[i]+'b' is
true then the letters should be grouped together
The test characters here must not be any that are used in contractions.
"""
return rlocale.sort_key(prev_key + "e") >= \
rlocale.sort_key(new_key + "f") or \
rlocale.sort_key(new_key + "e") >= \
rlocale.sort_key(prev_key + "f")
def get_first_letters(dbase, handle_list, key, rlocale=glocale):
"""
get the first letters of the handle_list
@param: handle_list -- One of a handle list for either person or
place handles or an evt types list
@param: key -- Either a person, place, or event type
The first letter (or letters if there is a contraction) are extracted from
all the objects in the handle list. There may be duplicates, and there may
be letters where there is only a secondary or tertiary difference, not a
primary difference. The list is sorted in collation order. For each group
with secondary or tertiary differences, the first in collation sequence is
retained. For example, assume the default collation sequence (DUCET) and
names Ånström and Apple. These will sort in the order shown. Å and A have a
secondary difference. If the first letter from these names was chosen then
the inex entry would be Å. This is not desirable. Instead, the initial
letters are extracted (Å and A). These are sorted, which gives A and Å. Then
the first of these is used for the index entry.
"""
index_list = []
for handle in handle_list:
if key == _KEYPERSON:
keyname = __get_person_keyname(dbase, handle)
elif key == _KEYPLACE:
keyname = __get_place_keyname(dbase, handle)
else:
if rlocale != glocale:
keyname = rlocale.translation.sgettext(handle)
else:
keyname = handle
ltr = first_letter(keyname)
index_list.append(ltr)
# Now remove letters where there is not a primary difference
index_list.sort(key=rlocale.sort_key)
first = True
prev_index = None
for key in index_list[:]: #iterate over a slice copy of the list
if first or primary_difference(prev_index, key, rlocale):
first = False
prev_index = key
else:
index_list.remove(key)
# return menu set letters for alphabet_navigation
return index_list
def get_index_letter(letter, index_list, rlocale=glocale):
"""
This finds the letter in the index_list that has no primary difference from
the letter provided. See the discussion in get_first_letters above.
Continuing the example, if letter is Å and index_list is A, then this would
return A.
"""
for index in index_list:
if not primary_difference(letter, index, rlocale):
return index
LOG.warning("Initial letter '%s' not found in alphabetic navigation list",
letter)
LOG.debug("filtered sorted index list %s", index_list)
return letter
def alphabet_navigation(index_list, rlocale=glocale):
"""
Will create the alphabet navigation bar for classes IndividualListPage,
SurnameListPage, PlaceListPage, and EventList
@param: index_list -- a dictionary of either letters or words
"""
sorted_set = defaultdict(int)
for menu_item in index_list:
sorted_set[menu_item] += 1
# remove the number of each occurance of each letter
sorted_alpha_index = sorted(sorted_set, key=rlocale.sort_key)
# if no letters, return None to its callers
if not sorted_alpha_index:
return None
num_ltrs = len(sorted_alpha_index)
num_of_cols = 26
num_of_rows = ((num_ltrs // num_of_cols) + 1)
# begin alphabet navigation division
with Html("div", id="alphanav") as alphabetnavigation:
index = 0
for row in range(num_of_rows):
unordered = Html("ul")
cols = 0
while cols <= num_of_cols and index < num_ltrs:
menu_item = sorted_alpha_index[index]
if menu_item == ' ':
menu_item = '&nbsp;'
# adding title to hyperlink menu for screen readers and
# braille writers
title_txt = "Alphabet Menu: %s" % menu_item
title_str = rlocale.translation.sgettext(title_txt)
hyper = Html("a", menu_item, title=title_str,
href="#%s" % menu_item)
unordered.extend(Html("li", hyper, inline=True))
index += 1
cols += 1
num_of_rows -= 1
alphabetnavigation += unordered
return alphabetnavigation
def _has_webpage_extension(url):
"""
determine if a filename has an extension or not...
@param: url -- filename to be checked
"""
return any(url.endswith(ext) for ext in _WEB_EXT)
def add_birthdate(dbase, ppl_handle_list, rlocale):
"""
This will sort a list of child handles in birth order
For each entry in the list, we'll have :
birth date
The transtated birth date for the configured locale
The transtated death date for the configured locale
The handle for the child
@param: dbase -- The database to use
@param: ppl_handle_list -- the handle for the people
@param: rlocale -- the locale for date translation
"""
sortable_individuals = []
for person_handle in ppl_handle_list:
birth_date = 0 # dummy value in case none is found
person = dbase.get_person_from_handle(person_handle)
if person:
birth_ref = person.get_birth_ref()
birth1 = ""
if birth_ref:
birth = dbase.get_event_from_handle(birth_ref.ref)
if birth:
birth1 = rlocale.get_date(birth.get_date_object())
birth_date = birth.get_date_object().get_sort_value()
death_event = get_death_or_fallback(dbase, person)
if death_event:
death = rlocale.get_date(death_event.get_date_object())
else:
death = ""
sortable_individuals.append((birth_date, birth1, death, person_handle))
# return a list of handles with the individual's birthdate attached
return sortable_individuals
def _find_birth_date(dbase, individual):
"""
will look for a birth date within the person's events
@param: dbase -- The database to use
@param: individual -- The individual for who we want to find the birth date
"""
date_out = None
birth_ref = individual.get_birth_ref()
if birth_ref:
birth = dbase.get_event_from_handle(birth_ref.ref)
if birth:
date_out = birth.get_date_object()
date_out.fallback = False
else:
person_evt_ref_list = individual.get_primary_event_ref_list()
if person_evt_ref_list:
for evt_ref in person_evt_ref_list:
event = dbase.get_event_from_handle(evt_ref.ref)
if event:
if event.get_type().is_birth_fallback():
date_out = event.get_date_object()
date_out.fallback = True
LOG.debug("setting fallback to true for '%s'", event)
break
return date_out
def _find_death_date(dbase, individual):
"""
will look for a death date within a person's events
@param: dbase -- The database to use
@param: individual -- The individual for who we want to find the death date
"""
date_out = None
death_ref = individual.get_death_ref()
if death_ref:
death = dbase.get_event_from_handle(death_ref.ref)
if death:
date_out = death.get_date_object()
date_out.fallback = False
else:
person_evt_ref_list = individual.get_primary_event_ref_list()
if person_evt_ref_list:
for evt_ref in person_evt_ref_list:
event = dbase.get_event_from_handle(evt_ref.ref)
if event:
if event.get_type().is_death_fallback():
date_out = event.get_date_object()
date_out.fallback = True
LOG.debug("setting fallback to true for '%s'", event)
break
return date_out
def build_event_data_by_individuals(dbase, ppl_handle_list):
"""
creates a list of event handles and event types for this database
@param: dbase -- The database to use
@param: ppl_handle_list -- the handle for the people
"""
event_handle_list = []
event_types = []
for person_handle in ppl_handle_list:
person = dbase.get_person_from_handle(person_handle)
if person:
evt_ref_list = person.get_event_ref_list()
if evt_ref_list:
for evt_ref in evt_ref_list:
event = dbase.get_event_from_handle(evt_ref.ref)
if event:
event_types.append(str(event.get_type()))
event_handle_list.append(evt_ref.ref)
person_family_handle_list = person.get_family_handle_list()
if person_family_handle_list:
for family_handle in person_family_handle_list:
family = dbase.get_family_from_handle(family_handle)
if family:
family_evt_ref_list = family.get_event_ref_list()
if family_evt_ref_list:
for evt_ref in family_evt_ref_list:
event = dbase.get_event_from_handle(evt_ref.ref)
if event:
event_types.append(str(event.type))
event_handle_list.append(evt_ref.ref)
# return event_handle_list and event types to its caller
return event_handle_list, event_types
def name_to_md5(text):
"""This creates an MD5 hex string to be used as filename."""
return md5(text.encode('utf-8')).hexdigest()
def get_gendex_data(database, event_ref):
"""
Given an event, return the date and place a strings
@param: database -- The database
@param: event_ref -- The event reference
"""
doe = "" # date of event
poe = "" # place of event
if event_ref and event_ref.ref:
event = database.get_event_from_handle(event_ref.ref)
if event:
date = event.get_date_object()
doe = format_date(date)
if event.get_place_handle():
place_handle = event.get_place_handle()
if place_handle:
place = database.get_place_from_handle(place_handle)
if place:
poe = _pd.display(database, place, date)
return doe, poe
def format_date(date):
"""
Format the date
"""
start = date.get_start_date()
if start != Date.EMPTY:
cal = date.get_calendar()
mod = date.get_modifier()
quality = date.get_quality()
if quality in DATE_QUALITY:
qual_text = DATE_QUALITY[quality] + " "
else:
qual_text = ""
if mod == Date.MOD_SPAN:
val = "%sFROM %s TO %s" % (
qual_text,
make_gedcom_date(start, cal, mod, None),
make_gedcom_date(date.get_stop_date(), cal, mod, None))
elif mod == Date.MOD_RANGE:
val = "%sBET %s AND %s" % (
qual_text,
make_gedcom_date(start, cal, mod, None),
make_gedcom_date(date.get_stop_date(), cal, mod, None))
else:
val = make_gedcom_date(start, cal, mod, quality)
return val
return ""
# This command then defines the 'html_escape' option for escaping
# special characters for presentation in HTML based on the above list.
def html_escape(text):
"""Convert the text and replace some characters with a &# variant."""
# First single characters, no quotes
text = escape(text)
# Deal with double quotes.
match = _HTML_DBL_QUOTES.match(text)
while match:
text = "%s" "&#8220;" "%s" "&#8221;" "%s" % match.groups()
match = _HTML_DBL_QUOTES.match(text)
# Replace remaining double quotes.
text = text.replace('"', '&#34;')
# Deal with single quotes.
text = text.replace("'s ", '&#8217;s ')
match = _HTML_SNG_QUOTES.match(text)
while match:
text = "%s" "&#8216;" "%s" "&#8217;" "%s" % match.groups()
match = _HTML_SNG_QUOTES.match(text)
# Replace remaining single quotes.
text = text.replace("'", '&#39;')
return text

View File

@ -0,0 +1,139 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
ContactPage
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.utils.config import get_researcher
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import FULLCLEAR
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
class ContactPage(BasePage):
"""
This class is responsible for displaying information about the 'Researcher'
"""
def __init__(self, report, title):
"""
@param: report -- The instance of the main report class for this report
@param: title -- Is the title of the web page
"""
BasePage.__init__(self, report, title)
output_file, sio = self.report.create_file("contact")
contactpage, head, body = self.write_header(self._('Contact'))
# begin contact division
with Html("div", class_="content", id="Contact") as section:
body += section
# begin summaryarea division
with Html("div", id='summaryarea') as summaryarea:
section += summaryarea
contactimg = self.add_image('contactimg', 200)
if contactimg is not None:
summaryarea += contactimg
# get researcher information
res = get_researcher()
with Html("div", id='researcher') as researcher:
summaryarea += researcher
if res.name:
res.name = res.name.replace(',,,', '')
researcher += Html("h3", res.name, inline=True)
if res.addr:
researcher += Html("span", res.addr,
id='streetaddress', inline=True)
if res.locality:
researcher += Html("span", res.locality,
id="locality", inline=True)
text = "".join([res.city, res.state, res.postal])
if text:
city = Html("span", res.city, id='city', inline=True)
state = Html("span", res.state, id='state', inline=True)
postal = Html("span", res.postal, id='postalcode',
inline=True)
researcher += (city, state, postal)
if res.country:
researcher += Html("span", res.country,
id='country', inline=True)
if res.email:
researcher += Html("span", id='email') + (
Html("a", res.email,
href='mailto:%s' % res.email, inline=True)
)
# add clear line for proper styling
summaryarea += FULLCLEAR
note_id = report.options['contactnote']
if note_id:
note = self.r_db.get_note_from_gramps_id(note_id)
note_text = self.get_note_format(note, False)
# attach note
summaryarea += note_text
# add clearline for proper styling
# add footer section
footer = self.write_footer(None)
body += (FULLCLEAR, footer)
# send page out for porcessing
# and close the file
self.xhtml_writer(contactpage, output_file, sio, 0)

View File

@ -0,0 +1,195 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
DownloadPage
"""
#------------------------------------------------
# python modules
#------------------------------------------------
import os
import datetime
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import (FULLCLEAR, html_escape)
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
class DownloadPage(BasePage):
"""
This class is responsible for displaying information about the Download page
"""
def __init__(self, report, title):
"""
@param: report -- The instance of the main report class for this report
@param: title -- Is the title of the web page
"""
BasePage.__init__(self, report, title)
# do NOT include a Download Page
if not self.report.inc_download:
return
# menu options for class
# download and description #1
dlfname1 = self.report.dl_fname1
dldescr1 = self.report.dl_descr1
# download and description #2
dlfname2 = self.report.dl_fname2
dldescr2 = self.report.dl_descr2
# if no filenames at all, return???
if dlfname1 or dlfname2:
output_file, sio = self.report.create_file("download")
downloadpage, head, body = self.write_header(self._('Download'))
# begin download page and table
with Html("div", class_="content", id="Download") as download:
body += download
msg = self._("This page is for the user/ creator "
"of this Family Tree/ Narrative website "
"to share a couple of files with you "
"regarding their family. If there are "
"any files listed "
"below, clicking on them will allow you "
"to download them. The "
"download page and files have the same "
"copyright as the remainder "
"of these web pages.")
download += Html("p", msg, id="description")
# begin download table and table head
with Html("table", class_="infolist download") as table:
download += table
thead = Html("thead")
table += thead
trow = Html("tr")
thead += trow
trow.extend(
Html("th", label, class_="Column" + colclass,
inline=True)
for (label, colclass) in [
(self._("File Name"), "Filename"),
(self._("Description"), "Description"),
(self._("Last Modified"), "Modified")])
# table body
tbody = Html("tbody")
table += tbody
# if dlfname1 is not None, show it???
if dlfname1:
trow = Html("tr", id='Row01')
tbody += trow
fname = os.path.basename(dlfname1)
# TODO dlfname1 is filename, convert disk path to URL
tcell = Html("td", class_="ColumnFilename") + (
Html("a", fname, href=dlfname1,
title=html_escape(dldescr1))
)
trow += tcell
dldescr1 = dldescr1 or "&nbsp;"
trow += Html("td", dldescr1,
class_="ColumnDescription", inline=True)
tcell = Html("td", class_="ColumnModified", inline=True)
trow += tcell
if os.path.exists(dlfname1):
modified = os.stat(dlfname1).st_mtime
last_mod = datetime.datetime.fromtimestamp(modified)
tcell += last_mod
else:
tcell += "&nbsp;"
# if download filename #2, show it???
if dlfname2:
# begin row #2
trow = Html("tr", id='Row02')
tbody += trow
fname = os.path.basename(dlfname2)
tcell = Html("td", class_="ColumnFilename") + (
Html("a", fname, href=dlfname2,
title=html_escape(dldescr2))
)
trow += tcell
dldescr2 = dldescr2 or "&nbsp;"
trow += Html("td", dldescr2,
class_="ColumnDescription", inline=True)
tcell = Html("td", id='Col04',
class_="ColumnModified", inline=True)
trow += tcell
if os.path.exists(dlfname2):
modified = os.stat(dlfname2).st_mtime
last_mod = datetime.datetime.fromtimestamp(modified)
tcell += last_mod
else:
tcell += "&nbsp;"
# clear line for proper styling
# create footer section
footer = self.write_footer(None)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(downloadpage, output_file, sio, 0)

View File

@ -0,0 +1,448 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
EventPage - Event index page and individual Event pages
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from collections import defaultdict
from operator import itemgetter
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.lib import (Date, Event)
from gramps.gen.plug.report import Bibliography
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import (get_first_letters, _ALPHAEVENT,
_EVENTMAP, alphabet_navigation,
FULLCLEAR, sort_event_types,
primary_difference,
get_index_letter)
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
#################################################
#
# creates the Event List Page and EventPages
#
#################################################
class EventPages(BasePage):
"""
This class is responsible for displaying information about the 'Person'
database objects. It displays this information under the 'Events'
tab. It is told by the 'add_instances' call which 'Person's to display,
and remembers the list of persons. A single call to 'display_pages'
displays both the Event List (Index) page and all the Event
pages.
The base class 'BasePage' is initialised once for each page that is
displayed.
"""
def __init__(self, report):
"""
@param: report -- The instance of the main report class for
this report
"""
BasePage.__init__(self, report, title="")
self.event_handle_list = []
self.event_types = []
self.event_dict = defaultdict(set)
def display_pages(self, title):
"""
Generate and output the pages under the Event tab, namely the event
index and the individual event pages.
@param: title -- Is the title of the web page
"""
LOG.debug("obj_dict[Event]")
for item in self.report.obj_dict[Event].items():
LOG.debug(" %s", str(item))
event_handle_list = self.report.obj_dict[Event].keys()
event_types = []
for event_handle in event_handle_list:
event = self.r_db.get_event_from_handle(event_handle)
event_types.append(self._(event.get_type().xml_str()))
with self.r_user.progress(_("Narrated Web Site Report"),
_("Creating event pages"),
len(event_handle_list) + 1
) as step:
self.eventlistpage(self.report, title, event_types,
event_handle_list)
for event_handle in event_handle_list:
step()
self.eventpage(self.report, title, event_handle)
def eventlistpage(self, report, title, event_types, event_handle_list):
"""
Will create the event list page
@param: report -- The instance of the main report class for
this report
@param: title -- Is the title of the web page
@param: event_types -- A list of the type in the events database
@param: event_handle_list -- A list of event handles
"""
BasePage.__init__(self, report, title)
ldatec = 0
prev_letter = " "
output_file, sio = self.report.create_file("events")
eventslistpage, head, body = self.write_header(self._("Events"))
# begin events list division
with Html("div", class_="content", id="EventList") as eventlist:
body += eventlist
msg = self._("This page contains an index of all the events in the "
"database, sorted by their type and date (if one is "
"present). Clicking on an event&#8217;s Gramps ID "
"will open a page for that event.")
eventlist += Html("p", msg, id="description")
# get alphabet navigation...
index_list = get_first_letters(self.r_db, event_types,
_ALPHAEVENT)
alpha_nav = alphabet_navigation(index_list, self.rlocale)
if alpha_nav:
eventlist += alpha_nav
# begin alphabet event table
with Html("table",
class_="infolist primobjlist alphaevent") as table:
eventlist += table
thead = Html("thead")
table += thead
trow = Html("tr")
thead += trow
trow.extend(
Html("th", label, class_=colclass, inline=True)
for (label, colclass) in [(self._("Letter"),
"ColumnRowLabel"),
(self._("Type"), "ColumnType"),
(self._("Date"), "ColumnDate"),
(self._("Gramps ID"),
"ColumnGRAMPSID"),
(self._("Person"), "ColumnPerson")
]
)
tbody = Html("tbody")
table += tbody
# separate events by their type and then thier event handles
for (evt_type,
data_list) in sort_event_types(self.r_db,
event_types,
event_handle_list,
self.rlocale):
first = True
_event_displayed = []
# sort datalist by date of event and by event handle...
data_list = sorted(data_list, key=itemgetter(0, 1))
first_event = True
for (sort_value, event_handle) in data_list:
event = self.r_db.get_event_from_handle(event_handle)
_type = event.get_type()
gid = event.get_gramps_id()
if event.get_change_time() > ldatec:
ldatec = event.get_change_time()
# check to see if we have listed this gramps_id yet?
if gid not in _event_displayed:
# family event
if int(_type) in _EVENTMAP:
handle_list = set(
self.r_db.find_backlink_handles(
event_handle,
include_classes=['Family', 'Person']))
else:
handle_list = set(
self.r_db.find_backlink_handles(
event_handle,
include_classes=['Person']))
if handle_list:
trow = Html("tr")
tbody += trow
# set up hyperlinked letter for
# alphabet_navigation
tcell = Html("td", class_="ColumnLetter",
inline=True)
trow += tcell
if evt_type and not evt_type.isspace():
letter = get_index_letter(
self._(str(evt_type)[0].capitalize()),
index_list, self.rlocale)
else:
letter = "&nbsp;"
if first or primary_difference(letter,
prev_letter,
self.rlocale):
first = False
prev_letter = letter
t_a = 'class = "BeginLetter BeginType"'
trow.attr = t_a
ttle = self._("Event types beginning "
"with letter %s") % letter
tcell += Html("a", letter, name=letter,
id_=letter, title=ttle,
inline=True)
else:
tcell += "&nbsp;"
# display Event type if first in the list
tcell = Html("td", class_="ColumnType",
title=self._(evt_type),
inline=True)
trow += tcell
if first_event:
tcell += self._(evt_type)
if trow.attr == "":
trow.attr = 'class = "BeginType"'
else:
tcell += "&nbsp;"
# event date
tcell = Html("td", class_="ColumnDate",
inline=True)
trow += tcell
date = Date.EMPTY
if event:
date = event.get_date_object()
if date and date is not Date.EMPTY:
tcell += self.rlocale.get_date(date)
else:
tcell += "&nbsp;"
# Gramps ID
trow += Html("td", class_="ColumnGRAMPSID") + (
self.event_grampsid_link(event_handle,
gid, None)
)
# Person(s) column
tcell = Html("td", class_="ColumnPerson")
trow += tcell
# classname can either be a person or a family
first_person = True
# get person(s) for ColumnPerson
sorted_list = sorted(handle_list)
self.complete_people(tcell, first_person,
sorted_list,
uplink=False)
_event_displayed.append(gid)
first_event = False
# add clearline for proper styling
# add footer section
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page ut for processing
# and close the file
self.xhtml_writer(eventslistpage, output_file, sio, ldatec)
def _geteventdate(self, event_handle):
"""
Get the event date
@param: event_handle -- The handle for the event to use
"""
event_date = Date.EMPTY
event = self.r_db.get_event_from_handle(event_handle)
if event:
date = event.get_date_object()
if date:
# returns the date in YYYY-MM-DD format
return Date(date.get_year_calendar("Gregorian"),
date.get_month(), date.get_day())
# return empty date string
return event_date
def event_grampsid_link(self, handle, grampsid, uplink):
"""
Create a hyperlink from event handle, but show grampsid
@param: handle -- The handle for the event
@param: grampsid -- The gramps ID to display
@param: uplink -- If True, then "../../../" is inserted in front of
the result.
"""
url = self.report.build_url_fname_html(handle, "evt", uplink)
# return hyperlink to its caller
return Html("a", grampsid, href=url, title=grampsid, inline=True)
def eventpage(self, report, title, event_handle):
"""
Creates the individual event page
@param: report -- The instance of the main report class for
this report
@param: title -- Is the title of the web page
@param: event_handle -- The event handle for the database
"""
event = report.database.get_event_from_handle(event_handle)
BasePage.__init__(self, report, title, event.get_gramps_id())
if not event:
return None
ldatec = event.get_change_time()
event_media_list = event.get_media_list()
self.uplink = True
subdirs = True
evt_type = self._(event.get_type().xml_str())
self.page_title = "%(eventtype)s" % {'eventtype' : evt_type}
self.bibli = Bibliography()
output_file, sio = self.report.create_file(event_handle, "evt")
eventpage, head, body = self.write_header(self._("Events"))
# start event detail division
with Html("div", class_="content", id="EventDetail") as eventdetail:
body += eventdetail
thumbnail = self.disp_first_img_as_thumbnail(event_media_list,
event)
if thumbnail is not None:
eventdetail += thumbnail
# display page title
eventdetail += Html("h3", self.page_title, inline=True)
# begin eventdetail table
with Html("table", class_="infolist eventlist") as table:
eventdetail += table
tbody = Html("tbody")
table += tbody
evt_gid = event.get_gramps_id()
if not self.noid and evt_gid:
trow = Html("tr") + (
Html("td", self._("Gramps ID"),
class_="ColumnAttribute", inline=True),
Html("td", evt_gid,
class_="ColumnGRAMPSID", inline=True)
)
tbody += trow
# get event data
#
# for more information: see get_event_data()
#
event_data = self.get_event_data(event, event_handle,
subdirs, evt_gid)
for (label, colclass, data) in event_data:
if data:
trow = Html("tr") + (
Html("td", label, class_="ColumnAttribute",
inline=True),
Html('td', data, class_="Column" + colclass)
)
tbody += trow
# Narrative subsection
notelist = event.get_note_list()
notelist = self.display_note_list(notelist)
if notelist is not None:
eventdetail += notelist
# get attribute list
attrlist = event.get_attribute_list()
if attrlist:
attrsection, attrtable = self.display_attribute_header()
self.display_attr_list(attrlist, attrtable)
eventdetail += attrsection
# event source references
srcrefs = self.display_ind_sources(event)
if srcrefs is not None:
eventdetail += srcrefs
# display additional images as gallery
if self.create_media:
addgallery = self.disp_add_img_as_gallery(event_media_list,
event)
if addgallery:
eventdetail += addgallery
# References list
ref_list = self.display_bkref_list(Event, event_handle)
if ref_list is not None:
eventdetail += ref_list
# add clearline for proper styling
# add footer section
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the page
self.xhtml_writer(eventpage, output_file, sio, ldatec)

View File

@ -0,0 +1,399 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
FamilyPage - Family index page and individual Family pages
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from collections import defaultdict
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.lib import (EventType, Family)
from gramps.gen.plug.report import Bibliography
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import (get_first_letters, _KEYPERSON,
alphabet_navigation, sort_people,
primary_difference, first_letter,
FULLCLEAR, get_index_letter)
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
#################################################
#
# creates the Family List Page and Family Pages
#
#################################################
class FamilyPages(BasePage):
"""
This class is responsible for displaying information about the 'Family'
database objects. It displays this information under the 'Families'
tab. It is told by the 'add_instances' call which 'Family's to display,
and remembers the list of Family. A single call to 'display_pages'
displays both the Family List (Index) page and all the Family
pages.
The base class 'BasePage' is initialised once for each page that is
displayed.
"""
def __init__(self, report):
"""
@param: report -- The instance of the main report class for
this report
"""
BasePage.__init__(self, report, title="")
self.family_dict = defaultdict(set)
self.person = None
self.familymappages = None
def display_pages(self, title):
"""
Generate and output the pages under the Family tab, namely the family
index and the individual family pages.
@param: title -- Is the title of the web page
"""
LOG.debug("obj_dict[Family]")
for item in self.report.obj_dict[Family].items():
LOG.debug(" %s", str(item))
with self.r_user.progress(_("Narrated Web Site Report"),
_("Creating family pages..."),
len(self.report.obj_dict[Family]) + 1
) as step:
self.familylistpage(self.report, title,
self.report.obj_dict[Family].keys())
for family_handle in self.report.obj_dict[Family]:
step()
self.familypage(self.report, title, family_handle)
def familylistpage(self, report, title, fam_list):
"""
Create a family index
@param: report -- The instance of the main report class for
this report
@param: title -- Is the title of the web page
@param: fam_list -- The handle for the place to add
"""
BasePage.__init__(self, report, title)
output_file, sio = self.report.create_file("families")
familieslistpage, head, body = self.write_header(self._("Families"))
ldatec = 0
prev_letter = " "
# begin Family Division
with Html("div", class_="content", id="Relationships") as relationlist:
body += relationlist
# Families list page message
msg = self._("This page contains an index of all the "
"families/ relationships in the "
"database, sorted by their family name/ surname. "
"Clicking on a person&#8217;s "
"name will take you to their "
"family/ relationship&#8217;s page.")
relationlist += Html("p", msg, id="description")
# go through all the families, and construct a dictionary of all the
# people and the families thay are involved in. Note that the people
# in the list may be involved in OTHER families, that are not listed
# because they are not in the original family list.
pers_fam_dict = defaultdict(list)
for family_handle in fam_list:
family = self.r_db.get_family_from_handle(family_handle)
if family:
if family.get_change_time() > ldatec:
ldatec = family.get_change_time()
husband_handle = family.get_father_handle()
spouse_handle = family.get_mother_handle()
if husband_handle:
pers_fam_dict[husband_handle].append(family)
if spouse_handle:
pers_fam_dict[spouse_handle].append(family)
# add alphabet navigation
index_list = get_first_letters(self.r_db, pers_fam_dict.keys(),
_KEYPERSON, rlocale=self.rlocale)
alpha_nav = alphabet_navigation(index_list, self.rlocale)
if alpha_nav:
relationlist += alpha_nav
# begin families table and table head
with Html("table", class_="infolist relationships") as table:
relationlist += table
thead = Html("thead")
table += thead
trow = Html("tr")
thead += trow
# set up page columns
trow.extend(
Html("th", trans, class_=colclass, inline=True)
for trans, colclass in [(self._("Letter"),
"ColumnRowLabel"),
(self._("Person"), "ColumnPartner"),
(self._("Family"), "ColumnPartner"),
(self._("Marriage"), "ColumnDate"),
(self._("Divorce"), "ColumnDate")]
)
tbody = Html("tbody")
table += tbody
# begin displaying index list
ppl_handle_list = sort_people(self.r_db, pers_fam_dict.keys(),
self.rlocale)
first = True
for (surname, handle_list) in ppl_handle_list:
if surname and not surname.isspace():
letter = get_index_letter(first_letter(surname),
index_list,
self.rlocale)
else:
letter = '&nbsp;'
# get person from sorted database list
for person_handle in sorted(
handle_list, key=self.sort_on_name_and_grampsid):
person = self.r_db.get_person_from_handle(person_handle)
if person:
family_list = person.get_family_handle_list()
first_family = True
for family_handle in family_list:
get_family = self.r_db.get_family_from_handle
family = get_family(family_handle)
trow = Html("tr")
tbody += trow
tcell = Html("td", class_="ColumnRowLabel")
trow += tcell
if first or primary_difference(letter,
prev_letter,
self.rlocale):
first = False
prev_letter = letter
trow.attr = 'class="BeginLetter"'
ttle = self._("Families beginning with "
"letter ")
tcell += Html("a", letter, name=letter,
title=ttle + letter,
inline=True)
else:
tcell += '&nbsp;'
tcell = Html("td", class_="ColumnPartner")
trow += tcell
if first_family:
trow.attr = 'class ="BeginFamily"'
tcell += self.new_person_link(
person_handle, uplink=self.uplink)
first_family = False
else:
tcell += '&nbsp;'
tcell = Html("td", class_="ColumnPartner")
trow += tcell
tcell += self.family_link(
family.get_handle(),
self.report.get_family_name(family),
family.get_gramps_id(), self.uplink)
# family events; such as marriage and divorce
# events
fam_evt_ref_list = family.get_event_ref_list()
tcell1 = Html("td", class_="ColumnDate",
inline=True)
tcell2 = Html("td", class_="ColumnDate",
inline=True)
trow += (tcell1, tcell2)
if fam_evt_ref_list:
fam_evt_srt_ref_list = sorted(
fam_evt_ref_list,
key=self.sort_on_grampsid)
for evt_ref in fam_evt_srt_ref_list:
evt = self.r_db.get_event_from_handle(
evt_ref.ref)
if evt:
evt_type = evt.get_type()
if evt_type in [EventType.MARRIAGE,
EventType.DIVORCE]:
cell = self.rlocale.get_date(
evt.get_date_object())
if (evt_type ==
EventType.MARRIAGE):
tcell1 += cell
else:
tcell1 += '&nbsp;'
if (evt_type ==
EventType.DIVORCE):
tcell2 += cell
else:
tcell2 += '&nbsp;'
else:
tcell1 += '&nbsp;'
tcell2 += '&nbsp;'
first_family = False
# add clearline for proper styling
# add footer section
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(familieslistpage, output_file, sio, ldatec)
def familypage(self, report, title, family_handle):
"""
Create a family page
@param: report -- The instance of the main report class for
this report
@param: title -- Is the title of the web page
@param: family_handle -- The handle for the family to add
"""
family = report.database.get_family_from_handle(family_handle)
if not family:
return
BasePage.__init__(self, report, title, family.get_gramps_id())
ldatec = family.get_change_time()
self.bibli = Bibliography()
self.uplink = True
family_name = self.report.get_family_name(family)
self.page_title = family_name
self.familymappages = report.options["familymappages"]
output_file, sio = self.report.create_file(family.get_handle(), "fam")
familydetailpage, head, body = self.write_header(family_name)
# begin FamilyDetaill division
with Html("div", class_="content",
id="RelationshipDetail") as relationshipdetail:
body += relationshipdetail
# family media list for initial thumbnail
if self.create_media:
media_list = family.get_media_list()
# If Event pages are not being created, then we need to display
# the family event media here
if not self.inc_events:
for evt_ref in family.get_event_ref_list():
event = self.r_db.get_event_from_handle(evt_ref.ref)
media_list += event.get_media_list()
thumbnail = self.disp_first_img_as_thumbnail(media_list,
family)
if thumbnail:
relationshipdetail += thumbnail
self.person = None # no longer used
relationshipdetail += Html(
"h2", self.page_title, inline=True) + (
Html('sup') + (Html('small') +
self.get_citation_links(
family.get_citation_list())))
# display relationships
families = self.display_family_relationships(family, None)
if families is not None:
relationshipdetail += families
# display additional images as gallery
if self.create_media and media_list:
addgallery = self.disp_add_img_as_gallery(media_list, family)
if addgallery:
relationshipdetail += addgallery
# Narrative subsection
notelist = family.get_note_list()
if notelist:
relationshipdetail += self.display_note_list(notelist)
# display family LDS ordinance...
family_lds_ordinance_list = family.get_lds_ord_list()
if family_lds_ordinance_list:
relationshipdetail += self.display_lds_ordinance(family)
# get attribute list
attrlist = family.get_attribute_list()
if attrlist:
attrsection, attrtable = self.display_attribute_header()
self.display_attr_list(attrlist, attrtable)
relationshipdetail += attrsection
# source references
srcrefs = self.display_ind_sources(family)
if srcrefs:
relationshipdetail += srcrefs
# add clearline for proper styling
# add footer section
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(familydetailpage, output_file, sio, ldatec)

View File

@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
HomePage
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import FULLCLEAR
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
class HomePage(BasePage):
"""
This class is responsible for displaying information about the Home page.
"""
def __init__(self, report, title):
"""
@param: report -- The instance of the main report class for
this report
@param: title -- Is the title of the web page
"""
BasePage.__init__(self, report, title)
ldatec = 0
output_file, sio = self.report.create_file("index")
homepage, head, body = self.write_header(self._('Home'))
# begin home division
with Html("div", class_="content", id="Home") as section:
body += section
homeimg = self.add_image('homeimg')
if homeimg is not None:
section += homeimg
note_id = report.options['homenote']
if note_id:
note = self.r_db.get_note_from_gramps_id(note_id)
note_text = self.get_note_format(note, False)
# attach note
section += note_text
# last modification of this note
ldatec = note.get_change_time()
# create clear line for proper styling
# create footer section
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(homepage, output_file, sio, ldatec)

View File

@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
IntroductionPage
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import FULLCLEAR
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
class IntroductionPage(BasePage):
"""
This class is responsible for displaying information
about the introduction page.
"""
def __init__(self, report, title):
"""
@param: report -- The instance of the main report class for
this report
@param: title -- Is the title of the web page
"""
BasePage.__init__(self, report, title)
ldatec = 0
output_file, sio = self.report.create_file(report.intro_fname)
intropage, head, body = self.write_header(self._('Introduction'))
# begin Introduction division
with Html("div", class_="content", id="Introduction") as section:
body += section
introimg = self.add_image('introimg')
if introimg is not None:
section += introimg
note_id = report.options['intronote']
if note_id:
note = self.r_db.get_note_from_gramps_id(note_id)
note_text = self.get_note_format(note, False)
# attach note
section += note_text
# last modification of this note
ldatec = note.get_change_time()
# add clearline for proper styling
# create footer section
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(intropage, output_file, sio, ldatec)

View File

@ -0,0 +1,641 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
MediaPage - Media index page and individual Media pages
"""
#------------------------------------------------
# python modules
#------------------------------------------------
import gc
import os
import shutil
import tempfile
from collections import defaultdict
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.lib import (Date, Media)
from gramps.gen.plug.report import Bibliography
from gramps.gen.utils.file import media_path_full
from gramps.gen.utils.thumbnails import run_thumbnailer
from gramps.gen.utils.image import image_size # , resize_to_jpeg_buffer
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import (FULLCLEAR, _WRONGMEDIAPATH,
html_escape)
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
#################################################
#
# creates the Media List Page and Media Pages
#
#################################################
class MediaPages(BasePage):
"""
This class is responsible for displaying information about the 'Media'
database objects. It displays this information under the 'Individuals'
tab. It is told by the 'add_instances' call which 'Media's to display,
and remembers the list of persons. A single call to 'display_pages'
displays both the Individual List (Index) page and all the Individual
pages.
The base class 'BasePage' is initialised once for each page that is
displayed.
"""
def __init__(self, report):
"""
@param: report -- The instance of the main report class for this report
"""
BasePage.__init__(self, report, title="")
self.media_dict = defaultdict(set)
def display_pages(self, title):
"""
Generate and output the pages under the Media tab, namely the media
index and the individual media pages.
@param: title -- Is the title of the web page
"""
LOG.debug("obj_dict[Media]")
for item in self.report.obj_dict[Media].items():
LOG.debug(" %s", str(item))
with self.r_user.progress(_("Narrated Web Site Report"),
_("Creating media pages"),
len(self.report.obj_dict[Media]) + 1
) as step:
# bug 8950 : it seems it's better to sort on desc + gid.
def sort_by_desc_and_gid(obj):
"""
Sort by media description and gramps ID
"""
return (obj.desc.lower(), obj.gramps_id)
sorted_media_handles = sorted(
self.report.obj_dict[Media].keys(),
key=lambda x: sort_by_desc_and_gid(
self.r_db.get_media_from_handle(x)))
self.medialistpage(self.report, title, sorted_media_handles)
prev = None
total = len(sorted_media_handles)
index = 1
for handle in sorted_media_handles:
gc.collect() # Reduce memory usage when there are many images.
next_ = None if index == total else sorted_media_handles[index]
step()
self.mediapage(self.report, title,
handle, (prev, next_, index, total))
prev = handle
index += 1
def medialistpage(self, report, title, sorted_media_handles):
"""
Generate and output the Media index page.
@param: report -- The instance of the main report class
for this report
@param: title -- Is the title of the web page
@param: sorted_media_handles -- A list of the handles of the media to be
displayed sorted by the media title
"""
BasePage.__init__(self, report, title)
output_file, sio = self.report.create_file("media")
medialistpage, head, body = self.write_header(self._('Media'))
ldatec = 0
# begin gallery division
with Html("div", class_="content", id="Gallery") as medialist:
body += medialist
msg = self._("This page contains an index of all the media objects "
"in the database, sorted by their title. Clicking on "
"the title will take you to that "
"media object&#8217;s page. "
"If you see media size dimensions "
"above an image, click on the "
"image to see the full sized version. ")
medialist += Html("p", msg, id="description")
# begin gallery table and table head
with Html("table",
class_="infolist primobjlist gallerylist") as table:
medialist += table
# begin table head
thead = Html("thead")
table += thead
trow = Html("tr")
thead += trow
trow.extend(
Html("th", trans, class_=colclass, inline=True)
for trans, colclass in [("&nbsp;", "ColumnRowLabel"),
(self._("Media | Name"),
"ColumnName"),
(self._("Date"), "ColumnDate"),
(self._("Mime Type"), "ColumnMime")]
)
# begin table body
tbody = Html("tbody")
table += tbody
index = 1
for media_handle in sorted_media_handles:
media = self.r_db.get_media_from_handle(media_handle)
if media:
if media.get_change_time() > ldatec:
ldatec = media.get_change_time()
title = media.get_description() or "[untitled]"
trow = Html("tr")
tbody += trow
media_data_row = [
[index, "ColumnRowLabel"],
[self.media_ref_link(media_handle,
title), "ColumnName"],
[self.rlocale.get_date(media.get_date_object()),
"ColumnDate"],
[media.get_mime_type(), "ColumnMime"]]
trow.extend(
Html("td", data, class_=colclass)
for data, colclass in media_data_row
)
index += 1
def sort_by_desc_and_gid(obj):
"""
Sort by media description and gramps ID
"""
return (obj.desc, obj.gramps_id)
unused_media_handles = []
if self.create_unused_media:
# add unused media
media_list = self.r_db.get_media_handles()
for media_ref in media_list:
if media_ref not in self.report.obj_dict[Media]:
unused_media_handles.append(media_ref)
unused_media_handles = sorted(
unused_media_handles,
key=lambda x: sort_by_desc_and_gid(
self.r_db.get_media_from_handle(x)))
idx = 1
prev = None
total = len(unused_media_handles)
if total > 0:
trow += Html("tr")
trow.extend(
Html("td", Html("h4", " "), inline=True) +
Html("td",
Html("h4",
self._("Below unused media objects"),
inline=True),
class_="") +
Html("td", Html("h4", " "), inline=True) +
Html("td", Html("h4", " "), inline=True)
)
for media_handle in unused_media_handles:
media = self.r_db.get_media_from_handle(media_handle)
gc.collect() # Reduce memory usage when many images.
next_ = None if idx == total else unused_media_handles[idx]
trow += Html("tr")
media_data_row = [
[index, "ColumnRowLabel"],
[self.media_ref_link(media_handle,
media.get_description()),
"ColumnName"],
[self.rlocale.get_date(media.get_date_object()),
"ColumnDate"],
[media.get_mime_type(), "ColumnMime"]]
trow.extend(
Html("td", data, class_=colclass)
for data, colclass in media_data_row
)
self.mediapage(self.report, title,
media_handle, (prev, next_, index, total))
prev = media_handle
index += 1
idx += 1
# add footer section
# add clearline for proper styling
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(medialistpage, output_file, sio, ldatec)
def media_ref_link(self, handle, name, uplink=False):
"""
Create a reference link to a media
@param: handle -- The media handle
@param: name -- The name to use for the link
@param: uplink -- If True, then "../../../" is inserted in front of the
result.
"""
# get media url
url = self.report.build_url_fname_html(handle, "img", uplink)
# get name
name = html_escape(name)
# begin hyper link
hyper = Html("a", name, href=url, title=name)
# return hyperlink to its callers
return hyper
def mediapage(self, report, title, media_handle, info):
"""
Generate and output an individual Media page.
@param: report -- The instance of the main report class
for this report
@param: title -- Is the title of the web page
@param: media_handle -- The media handle to use
@param: info -- A tuple containing the media handle for the
next and previous media, the current page
number, and the total number of media pages
"""
media = report.database.get_media_from_handle(media_handle)
BasePage.__init__(self, report, title, media.gramps_id)
(prev, next_, page_number, total_pages) = info
ldatec = media.get_change_time()
# get media rectangles
_region_items = self.media_ref_rect_regions(media_handle)
output_file, sio = self.report.create_file(media_handle, "img")
self.uplink = True
self.bibli = Bibliography()
# get media type to be used primarily with "img" tags
mime_type = media.get_mime_type()
#mtype = get_description(mime_type)
if mime_type:
#note_only = False
newpath = self.copy_source_file(media_handle, media)
target_exists = newpath is not None
else:
#note_only = True
target_exists = False
self.copy_thumbnail(media_handle, media)
self.page_title = media.get_description()
esc_page_title = html_escape(self.page_title)
(mediapage, head,
body) = self.write_header("%s - %s" % (self._("Media"),
self.page_title))
# if there are media rectangle regions, attach behaviour style sheet
if _region_items:
fname = "/".join(["css", "behaviour.css"])
url = self.report.build_url_fname(fname, None, self.uplink)
head += Html("link", href=url, type="text/css",
media="screen", rel="stylesheet")
# begin MediaDetail division
with Html("div", class_="content", id="GalleryDetail") as mediadetail:
body += mediadetail
# media navigation
with Html("div", id="GalleryNav", role="navigation") as medianav:
mediadetail += medianav
if prev:
medianav += self.media_nav_link(prev,
self._("Previous"), True)
data = self._('%(strong1_strt)s%(page_number)d%(strong_end)s '
'of %(strong2_strt)s%(total_pages)d%(strong_end)s'
) % {'strong1_strt' :
'<strong id="GalleryCurrent">',
'strong2_strt' : '<strong id="GalleryTotal">',
'strong_end' : '</strong>',
'page_number' : page_number,
'total_pages' : total_pages}
medianav += Html("span", data, id="GalleryPages")
if next_:
medianav += self.media_nav_link(next_, self._("Next"), True)
# missing media error message
errormsg = self._("The file has been moved or deleted.")
# begin summaryarea division
with Html("div", id="summaryarea") as summaryarea:
mediadetail += summaryarea
if mime_type:
if mime_type.startswith("image"):
if not target_exists:
with Html("div", id="MediaDisplay") as mediadisplay:
summaryarea += mediadisplay
mediadisplay += Html("span", errormsg,
class_="MissingImage")
else:
# Check how big the image is relative to the
# requested 'initial' image size.
# If it's significantly bigger, scale it down to
# improve the site's responsiveness. We don't want
# the user to have to await a large download
# unnecessarily. Either way, set the display image
# size as requested.
orig_image_path = media_path_full(self.r_db,
media.get_path())
#mtime = os.stat(orig_image_path).st_mtime
(width, height) = image_size(orig_image_path)
max_width = self.report.options[
'maxinitialimagewidth']
max_height = self.report.options[
'maxinitialimageheight']
if width != 0 and height != 0:
scale_w = (float(max_width)/width) or 1
# the 'or 1' is so that a max of
# zero is ignored
scale_h = (float(max_height)/height) or 1
else:
scale_w = 1.0
scale_h = 1.0
scale = min(scale_w, scale_h, 1.0)
new_width = int(width*scale)
new_height = int(height*scale)
# TODO. Convert disk path to URL.
url = self.report.build_url_fname(orig_image_path,
None, self.uplink)
with Html("div", id="GalleryDisplay",
style='width: %dpx; height: %dpx' % (
new_width,
new_height)) as mediadisplay:
summaryarea += mediadisplay
# Feature #2634; display the mouse-selectable
# regions. See the large block at the top of
# this function where the various regions are
# stored in _region_items
if _region_items:
ordered = Html("ol", class_="RegionBox")
mediadisplay += ordered
while len(_region_items) > 0:
(name, coord_x, coord_y,
width, height, linkurl
) = _region_items.pop()
ordered += Html(
"li",
style="left:%d%%; "
"top:%d%%; "
"width:%d%%; "
"height:%d%%;" % (
coord_x, coord_y,
width, height)) + (
Html("a", name,
href=linkurl)
)
# display the image
if orig_image_path != newpath:
url = self.report.build_url_fname(
newpath, None, self.uplink)
mediadisplay += Html("a", href=url) + (
Html("img", width=new_width,
height=new_height, src=url,
alt=esc_page_title)
)
else:
dirname = tempfile.mkdtemp()
thmb_path = os.path.join(dirname, "document.png")
if run_thumbnailer(mime_type,
media_path_full(self.r_db,
media.get_path()),
thmb_path, 320):
try:
path = self.report.build_path(
"preview", media.get_handle())
npath = os.path.join(path, media.get_handle())
npath += ".png"
self.report.copy_file(thmb_path, npath)
path = npath
os.unlink(thmb_path)
except EnvironmentError:
path = os.path.join("images", "document.png")
else:
path = os.path.join("images", "document.png")
os.rmdir(dirname)
with Html("div", id="GalleryDisplay") as mediadisplay:
summaryarea += mediadisplay
img_url = self.report.build_url_fname(path,
None,
self.uplink)
if target_exists:
# TODO. Convert disk path to URL
url = self.report.build_url_fname(newpath,
None,
self.uplink)
hyper = Html("a", href=url,
title=esc_page_title) + (
Html("img", src=img_url,
alt=esc_page_title)
)
mediadisplay += hyper
else:
mediadisplay += Html("span", errormsg,
class_="MissingImage")
else:
with Html("div", id="GalleryDisplay") as mediadisplay:
summaryarea += mediadisplay
url = self.report.build_url_image("document.png",
"images", self.uplink)
mediadisplay += Html("img", src=url,
alt=esc_page_title,
title=esc_page_title)
# media title
title = Html("h3", html_escape(self.page_title.strip()),
inline=True)
summaryarea += title
# begin media table
with Html("table", class_="infolist gallery") as table:
summaryarea += table
# Gramps ID
media_gid = media.gramps_id
if not self.noid and media_gid:
trow = Html("tr") + (
Html("td", self._("Gramps ID"),
class_="ColumnAttribute",
inline=True),
Html("td", media_gid, class_="ColumnValue",
inline=True)
)
table += trow
# mime type
if mime_type:
trow = Html("tr") + (
Html("td", self._("File Type"),
class_="ColumnAttribute",
inline=True),
Html("td", mime_type, class_="ColumnValue",
inline=True)
)
table += trow
# media date
date = media.get_date_object()
if date and date is not Date.EMPTY:
trow = Html("tr") + (
Html("td", self._("Date"), class_="ColumnAttribute",
inline=True),
Html("td", self.rlocale.get_date(date),
class_="ColumnValue",
inline=True)
)
table += trow
# get media notes
notelist = self.display_note_list(media.get_note_list())
if notelist is not None:
mediadetail += notelist
# get attribute list
attrlist = media.get_attribute_list()
if attrlist:
attrsection, attrtable = self.display_attribute_header()
self.display_attr_list(attrlist, attrtable)
mediadetail += attrsection
# get media sources
srclist = self.display_media_sources(media)
if srclist is not None:
mediadetail += srclist
# get media references
reflist = self.display_bkref_list(Media, media_handle)
if reflist is not None:
mediadetail += reflist
# add clearline for proper styling
# add footer section
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(mediapage, output_file, sio, ldatec)
def media_nav_link(self, handle, name, uplink=False):
"""
Creates the Media Page Navigation hyperlinks for Next and Prev
"""
url = self.report.build_url_fname_html(handle, "img", uplink)
name = html_escape(name)
return Html("a", name, name=name, id=name, href=url,
title=name, inline=True)
def display_media_sources(self, photo):
"""
Display media sources
@param: photo -- The source object (image, pdf, ...)
"""
list(map(
lambda i: self.bibli.add_reference(
self.r_db.get_citation_from_handle(i)),
photo.get_citation_list()))
sourcerefs = self.display_source_refs(self.bibli)
# return source references to its caller
return sourcerefs
def copy_source_file(self, handle, photo):
"""
Copy source file in the web tree.
@param: handle -- Handle of the source
@param: photo -- The source object (image, pdf, ...)
"""
ext = os.path.splitext(photo.get_path())[1]
to_dir = self.report.build_path('images', handle)
newpath = os.path.join(to_dir, handle) + ext
fullpath = media_path_full(self.r_db, photo.get_path())
if not os.path.isfile(fullpath):
_WRONGMEDIAPATH.append([photo.get_gramps_id(), fullpath])
return None
try:
mtime = os.stat(fullpath).st_mtime
if self.report.archive:
self.report.archive.add(fullpath, str(newpath))
else:
to_dir = os.path.join(self.html_dir, to_dir)
if not os.path.isdir(to_dir):
os.makedirs(to_dir)
new_file = os.path.join(self.html_dir, newpath)
shutil.copyfile(fullpath, new_file)
os.utime(new_file, (mtime, mtime))
return newpath
except (IOError, OSError) as msg:
error = _("Missing media object:"
) + "%s (%s)" % (photo.get_description(),
photo.get_gramps_id())
self.r_user.warn(error, str(msg))
return None

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,451 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
PlacePage - Place index page and individual Place pages
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from collections import defaultdict
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.lib import (PlaceType, Place)
from gramps.gen.plug.report import Bibliography
from gramps.plugins.lib.libhtml import Html
from gramps.gen.utils.place import conv_lat_lon
from gramps.gen.utils.location import get_main_location
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import (get_first_letters, first_letter,
alphabet_navigation, GOOGLE_MAPS,
primary_difference, _KEYPLACE,
get_index_letter, FULLCLEAR,
MARKER_PATH, OSM_MARKERS, MARKERS,
html_escape)
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
######################################################
# #
# Place Pages #
# #
######################################################
class PlacePages(BasePage):
"""
This class is responsible for displaying information about the 'Person'
database objects. It displays this information under the 'Events'
tab. It is told by the 'add_instances' call which 'Person's to display,
and remembers the list of persons. A single call to 'display_pages'
displays both the Event List (Index) page and all the Event
pages.
The base class 'BasePage' is initialised once for each page that is
displayed.
"""
def __init__(self, report):
"""
@param: report -- The instance of the main report class for
this report
"""
BasePage.__init__(self, report, title="")
self.place_dict = defaultdict(set)
self.placemappages = None
self.mapservice = None
self.person = None
self.familymappages = None
self.googlemapkey = None
def display_pages(self, title):
"""
Generate and output the pages under the Place tab, namely the place
index and the individual place pages.
@param: title -- Is the title of the web page
"""
LOG.debug("obj_dict[Place]")
for item in self.report.obj_dict[Place].items():
LOG.debug(" %s", str(item))
with self.r_user.progress(_("Narrated Web Site Report"),
_("Creating place pages"),
len(self.report.obj_dict[Place]) + 1
) as step:
self.placelistpage(self.report, title,
self.report.obj_dict[Place].keys())
for place_handle in self.report.obj_dict[Place]:
step()
self.placepage(self.report, title, place_handle)
def placelistpage(self, report, title, place_handles):
"""
Create a place index
@param: report -- The instance of the main report class for
this report
@param: title -- Is the title of the web page
@param: place_handles -- The handle for the place to add
"""
BasePage.__init__(self, report, title)
output_file, sio = self.report.create_file("places")
placelistpage, head, body = self.write_header(self._("Places"))
ldatec = 0
prev_letter = " "
# begin places division
with Html("div", class_="content", id="Places") as placelist:
body += placelist
# place list page message
msg = self._("This page contains an index of all the places in the "
"database, sorted by their title. "
"Clicking on a place&#8217;s "
"title will take you to that place&#8217;s page.")
placelist += Html("p", msg, id="description")
# begin alphabet navigation
index_list = get_first_letters(self.r_db, place_handles,
_KEYPLACE, rlocale=self.rlocale)
alpha_nav = alphabet_navigation(index_list, self.rlocale)
if alpha_nav is not None:
placelist += alpha_nav
# begin places table and table head
with Html("table",
class_="infolist primobjlist placelist") as table:
placelist += table
# begin table head
thead = Html("thead")
table += thead
trow = Html("tr")
thead += trow
trow.extend(
Html("th", label, class_=colclass, inline=True)
for (label, colclass) in [
[self._("Letter"), "ColumnLetter"],
[self._("Place Name | Name"), "ColumnName"],
[self._("State/ Province"), "ColumnState"],
[self._("Country"), "ColumnCountry"],
[self._("Latitude"), "ColumnLatitude"],
[self._("Longitude"), "ColumnLongitude"]
]
)
# bug 9495 : incomplete display of place hierarchy labels
def sort_by_place_name(obj):
""" sort by lower case place name. """
name = self.report.obj_dict[Place][obj][1]
return name.lower()
handle_list = sorted(place_handles,
key=lambda x: sort_by_place_name(x))
first = True
# begin table body
tbody = Html("tbody")
table += tbody
for place_handle in handle_list:
place = self.r_db.get_place_from_handle(place_handle)
if place:
if place.get_change_time() > ldatec:
ldatec = place.get_change_time()
plc_title = self.report.obj_dict[Place][place_handle][1]
main_location = get_main_location(self.r_db, place)
if plc_title and plc_title != " ":
letter = get_index_letter(first_letter(plc_title),
index_list,
self.rlocale)
else:
letter = '&nbsp;'
trow = Html("tr")
tbody += trow
tcell = Html("td", class_="ColumnLetter", inline=True)
trow += tcell
if first or primary_difference(letter, prev_letter,
self.rlocale):
first = False
prev_letter = letter
trow.attr = 'class = "BeginLetter"'
ttle = self._("Places beginning "
"with letter %s") % letter
tcell += Html("a", letter, name=letter, title=ttle)
else:
tcell += "&nbsp;"
trow += Html("td",
self.place_link(
place.get_handle(),
plc_title, place.get_gramps_id()),
class_="ColumnName")
trow.extend(
Html("td", data or "&nbsp;", class_=colclass,
inline=True)
for (colclass, data) in [
["ColumnState",
main_location.get(PlaceType.STATE, '')],
["ColumnCountry",
main_location.get(PlaceType.COUNTRY, '')]
]
)
tcell1 = Html("td", class_="ColumnLatitude",
inline=True)
tcell2 = Html("td", class_="ColumnLongitude",
inline=True)
trow += (tcell1, tcell2)
if place.lat and place.long:
latitude, longitude = conv_lat_lon(place.lat,
place.long,
"DEG")
tcell1 += latitude
tcell2 += longitude
else:
tcell1 += '&nbsp;'
tcell2 += '&nbsp;'
# add clearline for proper styling
# add footer section
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(placelistpage, output_file, sio, ldatec)
def placepage(self, report, title, place_handle):
"""
Create a place page
@param: report -- The instance of the main report class for
this report
@param: title -- Is the title of the web page
@param: place_handle -- The handle for the place to add
"""
place = report.database.get_place_from_handle(place_handle)
if not place:
return None
BasePage.__init__(self, report, title, place.get_gramps_id())
self.bibli = Bibliography()
place_name = self.report.obj_dict[Place][place_handle][1]
ldatec = place.get_change_time()
output_file, sio = self.report.create_file(place_handle, "plc")
self.uplink = True
self.page_title = place_name
placepage, head, body = self.write_header(_("Places"))
self.placemappages = self.report.options['placemappages']
self.mapservice = self.report.options['mapservice']
self.googlemapkey = self.report.options['googlemapkey']
# begin PlaceDetail Division
with Html("div", class_="content", id="PlaceDetail") as placedetail:
body += placedetail
if self.create_media:
media_list = place.get_media_list()
thumbnail = self.disp_first_img_as_thumbnail(media_list,
place)
if thumbnail is not None:
placedetail += thumbnail
# add section title
placedetail += Html("h3",
html_escape(place_name),
inline=True)
# begin summaryarea division and places table
with Html("div", id='summaryarea') as summaryarea:
placedetail += summaryarea
with Html("table", class_="infolist place") as table:
summaryarea += table
# list the place fields
self.dump_place(place, table)
# place gallery
if self.create_media:
placegallery = self.disp_add_img_as_gallery(media_list, place)
if placegallery is not None:
placedetail += placegallery
# place notes
notelist = self.display_note_list(place.get_note_list())
if notelist is not None:
placedetail += notelist
# place urls
urllinks = self.display_url_list(place.get_url_list())
if urllinks is not None:
placedetail += urllinks
# add place map here
# Link to Gramps marker
fname = "/".join(['images', 'marker.png'])
marker_path = self.report.build_url_image("marker.png",
"images", self.uplink)
if self.placemappages:
if place and (place.lat and place.long):
latitude, longitude = conv_lat_lon(place.get_latitude(),
place.get_longitude(),
"D.D8")
placetitle = place_name
# add narrative-maps CSS...
fname = "/".join(["css", "narrative-maps.css"])
url = self.report.build_url_fname(fname, None, self.uplink)
head += Html("link", href=url, type="text/css",
media="screen", rel="stylesheet")
# add MapService specific javascript code
src_js = GOOGLE_MAPS + "api/js?sensor=false"
if self.mapservice == "Google":
if self.googlemapkey:
src_js += "&key=" + self.googlemapkey
head += Html("script", type="text/javascript",
src=src_js, inline=True)
else:
url = self.secure_mode
url += ("maxcdn.bootstrapcdn.com/bootstrap/3.3.7/"
"css/bootstrap.min.css")
head += Html("link", href=url, type="text/javascript",
rel="stylesheet")
src_js = self.secure_mode
src_js += ("ajax.googleapis.com/ajax/libs/jquery/1.9.1/"
"jquery.min.js")
head += Html("script", type="text/javascript",
src=src_js, inline=True)
src_js = self.secure_mode
src_js += "openlayers.org/en/v3.17.1/build/ol.js"
head += Html("script", type="text/javascript",
src=src_js, inline=True)
url = self.secure_mode
url += "openlayers.org/en/v3.17.1/css/ol.css"
head += Html("link", href=url, type="text/javascript",
rel="stylesheet")
src_js = self.secure_mode
src_js += ("maxcdn.bootstrapcdn.com/bootstrap/3.3.7/"
"js/bootstrap.min.js")
head += Html("script", type="text/javascript",
src=src_js, inline=True)
# section title
placedetail += Html("h4", self._("Place Map"), inline=True)
# begin map_canvas division
with Html("div", id="map_canvas", inline=True) as canvas:
placedetail += canvas
# Begin inline javascript code because jsc is a
# docstring, it does NOT have to be properly indented
if self.mapservice == "Google":
with Html("script", type="text/javascript",
indent=False) as jsc:
head += jsc
# Google adds Latitude/ Longitude to its maps...
plce = placetitle.replace("'", "\\'")
jsc += MARKER_PATH % marker_path
jsc += MARKERS % ([[plce,
latitude,
longitude,
1]],
latitude, longitude,
10)
else:
# OpenStreetMap (OSM) adds Longitude/ Latitude
# to its maps, and needs a country code in
# lowercase letters...
with Html("script", type="text/javascript") as jsc:
canvas += jsc
#param1 = xml_lang()[3:5].lower()
jsc += MARKER_PATH % marker_path
jsc += OSM_MARKERS % ([[float(longitude),
float(latitude),
placetitle]],
longitude, latitude, 10)
# add javascript function call to body element
body.attr += ' onload = "initialize();" '
# add div for popups.
with Html("div", id="popup", inline=True) as popup:
placedetail += popup
# source references
srcrefs = self.display_ind_sources(place)
if srcrefs is not None:
placedetail += srcrefs
# References list
ref_list = self.display_bkref_list(Place, place_handle)
if ref_list is not None:
placedetail += ref_list
# add clearline for proper styling
# add footer section
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(placepage, output_file, sio, ldatec)

View File

@ -0,0 +1,287 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
RepositoryPage - Repository index page and individual Repository pages
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from collections import defaultdict
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.lib import Repository
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import (FULLCLEAR, html_escape)
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
#################################################
#
# creates the Repository List Page and Repository Pages
#
#################################################
class RepositoryPages(BasePage):
"""
This class is responsible for displaying information about the 'Repository'
database objects. It displays this information under the 'Individuals'
tab. It is told by the 'add_instances' call which 'Repository's to display,
and remembers the list of persons. A single call to 'display_pages'
displays both the Individual List (Index) page and all the Individual
pages.
The base class 'BasePage' is initialised once for each page that is
displayed.
"""
def __init__(self, report):
"""
@param: report -- The instance of the main report class for this report
"""
BasePage.__init__(self, report, title="")
self.repos_dict = defaultdict(set)
def display_pages(self, title):
"""
Generate and output the pages under the Repository tab, namely the
repository index and the individual repository pages.
@param: title -- Is the title of the web page
"""
LOG.debug("obj_dict[Person]")
for item in self.report.obj_dict[Repository].items():
LOG.debug(" %s", str(item))
# set progress bar pass for Repositories
with self.r_user.progress(_("Narrated Web Site Report"),
_('Creating repository pages'),
len(self.report.obj_dict[Repository]) + 1
) as step:
# Sort the repositories
repos_dict = {}
for repo_handle in self.report.obj_dict[Repository]:
repository = self.r_db.get_repository_from_handle(repo_handle)
key = repository.get_name() + str(repository.get_gramps_id())
repos_dict[key] = (repository, repo_handle)
keys = sorted(repos_dict, key=self.rlocale.sort_key)
# RepositoryListPage Class
self.repositorylistpage(self.report, title, repos_dict, keys)
for index, key in enumerate(keys):
(repo, handle) = repos_dict[key]
step()
self.repositorypage(self.report, title, repo, handle)
def repositorylistpage(self, report, title, repos_dict, keys):
"""
Create Index for repositories
@param: report -- The instance of the main report class
for this report
@param: title -- Is the title of the web page
@param: repos_dict -- The dictionary for all repositories
@param: keys -- The keys used to access repositories
"""
BasePage.__init__(self, report, title)
#inc_repos = self.report.options["inc_repository"]
output_file, sio = self.report.create_file("repositories")
repolistpage, head, body = self.write_header(_("Repositories"))
ldatec = 0
# begin RepositoryList division
with Html("div", class_="content",
id="RepositoryList") as repositorylist:
body += repositorylist
msg = self._("This page contains an index of "
"all the repositories in the "
"database, sorted by their title. "
"Clicking on a repositories&#8217;s title "
"will take you to that repositories&#8217;s page.")
repositorylist += Html("p", msg, id="description")
# begin repositories table and table head
with Html("table", class_="infolist primobjlist repolist") as table:
repositorylist += table
thead = Html("thead")
table += thead
trow = Html("tr") + (
Html("th", "&nbsp;", class_="ColumnRowLabel", inline=True),
Html("th", self._("Type"), class_="ColumnType",
inline=True),
Html("th", self._("Repository |Name"), class_="ColumnName",
inline=True)
)
thead += trow
# begin table body
tbody = Html("tbody")
table += tbody
for index, key in enumerate(keys):
(repo, handle) = repos_dict[key]
trow = Html("tr")
tbody += trow
# index number
trow += Html("td", index + 1, class_="ColumnRowLabel",
inline=True)
# repository type
rtype = self._(repo.type.xml_str())
trow += Html("td", rtype, class_="ColumnType", inline=True)
# repository name and hyperlink
if repo.get_name():
trow += Html("td",
self.repository_link(handle,
repo.get_name(),
repo.get_gramps_id(),
self.uplink),
class_="ColumnName")
ldatec = repo.get_change_time()
else:
trow += Html("td", "[ untitled ]", class_="ColumnName")
# add clearline for proper styling
# add footer section
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(repolistpage, output_file, sio, ldatec)
def repositorypage(self, report, title, repo, handle):
"""
Create one page for one repository.
@param: report -- The instance of the main report class for this report
@param: title -- Is the title of the web page
@param: repo -- the repository to use
@param: handle -- the handle to use
"""
gid = repo.get_gramps_id()
BasePage.__init__(self, report, title, gid)
ldatec = repo.get_change_time()
output_file, sio = self.report.create_file(handle, 'repo')
self.uplink = True
repositorypage, head, body = self.write_header(_('Repositories'))
# begin RepositoryDetail division and page title
with Html("div", class_="content",
id="RepositoryDetail") as repositorydetail:
body += repositorydetail
# repository name
repositorydetail += Html("h3", html_escape(repo.name),
inline=True)
# begin repository table
with Html("table", class_="infolist repolist") as table:
repositorydetail += table
tbody = Html("tbody")
table += tbody
if not self.noid and gid:
trow = Html("tr") + (
Html("td", self._("Gramps ID"),
class_="ColumnAttribute",
inline=True),
Html("td", gid, class_="ColumnValue", inline=True)
)
tbody += trow
trow = Html("tr") + (
Html("td", self._("Type"), class_="ColumnAttribute",
inline=True),
Html("td", self._(repo.get_type().xml_str()),
class_="ColumnValue",
inline=True)
)
tbody += trow
# repository: address(es)...
# repository addresses do NOT have Sources
repo_address = self.display_addr_list(repo.get_address_list(),
False)
if repo_address is not None:
repositorydetail += repo_address
# repository: urllist
urllist = self.display_url_list(repo.get_url_list())
if urllist is not None:
repositorydetail += urllist
# reposity: notelist
notelist = self.display_note_list(repo.get_note_list())
if notelist is not None:
repositorydetail += notelist
# display Repository Referenced Sources...
ref_list = self.display_bkref_list(Repository, repo.get_handle())
if ref_list is not None:
repositorydetail += ref_list
# add clearline for proper styling
# add footer section
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(repositorypage, output_file, sio, ldatec)

View File

@ -0,0 +1,306 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
SourcePage - Source index page and individual Source pages
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from collections import defaultdict
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.lib import Source
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import (FULLCLEAR, html_escape)
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb.source")
getcontext().prec = 8
#################################################
#
# creates the Source List Page and Source Pages
#
#################################################
class SourcePages(BasePage):
"""
This class is responsible for displaying information about the 'Source'
database objects. It displays this information under the 'Sources'
tab. It is told by the 'add_instances' call which 'Source's to display,
and remembers the list of persons. A single call to 'display_pages'
displays both the Individual List (Index) page and all the Individual
pages.
The base class 'BasePage' is initialised once for each page that is
displayed.
"""
def __init__(self, report):
"""
@param: report -- The instance of the main report class for
this report
"""
BasePage.__init__(self, report, title="")
self.source_dict = defaultdict(set)
self.navigation = None
self.citationreferents = None
def display_pages(self, title):
"""
Generate and output the pages under the Sources tab, namely the sources
index and the individual sources pages.
@param: title -- Is the title of the web page
"""
LOG.debug("obj_dict[Source]")
for item in self.report.obj_dict[Source].items():
LOG.debug(" %s", str(item))
with self.r_user.progress(_("Narrated Web Site Report"),
_("Creating source pages"),
len(self.report.obj_dict[Source]) + 1
) as step:
self.sourcelistpage(self.report, title,
self.report.obj_dict[Source].keys())
for source_handle in self.report.obj_dict[Source]:
step()
self.sourcepage(self.report, title, source_handle)
def sourcelistpage(self, report, title, source_handles):
"""
Generate and output the Sources index page.
@param: report -- The instance of the main report class for
this report
@param: title -- Is the title of the web page
@param: source_handles -- A list of the handles of the sources to be
displayed
"""
BasePage.__init__(self, report, title)
source_dict = {}
output_file, sio = self.report.create_file("sources")
sourcelistpage, head, body = self.write_header(self._("Sources"))
# begin source list division
with Html("div", class_="content", id="Sources") as sourceslist:
body += sourceslist
# Sort the sources
for handle in source_handles:
source = self.r_db.get_source_from_handle(handle)
if source is not None:
key = source.get_title() + source.get_author()
key += str(source.get_gramps_id())
source_dict[key] = (source, handle)
keys = sorted(source_dict, key=self.rlocale.sort_key)
msg = self._("This page contains an index of all the sources "
"in the database, sorted by their title. "
"Clicking on a source&#8217;s "
"title will take you to that source&#8217;s page.")
sourceslist += Html("p", msg, id="description")
# begin sourcelist table and table head
with Html("table",
class_="infolist primobjlist sourcelist") as table:
sourceslist += table
thead = Html("thead")
table += thead
trow = Html("tr")
thead += trow
header_row = [
(self._("Number"), "ColumnRowLabel"),
(self._("Author"), "ColumnAuthor"),
(self._("Source Name|Name"), "ColumnName")]
trow.extend(
Html("th", label or "&nbsp;", class_=colclass, inline=True)
for (label, colclass) in header_row
)
# begin table body
tbody = Html("tbody")
table += tbody
for index, key in enumerate(keys):
source, source_handle = source_dict[key]
trow = Html("tr") + (
Html("td", index + 1, class_="ColumnRowLabel",
inline=True)
)
tbody += trow
trow.extend(
Html("td", source.get_author(), class_="ColumnAuthor",
inline=True)
)
trow.extend(
Html("td", self.source_link(source_handle,
source.get_title(),
source.get_gramps_id()),
class_="ColumnName")
)
# add clearline for proper styling
# add footer section
footer = self.write_footer(None)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(sourcelistpage, output_file, sio, 0)
def sourcepage(self, report, title, source_handle):
"""
Generate and output an individual Source page.
@param: report -- The instance of the main report class
for this report
@param: title -- Is the title of the web page
@param: source_handle -- The handle of the source to be output
"""
source = report.database.get_source_from_handle(source_handle)
BasePage.__init__(self, report, title, source.get_gramps_id())
if not source:
return
self.page_title = source.get_title()
inc_repositories = self.report.options["inc_repository"]
self.navigation = self.report.options['navigation']
self.citationreferents = self.report.options['citationreferents']
output_file, sio = self.report.create_file(source_handle, "src")
self.uplink = True
sourcepage, head, body = self.write_header(
"%s - %s" % (self._('Sources'), self.page_title))
ldatec = 0
# begin source detail division
with Html("div", class_="content", id="SourceDetail") as sourcedetail:
body += sourcedetail
media_list = source.get_media_list()
if self.create_media and media_list:
thumbnail = self.disp_first_img_as_thumbnail(media_list,
source)
if thumbnail is not None:
sourcedetail += thumbnail
# add section title
sourcedetail += Html("h3", html_escape(source.get_title()),
inline=True)
# begin sources table
with Html("table", class_="infolist source") as table:
sourcedetail += table
tbody = Html("tbody")
table += tbody
source_gid = False
if not self.noid and self.gid:
source_gid = source.get_gramps_id()
# last modification of this source
ldatec = source.get_change_time()
for (label, value) in [(self._("Gramps ID"), source_gid),
(self._("Author"), source.get_author()),
(self._("Abbreviation"),
source.get_abbreviation()),
(self._("Publication information"),
source.get_publication_info())]:
if value:
trow = Html("tr") + (
Html("td", label, class_="ColumnAttribute",
inline=True),
Html("td", value, class_="ColumnValue", inline=True)
)
tbody += trow
# Source notes
notelist = self.display_note_list(source.get_note_list())
if notelist is not None:
sourcedetail += notelist
# additional media from Source (if any?)
if self.create_media and media_list:
sourcemedia = self.disp_add_img_as_gallery(media_list, source)
if sourcemedia is not None:
sourcedetail += sourcemedia
# Source Data Map...
src_data_map = self.write_srcattr(source.get_attribute_list())
if src_data_map is not None:
sourcedetail += src_data_map
# Source Repository list
if inc_repositories:
repo_list = self.dump_repository_ref_list(
source.get_reporef_list())
if repo_list is not None:
sourcedetail += repo_list
# Source references list
ref_list = self.display_bkref_list(Source, source_handle)
if ref_list is not None:
sourcedetail += ref_list
# add clearline for proper styling
# add footer section
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(sourcepage, output_file, sio, ldatec)

View File

@ -0,0 +1,243 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
StatisticsPage
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.lib import (Person, Family, Event, Place, Source,
Citation, Repository)
from gramps.gen.plug.report import Bibliography
from gramps.gen.utils.file import media_path_full
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import FULLCLEAR
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
_ = glocale.translation.sgettext
class StatisticsPage(BasePage):
"""
Create one page for statistics
"""
def __init__(self, report, title, step):
"""
@param: report -- The instance of the main report class
for this report
@param: title -- Is the title of the web page
"""
import posixpath
BasePage.__init__(self, report, title)
self.bibli = Bibliography()
self.uplink = False
self.report = report
# set the file name and open file
output_file, sio = self.report.create_file("statistics")
addressbookpage, head, body = self.write_header(_("Statistics"))
(males,
females,
unknown) = self.get_gender(report.database.iter_person_handles())
mobjects = report.database.get_number_of_media()
npersons = report.database.get_number_of_people()
nfamilies = report.database.get_number_of_families()
nsurnames = len(set(report.database.surname_list))
notfound = []
total_media = 0
mbytes = "0"
chars = 0
for media in report.database.iter_media():
total_media += 1
fullname = media_path_full(report.database, media.get_path())
try:
chars += posixpath.getsize(fullname)
length = len(str(chars))
if chars <= 999999:
mbytes = _("less than 1")
else:
mbytes = str(chars)[:(length-6)]
except OSError:
notfound.append(media.get_path())
with Html("div", class_="content", id='EventDetail') as section:
section += Html("h3", self._("Database overview"), inline=True)
body += section
with Html("div", class_="content", id='subsection narrative') as sec11:
sec11 += Html("h4", self._("Individuals"), inline=True)
body += sec11
with Html("div", class_="content", id='subsection narrative') as sec1:
sec1 += Html("br", self._("Number of individuals") + self.colon +
"%d" % npersons, inline=True)
sec1 += Html("br", self._("Males") + self.colon +
"%d" % males, inline=True)
sec1 += Html("br", self._("Females") + self.colon +
"%d" % females, inline=True)
sec1 += Html("br", self._("Individuals with unknown gender") +
self.colon + "%d" % unknown, inline=True)
body += sec1
with Html("div", class_="content", id='subsection narrative') as sec2:
sec2 += Html("h4", self._("Family Information"), inline=True)
sec2 += Html("br", self._("Number of families") + self.colon +
"%d" % nfamilies, inline=True)
sec2 += Html("br", self._("Unique surnames") + self.colon +
"%d" % nsurnames, inline=True)
body += sec2
with Html("div", class_="content", id='subsection narrative') as sec3:
sec3 += Html("h4", self._("Media Objects"), inline=True)
sec3 += Html("br",
self._("Total number of media object references") +
self.colon + "%d" % total_media, inline=True)
sec3 += Html("br", self._("Number of unique media objects") +
self.colon + "%d" % mobjects, inline=True)
sec3 += Html("br", self._("Total size of media objects") +
self.colon +
"%8s %s" % (mbytes, self._("Megabyte|MB")),
inline=True)
sec3 += Html("br", self._("Missing Media Objects") +
self.colon + "%d" % len(notfound), inline=True)
body += sec3
with Html("div", class_="content", id='subsection narrative') as sec4:
sec4 += Html("h4", self._("Miscellaneous"), inline=True)
sec4 += Html("br", self._("Number of events") + self.colon +
"%d" % report.database.get_number_of_events(),
inline=True)
sec4 += Html("br", self._("Number of places") + self.colon +
"%d" % report.database.get_number_of_places(),
inline=True)
nsources = report.database.get_number_of_sources()
sec4 += Html("br", self._("Number of sources") +
self.colon + "%d" % nsources,
inline=True)
ncitations = report.database.get_number_of_citations()
sec4 += Html("br", self._("Number of citations") +
self.colon + "%d" % ncitations,
inline=True)
nrepo = report.database.get_number_of_repositories()
sec4 += Html("br", self._("Number of repositories") +
self.colon + "%d" % nrepo,
inline=True)
body += sec4
(males,
females,
unknown) = self.get_gender(self.report.bkref_dict[Person].keys())
origin = " :<br/>" + report.filter.get_name(self.rlocale)
with Html("div", class_="content", id='EventDetail') as section:
section += Html("h3",
self._("Narrative web content report for") + origin,
inline=True)
body += section
with Html("div", class_="content", id='subsection narrative') as sec5:
sec5 += Html("h4", self._("Individuals"), inline=True)
sec5 += Html("br", self._("Number of individuals") + self.colon +
"%d" % len(self.report.bkref_dict[Person]),
inline=True)
sec5 += Html("br", self._("Males") + self.colon +
"%d" % males, inline=True)
sec5 += Html("br", self._("Females") + self.colon +
"%d" % females, inline=True)
sec5 += Html("br", self._("Individuals with unknown gender") +
self.colon + "%d" % unknown, inline=True)
body += sec5
with Html("div", class_="content", id='subsection narrative') as sec6:
sec6 += Html("h4", self._("Family Information"), inline=True)
sec6 += Html("br", self._("Number of families") + self.colon +
"%d" % len(self.report.bkref_dict[Family]),
inline=True)
body += sec6
with Html("div", class_="content", id='subsection narrative') as sec7:
sec7 += Html("h4", self._("Miscellaneous"), inline=True)
sec7 += Html("br", self._("Number of events") + self.colon +
"%d" % len(self.report.bkref_dict[Event]),
inline=True)
sec7 += Html("br", self._("Number of places") + self.colon +
"%d" % len(self.report.bkref_dict[Place]),
inline=True)
sec7 += Html("br", self._("Number of sources") + self.colon +
"%d" % len(self.report.bkref_dict[Source]),
inline=True)
sec7 += Html("br", self._("Number of citations") + self.colon +
"%d" % len(self.report.bkref_dict[Citation]),
inline=True)
sec7 += Html("br", self._("Number of repositories") + self.colon +
"%d" % len(self.report.bkref_dict[Repository]),
inline=True)
body += sec7
# add fullclear for proper styling
# and footer section to page
footer = self.write_footer(None)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(addressbookpage, output_file, sio, 0)
def get_gender(self, person_list):
"""
This function return the number of males, females and unknown gender
from a person list.
"""
males = 0
females = 0
unknown = 0
for person_handle in person_list:
person = self.report.database.get_person_from_handle(person_handle)
gender = person.get_gender()
if gender == Person.MALE:
males += 1
elif gender == Person.FEMALE:
females += 1
else:
unknown += 1
return (males, females, unknown)

View File

@ -0,0 +1,265 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
SurnamePage - creates list of individuals with same surname
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.plug.report import utils
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import (name_to_md5, _NAME_STYLE_FIRST,
_find_birth_date, _find_death_date,
FULLCLEAR, html_escape)
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
#################################################
#
# create the page from SurnameListPage
#
#################################################
class SurnamePage(BasePage):
"""
This will create a list of individuals with the same surname
"""
def __init__(self, report, title, surname, ppl_handle_list):
"""
@param: report -- The instance of the main report class for
this report
@param: title -- Is the title of the web page
@param: surname -- The surname to use
@param: ppl_handle_list -- The list of people for whom we need to create
a page.
"""
BasePage.__init__(self, report, title)
# module variables
showbirth = report.options['showbirth']
showdeath = report.options['showdeath']
showpartner = report.options['showpartner']
showparents = report.options['showparents']
if surname == '':
surname = self._("<absent>")
output_file, sio = self.report.create_file(name_to_md5(surname), "srn")
self.uplink = True
(surnamepage, head,
body) = self.write_header("%s - %s" % (self._("Surname"), surname))
ldatec = 0
# begin SurnameDetail division
with Html("div", class_="content", id="SurnameDetail") as surnamedetail:
body += surnamedetail
# section title
surnamedetail += Html("h3", html_escape(surname), inline=True)
# feature request 2356: avoid genitive form
msg = self._("This page contains an index of all the individuals "
"in the database with the surname of %s. "
"Selecting the person&#8217;s name "
"will take you to that person&#8217;s "
"individual page.") % html_escape(surname)
surnamedetail += Html("p", msg, id="description")
# begin surname table and thead
with Html("table", class_="infolist primobjlist surname") as table:
surnamedetail += table
thead = Html("thead")
table += thead
trow = Html("tr")
thead += trow
# Name Column
trow += Html("th", self._("Given Name"), class_="ColumnName",
inline=True)
if showbirth:
trow += Html("th", self._("Birth"), class_="ColumnDate",
inline=True)
if showdeath:
trow += Html("th", self._("Death"), class_="ColumnDate",
inline=True)
if showpartner:
trow += Html("th", self._("Partner"),
class_="ColumnPartner",
inline=True)
if showparents:
trow += Html("th", self._("Parents"),
class_="ColumnParents",
inline=True)
# begin table body
tbody = Html("tbody")
table += tbody
for person_handle in sorted(ppl_handle_list,
key=self.sort_on_name_and_grampsid):
person = self.r_db.get_person_from_handle(person_handle)
if person.get_change_time() > ldatec:
ldatec = person.get_change_time()
trow = Html("tr")
tbody += trow
# firstname column
link = self.new_person_link(person_handle, uplink=True,
person=person,
name_style=_NAME_STYLE_FIRST)
trow += Html("td", link, class_="ColumnName")
# birth column
if showbirth:
tcell = Html("td", class_="ColumnBirth", inline=True)
trow += tcell
birth_date = _find_birth_date(self.r_db, person)
if birth_date is not None:
if birth_date.fallback:
tcell += Html('em',
self.rlocale.get_date(birth_date),
inline=True)
else:
tcell += self.rlocale.get_date(birth_date)
else:
tcell += "&nbsp;"
# death column
if showdeath:
tcell = Html("td", class_="ColumnDeath", inline=True)
trow += tcell
death_date = _find_death_date(self.r_db, person)
if death_date is not None:
if death_date.fallback:
tcell += Html('em',
self.rlocale.get_date(death_date),
inline=True)
else:
tcell += self.rlocale.get_date(death_date)
else:
tcell += "&nbsp;"
# partner column
if showpartner:
tcell = Html("td", class_="ColumnPartner")
trow += tcell
family_list = person.get_family_handle_list()
if family_list:
fam_count = 0
for family_handle in family_list:
fam_count += 1
family = self.r_db.get_family_from_handle(
family_handle)
partner_handle = utils.find_spouse(
person, family)
if partner_handle:
link = self.new_person_link(partner_handle,
uplink=True)
if fam_count < len(family_list):
if isinstance(link, Html):
link.inside += ","
else:
link += ','
tcell += link
else:
tcell += "&nbsp;"
# parents column
if showparents:
parent_hdl_list = person.get_parent_family_handle_list()
if parent_hdl_list:
parent_hdl = parent_hdl_list[0]
fam = self.r_db.get_family_from_handle(parent_hdl)
f_id = fam.get_father_handle()
m_id = fam.get_mother_handle()
mother = father = None
if f_id:
father = self.r_db.get_person_from_handle(f_id)
if father:
father_name = self.get_name(father)
if m_id:
mother = self.r_db.get_person_from_handle(m_id)
if mother:
mother_name = self.get_name(mother)
if mother and father:
tcell = Html("span", father_name,
class_="father fatherNmother")
tcell += Html("span", mother_name,
class_="mother")
elif mother:
tcell = Html("span", mother_name,
class_="mother", inline=True)
elif father:
tcell = Html("span", father_name,
class_="father", inline=True)
samerow = False
else:
tcell = "&nbsp;" # pylint: disable=R0204
samerow = True
trow += Html("td", tcell,
class_="ColumnParents", inline=samerow)
# add clearline for proper styling
# add footer section
footer = self.write_footer(ldatec)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(surnamepage, output_file, sio, ldatec)

View File

@ -0,0 +1,249 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
SurnameListPage - Index for first letters of surname
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import (get_first_letters, _KEYPERSON,
alphabet_navigation, html_escape,
sort_people, name_to_md5,
first_letter, get_index_letter,
primary_difference, FULLCLEAR)
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
#################################################
#
# Creates the Surname List page
#
#################################################
class SurnameListPage(BasePage):
"""
This class is responsible for displaying the list of Surnames
"""
ORDER_BY_NAME = 0
ORDER_BY_COUNT = 1
def __init__(self, report, title, ppl_handle_list,
order_by=ORDER_BY_NAME, filename="surnames"):
"""
@param: report -- The instance of the main report class for
this report
@param: title -- Is the title of the web page
@param: ppl_handle_list -- The list of people for whom we need to create
a page.
@param: order_by -- The way to sort surnames :
Surnames or Surnames count
@param: filename -- The name to use for the Surnames page
"""
BasePage.__init__(self, report, title)
prev_surname = ""
prev_letter = " "
if order_by == self.ORDER_BY_NAME:
output_file, sio = self.report.create_file(filename)
surnamelistpage, head, body = self.write_header(self._('Surnames'))
else:
output_file, sio = self.report.create_file("surnames_count")
(surnamelistpage, head,
body) = self.write_header(self._('Surnames by person count'))
# begin surnames division
with Html("div", class_="content", id="surnames") as surnamelist:
body += surnamelist
# page message
msg = self._('This page contains an index of all the '
'surnames in the database. Selecting a link '
'will lead to a list of individuals in the '
'database with this same surname.')
surnamelist += Html("p", msg, id="description")
# add alphabet navigation...
# only if surname list not surname count
if order_by == self.ORDER_BY_NAME:
index_list = get_first_letters(self.r_db, ppl_handle_list,
_KEYPERSON, rlocale=self.rlocale)
alpha_nav = alphabet_navigation(index_list, self.rlocale)
if alpha_nav is not None:
surnamelist += alpha_nav
if order_by == self.ORDER_BY_COUNT:
table_id = 'SortByCount'
else:
table_id = 'SortByName'
# begin surnamelist table and table head
with Html("table", class_="infolist primobjlist surnamelist",
id=table_id) as table:
surnamelist += table
thead = Html("thead")
table += thead
trow = Html("tr")
thead += trow
trow += Html("th", self._("Letter"), class_="ColumnLetter",
inline=True)
# create table header surname hyperlink
fname = self.report.surname_fname + self.ext
tcell = Html("th", class_="ColumnSurname", inline=True)
trow += tcell
hyper = Html("a", self._("Surname"),
href=fname, title=self._("Surnames"))
tcell += hyper
# create table header number of people hyperlink
fname = "surnames_count" + self.ext
tcell = Html("th", class_="ColumnQuantity", inline=True)
trow += tcell
num_people = self._("Number of People")
hyper = Html("a", num_people, href=fname, title=num_people)
tcell += hyper
# begin table body
with Html("tbody") as tbody:
table += tbody
ppl_handle_list = sort_people(self.r_db, ppl_handle_list,
self.rlocale)
if order_by == self.ORDER_BY_COUNT:
temp_list = {}
for (surname, data_list) in ppl_handle_list:
index_val = "%90d_%s" % (999999999-len(data_list),
surname)
temp_list[index_val] = (surname, data_list)
lkey = self.rlocale.sort_key
ppl_handle_list = (temp_list[key]
for key in sorted(temp_list,
key=lkey))
first = True
first_surname = True
for (surname, data_list) in ppl_handle_list:
if surname and not surname.isspace():
letter = first_letter(surname)
if order_by == self.ORDER_BY_NAME:
# There will only be an alphabetic index list if
# the ORDER_BY_NAME page is being generated
letter = get_index_letter(letter, index_list,
self.rlocale)
else:
letter = '&nbsp;'
surname = self._("<absent>")
trow = Html("tr")
tbody += trow
tcell = Html("td", class_="ColumnLetter", inline=True)
trow += tcell
if first or primary_difference(letter, prev_letter,
self.rlocale):
first = False
prev_letter = letter
trow.attr = 'class = "BeginLetter"'
ttle = self._("Surnames beginning with "
"letter %s") % letter
hyper = Html("a", letter, name=letter,
title=ttle, inline=True)
tcell += hyper
elif first_surname or surname != prev_surname:
first_surname = False
tcell += "&nbsp;"
prev_surname = surname
trow += Html("td",
self.surname_link(name_to_md5(surname),
#html_escape(surname)),
surname),
class_="ColumnSurname", inline=True)
trow += Html("td", len(data_list),
class_="ColumnQuantity", inline=True)
# create footer section
# add clearline for proper styling
footer = self.write_footer(None)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(surnamelistpage,
output_file, sio, 0) # 0 => current date modification
def surname_link(self, fname, name, opt_val=None, uplink=False):
"""
Create a link to the surname page.
@param: fname -- Path to the file name
@param: name -- Name to see in the link
@param: opt_val -- Option value to use
@param: uplink -- If True, then "../../../" is inserted in front of
the result.
"""
url = self.report.build_url_fname_html(fname, "srn", uplink)
hyper = Html("a", html_escape(name), href=url,
title=name, inline=True)
if opt_val is not None:
hyper += opt_val
# return hyperlink to its caller
return hyper

View File

@ -0,0 +1,277 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2007 Johan Gonqvist <johan.gronqvist@gmail.com>
# Copyright (C) 2007-2009 Gary Burton <gary.burton@zen.co.uk>
# Copyright (C) 2007-2009 Stephane Charette <stephanecharette@gmail.com>
# Copyright (C) 2008-2009 Brian G. Matherly
# Copyright (C) 2008 Jason M. Simanek <jason@bohemianalps.com>
# Copyright (C) 2008-2011 Rob G. Healey <robhealey1@gmail.com>
# Copyright (C) 2010 Doug Blank <doug.blank@gmail.com>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2010-2017 Serge Noiraud
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013 Benny Malengier
# Copyright (C) 2016 Allen Crider
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Narrative Web Page generator.
Classe:
ThumbnailPreviewPage
"""
#------------------------------------------------
# python modules
#------------------------------------------------
from decimal import getcontext
import logging
#------------------------------------------------
# Gramps module
#------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
from gramps.gen.lib import Media
from gramps.plugins.lib.libhtml import Html
#------------------------------------------------
# specific narrative web import
#------------------------------------------------
from gramps.plugins.webreport.basepage import BasePage
from gramps.plugins.webreport.common import (FULLCLEAR, html_escape)
_ = glocale.translation.sgettext
LOG = logging.getLogger(".NarrativeWeb")
getcontext().prec = 8
class ThumbnailPreviewPage(BasePage):
"""
This class is responsible for displaying information about
the Thumbnails page.
"""
def __init__(self, report, title, cb_progress):
"""
@param: report -- The instance of the main report class
for this report
@param: title -- Is the title of the web page
@param: cb_progress -- The step used for the progress bar.
"""
BasePage.__init__(self, report, title)
self.create_thumbs_only = report.options['create_thumbs_only']
# bug 8950 : it seems it's better to sort on desc + gid.
def sort_by_desc_and_gid(obj):
"""
Sort by media description and gramps ID
"""
return (obj.desc, obj.gramps_id)
self.photo_keys = sorted(self.report.obj_dict[Media],
key=lambda x: sort_by_desc_and_gid(
self.r_db.get_media_from_handle(x)))
if self.create_unused_media:
# add unused media
media_list = self.r_db.get_media_handles()
for media_ref in media_list:
if media_ref not in self.report.obj_dict[Media]:
self.photo_keys.append(media_ref)
media_list = []
for person_handle in self.photo_keys:
photo = self.r_db.get_media_from_handle(person_handle)
if photo:
if photo.get_mime_type().startswith("image"):
media_list.append((photo.get_description(), person_handle,
photo))
if self.create_thumbs_only:
self.copy_thumbnail(person_handle, photo)
media_list.sort(key=lambda x: self.rlocale.sort_key(x[0]))
# Create thumbnail preview page...
output_file, sio = self.report.create_file("thumbnails")
thumbnailpage, head, body = self.write_header(self._("Thumbnails"))
with Html("div", class_="content", id="Preview") as previewpage:
body += previewpage
msg = self._("This page displays a indexed list "
"of all the media objects "
"in this database. It is sorted by media title. "
"There is an index "
"of all the media objects in this database. "
"Clicking on a thumbnail "
"will take you to that image&#8217;s page.")
previewpage += Html("p", msg, id="description")
with Html("table", class_="calendar") as table:
previewpage += table
thead = Html("thead")
table += thead
# page title...
trow = Html("tr")
thead += trow
trow += Html("th", self._("Thumbnail Preview"),
class_="monthName", colspan=7, inline=True)
# table header cells...
trow = Html("tr")
thead += trow
ltrs = ["&nbsp;", "&nbsp;", "&nbsp;",
"&nbsp;", "&nbsp;", "&nbsp;", "&nbsp;"]
for ltr in ltrs:
trow += Html("th", ltr, class_="weekend", inline=True)
tbody = Html("tbody")
table += tbody
index, indexpos = 1, 0
num_of_images = len(media_list)
num_of_rows = ((num_of_images // 7) + 1)
num_of_cols = 7
grid_row = 0
while grid_row < num_of_rows:
trow = Html("tr", id="RowNumber: %08d" % grid_row)
tbody += trow
cols = 0
while cols < num_of_cols and indexpos < num_of_images:
ptitle = media_list[indexpos][0]
person_handle = media_list[indexpos][1]
photo = media_list[indexpos][2]
# begin table cell and attach to table row(trow)...
tcell = Html("td", class_="highlight weekend")
trow += tcell
# attach index number...
numberdiv = Html("div", class_="date")
tcell += numberdiv
# attach anchor name to date cell in upper right
# corner of grid...
numberdiv += Html("a", index, name=index, title=index,
inline=True)
# begin unordered list and
# attach to table cell(tcell)...
unordered = Html("ul")
tcell += unordered
# create thumbnail
(real_path,
newpath) = self.report.prepare_copy_media(photo)
newpath = self.report.build_url_fname(newpath)
list_html = Html("li")
unordered += list_html
# attach thumbnail to list...
list_html += self.thumb_hyper_image(newpath, "img",
person_handle,
ptitle)
index += 1
indexpos += 1
cols += 1
grid_row += 1
# if last row is incomplete, finish it off?
if grid_row == num_of_rows and cols < num_of_cols:
for emptycols in range(cols, num_of_cols):
trow += Html("td", class_="emptyDays", inline=True)
# begin Thumbnail Reference section...
with Html("div", class_="subsection", id="references") as section:
body += section
section += Html("h4", self._("References"), inline=True)
with Html("table", class_="infolist") as table:
section += table
tbody = Html("tbody")
table += tbody
index = 1
for ptitle, person_handle, photo in media_list:
trow = Html("tr")
tbody += trow
tcell1 = Html("td",
self.thumbnail_link(ptitle, index),
class_="ColumnRowLabel")
tcell2 = Html("td", ptitle, class_="ColumnName")
trow += (tcell1, tcell2)
# increase index for row number...
index += 1
# increase progress meter...
cb_progress()
# add body id element
body.attr = 'id ="ThumbnailPreview"'
# add footer section
# add clearline for proper styling
footer = self.write_footer(None)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(thumbnailpage, output_file, sio, 0)
def thumbnail_link(self, name, index):
"""
creates a hyperlink for Thumbnail Preview Reference...
"""
return Html("a", index, title=html_escape(name),
href="#%d" % index)
def thumb_hyper_image(self, thumbnail_url, subdir, fname, name):
"""
eplaces media_link() because it doesn't work for this instance
"""
name = html_escape(name)
url = "/".join(self.report.build_subdirs(subdir,
fname) + [fname]) + self.ext
with Html("div", class_="content", id="ThumbnailPreview") as section:
with Html("div", class_="snapshot") as snapshot:
section += snapshot
with Html("div", class_="thumbnail") as thumbnail:
snapshot += thumbnail
if not self.create_thumbs_only:
thumbnail_link = Html("a", href=url, title=name) + (
Html("img", src=thumbnail_url, alt=name)
)
else:
thumbnail_link = Html("img", src=thumbnail_url,
alt=name)
thumbnail += thumbnail_link
return section

View File

@ -34,13 +34,13 @@ plg.id = 'navwebpage'
plg.name = _("Narrated Web Site")
plg.description = _("Produces web (HTML) pages for individuals, or a set of "
"individuals")
plg.version = '1.0'
plg.version = '2.0'
plg.gramps_target_version = MODULE_VERSION
plg.status = STABLE
plg.fname = 'narrativeweb.py'
plg.ptype = REPORT
plg.authors = ["Donald N. Allingham", "Rob G. Healey"]
plg.authors_email = ["don@gramps-project.org", "robhealey1@gmail.com"]
plg.authors = ["Donald N. Allingham", "Rob G. Healey", "Serge Noiraud"]
plg.authors_email = ["don@gramps-project.org", "serge.noiraud@free.fr"]
plg.category = CATEGORY_WEB
plg.reportclass = 'NavWebReport'
plg.optionclass = 'NavWebOptions'