# -*- 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 # Copyright (C) 2007-2009 Gary Burton # Copyright (C) 2007-2009 Stephane Charette # Copyright (C) 2008-2009 Brian G. Matherly # Copyright (C) 2008 Jason M. Simanek # Copyright (C) 2008-2011 Rob G. Healey # Copyright (C) 2010 Doug Blank # Copyright (C) 2010 Jakim Friant # Copyright (C) 2010- Serge Noiraud # Copyright (C) 2011 Tim G L Lyons # Copyright (C) 2013 Benny Malengier # Copyright (C) 2016 Allen Crider # Copyright (C) 2018 Theo van Rijn # # 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: BasePage - super class for producing a web page. This class is instantiated once for each page. Provdes various common functions. """ #------------------------------------------------ # python modules #------------------------------------------------ from functools import partial import os import copy import datetime from decimal import getcontext #------------------------------------------------ # Set up logging #------------------------------------------------ import logging from gi.repository import Gdk #------------------------------------------------ # Gramps module #------------------------------------------------ from gramps.gen.const import GRAMPS_LOCALE as glocale from gramps.gen.lib import (FamilyRelType, NoteType, NameType, Person, UrlType, Name, PlaceType, EventRoleType, Source, Attribute, Media, Repository, Event, Family, Citation, Place, Date) from gramps.gen.lib.date import Today from gramps.gen.mime import is_image_type from gramps.gen.const import PROGRAM_NAME, URL_HOMEPAGE from gramps.version import VERSION from gramps.gen.plug.report import Bibliography from gramps.gen.plug.report import utils from gramps.gen.utils.config import get_researcher from gramps.gen.utils.string import conf_strings from gramps.gen.utils.file import media_path_full from gramps.gen.utils.thumbnails import get_thumbnail_path from gramps.gen.display.name import displayer as _nd from gramps.gen.display.place import displayer as _pd from gramps.plugins.lib.libhtmlconst import _CC from gramps.gen.utils.db import get_birth_or_fallback, get_death_or_fallback from gramps.gen.datehandler import parser as _dp from gramps.plugins.lib.libhtml import Html, xml_lang from gramps.plugins.lib.libhtmlbackend import HtmlBackend, process_spaces from gramps.gen.utils.place import conv_lat_lon from gramps.gen.utils.location import get_main_location from gramps.plugins.webreport.common import (_NAME_STYLE_DEFAULT, HTTP, HTTPS, add_birthdate, CSS, html_escape, _NARRATIVESCREEN, _NARRATIVEPRINT, FULLCLEAR, _has_webpage_extension) _ = glocale.translation.sgettext LOG = logging.getLogger(".NarrativeWeb") getcontext().prec = 8 TOGGLE = """ """ GOTOTOP = """ """ class BasePage: """ Manages all the functions, variables, and everything needed for all of the classes contained within this plugin """ def __init__(self, report, the_lang, the_title, gid=None): """ @param: report -- The instance of the main report class for this report @param: the_lang -- Is the lang to process @param: the_title -- Is the title of the web page @param: gid -- The family gramps ID """ self.uplink = False # class to do conversion of styled notes to html markup self._backend = HtmlBackend() self._backend.build_link = report.build_link self.report = report self.r_db = report.database self.r_user = report.user self.title_str = the_title self.gid = gid self.bibli = Bibliography() self.the_lang = the_lang self.the_title = the_title self.not_holiday = True self.page_title = "" self.author = get_researcher().get_name() if self.author: self.author = self.author.replace(',,,', '') # TODO. All of these attributes are not necessary, because we have # also the options in self.options. Besides, we need to check which # are still required. self.html_dir = report.options['target'] self.ext = report.options['ext'] self.noid = not report.options['inc_id'] self.inc_tags = report.options['inc_tags'] self.linkhome = report.options['linkhome'] self.create_media = report.options['gallery'] self.create_unused_media = report.options['unused'] self.create_thumbs_only = report.options['create_thumbs_only'] self.create_images_index = report.options['create_images_index'] self.create_thumbs_index = report.options['create_thumbs_index'] self.inc_families = report.options['inc_families'] self.inc_events = report.options['inc_events'] self.usecms = report.options['usecms'] self.prevnext = report.options['prevnext'] self.target_uri = report.options['cmsuri'] self.usecal = report.options['usecal'] self.extrapage = report.options['extrapage'] self.extrapagename = report.options['extrapagename'] self.familymappages = None self.reference_sort = report.options['reference_sort'] if the_lang: self.rlocale = report.set_locale(the_lang) else: self.rlocale = report.set_locale(report.options['trans']) self._ = self.rlocale.translation.sgettext self.colon = self._(':') # Translators: needed for French, else ignore if report.options['securesite']: self.secure_mode = HTTPS else: self.secure_mode = HTTP self.target_cal_uri = "cal/%s/index" % Today().get_year() # Functions used when no Web Page plugin is provided def add_instance(self, *param): """ Add an instance """ pass def display_pages(self, the_lang, the_title): """ Display the pages """ pass def sort_on_name_and_grampsid(self, handle): """ Used to sort on name and gramps ID. """ person = self.r_db.get_person_from_handle(handle) name = _nd.display(person) return (name, person.get_gramps_id()) def sort_on_given_and_birth(self, handle): """ Used to sort on given name and birth date. """ person = self.r_db.get_person_from_handle(handle) name = _nd.display_given(person) bd_event = get_birth_or_fallback(self.r_db, person) birth = "" if bd_event: birth_iso = str(bd_event.get_date_object()).replace('abt ', '') # we need to remove abt, bef, aft, ... birth = birth_iso.replace('aft ', '').replace('bef ', '') return (name, birth) def sort_on_grampsid(self, event_ref): """ Sort on gramps ID """ evt = self.r_db.get_event_from_handle( event_ref.ref) return evt.get_gramps_id() def copy_thumbnail(self, handle, photo, region=None): """ Given a handle (and optional region) make (if needed) an up-to-date cache of a thumbnail, and call report.copy_file to copy the cached thumbnail to the website. Return the new path to the image. @param: handle -- The handle for this thumbnail @param: photo -- The image related to this thumbnail @param: region -- The image region to associate """ to_dir = self.report.build_path('thumb', handle) to_path = os.path.join(to_dir, handle) + ( ('%d,%d-%d,%d.png' % region) if region else '.png' ) if photo.get_mime_type(): full_path = media_path_full(self.r_db, photo.get_path()) from_path = get_thumbnail_path(full_path, photo.get_mime_type(), region) if not os.path.isfile(from_path): from_path = CSS["Document"]["filename"] else: from_path = CSS["Document"]["filename"] if (self.the_lang is None or self.the_lang == self.report.languages[0][0]): # if multi languages, copy the thumbnail only for the first lang. self.report.copy_file(from_path, to_path) return to_path def get_nav_menu_hyperlink(self, url_fname, nav_text, cal=0): """ Returns the navigation menu hyperlink """ uplink = self.uplink sub_cal = cal if cal > 0 else 1 # check for web page file extension? if not _has_webpage_extension(url_fname): url_fname += self.ext # get menu item url and begin hyperlink... if self.usecms: if self.the_lang: url_name = "/".join([self.target_uri, self.the_lang, url_fname]) else: url_name = "/".join([self.target_uri, url_fname]) else: if cal > 0: url_fname = "/".join(([".."]*sub_cal + [url_fname])) url_name = self.report.build_url_fname(url_fname, None, uplink) return Html("a", nav_text, href=url_name, title=nav_text, inline=True) def get_column_data(self, unordered, data_list, column_title): """ Returns the menu column for Drop Down Menus and Drop Down Citations """ if not data_list: return elif len(data_list) == 1: url_fname, nav_text = data_list[0][0], data_list[0][1] hyper = self.get_nav_menu_hyperlink(url_fname, nav_text) unordered.extend( Html("li", hyper, inline=True) ) else: col_list = Html("li") + ( Html("a", column_title, href="#", title=column_title, inline=True) ) unordered += col_list unordered1 = Html("ul") col_list += unordered1 for url_fname, nav_text in data_list: hyper = self.get_nav_menu_hyperlink(url_fname, nav_text) unordered1.extend(Html("li", hyper, inline=True)) def display_relationships(self, individual, place_lat_long): """ Displays a person's relationships ... @param: family_handle_list -- families in this report database @param: place_lat_long -- for use in Family Map Pages. This will be None if called from Family pages, which do not create a Family Map """ family_list = individual.get_family_handle_list() if not family_list: return None with Html("div", class_="subsection", id="families") as section: with self.create_toggle("families") as h4_head: section += h4_head h4_head += self._("Families") table_class = "infolist" if len(family_list) > 1: table_class += " fixed_subtables" disp = "none" if self.report.options['toggle'] else "block" with Html("table", class_=table_class, id="toggle_families", style="display:%s" % disp) as table: section += table for family_handle in family_list: family = self.r_db.get_family_from_handle(family_handle) if family: fam_name = self.report.get_family_name(family) link = self.family_link(family_handle, fam_name, gid=family.get_gramps_id(), uplink=True) link1 = Html("H4", link, class_="subsection") trow = Html("tr", class_="BeginFamily") + ( Html("td", link1, class_="ColumnValue", colspan=3, inline=True) ) table += trow # find the spouse of the principal individual and # display that person sp_hdl = utils.find_spouse(individual, family) if sp_hdl: spouse = self.r_db.get_person_from_handle(sp_hdl) if spouse: table += self.display_spouse(spouse, family, place_lat_long) details = self.display_family_details(family, place_lat_long) if details is not None: table += details return section def display_family_relationships(self, family, place_lat_long): """ Displays a family's relationships ... @param: family -- the family to be displayed @param: place_lat_long -- for use in Family Map Pages. This will be None if called from Family pages, which do not create a Family Map """ with Html("div", class_="subsection", id="families") as section: section += Html("h4", self._("Families"), inline=True) table_class = "infolist" with Html("table", class_=table_class) as table: section += table for person_hdl in [family.get_father_handle(), family.get_mother_handle()]: person = None if person_hdl: person = self.r_db.get_person_from_handle(person_hdl) if person: table += self.display_spouse(person, family, place_lat_long) details = self.display_family_details(family, place_lat_long) if details is not None: table += details return section def display_family_details(self, family, place_lat_long): """ Display details about one family: family events, children, family LDS ordinances, family attributes @param: family -- The family @param: place_lat_long -- For use in Family Map Pages. This will be None if called from Family pages, which do not create a Family Map """ table = None birthorder = self.report.options["birthorder"] # display family events; such as marriage and divorce... family_events = family.get_event_ref_list() if family_events: trow = Html("tr") + ( Html("td", " ", class_="ColumnType", inline=True), Html("td", self.format_family_events(family_events, place_lat_long), class_="ColumnValue", colspan=2) ) table = trow # If the families pages are not output, display family notes if not self.inc_families: notelist = family.get_note_list() for notehandle in notelist: note = self.r_db.get_note_from_handle(notehandle) if note: trow = Html("tr") + ( Html("td", " ", class_="ColumnType", inline=True), Html("td", self._("Narrative"), class_="ColumnAttribute", inline=True), Html("td", self.get_note_format(note, True), class_="ColumnValue") ) table = table + trow if table is not None else trow childlist = family.get_child_ref_list() if childlist: trow = Html("tr") + ( Html("td", self._("Children"), class_="ColumnAttribute", inline=True) ) table = table + trow if table is not None else trow tcell = Html("td", class_="ColumnValue Child", close=False, colspan=2) trow += tcell with Html("table", class_="infolist eventlist") as table2: thead = Html("thead") table2 += thead header = Html("tr") header.extend( Html("th", label, class_=colclass, inline=True) for (label, colclass) in [ [self._("Name"), "ColumnName"], [self._("Birth Date"), "ColumnDate"], [self._("Death Date"), "ColumnDate"], ] ) thead += header # begin table body tbody = Html("tbody") table2 += tbody childlist = [child_ref.ref for child_ref in childlist] # add individual's children event places to family map... if self.familymappages: for handle in childlist: child = self.r_db.get_person_from_handle(handle) if child: self._get_event_place(child, place_lat_long) children = add_birthdate(self.r_db, childlist, self.rlocale) if birthorder: children = sorted(children) tbody.extend((Html("tr", inline=True) + Html("td", inline=True, close=False) + self.display_child_link(chandle) + Html("td", birth, inline=True) + Html("td", death, inline=True)) for birth_date, birth, death, chandle in children ) trow += table2 # family LDS ordinance list family_lds_ordinance_list = family.get_lds_ord_list() if family_lds_ordinance_list: trow = Html("tr") + ( Html("td", " ", class_="ColumnType", inline=True), Html("td", self._("LDS Ordinance"), class_="ColumnAttribute", inline=True), Html("td", self.dump_ordinance(family, "Family", toggle=False), class_="ColumnValue") ) table = table + trow if table is not None else trow # Family Attribute list family_attribute_list = family.get_attribute_list() if family_attribute_list: trow = Html("tr") + ( Html("td", " ", class_="ColumnType", inline=True), Html("td", self._("Attributes"), class_="ColumnAttribute", inline=True) ) table = table + trow if table is not None else trow tcell = Html("td", class_="ColumnValue") trow += tcell # we do not need the section variable for this instance # of Attributes... dummy, attrtable = self.display_attribute_header(toggle=False) tcell += attrtable self.display_attr_list(family_attribute_list, attrtable) return table def complete_people(self, tcell, first_person, handle_list, uplink=True): """ completes the person column for classes EventListPage and EventPage @param: tcell -- table cell from its caller @param: first_person -- Not used any more, done via css @param: handle_list -- handle list from the backlink of the event_handle @param: uplink -- If True, then "../../../" is inserted in front of the result. """ dummy_first_person = first_person for (classname, handle) in handle_list: # personal event if classname == "Person": tcell += Html("span", self.new_person_link(handle, uplink), class_="person", inline=True) # family event else: _obj = self.r_db.get_family_from_handle(handle) if _obj: # husband and spouse in this example, # are called father and mother husband_handle = _obj.get_father_handle() if husband_handle: hlink = self.new_person_link(husband_handle, uplink) spouse_handle = _obj.get_mother_handle() if spouse_handle: slink = self.new_person_link(spouse_handle, uplink) if spouse_handle and husband_handle: tcell += Html("span", hlink, class_="father", inline=True) tcell += Html("span", slink, class_="mother", inline=True) elif spouse_handle: tcell += Html("span", slink, class_="mother", inline=True) elif husband_handle: tcell += Html("span", hlink, class_="father", inline=True) return tcell def dump_attribute(self, attr): """ dump attribute for object presented in display_attr_list() @param: attr = attribute object """ trow = Html("tr") trow.extend( Html("td", data or " ", class_=colclass, inline=True if (colclass == "Type" or "Sources") else False) for (data, colclass) in [ (str(attr.get_type()), "ColumnType"), (attr.get_value(), "ColumnValue"), (self.dump_notes(attr.get_note_list(), Attribute), "ColumnNotes"), (self.get_citation_links(attr.get_citation_list()), "ColumnSources") ] ) return trow def get_citation_links(self, citation_handle_list): """ get citation link from the citation handle list @param: citation_handle_list = list of gen/lib/Citation """ text = "" for citation_handle in citation_handle_list: citation = self.r_db.get_citation_from_handle(citation_handle) if citation: index, key = self.bibli.add_reference(citation) id_ = "%d%s" % (index+1, key) text += ' %s' % (id_, id_) return text def get_note_format(self, note, uplink): """ will get the note from the database, and will return either the styled text or plain note @param: note -- the note to process @param: uplink -- If True, then "../../../" is inserted in front of the result. """ self.report.link_prefix_up = uplink text = "" if note is not None: # retrieve the body of the note note_text = note.get() # styled notes htmlnotetext = self.styled_note( note.get_styledtext(), note.get_format(), contains_html=(note.get_type() == NoteType.HTML_CODE)) text = htmlnotetext or Html("p", note_text) # return text of the note to its callers return text def styled_note(self, styledtext, styled_format, contains_html=False): """ @param: styledtext -- assumed a StyledText object to write @param: styled_format -- = 0 : Flowed, = 1 : Preformatted @param: style_name -- name of the style to use for default presentation """ text = str(styledtext) if not text: return '' s_tags = styledtext.get_tags() htmllist = Html("div", class_="grampsstylednote") if contains_html: markuptext = self._backend.add_markup_from_styled(text, s_tags, split='\n', escape=False) htmllist += markuptext else: markuptext = self._backend.add_markup_from_styled(text, s_tags, split='\n') linelist = [] linenb = 1 for line in markuptext.split('\n'): [line, sigcount] = process_spaces(line, styled_format) if sigcount == 0: # The rendering of an empty paragraph '

' # is undefined so we use a non-breaking space if linenb == 1: linelist.append(' ') htmllist.extend(Html('p') + linelist) linelist = [] linenb = 1 else: if linenb > 1: linelist[-1] += '
' linelist.append(line) linenb += 1 if linenb > 1: htmllist.extend(Html('p') + linelist) # if the last line was blank, then as well as outputting # the previous para, which we have just done, # we also output a new blank para if sigcount == 0: linelist = [" "] htmllist.extend(Html('p') + linelist) return htmllist def show_tags(self, obj): """ Show all tags associated to an object (Person, Family, Media,...) @param: obj -- the object for which we show tags """ tags_text = "" if obj is None: return tags_text tags = [] for tag_handle in obj.get_tag_list(): tags.append(self.r_db.get_tag_from_handle(tag_handle)) if tags and self.report.inc_tags: for tag in tags: if tags_text: tags_text += ", " # convert tag color to html format: #RRGGBB rgba = Gdk.RGBA() rgba.parse(tag.get_color()) color = '#%02x%02x%02x' % (int(rgba.red * 255), int(rgba.green * 255), int(rgba.blue * 255)) tags_text += ("" "%s" % (color, self._(tag.get_name()))) return tags_text def dump_notes(self, notelist, parent=None): """ dump out of list of notes with very little elements of its own @param: notelist -- list of notes @param: parent -- The parent object (Person, Family, Media,...) """ if not notelist: return Html("div") # begin unordered list notesection = Html("div") idx = 0 for notehandle in notelist: this_note = self.r_db.get_note_from_handle(notehandle) title = self._(this_note.type.xml_str()) if this_note is not None: idx += 1 if len(notelist) > 1: if (self.default_note(parent, int(this_note.type)) or int(this_note.type) == NoteType.HTML_CODE): title_text = self._("Note: %s") % str(idx) else: title = " (" + title + ")" title_text = self._("Note: %s") % str(idx) + title else: if (self.default_note(parent, int(this_note.type)) or int(this_note.type) == NoteType.HTML_CODE): title_text = self._("Note") else: title_text = title # Tags if parent: tags = self.show_tags(this_note) if tags and self.report.inc_tags: title_text += " (" + tags + ")" notesection.extend(Html("i", title_text, class_="NoteType")) notesection.extend(self.get_note_format(this_note, True)) return notesection def event_header_row(self): """ creates the event header row for all events """ trow = Html("tr", close=None) trow.extend( Html("th", trans, class_=colclass, inline=True) for trans, colclass in [ (self._("Event"), "ColumnEvent"), (self._("Date"), "ColumnDate"), (self._("Place"), "ColumnPlace"), (self._("Description"), "ColumnDescription"), (self._("Sources"), "ColumnSources")] ) trow += Html("/tr", close=None) return trow def display_event_row(self, event, event_ref, place_lat_long, uplink, hyperlink, omit): """ display the event row for IndividualPage @param: evt -- Event object from report database @param: evt_ref -- Event reference @param: place_lat_long -- For use in Family Map Pages. This will be None if called from Family pages, which do not create a Family Map @param: uplink -- If True, then "../../../" is inserted in front of the result. @param: hyperlink -- Add a hyperlink or not @param: omit -- Role to be omitted in output """ event_gid = event.get_gramps_id() place_handle = event.get_place_handle() if place_handle: place = self.r_db.get_place_from_handle(place_handle) if place: self.append_to_place_lat_long(place, event, place_lat_long) # begin event table row trow = Html("tr") # get event type and hyperlink to it or not? etype = self._(event.get_type().xml_str()) event_role = event_ref.get_role() if not event_role == omit: etype += " (%s)" % event_role event_hyper = self.event_link(event_ref.ref, etype, event_gid, uplink) if hyperlink else etype trow += Html("td", event_hyper, class_="ColumnEvent", rowspan=2) # get event data event_data = self.get_event_data(event, event_ref, uplink) trow.extend( Html("td", data or " ", class_=colclass, inline=(not data or colclass == "ColumnDate")) for (label, colclass, data) in event_data ) trow2 = Html("tr") # get event source references srcrefs = self.get_citation_links(event.get_citation_list()) or " " trow += Html("td", srcrefs, class_="ColumnSources", rowspan=2) # get event notes notelist = event_ref.get_note_list() notelist.extend(event.get_note_list()[:]) # we don't want to modify # cached original htmllist = self.dump_notes(notelist, Event) # if the event or event reference has an attribute attached to it, # get the text and format it correctly? attrlist = event.get_attribute_list()[:] # we don't want to modify # cached original attrlist.extend(event_ref.get_attribute_list()) for attr in attrlist: htmllist.extend(Html("p", self._("%(str1)s: %(str2)s") % { 'str1' : Html("b", attr.get_type()), 'str2' : attr.get_value() })) #also output notes attached to the attributes notelist = attr.get_note_list() if notelist: htmllist.extend(self.dump_notes(notelist, Event)) trow2 += Html("td", htmllist, class_="ColumnNotes", colspan=3) trow += trow2 # return events table row to its callers return trow def append_to_place_lat_long(self, place, event, place_lat_long): """ Create a list of places with coordinates. @param: place_lat_long -- for use in Family Map Pages. This will be None if called from Family pages, which do not create a Family Map """ if place_lat_long is None: return place_handle = place.get_handle() event_date = event.get_date_object() # 0 = latitude, 1 = longitude, 2 - placetitle, # 3 = place handle, 4 = event found = any(data[3] == place_handle and data[4] == event_date for data in place_lat_long) if not found: placetitle = _pd.display(self.r_db, place) latitude = place.get_latitude() longitude = place.get_longitude() if latitude and longitude: latitude, longitude = conv_lat_lon(latitude, longitude, "D.D8") if latitude is not None: place_lat_long.append([latitude, longitude, placetitle, place_handle, event]) def _get_event_place(self, person, place_lat_long): """ Retrieve from a person their events, and places for family map @param: person -- Person object from the database @param: place_lat_long -- For use in Family Map Pages. This will be None if called from Family pages, which do not create a Family Map """ if not person: return # check to see if this person is in the report database? use_link = self.report.person_in_webreport(person.get_handle()) if use_link: evt_ref_list = person.get_event_ref_list() if evt_ref_list: for evt_ref in evt_ref_list: event = self.r_db.get_event_from_handle(evt_ref.ref) if event: pl_handle = event.get_place_handle() if pl_handle: place = self.r_db.get_place_from_handle(pl_handle) if place: self.append_to_place_lat_long(place, event, place_lat_long) def family_link(self, family_handle, name, gid=None, uplink=False): """ Create the url and link for FamilyPage @param: family_handle -- The handle for the family to link @param: name -- The family name @param: gid -- The family gramps ID @param: uplink -- If True, then "../../../" is inserted in front of the result. """ name = html_escape(name) if not self.noid and gid: gid_html = Html("span", " [%s]" % gid, class_="grampsid", inline=True) else: gid_html = "" result = self.report.obj_dict.get(Family).get(family_handle) if result is None: # the family is not included in the webreport return name + str(gid_html) url = self.report.build_url_fname(result[0], uplink=uplink) hyper = Html("a", name, href=url, title=name) hyper += gid_html return hyper def event_link(self, event_handle, event_title, gid=None, uplink=False): """ Creates a hyperlink for an event based on its type @param: event_handle -- Event handle @param: event_title -- Event title @param: gid -- The gramps ID for the event @param: uplink -- If True, then "../../../" is inserted in front of the result. """ if not self.inc_events: return event_title url = self.report.build_url_fname_html(event_handle, "evt", uplink) hyper = Html("a", event_title, href=url, title=event_title) if not self.noid and gid: hyper += Html("span", " [%s]" % gid, class_="grampsid", inline=True) return hyper def format_family_events(self, event_ref_list, place_lat_long): """ displays the event row for events such as marriage and divorce @param: event_ref_list -- List of events reference @param: place_lat_long -- For use in Family Map Pages. This will be None if called from Family pages, which do not create a Family Map """ with Html("table", class_="infolist eventlist") as table: thead = Html("thead") table += thead # attach event header row thead += self.event_header_row() # begin table body tbody = Html("tbody") table += tbody for evt_ref in event_ref_list: event = self.r_db.get_event_from_handle(evt_ref.ref) # add event body row tbody += self.display_event_row(event, evt_ref, place_lat_long, uplink=True, hyperlink=True, omit=EventRoleType.FAMILY) return table def get_event_data(self, evt, evt_ref, uplink, gid=None): """ retrieve event data from event and evt_ref @param: evt -- Event from database @param: evt_ref -- Event reference @param: uplink -- If True, then "../../../" is inserted in front of the result. """ dummy_evt_ref = evt_ref dummy_gid = gid place = None place_handle = evt.get_place_handle() if place_handle: place = self.r_db.get_place_from_handle(place_handle) place_hyper = None if place: place_name = _pd.display(self.r_db, place, evt.get_date_object()) place_hyper = self.place_link(place_handle, place_name, uplink=uplink) evt_desc = evt.get_description() # wrap it all up and return to its callers # position 0 = translatable label, position 1 = column class # position 2 = data return [(self._("Date"), "ColumnDate", self.rlocale.get_date(evt.get_date_object())), (self._("Place"), "ColumnPlace", place_hyper), (self._("Description"), "ColumnDescription", evt_desc)] def dump_ordinance(self, ldsobj, ldssealedtype, toggle=True): """ will dump the LDS Ordinance information for either a person or a family ... @param: ldsobj -- Either person or family @param: ldssealedtype -- Either Sealed to Family or Spouse """ dummy_ldssealedtype = ldssealedtype objectldsord = ldsobj.get_lds_ord_list() if not objectldsord: return None if toggle: disp = "none" if self.report.options['toggle'] else "block" ordin = Html("table", class_="infolist ldsordlist", id="toggle_lds", style="display:%s" % disp) else: ordin = Html("table", class_="infolist ldsordlist") # begin LDS ordinance table and table head with ordin as table: thead = Html("thead") table += thead # begin HTML row trow = Html("tr") thead += trow trow.extend( Html("th", label, class_=colclass, inline=True) for (label, colclass) in [ [self._("Type"), "ColumnLDSType"], [self._("Date"), "ColumnDate"], [self._("Temple"), "ColumnLDSTemple"], [self._("Place"), "ColumnLDSPlace"], [self._("Status"), "ColumnLDSStatus"], [self._("Sources"), "ColumnLDSSources"] ] ) # start table body tbody = Html("tbody") table += tbody for ordobj in objectldsord: place_hyper = " " place_handle = ordobj.get_place_handle() if place_handle: place = self.r_db.get_place_from_handle(place_handle) if place: place_title = _pd.display(self.r_db, place) place_hyper = self.place_link( place_handle, place_title, place.get_gramps_id(), uplink=True) # begin ordinance rows trow = Html("tr") trow.extend( Html("td", value or " ", class_=colclass, inline=(not value or colclass == "ColumnDate")) for (value, colclass) in [ (ordobj.type2xml(), "ColumnType"), (self.rlocale.get_date(ordobj.get_date_object()), "ColumnDate"), (ordobj.get_temple(), "ColumnLDSTemple"), (place_hyper, "ColumnLDSPlace"), (ordobj.get_status(), "ColumnLDSStatus"), (self.get_citation_links(ordobj.get_citation_list()), "ColumnSources") ] ) tbody += trow return table def write_srcattr(self, srcattr_list): """ Writes out the srcattr for the different objects @param: srcattr_list -- List of source attributes """ if not srcattr_list: return None # begin data map division and section title... with Html("div", class_="subsection", id="data_map") as section: with self.create_toggle("srcattr") as h4_head: section += h4_head h4_head += self._("Attributes") disp = "none" if self.report.options['toggle'] else "block" with Html("table", class_="infolist", id="toggle_srcattr", style="display:%s" % disp) as table: section += table thead = Html("thead") table += thead trow = Html("tr") + ( Html("th", self._("Key"), class_="ColumnAttribute", inline=True), Html("th", self._("Value"), class_="ColumnValue", inline=True) ) thead += trow tbody = Html("tbody") table += tbody for srcattr in srcattr_list: trow = Html("tr") + ( Html("td", str(srcattr.get_type()), class_="ColumnAttribute", inline=True), Html("td", srcattr.get_value(), class_="ColumnValue", inline=True) ) tbody += trow return section def source_link(self, source_handle, source_title, gid=None, cindex=None, uplink=False): """ Creates a link to the source object @param: source_handle -- Source handle from database @param: source_title -- Title from the source object @param: gid -- Source gramps id from the source object @param: cindex -- Count index @param: uplink -- If True, then "../../../" is inserted in front of the result. """ url = self.report.build_url_fname_html(source_handle, "src", uplink) hyper = Html("a", source_title, href=url, title=source_title) # if not None, add name reference to hyperlink element if cindex: hyper.attr += ' name ="sref%d"' % cindex # add Gramps ID if not self.noid and gid: hyper += Html("span", ' [%s]' % gid, class_="grampsid", inline=True) return hyper def display_addr_list(self, addrlist, showsrc): """ Display a person's or repository's addresses ... @param: addrlist -- a list of address handles @param: showsrc -- True = show sources False = do not show sources None = djpe """ if not addrlist: return None # begin addresses division and title with Html("div", class_="subsection", id="Addresses") as section: with self.create_toggle("addr") as h4_head: section += h4_head h4_head += self._("Addresses") # write out addresses() section += self.dump_addresses(addrlist, showsrc) # return address division to its caller return section def dump_addresses(self, addrlist, showsrc): """ will display an object's addresses, url list, note list, and source references. @param: addrlist = either person or repository address list @param: showsrc = True -- person and their sources False -- repository with no sources None -- Address Book address with sources """ if not addrlist: return None # begin summaryarea division disp = "none" if self.report.options['toggle'] else "block" with Html("div", class_="AddressTable", id="toggle_addr", style="display:%s" % disp) as summaryarea: # begin address table with Html("table") as table: summaryarea += table # get table class based on showsrc if showsrc is True: table.attr = 'class = "infolist addrlist"' elif showsrc is False: table.attr = 'class = "infolist repolist"' else: table.attr = 'class = "infolist addressbook"' # begin table head thead = Html("thead") table += thead trow = Html("tr") thead += trow addr_header = [[self._("Date"), "Date"], [self._("Street"), "StreetAddress"], [self._("Locality"), "Locality"], [self._("City"), "City"], [self._("State/ Province"), "State"], [self._("County"), "County"], [self._("Postal Code"), "Postalcode"], [self._("Country"), "Cntry"], [self._("Phone"), "Phone"]] # True, False, or None ** see docstring for explanation if showsrc in [True, None]: addr_header.append([self._("Sources"), "Sources"]) trow.extend( Html("th", self._(label), class_="Colummn" + colclass, inline=True) for (label, colclass) in addr_header ) # begin table body tbody = Html("tbody") table += tbody # get address list from an object; either repository or person for address in addrlist: trow = Html("tr") tbody += trow addr_data_row = [ (self.rlocale.get_date(address.get_date_object()), "ColumnDate"), (address.get_street(), "ColumnStreetAddress"), (address.get_locality(), "ColumnLocality"), (address.get_city(), "ColumnCity"), (address.get_state(), "ColumnState"), (address.get_county(), "ColumnCounty"), (address.get_postal_code(), "ColumnPostalCode"), (address.get_country(), "ColumnCntry"), (address.get_phone(), "ColumnPhone") ] # get source citation list if showsrc in [True, None]: addr_data_row.append( [self.get_citation_links( address.get_citation_list()), "ColumnSources"]) trow.extend( Html("td", value or " ", class_=colclass, inline=True) for (value, colclass) in addr_data_row ) # address: notelist if showsrc is not None: notelist = self.display_note_list( address.get_note_list(), toggle=False) if notelist is not None: summaryarea += notelist return summaryarea def addressbook_link(self, person_handle, uplink=False): """ Creates a hyperlink for an address book link based on person's handle @param: person_handle -- Person's handle from the database @param: uplink -- If True, then "../../../" is inserted in front of the result. """ url = self.report.build_url_fname_html(person_handle, "addr", uplink) person = self.r_db.get_person_from_handle(person_handle) person_name = self.get_name(person) # return addressbook hyperlink to its caller return Html("a", person_name, href=url, title=html_escape(person_name)) def get_name(self, person, maiden_name=None): """ I5118 Return person's name, unless maiden_name given, unless married_name listed. @param: person -- person object from database @param: maiden_name -- Female's family surname """ # get name format for displaying names name_format = self.report.options['name_format'] # Get all of a person's names primary_name = person.get_primary_name() married_name = None names = [primary_name] + person.get_alternate_names() for name in names: if int(name.get_type()) == NameType.MARRIED: married_name = name break # use first # Now, decide which to use: if maiden_name is not None: if married_name is not None: name = Name(married_name) else: name = Name(primary_name) surname_obj = name.get_primary_surname() surname_obj.set_surname(maiden_name) else: name = Name(primary_name) name.set_display_as(name_format) return _nd.display_name(name) def display_attribute_header(self, toggle=True): """ Display the attribute section and its table header """ # begin attributes division and section title if toggle: with Html("div", class_="subsection", id="attributes") as section: with self.create_toggle("attr") as h4_head: section += h4_head h4_head += self._("Attributes") disp = "none" if self.report.options['toggle'] else "block" head = Html("table", class_="infolist attrlist", id="toggle_attr", style="display:%s" % disp) else: section = Html("h4", self._("Attributes"), inline=True) head = Html("table", class_="infolist attrlist") # begin attributes table with head as attrtable: section += attrtable thead = Html("thead") attrtable += thead trow = Html("tr") thead += trow trow.extend( Html("th", label, class_=colclass, inline=True) for (label, colclass) in [ (self._("Type"), "ColumnType"), (self._("Value"), "ColumnValue"), (self._("Notes"), "ColumnNotes"), (self._("Sources"), "ColumnSources")] ) return section, attrtable def display_attr_list(self, attrlist, attrtable): """ Will display a list of attributes @param: attrlist -- a list of attributes @param: attrtable -- the table element that is being added to """ tbody = Html("tbody") attrtable += tbody tbody.extend( self.dump_attribute(attr) for attr in attrlist ) def write_footer(self, date, cal=0): """ Will create and display the footer section of each page... @param: bottom -- whether to specify location of footer section or not? """ # begin footer division with Html("div", id="footer") as footer: footer_note = self.report.options['footernote'] if footer_note: note = self.get_note_format( self.r_db.get_note_from_gramps_id(footer_note), False ) user_footer = Html("div", id='user_footer') footer += user_footer # attach note user_footer += note msg = self._('Generated by %(gramps_home_html_start)s' 'Gramps%(html_end)s %(version)s' ) % {'gramps_home_html_start' : '', 'html_end' : '', 'version' : VERSION} if date is not None and date > 0: msg += "
" last_modif = datetime.datetime.fromtimestamp(date).strftime( '%Y-%m-%d %H:%M:%S') msg += self._('Last change was the %(date)s') % {'date' : last_modif} else: dat_txt = self._(' on %(date)s') msg += dat_txt % {'date' : self.rlocale.get_date(Today())} origin1 = self.report.filter.get_name(self.rlocale) filt_number = self.report.options['filter'] # optional "link-home" feature; see bug report #2736 if self.report.options['linkhome']: center_person = self.r_db.get_person_from_gramps_id( self.report.options['pid']) if (center_person and self.report.person_in_webreport(center_person.handle)): if cal > 0 and not self.usecms: prfx = "/".join(([".."]*2 + ["ppl"])) else: prfx = "ppl" center_person_url = self.report.build_url_fname_html( center_person.handle, prfx, uplink=False) #person_name = self.get_name(center_person) if filt_number > 0 and filt_number < 5: subject_url = '' subject_url += origin1 + '' else: subject_url = origin1 msg += self._( '%(http_break)sCreated for %(subject_url)s') % { 'http_break' : '
', 'subject_url' : subject_url} else: msg += self._( '%(http_break)sCreated for %(subject_url)s') % { 'http_break' : '
', 'subject_url' : origin1} # creation author footer += Html("p", msg, id='createdate') # get copyright license for all pages copy_nr = self.report.copyright text = '' if copy_nr == 0: if self.author: year = Today().get_year() text = '© %(year)d %(person)s' % { 'person' : self.author, 'year' : year} elif copy_nr < len(_CC): # Note. This is a URL sub_cal = cal + 1 if cal > 0 else 1 if self.usecms: fname = "/".join(["images", "somerights20.gif"]) elif self.the_lang: fname = "/".join(([".."]*sub_cal + ['images', 'somerights20.gif'])) else: fname = "/".join(['images', "somerights20.gif"]) url = self.report.build_url_fname(fname, None, self.uplink, image=True) text = _CC[copy_nr] % {'gif_fname' : url} footer += Html("p", text, id='copyright') # return footer to its callers return footer def write_header(self, the_title, cal=0): """ Note. 'title' is used as currentsection in the navigation links and as part of the header title. @param: title -- Is the title of the web page @param: cal -- The number of directories to use """ # If .php extension and a note selected, add it to the head section. phpnote = self.report.options['phpnote'] note = None if phpnote and self.ext == ".php": # This is used to give the ability to have a php init session. # This note must not contains formatting # and should only contains php code. ie: # note = self.r_db.get_note_from_gramps_id(phpnote).get() # begin each html page... if self.the_lang: xmllang = self.the_lang.replace('_', '-') else: xmllang = xml_lang() page, head, body = Html.page('%s - %s' % (html_escape(self.title_str.strip()), html_escape(the_title)), self.report.encoding, xmllang, cms=self.usecms, php_session=note) # temporary fix for .php parsing error if self.ext in [".php", ".cgi"]: del page[0] # remove the "DOCTYPE" directive # Header constants _meta1 = 'name ="viewport" content="width=device-width, ' _meta1 += 'height=device-height, initial-scale=1.0, ' _meta1 += 'minimum-scale=0.5, maximum-scale=10.0, user-scalable=yes"' _meta2 = 'name ="apple-mobile-web-app-capable" content="yes"' _meta3 = 'name="generator" content="%s %s %s"' % ( PROGRAM_NAME, VERSION, URL_HOMEPAGE) _meta4 = 'name="author" content="%s"' % self.author # create additional meta tags meta = Html("meta", attr=_meta1) + ( Html("meta", attr=_meta2, indent=False), Html("meta", attr=_meta3, indent=False), Html("meta", attr=_meta4, indent=False) ) # Link to _NARRATIVESCREEN stylesheet sub_cal = cal + 1 if cal > 0 else 1 if self.usecms: fname = "/".join(["css", _NARRATIVESCREEN]) elif self.the_lang: fname = "/".join(([".."]*sub_cal + ["css", _NARRATIVESCREEN])) elif cal > 0: fname = "/".join(([".."]*cal + ["css", _NARRATIVESCREEN])) else: fname = "/".join(["css", _NARRATIVESCREEN]) url2 = self.report.build_url_fname(fname, None, self.uplink) # Link to _NARRATIVEPRINT stylesheet if self.usecms: fname = "/".join(["css", _NARRATIVEPRINT]) elif self.the_lang: fname = "/".join(([".."]*sub_cal + ["css", _NARRATIVEPRINT])) elif cal > 0: fname = "/".join(([".."]*cal + ["css", _NARRATIVEPRINT])) else: fname = "/".join(["css", _NARRATIVEPRINT]) url3 = self.report.build_url_fname(fname, None, self.uplink) # Link to Gramps favicon if self.usecms: fname = "/".join(["images", "favicon2.ico"]) elif self.the_lang: fname = "/".join(([".."]*sub_cal + ['images', 'favicon2.ico'])) elif cal > 0: fname = "/".join(([".."]*cal + ["images", "favicon2.ico"])) else: fname = "/".join(['images', 'favicon2.ico']) url4 = self.report.build_url_fname(fname, None, self.uplink, image=True) # create stylesheet and favicon links links = Html("link", type="image/x-icon", href=url4, rel="shortcut icon") # attach the ancestortree style sheet if ancestor # graph is being created? if self.report.options["ancestortree"]: if self.usecms: fname = "/".join(["css", "ancestortree.css"]) elif self.the_lang: fname = "/".join(([".."]*sub_cal + ["css", "ancestortree.css"])) elif cal > 0: fname = "/".join(([".."]*cal + ["css", "ancestortree.css"])) else: fname = "/".join(["css", "ancestortree.css"]) url5 = self.report.build_url_fname(fname, None, self.uplink) links += Html("link", type="text/css", href=url5, media="screen", rel="stylesheet", indent=False) links += Html("link", type="text/css", href=url3, media='print', rel="stylesheet", indent=False) links += Html("link", type="text/css", href=url2, media="screen", rel="stylesheet", indent=False) # create all alternate stylesheets # Cannot use it on local files (file://) for css_f in CSS: already_done = [] for css_fn in ("UsEr_", "Basic", "Mainz", "Nebraska"): if css_fn in css_f and css_f not in already_done: css_f = css_f.replace("UsEr_", "") already_done.append(css_f) if self.usecms: fname = "/".join(["css", css_f + ".css"]) elif self.the_lang: fname = "/".join(([".."]*sub_cal + ["css", css_f + ".css"])) elif cal > 0: fname = "/".join(([".."]*cal + ["css", css_f + ".css"])) else: fname = "/".join(["css", css_f + ".css"]) urlx = self.report.build_url_fname(fname, None, self.uplink) links += Html("link", rel="alternate stylesheet", title=self._(css_f), indent=False, media="screen", type="text/css", href=urlx) # Link to Navigation Menus stylesheet if CSS[self.report.css]["navigation"]: if self.the_lang and not self.usecms: fname = "/".join(["..", "css", "narrative-menus.css"]) else: fname = "/".join(["css", "narrative-menus.css"]) url = self.report.build_url_fname(fname, None, self.uplink) links += Html("link", type="text/css", href=url, media="screen", rel="stylesheet", indent=False) # add additional meta and link tags head += meta head += links # Add the script to control the menu menuscript = Html("") head += menuscript # add outerwrapper to set the overall page width outerwrapperdiv = Html("div", id='outerwrapper') body += outerwrapperdiv # begin header section headerdiv = Html("div", id='header') + ( Html("")) headerdiv += Html("h1", html_escape(self.title_str), id="SiteTitle", inline=True) outerwrapperdiv += headerdiv header_note = self.report.options['headernote'] if header_note: note = self.get_note_format( self.r_db.get_note_from_gramps_id(header_note), False) user_header = Html("div", id='user_header') headerdiv += user_header # attach note user_header += note # Begin Navigation Menu-- # is the style sheet either Basic-Blue or Visually Impaired, # and menu layout is Drop Down? if (self.report.css == _("Basic-Blue") or self.report.css == _("Visually Impaired") ) and self.report.navigation == "dropdown": outerwrapperdiv += self.display_drop_menu() else: outerwrapperdiv += self.display_nav_links(the_title, cal=cal) if self.report.options['toggle']: head += TOGGLE # Create a button to go to the top of the page viewbox = "0 0 100 100" points = "0,100 100,100, 50,10" svg = Html("svg", viewBox=viewbox, class_="triangle", inline=False) svg += Html("polygon", points=points) outerwrapperdiv += Html("button", svg, id="gototop", title=_("Go to top"), onclick="GoToTop()") outerwrapperdiv += GOTOTOP # This must be positioned # after the button for it to work # message for Codacy : # body is used in some modules to add functions like onload(), # initialize(), ... # some modules doesn't need that, so body is an unused variable # in these modules. # return page, head, and body to its classes... return page, head, body, outerwrapperdiv def display_nav_links(self, currentsection, cal=0): """ Creates the navigation menu @param: currentsection = which menu item are you on """ # include repositories or not? inc_repos = True if (not self.report.inc_repository or not self.r_db.get_repository_handles()): inc_repos = False # create media pages... if self.create_media: _create_media_link = True if self.create_thumbs_only: _create_media_link = False # Determine which menu items will be available? # Menu items have been adjusted to concide with Gramps Navigation # Sidebar order... navs = [ (self.report.index_fname, self._("Home", "Html"), self.report.use_home), (self.report.intro_fname, self._("Introduction"), self.report.use_intro), (self.report.extrapage, self.extrapagename, (self.extrapage != "")), ('individuals', self._("Individuals"), True), (self.report.surname_fname, self._("Surnames"), True), ('families', self._("Families"), self.report.inc_families), ('events', self._("Events"), self.report.inc_events), ('places', self._("Places"), self.report.inc_places), ('sources', self._("Sources"), self.report.inc_sources), ('repositories', self._("Repositories"), inc_repos), ('media', self._("Media"), self.create_images_index and self.report.inc_gallery and not self.report.create_thumbs_only), ('thumbnails', self._("Thumbnails"), self.create_thumbs_index and self.report.inc_gallery), ('download', self._("Download"), self.report.inc_download), ("addressbook", self._("Address Book"), self.report.inc_addressbook), ('contact', self._("Contact"), self.report.use_contact), ('updates', self._("Updates"), self.report.inc_updates), ('statistics', self._("Statistics"), self.report.inc_stats), (self.target_cal_uri, self._("Web Calendar"), self.usecal) ] # Remove menu sections if they are not being created? navs = ((url_text, nav_text) for url_text, nav_text, cond in navs if cond) menu_items = [[url, text] for url, text in navs] number_items = len(menu_items) # begin navigation menu division... with Html("div", class_="wrappernav", id="nav", role="navigation") as navigation: with Html("div", class_="container") as container: index = 0 unordered = Html("ul", class_="nav", id="dropmenu") while index < number_items: url_fname, nav_text = menu_items[index] hyper = self.get_nav_menu_hyperlink(url_fname, nav_text, cal=cal) # Define 'currentsection' to correctly set navlink item # CSS id 'CurrentSection' for Navigation styling. # Use 'self.report.cur_fname' to determine # 'CurrentSection' for individual elements for # Navigation styling. # Figure out if we need
  • # or just
  • check_cs = False if nav_text == currentsection: check_cs = True elif nav_text == self._("Home", "Html"): if "index" in self.report.cur_fname: check_cs = True elif nav_text == self._("Surnames"): if "srn" in self.report.cur_fname: check_cs = True elif self._("Surnames") in currentsection: check_cs = True elif nav_text == self._("Individuals"): if "ppl" in self.report.cur_fname: check_cs = True elif nav_text == self._("Families"): if "fam" in self.report.cur_fname: check_cs = True elif nav_text == self._("Sources"): if "src" in self.report.cur_fname: check_cs = True elif nav_text == self._("Repositories"): if "repo" in self.report.cur_fname: check_cs = True elif nav_text == self._("Places"): if "plc" in self.report.cur_fname: check_cs = True elif nav_text == self._("Events"): if "evt" in self.report.cur_fname: check_cs = True elif nav_text == self._("Media"): if "img" in self.report.cur_fname: check_cs = True elif nav_text == self._("Address Book"): if "addr" in self.report.cur_fname: check_cs = True elif nav_text == self._("Updates"): if "updates" in self.report.cur_fname: check_cs = True elif nav_text == self._("Statistics"): if "statistics" in self.report.cur_fname: check_cs = True elif nav_text == self._("Web Calendar"): if "cal/" in self.report.cur_fname: check_cs = True temp_cs = 'class = "CurrentSection"' check_cs = temp_cs if check_cs else False if check_cs: unordered.extend( Html("li", hyper, attr=check_cs, inline=True) ) else: if self.report.extrapage != "": if (url_fname[:4] == "http" or url_fname[:1] == "/"): hyper = Html("a", nav_text, href=url_fname, title=nav_text) elif self.report.extrapagename == nav_text: if cal > 0: url_fname = "/".join(([".."]*cal + [url_fname])) hyper = Html("a", nav_text, href=url_fname, title=nav_text) unordered.extend( Html("li", hyper, inline=True) ) index += 1 if self.report.options['multitrans'] and self.not_holiday: langs = Html("li", self._("Language"), class_="lang") en_locale = self.report.set_locale("en") languages = en_locale.get_language_dict() choice = Html("ul", class_="lang") langs += choice for language in languages: for extra_lang, dummy_title in self.report.languages: if languages[language] == extra_lang: lang_txt = html_escape(self._(language)) n_lang = languages[language] nfname = self.report.cur_fname if "cal" in nfname: (dummy_field, dummy_sep, field2) = nfname.partition("cal/") sub_cal = 3 if self.the_lang else 2 url = "/".join(([".."]*sub_cal + [n_lang, "cal", field2] )) else: upl = self.uplink url = self.report.build_url_lang(nfname, n_lang, upl) lnk = Html("a", lang_txt, href=url, title=lang_txt) choice += Html("li", lnk, inline=True) unordered.extend(langs) if self.prevnext: prv = Html('%s' % self._("Previous")) nxt = Html('%s' % self._("Next")) unordered.extend(Html("li", prv, inline=True)) unordered.extend(Html("li", nxt, inline=True)) container += unordered navigation += container return navigation def display_drop_menu(self): """ Creates the Drop Down Navigation Menu """ # include repositories or not? inc_repos = True if (not self.report.inc_repository or not self.r_db.get_repository_handles()): inc_repos = False # create media pages... _create_media_link = False if self.create_media: _create_media_link = True if self.create_thumbs_only: _create_media_link = False personal = [ (self.report.intro_fname, self._("Introduction"), self.report.use_intro), ("individuals", self._("Individuals"), True), (self.report.surname_fname, self._("Surnames"), True), ("families", self._("Families"), self.report.inc_families) ] personal = ((url_text, nav_text) for url_text, nav_text, cond in personal if cond) personal = [[url, text] for url, text in personal] navs1 = [ ("events", self._("Events"), self.report.inc_events), ("places", self._("Places"), True), ("sources", self._("Sources"), True), ("repositories", self._("Repositories"), inc_repos) ] navs1 = ((url_text, nav_text) for url_text, nav_text, cond in navs1 if cond) navs1 = [[url, text] for url, text in navs1] media = [ ("media", self._("Media"), _create_media_link), ("thumbnails", self._("Thumbnails"), True) ] media = ((url_text, nav_text) for url_text, nav_text, cond in media if cond) media = [[url, text] for url, text in media] misc = [ ('download', self._("Download"), self.report.inc_download), ("addressbook", self._("Address Book"), self.report.inc_addressbook) ] misc = ((url_text, nav_text) for url_text, nav_text, cond in misc if cond) misc = [[url, text] for url, text in misc] contact = [ ('contact', self._("Contact"), self.report.use_contact) ] contact = ((url_text, nav_text) for url_text, nav_text, cond in contact if cond) contact = [[url, text] for url, text in contact] # begin navigation menu division... with Html("div", class_="wrapper", id="nav", role="navigation") as navigation: with Html("div", class_="container") as container: unordered = Html("ul", class_="menu", id="dropmenu") if self.report.use_home: list_html = Html("li", self.get_nav_menu_hyperlink( self.report.index_fname, self._("Home", "Html"))) unordered += list_html # add personal column self.get_column_data(unordered, personal, self._("Personal")) if navs1: for url_fname, nav_text in navs1: unordered.extend( Html("li", self.get_nav_menu_hyperlink(url_fname, nav_text), inline=True) ) # add media column self.get_column_data(unordered, media, self._("Media")) # add miscellaneous column self.get_column_data(unordered, misc, self._("Miscellaneous")) # add contact column self.get_column_data(unordered, contact, _("Contact")) container += unordered navigation += container return navigation def add_image(self, option_name, head, height=0): """ Will add an image (if present) to the page If this image contains regions, try to add them. @param: option_name -- The name of the report option @param: height -- Height of the image """ pic_id = self.report.options[option_name] if pic_id: obj = self.r_db.get_media_from_gramps_id(pic_id) if obj is None: return None # get media rectangles _region_items = self.media_ref_rect_regions(obj.get_handle(), linkurl=self.uplink) # if there are media rectangle regions, attach behaviour style sheet if _region_items: if self.the_lang and not self.usecms: fname = "/".join(["..", "css", "behaviour.css"]) else: 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") mime_type = obj.get_mime_type() if mime_type and is_image_type(mime_type): try: newpath, dummy_tpath = self.report.prepare_copy_media(obj) newpathc = newpath if self.the_lang and self.report.archive: (dummy_1_field, dummy_sep, second_field) = newpath.partition("/") newpathc = second_field if self.usecms: newpathc = newpathc.replace(self.target_uri + "/", "") # In some case, we have the target_uri without # the leading "/" newpathc = newpathc.replace(self.target_uri[1:] + "/", "") self.report.copy_file(media_path_full( self.r_db, obj.get_path()), newpathc) # begin image with Html("div", id="GalleryDisplay", style='width: auto; height: auto') as image: if _region_items: # add all regions and links to persons regions = Html("ol", class_="RegionBox") while _region_items: (name, coord_x, coord_y, width, height, linkurl ) = _region_items.pop() regions += Html( "li", style="left:%d%%; " "top:%d%%; " "width:%d%%; " "height:%d%%;" % ( coord_x, coord_y, width, height)) + ( Html("a", name, href=linkurl) ) image += regions # add image imag = Html("img") imag.attr = '' if height: imag.attr += 'height = "%d"' % height descr = html_escape(obj.get_description()) newpath = self.report.build_url_fname(newpath, image=True) imag.attr += ' src = "%s" alt = "%s"' % (newpath, descr) fname = self.report.build_url_fname(obj.get_handle(), "img", uplink=2, image=True, ) + self.ext inc_gallery = self.report.options['gallery'] if not self.create_thumbs_only and inc_gallery: img_link = Html("a", href=fname, title=descr) + ( Html("img", src=newpath, alt=descr)) else: # We can't show the image html page. # This page doesn't exist. img_link = Html("img", src=newpath, alt=descr) image += img_link return image except (IOError, OSError) as msg: self.r_user.warn(_("Could not add photo to page"), str(msg)) # no image to return return None def media_ref_rect_regions(self, handle, linkurl=True): """ Gramps feature #2634 -- attempt to highlight subregions in media objects and link back to the relevant web page. This next section of code builds up the "records" we'll need to generate the html/css code to support the subregions @param: handle -- The media handle to use """ # get all of the backlinks to this media object; meaning all of # the people, events, places, etc..., that use this image _region_items = set() for (classname, newhandle) in self.r_db.find_backlink_handles( handle, include_classes=["Person", "Family", "Event", "Place"]): # for each of the backlinks, get the relevant object from the db # and determine a few important things, such as a text name we # can use, and the URL to a relevant web page _obj = None _name = "" _linkurl = "#" if classname == "Person": # Is this a person for whom we have built a page: if self.report.person_in_webreport(newhandle): # If so, let's add a link to them: _obj = self.r_db.get_person_from_handle(newhandle) if _obj: # What is the shortest possible name we could use # for this person? _name = (_obj.get_primary_name().get_call_name() or _obj.get_primary_name().get_first_name() or self._("Unknown") ) _linkurl = self.report.build_url_fname_html(_obj.handle, "ppl", linkurl) elif classname == "Family" and self.inc_families: _obj = self.r_db.get_family_from_handle(newhandle) partner1_handle = _obj.get_father_handle() partner2_handle = _obj.get_mother_handle() partner1 = None partner2 = None if partner1_handle: partner1 = self.r_db.get_person_from_handle( partner1_handle) if partner2_handle: partner2 = self.r_db.get_person_from_handle( partner2_handle) if partner2 and partner1: _name = partner1.get_primary_name().get_first_name() _linkurl = self.report.build_url_fname_html(partner1_handle, "ppl", True) elif partner1: _name = partner1.get_primary_name().get_first_name() _linkurl = self.report.build_url_fname_html(partner1_handle, "ppl", True) elif partner2: _name = partner2.get_primary_name().get_first_name() _linkurl = self.report.build_url_fname_html(partner2_handle, "ppl", True) if not _name: _name = self._("Unknown") elif classname == "Event" and self.inc_events: _obj = self.r_db.get_event_from_handle(newhandle) _name = _obj.get_description() if not _name: _name = self._("Unknown") _linkurl = self.report.build_url_fname_html(_obj.handle, "evt", True) elif classname == "Place": _obj = self.r_db.get_place_from_handle(newhandle) _name = _pd.display(self.r_db, _obj) if not _name: _name = self._("Unknown") _linkurl = self.report.build_url_fname_html(newhandle, "plc", True) # continue looking through the loop for an object... if _obj is None: continue # get a list of all media refs for this object media_list = _obj.get_media_list() # go media refs looking for one that points to this image for mediaref in media_list: # is this mediaref for this image? do we have a rect? if mediaref.ref == handle and mediaref.rect is not None: (coord_x1, coord_y1, coord_x2, coord_y2) = mediaref.rect # Gramps gives us absolute coordinates, # but we need relative width + height width = coord_x2 - coord_x1 height = coord_y2 - coord_y1 # remember all this information, cause we'll need # need it later when we output the
  • ...
  • tags item = (_name, coord_x1, coord_y1, width, height, _linkurl) _region_items.add(item) # End of code that looks for and prepares the media object regions return sorted(_region_items) def media_ref_region_to_object(self, media_handle, obj): """ Return a region of this image if it refers to this object. @param: media_handle -- The media handle to use @param: obj -- The object reference """ # get a list of all media refs for this object for mediaref in obj.get_media_list(): # is this mediaref for this image? do we have a rect? if (mediaref.ref == media_handle and mediaref.rect is not None): return mediaref.rect # (x1, y1, x2, y2) return None def disp_first_img_as_thumbnail(self, photolist, object_): """ Return the Html of the first image of photolist that is associated with object. First image might be a region in an image. Or, the first image might have regions defined in it. @param: photolist -- The list of media @param: object_ -- The object reference """ if not photolist or not self.create_media: return None photo_handle = photolist[0].get_reference_handle() photo = self.r_db.get_media_from_handle(photo_handle) mime_type = photo.get_mime_type() descr = photo.get_description() # begin snapshot division with Html("div", class_="snapshot") as snapshot: if mime_type and is_image_type(mime_type): region = self.media_ref_region_to_object(photo_handle, object_) if region: # make a thumbnail of this region newpath = self.copy_thumbnail(photo_handle, photo, region) newpath = self.report.build_url_fname(newpath, uplink=True, image=True) snapshot += self.media_link(photo_handle, newpath, descr, uplink=self.uplink, usedescr=False) else: dummy_rpath, newpath = self.report.prepare_copy_media(photo) newpath = self.report.build_url_fname(newpath, image=True, uplink=self.uplink) snapshot += self.media_link(photo_handle, newpath, descr, uplink=self.uplink, usedescr=False) else: # begin hyperlink snapshot += self.doc_link(photo_handle, descr, uplink=self.uplink, usedescr=False) # return snapshot division to its callers return snapshot def disp_add_img_as_gallery(self, photolist, object_): """ Display additional image as gallery @param: photolist -- The list of media @param: object_ -- The object reference """ if not photolist or not self.create_media: return None # make referenced images have the same order as in media list: photolist_handles = {} for mediaref in photolist: photolist_handles[mediaref.get_reference_handle()] = mediaref photolist_ordered = [] for photoref in copy.copy(object_.get_media_list()): if photoref.ref in photolist_handles: photo = photolist_handles[photoref.ref] photolist_ordered.append(photo) # and add any that are left (should there be any?) photolist_ordered += photolist # begin individualgallery division and section title with Html("div", class_="subsection", id="indivgallery") as section: with self.create_toggle("media") as h4_head: section += h4_head h4_head += self._("Media") disp = "none" if self.report.options['toggle'] else "block" with Html("div", style="display:%s" % disp, id="toggle_media") as toggle: section += toggle displayed = [] for mediaref in photolist_ordered: photo_handle = mediaref.get_reference_handle() photo = self.r_db.get_media_from_handle(photo_handle) if photo_handle in displayed: continue mime_type = photo.get_mime_type() # get media description descr = photo.get_description() if mime_type: try: # create thumbnail url # extension needs to be added as it is not # already there url = (self.report.build_url_fname(photo_handle, "thumb", True, image=True) + ".png") # begin hyperlink toggle += self.media_link(photo_handle, url, descr, uplink=self.uplink, usedescr=True) except (IOError, OSError) as msg: self.r_user.warn(_("Could not add photo to page"), str(msg)) else: try: # begin hyperlink toggle += self.doc_link(photo_handle, descr, uplink=self.uplink) except (IOError, OSError) as msg: self.r_user.warn(_("Could not add photo to page"), str(msg)) displayed.append(photo_handle) # add fullclear for proper styling section += FULLCLEAR # return indivgallery division to its caller return section def default_note(self, parent, notetype): """ return true if the notetype is the same as the parent @param: parent -- The parent object (Person, Family, Media,...) @param: notetype -- The type for the current note """ if parent == Person and notetype == NoteType.PERSON: return True elif parent == Family and notetype == NoteType.FAMILY: return True elif parent == Media and notetype == NoteType.MEDIA: return True elif parent == Repository and notetype == NoteType.REPO: return True elif parent == Source and notetype == NoteType.SOURCE: return True elif parent == Event and notetype == NoteType.EVENT: return True elif parent == Place and notetype == NoteType.PLACE: return True elif parent == Citation and notetype == NoteType.CITATION: return True elif parent == Attribute and notetype == NoteType.ATTRIBUTE: return True return False def display_note_list(self, notelist=None, parent=None, toggle=True): """ Display note list @param: notelist -- The list of notes @param: parent -- The parent object (Person, Family, Media,...) """ if not notelist: return None # begin LDS ordinance table and table head if toggle: with Html("div", class_="subsection narrative") as hdiv: with self.create_toggle("note") as h4_head: hdiv += h4_head h4_head += self._("Notes") disp = "none" if self.report.options['toggle'] else "block" with Html("div", class_="subsection narrative", id="toggle_note", style="display:%s" % disp) as section: hdiv += section else: with Html("div", class_="subsection narrative") as section: hdiv = section idx = 0 for notehandle in notelist: note = self.r_db.get_note_from_handle(notehandle) title = self._(note.type.xml_str()) if note: note_text = self.get_note_format(note, True) idx += 1 if len(notelist) > 1: if (self.default_note(parent, int(note.type)) or int(note.type) == NoteType.HTML_CODE): title_text = self._("Note: %s") % str(idx) else: title = " (" + title + ")" title_text = self._("Note: %s") % str(idx) + title else: if (self.default_note(parent, int(note.type)) or int(note.type) == NoteType.HTML_CODE): title_text = self._("Note") else: title_text = title # Tags if parent: tags = self.show_tags(note) if tags and self.report.inc_tags: title_text += " (" + tags + ")" # add section title section += Html("h4", title_text, inline=True) # attach note section += note_text # return notes to its callers return hdiv def display_url_list(self, urllist=None): """ Display URL list @param: urllist -- The list of urls """ if not urllist: return None # begin web links division with Html("div", class_="subsection", id="WebLinks") as section: with self.create_toggle("links") as h4_head: section += h4_head h4_head += self._("Web Links") disp = "none" if self.report.options['toggle'] else "block" with Html("table", class_="infolist weblinks", id="toggle_links", style="display:%s" % disp) as table: section += 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._("Type"), "ColumnType"), (self._("Description"), "ColumnDescription")] ) tbody = Html("tbody") table += tbody for url in urllist: trow = Html("tr") tbody += trow _type = self._(url.get_type().xml_str()) uri = url.get_path() descr = url.get_description() # Email address if _type == UrlType.EMAIL: if not uri.startswith("mailto:"): uri = "mailto:%(email)s" % {'email' : uri} # Web Site address elif _type == UrlType.WEB_HOME: if not (uri.startswith("http://") or uri.startswith("https://")): url = self.secure_mode uri = url + "%(website)s" % {"website" : uri} # FTP server address elif _type == UrlType.WEB_FTP: if not (uri.startswith("ftp://") or uri.startswith("ftps://")): uri = "ftp://%(ftpsite)s" % {"ftpsite" : uri} descr = Html("p", html_escape(descr)) + ( Html("a", self._(" [Click to Go]"), href=uri, title=uri) ) trow.extend( Html("td", data, class_=colclass, inline=True) for (data, colclass) in [ (str(_type), "ColumnType"), (descr, "ColumnDescription") ] ) return section def display_lds_ordinance(self, db_obj_): """ Display LDS information for a person or family @param: db_obj_ -- The database object """ ldsordlist = db_obj_.lds_ord_list if not ldsordlist: return None # begin LDS Ordinance division and section title with Html("div", class_="subsection", id="LDSOrdinance") as section: with self.create_toggle("lds") as h4_head: section += h4_head h4_head += self._("Latter-Day Saints/ LDS Ordinance") # dump individual LDS ordinance list section += self.dump_ordinance(db_obj_, "Person") # return section to its caller return section def display_ind_sources(self, srcobj): """ Will create the "Source References" section for an object @param: srcobj -- Sources object """ list(map( lambda i: self.bibli.add_reference( self.r_db.get_citation_from_handle(i)), srcobj.get_citation_list())) sourcerefs = self.display_source_refs(self.bibli) # return to its callers return sourcerefs # Only used in IndividualPage.display_ind_sources(), # and MediaPage.display_media_sources() def display_source_refs(self, bibli): """ Display source references @param: bibli -- List of sources """ if bibli.get_citation_count() == 0: return None with Html("div", class_="subsection", id="sourcerefs") as section: section += Html("h4", self._("Source References"), inline=True) ordered = Html("ol", id="srcr") cindex = 0 citationlist = bibli.get_citation_list() for citation in citationlist: cindex += 1 # Add this source and its references to the page source = self.r_db.get_source_from_handle( citation.get_source_handle()) if source is not None: if source.get_author(): authorstring = source.get_author() + ": " else: authorstring = "" list_html = Html("li", self.source_link( source.get_handle(), authorstring + source.get_title(), source.get_gramps_id(), cindex, uplink=self.uplink)) else: list_html = Html("li", "None") ordered1 = Html("ol", id="citr") citation_ref_list = citation.get_ref_list() for key, sref in citation_ref_list: cit_ref_li = Html("li", id="sref%d%s" % (cindex, key)) tmp = Html("ul") conf = conf_strings.get(sref.confidence, self._('Unknown')) if conf == conf_strings[Citation.CONF_NORMAL]: conf = None else: conf = self._(conf) for (label, data) in [[self._("Date"), self.rlocale.get_date(sref.date)], [self._("Page"), sref.page], [self._("Confidence"), conf]]: if data: tmp += Html("li", self._("%(str1)s: %(str2)s") % { 'str1' : label, 'str2' : data }) if self.create_media: for media_ref in sref.get_media_list(): media_handle = media_ref.get_reference_handle() media = self.r_db.get_media_from_handle( media_handle) if media: mime_type = media.get_mime_type() if mime_type: if mime_type.startswith("image/"): real_path, new_path = \ self.report.prepare_copy_media( media) newpath = self.report.build_url_fname( new_path, uplink=self.uplink) self.report.copy_file( media_path_full(self.r_db, media.get_path()), real_path) tmp += Html("li", self.media_link( media_handle, newpath, media.get_description(), self.uplink, usedescr=False), inline=True) else: tmp += Html("li", self.doc_link( media_handle, media.get_description(), self.uplink, usedescr=False), inline=True) for handle in sref.get_note_list(): this_note = self.r_db.get_note_from_handle(handle) if this_note is not None: note_format = self.get_note_format(this_note, True) tmp += Html("li", self._("%(str1)s: %(str2)s") % { 'str1' : str(this_note.get_type()), 'str2' : note_format }) if tmp: cit_ref_li += tmp ordered1 += cit_ref_li if citation_ref_list: list_html += ordered1 ordered += list_html section += ordered # return section to its caller return section def family_map_link(self, handle, url): """ Creates a link to the family map @param: handle -- The family handle @param: url -- url to be linked """ self.report.fam_link[handle] = url return Html("a", self._("Family Map"), href=url, title=self._("Family Map"), class_="familymap", inline=True) def display_spouse(self, partner, family, place_lat_long): """ Display an individual's partner @param: partner -- The partner @param: family -- The family @param: place_lat_long -- For use in Family Map Pages. This will be None if called from Family pages, which do not create a Family Map """ gender = partner.get_gender() reltype = family.get_relationship() rtype = self._(str(family.get_relationship().xml_str())) if reltype == FamilyRelType.MARRIED: if gender == Person.FEMALE: relstr = self._("Wife") elif gender == Person.MALE: relstr = self._("Husband") else: relstr = self._("Partner") else: relstr = self._("Partner") # display family relationship status, and add spouse to FamilyMapPages if self.familymappages: self._get_event_place(partner, place_lat_long) trow = Html("tr", class_="BeginFamily") + ( Html("td", rtype, class_="ColumnType", inline=True), Html("td", relstr, class_="ColumnAttribute", inline=True) ) tcell = Html("td", class_="ColumnValue") trow += tcell tcell += self.new_person_link(partner.get_handle(), uplink=True, person=partner) birth = death = "" bd_event = get_birth_or_fallback(self.r_db, partner) if bd_event: birth = self.rlocale.get_date(bd_event.get_date_object()) dd_event = get_death_or_fallback(self.r_db, partner) if dd_event: death = self.rlocale.get_date(dd_event.get_date_object()) if death == "": death = "..." tcell += " ( * ", birth, " + ", death, " )" return trow def display_child_link(self, chandle): """ display child link ... @param: chandle -- Child handle """ return self.new_person_link(chandle, uplink=True) def new_person_link(self, person_handle, uplink=False, person=None, name_style=_NAME_STYLE_DEFAULT): """ creates a link for a person. If a page is generated for the person, a hyperlink is created, else just the name of the person. The returned vale will be an Html object if a hyperlink is generated, otherwise just a string @param: person_handle -- Person in database @param: uplink -- If True, then "../../../" is inserted in front of the result @param: person -- Person object. This does not need to be passed. It should be passed if the person object has already been retrieved, as it will be used to improve performance """ result = self.report.obj_dict.get(Person).get(person_handle) # construct link, name and gid if result is None: # The person is not included in the webreport link = "" if person is None: person = self.r_db.get_person_from_handle(person_handle) if person: name = self.report.get_person_name(person) gid = person.get_gramps_id() else: name = self._("Unknown") gid = "" else: # The person has been encountered in the web report, but this does # not necessarily mean that a page has been generated (link, name, gid) = result name = html_escape(name) # construct the result if not self.noid and gid != "": gid_html = Html("span", " [%s]" % gid, class_="grampsid", inline=True) else: gid_html = "" if link != "": url = self.report.build_url_fname(link, uplink=uplink) hyper = Html("a", name, gid_html, href=url, inline=True) else: hyper = name + str(gid_html) return hyper def media_link(self, media_handle, img_url, name, uplink=False, usedescr=True): """ creates and returns a hyperlink to the thumbnail image @param: media_handle -- Photo handle from report database @param: img_url -- Thumbnail url @param: name -- Photo description @param: uplink -- If True, then "../../../" is inserted in front of the result. @param: usedescr -- Add media description """ url = self.report.build_url_fname(media_handle, "img", uplink, image=True) + self.ext name = html_escape(name) # begin thumbnail division with Html("div", class_="thumbnail") as thumbnail: # begin hyperlink if not self.create_thumbs_only: hyper = Html("a", href=url, title=name) + ( Html("img", src=img_url, alt=name) ) else: hyper = Html("img", src=img_url, alt=name) thumbnail += hyper if usedescr: hyper += Html("p", name, inline=True) return thumbnail def doc_link(self, handle, name, uplink=False, usedescr=True): """ create a hyperlink for the media object and returns it @param: handle -- Document handle @param: name -- Document name @param: uplink -- If True, then "../../../" is inserted in front of the result. @param: usedescr -- Add description to hyperlink """ url = self.report.build_url_fname_html(handle, "img", uplink) name = html_escape(name) # begin thumbnail division with Html("div", class_="thumbnail") as thumbnail: document_url = self.report.build_url_image("document.png", "images", uplink) if not self.create_thumbs_only: document_link = Html("a", href=url, title=name) + ( Html("img", src=document_url, alt=name) ) else: document_link = Html("img", src=document_url, alt=name) if usedescr: document_link += Html('br') + ( Html("span", name, inline=True) ) thumbnail += document_link return thumbnail def place_link(self, handle, name, gid=None, uplink=False): """ Returns a hyperlink for place link @param: handle -- repository handle from report database @param: name -- repository title @param: gid -- gramps id @param: uplink -- If True, then "../../../" is inserted in front of the result. """ url = self.report.build_url_fname_html(handle, "plc", uplink) hyper = Html("a", html_escape(name), href=url, title=html_escape(name)) if not self.noid and gid: hyper += Html("span", " [%s]" % gid, class_="grampsid", inline=True) # return hyperlink to its callers return hyper def dump_place(self, place, table): """ Dump a place's information from within the database @param: place -- Place object from the database @param: table -- Table from Placedetail """ # add table body tbody = Html("tbody") table += tbody gid = place.gramps_id 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 data = place.get_latitude() v_lat, v_lon = conv_lat_lon(data, "0.0", "D.D8") if not v_lat: data += self._(":") # We use the same message as in: # gramps/gui/editors/editplace.py # gramps/gui/editors/editplaceref.py data += self._("Invalid latitude\n(syntax: 18\\u00b09'48.21\"S," " -18.2412 or -18:9:48.21)") # We need to convert "\\u00b0" to "°" for html data = data.replace("\\u00b0", "°") if data != "": trow = Html('tr') + ( Html("td", self._("Latitude"), class_="ColumnAttribute", inline=True), Html("td", data, class_="ColumnValue", inline=True) ) tbody += trow data = place.get_longitude() v_lat, v_lon = conv_lat_lon("0.0", data, "D.D8") if not v_lon: data += self._(":") # We use the same message as in: # gramps/gui/editors/editplace.py # gramps/gui/editors/editplaceref.py data += self._("Invalid longitude\n(syntax: 18\\u00b09'48.21\"E," " -18.2412 or -18:9:48.21)") # We need to convert "\\u00b0" to "°" for html data = data.replace("\\u00b0", "°") if data != "": trow = Html('tr') + ( Html("td", self._("Longitude"), class_="ColumnAttribute", inline=True), Html("td", data, class_="ColumnValue", inline=True) ) tbody += trow mlocation = get_main_location(self.r_db, place) for (label, data) in [ (self._("Street"), mlocation.get(PlaceType.STREET, '')), (self._("Locality"), mlocation.get(PlaceType.LOCALITY, '')), (self._("City"), mlocation.get(PlaceType.CITY, '')), (self._("Church Parish"), mlocation.get(PlaceType.PARISH, '')), (self._("County"), mlocation.get(PlaceType.COUNTY, '')), (self._("State/ Province"), mlocation.get(PlaceType.STATE, '')), (self._("Postal Code"), place.get_code()), (self._("Province"), mlocation.get(PlaceType.PROVINCE, '')), (self._("Country"), mlocation.get(PlaceType.COUNTRY, ''))]: if data: trow = Html("tr") + ( Html("td", label, class_="ColumnAttribute", inline=True), Html("td", data, class_="ColumnValue", inline=True) ) tbody += trow # display all related locations for placeref in place.get_placeref_list(): place_date = self.rlocale.get_date(placeref.get_date_object()) if place_date != "": parent_place = self.r_db.get_place_from_handle(placeref.ref) parent_name = parent_place.get_name().get_value() trow = Html('tr') + ( Html("td", self._("Locations"), class_="ColumnAttribute", inline=True), Html("td", parent_name, class_="ColumnValue", inline=True), Html("td", place_date, class_="ColumnValue", inline=True) ) tbody += trow altloc = place.get_alternative_names() if altloc: tbody += Html("tr") + Html("td", " ", colspan=2) date_msg = self._("Date range in which the name is valid.") trow = Html("tr") + ( Html("th", self._("Alternate Names"), colspan=1, class_="ColumnAttribute", inline=True), Html("th", self._("Language"), colspan=1, class_="ColumnAttribute", inline=True), Html("th", date_msg, colspan=1, class_="ColumnAttribute", inline=True), ) tbody += trow for loc in altloc: place_date = self.rlocale.get_date(loc.date) trow = Html("tr") + ( Html("td", loc.get_value(), class_="ColumnValue", inline=True), Html("td", loc.get_language(), class_="ColumnValue", inline=True), Html("td", place_date, class_="ColumnValue", inline=True), ) tbody += trow altloc = place.get_alternate_locations() if altloc: tbody += Html("tr") + Html("td", " ", colspan=2) trow = Html("tr") + ( Html("th", self._("Alternate Locations"), colspan=2, class_="ColumnAttribute", inline=True), ) tbody += trow for loc in (nonempt for nonempt in altloc if not nonempt.is_empty()): for (label, data) in [(self._("Street"), loc.street), (self._("Locality"), loc.locality), (self._("City"), loc.city), (self._("Church Parish"), loc.parish), (self._("County"), loc.county), (self._("State/ Province"), loc.state), (self._("Postal Code"), loc.postal), (self._("Country"), loc.country),]: if data: trow = Html("tr") + ( Html("td", label, class_="ColumnAttribute", inline=True), Html("td", data, class_="ColumnValue", inline=True) ) tbody += trow tbody += Html("tr") + Html("td", " ", colspan=2) # Tags tags = self.show_tags(place) if tags and self.report.inc_tags: trow = Html("tr") + ( Html("td", self._("Tags"), class_="ColumnAttribute", inline=True), Html("td", tags, class_="ColumnValue", inline=True) ) tbody += trow # enclosed by tbody += Html("tr") + Html("td", " ") trow = Html("tr") + ( Html("th", self._("Enclosed By"), class_="ColumnAttribute", inline=True), ) tbody += trow def sort_by_enclosed_by(obj): """ Sort by enclosed by """ place_name = "" parent_place = self.r_db.get_place_from_handle(obj.ref) if parent_place: place_name = parent_place.get_name().get_value() return place_name def sort_by_encl(obj): """ Sort by encloses """ return obj[0] for placeref in sorted(place.get_placeref_list(), key=sort_by_enclosed_by): parent_place = self.r_db.get_place_from_handle(placeref.ref) if parent_place: place_name = parent_place.get_name().get_value() if parent_place.handle in self.report.obj_dict[Place]: place_hyper = self.place_link(parent_place.handle, place_name, uplink=self.uplink) else: place_hyper = place_name trow = Html("tr") + ( Html("td", place_hyper, class_="ColumnPlace", inline=True)) tbody += trow # enclose tbody += Html("tr") + Html("td", " ") trow = Html("tr") + ( Html("th", self._("Place Encloses"), class_="ColumnAttribute", inline=True), ) tbody += trow encloses = [] for link in self.r_db.find_backlink_handles( place.handle, include_classes=['Place']): child_place = self.r_db.get_place_from_handle(link[1]) placeref = None for placeref in child_place.get_placeref_list(): if placeref.ref == place.handle: place_name = child_place.get_name().get_value() if link[1] in self.report.obj_dict[Place]: encloses.append((place_name, link[1])) else: encloses.append((place_name, "")) for (name, handle) in sorted(encloses, key=sort_by_encl): place_name = child_place.get_name().get_value() if handle and handle in self.report.obj_dict[Place]: place_hyper = self.place_link(handle, name, uplink=self.uplink) else: place_hyper = name trow = Html("tr") + ( Html("td", place_hyper, class_="ColumnPlace", inline=True)) tbody += trow # return place table to its callers return table def repository_link(self, repository_handle, name, gid=None, uplink=False): """ Returns a hyperlink for repository links @param: repository_handle -- repository handle from report database @param: name -- repository title @param: gid -- gramps id @param: uplink -- If True, then "../../../" is inserted in front of the result. """ url = self.report.build_url_fname_html(repository_handle, 'repo', uplink) name = html_escape(name) hyper = Html("a", name, href=url, title=name) if not self.noid and gid: hyper += Html("span", '[%s]' % gid, class_="grampsid", inline=True) return hyper def dump_repository_ref_list(self, repo_ref_list): """ Dumps the repository @param: repo_ref_list -- The list of repositories references """ if not repo_ref_list: return None # Repository list division... with Html("div", class_="subsection", id="repositories") as repositories: repositories += Html("h4", self._("Repositories"), inline=True) with Html("table", class_="infolist") as table: repositories += table thead = Html("thead") table += thead trow = Html("tr") + ( Html("th", self._("Number"), class_="ColumnRowLabel", inline=True), Html("th", self._("Title"), class_="ColumnName", inline=True), Html("th", self._("Type"), class_="ColumnName", inline=True), Html("th", self._("Call number"), class_="ColumnName", inline=True) ) thead += trow tbody = Html("tbody") table += tbody index = 1 for repo_ref in repo_ref_list: repo = self.r_db.get_repository_from_handle(repo_ref.ref) if repo: trow = Html("tr") + ( Html("td", index, class_="ColumnRowLabel", inline=True), Html("td", self.repository_link(repo_ref.ref, repo.get_name(), repo.get_gramps_id(), self.uplink)), Html("td", self._(repo_ref.get_media_type().xml_str()), class_="ColumnName"), Html("td", repo_ref.get_call_number(), class_="ColumnName") ) tbody += trow index += 1 return repositories def dump_residence(self, has_res): """ Creates a residence from the database @param: has_res -- The residence to use """ if not has_res: return None # begin residence division with Html("div", class_="content Residence") as residence: residence += Html("h4", self._("Residence"), inline=True) with Html("table", class_="infolist place") as table: residence += table place_handle = has_res.get_place_handle() if place_handle: place = self.r_db.get_place_from_handle(place_handle) if place: self.dump_place(place, table) descr = has_res.get_description() if descr: trow = Html("tr") if len(table) == 3: # append description row to tbody element # of dump_place table[-2] += trow else: # append description row to table element table += trow trow.extend(Html("td", self._("Description"), class_="ColumnAttribute", inline=True)) trow.extend(Html("td", descr, class_="ColumnValue", inline=True)) # return information to its callers return residence def display_bkref(self, bkref_list, depth): """ Display a reference list for an object class @param: bkref_list -- The reference list @param: depth -- The style of list to use """ list_style = "1", "a", "I", "A", "i" ordered = Html("ol", class_="Col1", role="Volume-n-Page") ordered.attr += " type=%s" % list_style[depth] if depth > len(list_style): return "" # Sort by the role of the object at the bkref_class, bkref_handle def sort_by_role(obj): """ Sort by role """ if obj[2] == "Primary": role = "0" elif obj[2] == "Family": role = "1" else: if self.reference_sort: role = obj[2] # name elif len(obj[2].split('-')) > 1: dummy_cal, role = obj[2].split(':') # date in ISO format # dummy_cal is the original calendar. remove it. if len(role.split(' ')) == 2: # for sort, remove the modifier before, after... (dummy_modifier, role) = role.split(' ') else: role = "3" return role for (bkref_class, bkref_handle, role) in sorted( bkref_list, key=lambda x: sort_by_role(x)): list_html = Html("li") path = self.report.obj_dict[bkref_class][bkref_handle][0] name = self.report.obj_dict[bkref_class][bkref_handle][1] gid = self.report.obj_dict[bkref_class][bkref_handle][2] if role != "": if self.reference_sort: role = self.birth_death_dates(gid) elif role[1:2] == ':': # cal is the original calendar cal, role = role.split(':') # conver ISO date to Date for translation. # all modifiers are in english, so convert them # to the local language if len(role.split(' - ')) > 1: (date1, date2) = role.split(' - ') role = self._("between") + " " + date1 + " " role += self._("and") + " " + date2 elif len(role.split(' ')) == 2: (pref, date) = role.split(' ') if "aft" in pref: role = self._("after") + " " + date elif "bef" in pref: role = self._("before") + " " + date elif pref in ("abt", "about"): role = self._("about") + " " + date elif "c" in pref: role = self._("circa") + " " + date elif "around" in pref: role = self._("around") + " " + date # parse is done in the default language date = _dp.parse(role) # reset the date to the original calendar cdate = date.to_calendar(Date.calendar_names[int(cal)]) ldate = self.rlocale.get_date(cdate) evtype = self.event_for_date(gid, cdate) if evtype: evtype = " " + evtype role = " (%s) " % (ldate + evtype) else: role = " (%s) " % self._(role) ordered += list_html if path == "": list_html += name list_html += self.display_bkref( self.report.bkref_dict[bkref_class][bkref_handle], depth+1) else: url = self.report.build_url_fname(path, uplink=self.uplink) if not self.noid and gid != "": gid_html = Html("span", " [%s]" % gid, class_="grampsid", inline=True) else: gid_html = "" list_html += Html("a", href=url) + name + role + gid_html return ordered def event_for_date(self, gid, date): """ return the event type @param: gid -- the person gramps ID @param: date -- the event to look for this date """ pers = self.r_db.get_person_from_gramps_id(gid) if pers: evt_ref_list = pers.get_event_ref_list() if evt_ref_list: for evt_ref in evt_ref_list: evt = self.r_db.get_event_from_handle(evt_ref.ref) if evt: evdate = evt.get_date_object() # convert date to gregorian _date = str(evdate.to_calendar("gregorian")) if _date == str(date): return self._(str(evt.get_type())) return "" def birth_death_dates(self, gid): """ return the birth and death date for the person @param: gid -- the person gramps ID """ pers = self.r_db.get_person_from_gramps_id(gid) if pers: birth = death = "" evt_birth = get_birth_or_fallback(self.r_db, pers) if evt_birth: birthd = evt_birth.get_date_object() # convert date to gregorian to avoid strange years birth = str(birthd.to_calendar("gregorian").get_year()) evt_death = get_death_or_fallback(self.r_db, pers) if evt_death: deathd = evt_death.get_date_object() # convert date to gregorian to avoid strange years death = str(deathd.to_calendar("gregorian").get_year()) return "(%s-%s)" % (birth, death) else: return "" def display_bkref_list(self, obj_class, obj_handle): """ Display a reference list for an object class @param: obj_class -- The object class to use @param: obj_handle -- The handle to use """ bkref_list = self.report.bkref_dict[obj_class][obj_handle] if not bkref_list: return None # begin references division and title with Html("div", class_="subsection", id="references") as section: section += Html("h4", self._("References"), inline=True) depth = 0 ordered = self.display_bkref(bkref_list, depth) section += ordered return section # ----------------------------------------------------------------------- # # Web Page Fortmatter and writer # ----------------------------------------------------------------------- def xhtml_writer(self, htmlinstance, output_file, sio, date): """ Will format, write, and close the file @param: output_file -- Open file that is being written to @param: htmlinstance -- Web page created with libhtml gramps/plugins/lib/libhtml.py """ htmlinstance.write(partial(print, file=output_file)) # closes the file self.report.close_file(output_file, sio, date) def create_toggle(self, element): """ will produce a toggle button @param: element -- The html element name """ use_toggle = self.report.options['toggle'] if use_toggle: viewbox = "0 0 100 100" points = "5.9,88.2 50,11.8 94.1,88.2" svg = Html("svg", viewBox=viewbox, class_="triangle", inline=False) svg += Html("polygon", points=points) toggle_name = 'toggle_' + element id_name = 'icon_' + element with Html("h4", onclick="toggleContent('" + toggle_name + "', '" + id_name + "');") as toggle: toggle += Html("button", svg, id=id_name, class_='icon') else: toggle = Html("h4", inline=True) return toggle