From 763f2738dddd472bc3dc9243ed04a5e7e106fc5e Mon Sep 17 00:00:00 2001 From: Serge Noiraud Date: Fri, 17 Jan 2020 11:46:40 +0100 Subject: [PATCH] NAVWEB and WEBCAL: some minor corrections (#980) * NAVWEB: set unused media to False by default Fixes #11496 * Navweb: Center correctly the map in the web page * Webcal: Dropmenu doesn't work if only one year. * Navweb: Add notes to updates and delete empty rows * Navweb: some code cleanup. * Navweb: remove unused variable * Narweb: references enhancement on place pages. * Navweb: convert the years in gregorian cal. * Narweb: remove unused argument * Narweb: really solves the pyICU problem * WEBCAL: missing death symbol --- data/css/narrative-maps.css | 2 +- gramps/plugins/webreport/basepage.py | 46 ++++++- gramps/plugins/webreport/common.py | 53 +++++--- gramps/plugins/webreport/narrativeweb.py | 2 +- gramps/plugins/webreport/updates.py | 147 +++++++++++++++++++++-- gramps/plugins/webreport/webcal.py | 25 ++-- 6 files changed, 233 insertions(+), 42 deletions(-) diff --git a/data/css/narrative-maps.css b/data/css/narrative-maps.css index ab52d67f5..5c0682557 100644 --- a/data/css/narrative-maps.css +++ b/data/css/narrative-maps.css @@ -31,7 +31,7 @@ body#FamilyMap { margin-left: 10px; margin-right: 10px; border: solid 4px #000; - margin: 0px auto; + margin: 20px auto; width: 800px; height: 400px; max-width: 90%; diff --git a/gramps/plugins/webreport/basepage.py b/gramps/plugins/webreport/basepage.py index 123c08309..a5b8dbb5f 100644 --- a/gramps/plugins/webreport/basepage.py +++ b/gramps/plugins/webreport/basepage.py @@ -2984,7 +2984,7 @@ class BasePage: # pylint: disable=C1001 gid = self.report.obj_dict[bkref_class][bkref_handle][2] if role != "": if self.reference_sort: - role = "" + role = self.birth_death_dates(gid) elif role[1:2] == ':': # cal is the original calendar cal, role = role.split(':') @@ -3012,7 +3012,10 @@ class BasePage: # pylint: disable=C1001 # reset the date to the original calendar cdate = date.to_calendar(Date.calendar_names[int(cal)]) ldate = self.rlocale.get_date(cdate) - role = " (%s) " % ldate + evtype = self.event_for_date(gid, cdate) + if evtype: + evtype = " " + evtype + role = " (%s) " % (ldate + evtype) else: role = " (%s) " % self._(role) ordered += list_html @@ -3031,6 +3034,45 @@ class BasePage: # pylint: disable=C1001 list_html += Html("a", href=url) + name + role + gid_html return ordered + def event_for_date(self, gid, date): + """ + return the event type + """ + 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 + """ + 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 diff --git a/gramps/plugins/webreport/common.py b/gramps/plugins/webreport/common.py index e000b54f6..2ac33490c 100644 --- a/gramps/plugins/webreport/common.py +++ b/gramps/plugins/webreport/common.py @@ -31,6 +31,7 @@ from unicodedata import normalize from collections import defaultdict from hashlib import md5 import re +import locale # Used only with pyICU import logging from xml.sax.saxutils import escape @@ -439,7 +440,10 @@ def sort_places(dbase, handle_list, rlocale=glocale): for name in temp_list: if isinstance(name, bytes): name = name.decode('utf-8') - sorted_lists.append((name, pname_sub[name][0])) + slist = sorted(((sortnames[x], x) for x in pname_sub[name]), + key=lambda x: rlocale.sort_key(x[0])) + for entry in slist: + sorted_lists.append(entry) return sorted_lists @@ -622,23 +626,42 @@ def first_letter(string, rlocale=glocale): # no special case return norm_unicode[0].upper() -def primary_difference(prev_key, new_key, rlocale=glocale): - """ - The PyICU collation doesn't work if you want to sort in another language - So we use this method to do the work correctly. - Returns true if there is a primary difference between the two parameters - See http://www.gramps-project.org/bugs/view.php?id=2933#c9317 if - letter[i]+'a' < letter[i+1]+'b' and letter[i+1]+'a' < letter[i]+'b' is - true then the letters should be grouped together +try: + import PyICU # pylint : disable=wrong-import-position + PRIM_COLL = PyICU.Collator.createInstance(PyICU.Locale(COLLATE_LANG)) + PRIM_COLL.setStrength(PRIM_COLL.PRIMARY) - The test characters here must not be any that are used in contractions. - """ + def primary_difference(prev_key, new_key, rlocale=glocale): + """ + Try to use the PyICU collation. + If we generate a report for another language, make sure we use the good + collation sequence + """ + collation = PRIM_COLL + if rlocale.lang != locale.getlocale(locale.LC_COLLATE)[0]: + encoding = rlocale.encoding if rlocale.encoding else "UTF-8" + collate_lang = PyICU.Locale(rlocale.collation+"."+encoding) + collation = PyICU.Collator.createInstance(collate_lang) + return collation.compare(prev_key, new_key) != 0 - return rlocale.sort_key(prev_key + "e") >= \ - rlocale.sort_key(new_key + "f") or \ - rlocale.sort_key(new_key + "e") >= \ - rlocale.sort_key(prev_key + "f") +except: + def primary_difference(prev_key, new_key, rlocale=glocale): + """ + The PyICU collation is not available. + + Returns true if there is a primary difference between the two parameters + See http://www.gramps-project.org/bugs/view.php?id=2933#c9317 if + letter[i]+'a' < letter[i+1]+'b' and letter[i+1]+'a' < letter[i]+'b' is + true then the letters should be grouped together + + The test characters here must not be any that are used in contractions. + """ + + return rlocale.sort_key(prev_key + "e") >= \ + rlocale.sort_key(new_key + "f") or \ + rlocale.sort_key(new_key + "e") >= \ + rlocale.sort_key(prev_key + "f") def get_first_letters(dbase, handle_list, key, rlocale=glocale): """ diff --git a/gramps/plugins/webreport/narrativeweb.py b/gramps/plugins/webreport/narrativeweb.py index 5d4ca9e29..d72eba76d 100644 --- a/gramps/plugins/webreport/narrativeweb.py +++ b/gramps/plugins/webreport/narrativeweb.py @@ -1948,7 +1948,7 @@ class NavWebOptions(MenuReportOptions): self.__gallery_changed) self.__unused = BooleanOption( - _("Include unused images and media objects"), True) + _("Include unused images and media objects"), False) self.__unused.set_help(_('Whether to include unused or unreferenced' ' media objects')) addopt("unused", self.__unused) diff --git a/gramps/plugins/webreport/updates.py b/gramps/plugins/webreport/updates.py index 8989d49b1..4d752cd16 100644 --- a/gramps/plugins/webreport/updates.py +++ b/gramps/plugins/webreport/updates.py @@ -45,9 +45,9 @@ from gramps.plugins.lib.libhtml import Html #------------------------------------------------ from gramps.plugins.webreport.basepage import BasePage from gramps.gen.display.place import displayer as _pd -from gramps.plugins.webreport.common import (FULLCLEAR, _EVENTMAP) +from gramps.plugins.webreport.common import (FULLCLEAR, _EVENTMAP, html_escape) from gramps.gen.lib import (Person, Family, Event, Place, Source, Repository, - Media) + Media, Note, Citation) from gramps.gen.lib.date import Date _ = glocale.translation.sgettext @@ -66,6 +66,12 @@ class UpdatesPage(BasePage): """ BasePage.__init__(self, report, title) ldatec = 0 + self.inc_repository = self.report.options['inc_repository'] + self.inc_families = self.report.options['inc_families'] + self.inc_events = self.report.options['inc_events'] + self.inc_places = self.report.options['inc_places'] + self.inc_sources = self.report.options['inc_sources'] + self.inc_gallery = False output_file, sio = self.report.create_file("updates") result = self.write_header(self._('New and updated objects')) @@ -93,35 +99,35 @@ class UpdatesPage(BasePage): if people is not None: section += people - if self.report.options['inc_families']: + if self.inc_families: header = self._("Families") section += Html("h4", header) families = self.list_people_changed(Family) if families is not None: section += families - if self.report.options['inc_events']: + if self.inc_events: header = self._("Events") section += Html("h4", header) events = self.list_people_changed(Event) if events is not None: section += events - if self.report.options['inc_places']: + if self.inc_places: header = self._("Places") section += Html("h4", header) places = self.list_people_changed(Place) if places is not None: section += places - if self.report.options['inc_sources']: + if self.inc_sources: header = self._("Sources") section += Html("h4", header) sources = self.list_people_changed(Source) if sources is not None: section += sources - if self.report.options['inc_repository']: + if self.inc_repository: header = self._("Repositories") section += Html("h4", header) repos = self.list_people_changed(Repository) @@ -130,12 +136,19 @@ class UpdatesPage(BasePage): if (self.report.options['gallery'] and not self.report.options['create_thumbs_only']): + self.inc_gallery = True header = self._("Media") section += Html("h4", header) media = self.list_people_changed(Media) if media is not None: section += media + header = self._("Notes") + section += Html("h4", header) + events = self.list_notes() + if events is not None: + section += events + # create clear line for proper styling # create footer section footer = self.write_footer(ldatec) @@ -145,6 +158,122 @@ class UpdatesPage(BasePage): # and close the file self.xhtml_writer(homepage, output_file, sio, ldatec) + def list_notes(self): + """ + List all notes with last change date + """ + nb_items = 0 + section = "" + + def sort_on_change(handle): + """ sort records based on the last change time """ + fct = self.report.database.get_note_from_handle + obj = fct(handle) + timestamp = obj.get_change_time() + return timestamp + + note_list = self.report.database.get_note_handles() + obj_list = sorted(note_list, key=sort_on_change, reverse=True) + with Html("table", class_="list", id="list") as section: + for handle in obj_list: + show = False + date = obj = None + obj = self.report.database.get_note_from_handle(handle) + if obj: + text = html_escape(obj.get()[:50]) + timestamp = obj.get_change_time() + if timestamp - self.maxdays > 0: + handle_list = set( + self.report.database.find_backlink_handles( + handle, + include_classes=['Person', 'Family', 'Event', + 'Place', 'Media', 'Source', + 'Citation', 'Repository', + ])) + tims = localtime(timestamp) + odat = Date(tims.tm_year, tims.tm_mon, tims.tm_mday) + date = self.rlocale.date_displayer.display(odat) + date += strftime(' %X', tims) + if handle_list: + srbd = self.report.database + srbkref = self.report.bkref_dict + for obj_t, r_handle in handle_list: + if obj_t == 'Person': + if r_handle in srbkref[Person]: + name = self.new_person_link(r_handle) + show = True + elif obj_t == 'Family': + if r_handle in srbkref[Family]: + fam = srbd.get_family_from_handle( + r_handle) + fam = self._("Family") + name = self.family_link(r_handle, fam) + if self.inc_families: + show = True + elif obj_t == 'Place': + if r_handle in srbkref[Place]: + plc = srbd.get_place_from_handle( + r_handle) + plcn = _pd.display(self.report.database, + plc) + name = self.place_link(r_handle, plcn) + if self.inc_places: + show = True + elif obj_t == 'Event': + if r_handle in srbkref[Event]: + evt = srbd.get_event_from_handle( + r_handle) + evtn = self._(evt.get_type().xml_str()) + name = self.event_link(r_handle, evtn) + if self.inc_events: + show = True + elif obj_t == 'Media': + if r_handle in srbkref[Media]: + media = srbd.get_media_from_handle( + r_handle) + evtn = media.get_description() + name = self.media_link(r_handle, evtn, + evtn, + usedescr=False) + if self.inc_gallery: + show = True + elif obj_t == 'Citation': + if r_handle in srbkref[Citation]: + cit = srbd.get_event_from_handle( + r_handle) + citsrc = cit.source_handle + evtn = self._("Citation") + name = self.source_link(citsrc, evtn) + if self.inc_sources: + show = True + elif obj_t == 'Source': + if r_handle in srbkref[Source]: + src = srbd.get_source_from_handle( + r_handle) + evtn = src.get_title() + name = self.source_link(r_handle, evtn) + if self.inc_sources: + show = True + elif obj_t == 'Repository': + if r_handle in srbkref[Repository]: + rep = srbd.get_repository_from_handle( + r_handle) + evtn = rep.get_name() + name = self.repository_link(r_handle, + evtn) + if self.inc_repository: + show = True + if show: + row = Html("tr") + section += row + row += Html("td", date, class_="date") + row += Html("td", text) + row += Html("td", name) + nb_items += 1 + if nb_items > self.nbr: + break + return section + def list_people_changed(self, object_type): """ List all records with last change date @@ -180,8 +309,6 @@ class UpdatesPage(BasePage): key=sort_on_change, reverse=True) with Html("table", class_="list", id="list") as section: for handle in obj_list: - row = Html("tr") - section += row date = obj = None name = "" obj = fct(handle) @@ -236,6 +363,8 @@ class UpdatesPage(BasePage): odat = Date(tims.tm_year, tims.tm_mon, tims.tm_mday) date = self.rlocale.date_displayer.display(odat) date += strftime(' %X', tims) + row = Html("tr") + section += row row += Html("td", date, class_="date") row += Html("td", name) return section diff --git a/gramps/plugins/webreport/webcal.py b/gramps/plugins/webreport/webcal.py index f89f4aea6..67322dca1 100644 --- a/gramps/plugins/webreport/webcal.py +++ b/gramps/plugins/webreport/webcal.py @@ -63,6 +63,7 @@ from gramps.gen.plug.menu import (BooleanOption, NumberOption, StringOption, from gramps.gen.utils.config import get_researcher from gramps.gen.utils.alive import probably_alive from gramps.gen.utils.db import get_death_or_fallback +from gramps.gen.utils.symbols import Symbols from gramps.gen.datehandler import displayer as _dd from gramps.gen.display.name import displayer as _nd @@ -464,20 +465,14 @@ class WebCalReport(Report): "if (x.className === \"nav\") { x.className += \"" " responsive\"; } else { x.className = \"nav\"; }" " }") - if self.multiyear: - head += menuscript + head += menuscript # begin header section - if self.multiyear: - headerdiv = Html("div", id='header') + ( - Html("")) + ( - Html("h1", html_escape(title), - id="SiteTitle", inline=True)) - else: - headerdiv = Html("div", id='header') + ( - Html("h1", html_escape(title), - id="SiteTitle", inline=True)) + headerdiv = Html("div", id='header') + ( + Html("")) + ( + Html("h1", self.title_text, + id="SiteTitle", inline=True)) body += headerdiv # add body id tag if not None @@ -2168,12 +2163,14 @@ def get_day_list(event_date, holiday_list, bday_anniv_list, rlocale=glocale): #age_str.format(precision=1, as_age=False, dlocale=rlocale) age_str = age_str.format(precision=1, as_age=False, dlocale=rlocale) + symbols = Symbols() + death_idx = symbols.DEATH_SYMBOL_SHADOWED_LATIN_CROSS + death_symbol = symbols.get_death_symbol_for_char(death_idx) # a birthday if event == 'Birthday': if age_at_death is not None: - death_symbol = "✞" # latin cross for html code trans_date = trans_text("Died %(death_date)s.") translated_date = rlocale.get_date(dead_event_date) mess = trans_date % {'death_date' : translated_date} @@ -2194,7 +2191,7 @@ def get_day_list(event_date, holiday_list, bday_anniv_list, rlocale=glocale): # a death if event == 'Death': - txt_str = (text + ', ' + txt_str = (text + ', ' + death_symbol + ' ' + (_('%s since death') % str(age_str) if nyears else _('death')) + '')