diff -Nru gramps-4.2.6~dfsg/ChangeLog gramps-4.2.8~dfsg/ChangeLog --- gramps-4.2.6~dfsg/ChangeLog 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/ChangeLog 2018-02-09 21:05:56.000000000 +0000 @@ -1,253 +1,13 @@ -2017-08-01 romjerome +2018-02-09 prculley - * po/fr.po: typos + * gramps/plugins/view/geoclose.py, + gramps/plugins/view/geoevents.py, + gramps/plugins/view/geofamclose.py, + gramps/plugins/view/geofamily.py, gramps/plugins/view/geoperson.py, + gramps/plugins/view/geoplaces.py: Fix Geography views for bad + 'dbstate.is_open()' test Fixes #10417 -2017-07-31 Zdeněk Hataš +2018-02-08 Nick Hall - * po/cs.po: update to recent pot - -2017-07-29 romjerome - - * NEWS: start '4.2.6' section - -2017-07-29 romjerome - - * po/fr.po, po/gramps.pot: Update template no modified or new message id, update references (header and - comments) - -2017-07-26 vantu5z - - * po/ru.po: update Russian translation - merge last template - fix typo - change 'е' to 'ё' in some words - -2017-06-21 Nick Hall - - * gramps/gui/filters/sidebar/_citationsidebarfilter.py: Fix - HasCitation rule in citation filter sidebar Filter parameters should be of type str. Fixes #10076. (cherry picked from commit adb4883291159298781144706fa5bc6331870ef2) - -2016-04-06 Nick Hall - - * gramps/gen/filters/rules/_rule.py: Remove deprecated locale flag re.L is deprecated and re.U is now default. (cherry picked from commit da3db4bc2828210fa77d6d57bb28a7b0cc2c19e8) Fixes #10136 - -2017-07-23 Paul Franklin - - * gramps/gui/glade/editdate.glade: Date Editor has 'Type' and - 'Quality' labels swapped Fixes #10135 - -2017-07-15 Leonhaeuser - - * po/de.po: update German translation Fix #0010131 - -2017-07-08 Lajos Nemeséri - - * po/hu.po: Update Hungarian translation - -2017-06-30 John Ralls - - * gramps/gui/display.py: Open web links with /usr/bin/open on Mac - and Python older than 3.5 Works around https://bugs.python.org/issue24452 Fixes #10105 - -2017-06-27 John Ralls - - * gramps/gen/utils/grampslocale.py: FamilyGroup Report crash Python's sort routine gratuitously converts the bytearrays returned - by ICU::Collator::getByteArray to a string when storing it. This - resulted in a TypeError when attempting to compare a just-returned - bytearray with a stored string. We work around this by converting the bytearray into its hexadecimal - representation and then decoding that into a string. Fixes #10077. - -2017-06-22 Paul Franklin - - * gramps/gen/plug/docgen/graphdoc.py: names not displayed in - relationship graph Issue #10093 - -2017-06-21 Paul Franklin - - * gramps/gen/const.py: Outdated Bugtracker link in Unexpected Error - reporting wizard Fixes #10100 - -2017-06-21 Paul Franklin - - * gramps/plugins/graph/gvfamilylines.py: Family Lines Report - generates empty PDFs when name [has double-quotes] Fixes #10096 - -2017-06-19 Paul Franklin - - * gramps/gui/dbman.py: non-local character in DB name causes crash - on Windows Fixes #10095 - -2017-05-28 Josip - - * gramps/gui/views/listview.py, - gramps/gui/widgets/interactivesearchbox.py: Quick search with Czech - characters -> Crash Crash happen when checking for "event.string" in "treeview_keypress" - function in "gramps/gui/widgets/interactivesearchbox.py" Note that - https://lazka.github.io/pgi-docs/Gdk-3.0/classes/EventKey.html#Gdk.EventKeysays it is deprecated and should never be used. Gdk.keyval_to_unicode return the corresponding unicode character, or - 0 if there is no corresponding character. Fixes #9130. (cherry picked from commit bc1724533171fe69a6a775101d8d4318ba05b396) - -2017-05-31 John Ralls - - * gramps/gen/datehandler/_dateparser.py: 8366: February 29th invalid - date in Julian dual-dated leap year - -2017-05-19 Paul Franklin - - * gramps/plugins/textreport/indivcomplete.py: 10033: Note isn't - included on CIR when it is attached to a name - -2017-05-15 Nick Hall - - * gramps/gui/editors/displaytabs/citationembedlist.py, - gramps/gui/selectors/baseselector.py: Revert bugs #8785 and #9700 Expanding tree selectors by default caused performance issues. The - expanded person selector also made it more difficult to select a - specific person in some circumstances. GEPS 041 has been created to discuss a better selector design. - -2017-05-05 Sam Manzi - - * gramps/gen/soundex.py: Fix bug 9975 Incorrect SoundEx result - (#388) - -2017-04-29 Paul Culley - - * gramps/gui/editors/filtereditor.py: bug 9564; fix exception on - Event filter editor (#378) for 'Events occurring on a particular day of the week' filter - -2017-03-22 Paul Franklin - - * gramps/plugins/export/exportxml.py: 9995: Bug in the Name Editor / - Group As - -2017-03-16 Paul Franklin - - * po/tr.po: add datestrings to gramps42 Turkish translation - -2017-02-11 Nick Hall - - * gramps/plugins/export/exportcsv.py: 9945: Write PlaceID links in - CSV export When places are included in the export use PlaceID links, otherwise - generate a formatted place for the event. - -2017-02-08 Doug Reider - - * mac/gramps.accel: Fix bookmarks keybinding on Mac to match the - documentation. - -2017-02-08 Bernard Banko - - * po/sl.po: updated sl translation - -2017-02-08 Bernard Banko - - * po/sl.po: corrected slovenian name editor keywords - -2017-02-07 Paul Franklin - - * gramps/plugins/drawreport/ancestortree.py, - gramps/plugins/lib/librecurse.py: 9004: Error printing graphical - report ancestor tree - -2017-02-07 Jérôme Rapinat - - * gramps/plugins/drawreport/ancestortree.py: 9004: Error printing - graphical report ancestor tree - -2017-02-02 Peter Landgren - - * po/sv.po: Update Swedish translation - -2017-02-02 romjerome - - * gramps/plugins/tool/changenames.glade: 9907: add a spacing value - for children widgets fit better for some Gtk themes - -2017-02-02 romjerome - - * docs/gen/gen_display.rst: 8855: update API doc for place displayer - -2017-01-25 Matti Niemelä - - * po/fi.po: update finnish translation - -2017-01-25 romjerome - - * gramps/plugins/drawreport/ancestortree.py: 9904: revert fd83162 TODO: need a solution for recursive iteration and private records - -2017-01-24 romjerome - - * gramps/plugins/drawreport/ancestortree.py: 9904: Errors printing - graphical report ancestor tree - -2017-01-24 romjerome - - * gramps/gui/filters/sidebar/_familysidebarfilter.py: 9908: Custom - Family Relations not shown in the filter siderbar - -2017-01-14 romjerome - - * gramps/plugins/textreport/tagreport.py: 9899: fix non-textual - value on place name - -2017-01-11 Luigi Toscano - - * po/it.po: Italian translation: updates and fixes - -2017-01-08 Luigi Toscano - - * po/it.po: Refresh it.po using the current pot template - -2017-01-03 Nick Hall - - * gramps/gui/editors/editnote.py: 9878: Update note text before - closing The object must be updated so that changes can be detected. - -2017-01-02 SNoiraud - - * gramps/plugins/lib/maps/placeselection.py: 9865: Can not link the - place on geography view - -2016-12-28 Paul Franklin - - * gramps/plugins/drawreport/ancestortree.py: 9862: ancestor tree - doesn't use replacements - -2016-12-23 Josip - - * gramps/gui/glade/reorder.glade: 8128: GtkDialog mapped without a - transient parent Fix Reorder Relationships dialog (cherry picked from commit 3b4ceeb630fff4d1f9ed1d64a6db20bef7262ec5) - -2016-12-17 prculley - - * gramps/gui/glade/dialog.glade: bug 9235: Shrink size of Break Lock - (and other QuestionDialogs) - -2016-12-17 prculley - - * gramps/gui/editors/editperson.py: bug 9470; Don't allow selecton - of Active or Home person until actually commited - -2016-12-18 prculley - - * gramps/gui/widgets/interactivesearchbox.py: bug 9478; fix quick - search exception when nothing in searched list - -2016-12-17 Paul Franklin - - * gramps/gen/const.py, gramps/version.py: bump to 4.2.6 - -2016-12-17 Paul Franklin - - * gramps/gui/editors/editfamily.py: 9612: Problem adding parents - [with Latin names] - -2016-12-16 John Ralls - - * mac/Info.plist, mac/gramps.bundle, mac/gramps.modules: Release - 4.2.5 on Mac. - -2016-12-16 John Ralls - - * gramps/plugins/gramplet/gramplet.gpr.py: Fix failure to load - default gramplets if GExiv2 is missing or too old. - -2016-12-15 romjerome - - * make official 4.2.5 release + * Bump to 4.2.8 diff -Nru gramps-4.2.6~dfsg/data/authors.xml gramps-4.2.8~dfsg/data/authors.xml --- gramps-4.2.6~dfsg/data/authors.xml 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/data/authors.xml 2018-02-09 21:05:56.000000000 +0000 @@ -95,6 +95,9 @@ Nick Hall <nick__hall@hotmail.com> + Paul Culley <paulr2787@gmail.com> + + Peter Landgren <peter.talken@telia.com> diff -Nru gramps-4.2.6~dfsg/debian/changelog gramps-4.2.8~dfsg/debian/changelog --- gramps-4.2.6~dfsg/debian/changelog 2017-08-01 18:21:12.000000000 +0000 +++ gramps-4.2.8~dfsg/debian/changelog 2018-02-10 08:28:04.000000000 +0000 @@ -1,3 +1,28 @@ +gramps (4.2.8~dfsg-1) unstable; urgency=medium + + * New upstream release + * Switch to debhelper version 11 + * Use Debian email address + * Update upstream copyrights + * Bump standards version, no changes required + * Move Vcs from Alioth to Salsa + + -- Ross Gammon Sat, 10 Feb 2018 09:28:04 +0100 + +gramps (4.2.6~dfsg-1~bpo8+1) jessie-backports-sloppy; urgency=medium + + * Rebuild for jessie-backports. + * Use Debian email address + + -- Ross Gammon Sat, 19 Aug 2017 14:52:43 +0200 + +gramps (4.2.6~dfsg-1~bpo9+1) stretch-backports; urgency=medium + + * Rebuild for stretch-backports. + * Update branch in gbp.conf & Vcs-Git URL + + -- Ross Gammon Sat, 19 Aug 2017 12:32:21 +0200 + gramps (4.2.6~dfsg-1) unstable; urgency=medium * New upstream release @@ -7,6 +32,13 @@ -- Ross Gammon Tue, 01 Aug 2017 20:21:12 +0200 +gramps (4.2.5~dfsg-1~bpo8+1) jessie-backports; urgency=medium + + * Rebuild for jessie-backports. + * Disable tests for jessie-backports + + -- Ross Gammon Sat, 11 Feb 2017 19:40:47 +0100 + gramps (4.2.5~dfsg-1) unstable; urgency=medium * New upstream release @@ -206,7 +238,7 @@ * Drop patch enabling HTML view - now included in this release * Drop patch for empty string bug - now included in this release * Drop patch for editing notes bug - now included in this release - * Improve Debian packaging + * Improve Debian packaging + Provide get-orig-source target + Explain repacking of source tarball in README.source + Updated copyright file with new dates @@ -1017,7 +1049,7 @@ * Added new entry to the upstream NEWS file - it was missing. * Added '#! usr/bin/python -O' line to src/AddMedia.py to make lintian happy. Also removed this line from src/DbPrompter.py for the same reason. - * Edited debian/rules to call '$(MAKE) clean' instead of + * Edited debian/rules to call '$(MAKE) clean' instead of '$(MAKE) distclean' which did not exist. * Edited src/Makefile.in - 'clean' target should also remove *.so files. * Pre-built static HTMLs since the on-the-fly generation from SGML is buggy. @@ -1152,7 +1184,7 @@ * The author has finally addressed the issue of a missing help file. Though as of now none have been created the error produced before is gone and the author is working on better documentation. - Closes: #99617 + Closes: #99617 -- Brandon L. Griffith Thu, 28 Jun 2001 20:27:30 -0500 @@ -1229,7 +1261,7 @@ This should take care of the startup problem some people have had. Bug Fixed. Closes: #98646 - * Silly me named the menu file wrong so it never got included into the + * Silly me named the menu file wrong so it never got included into the Debian Menu system. Gramps should now show up under Apps->Tools. Have no idea how I overlooked this. diff -Nru gramps-4.2.6~dfsg/debian/compat gramps-4.2.8~dfsg/debian/compat --- gramps-4.2.6~dfsg/debian/compat 2017-08-01 18:21:12.000000000 +0000 +++ gramps-4.2.8~dfsg/debian/compat 2018-02-10 08:28:04.000000000 +0000 @@ -1 +1 @@ -9 +11 diff -Nru gramps-4.2.6~dfsg/debian/control gramps-4.2.8~dfsg/debian/control --- gramps-4.2.6~dfsg/debian/control 2017-08-01 18:21:12.000000000 +0000 +++ gramps-4.2.8~dfsg/debian/control 2018-02-10 08:28:04.000000000 +0000 @@ -1,7 +1,7 @@ Source: gramps Section: gnome Priority: optional -Maintainer: Ross Gammon +Maintainer: Ross Gammon Build-Depends-Indep: dh-python, gettext, @@ -15,10 +15,10 @@ python3-gi-cairo, python3-bsddb3 Build-Depends: - debhelper (>= 9.0.0) -Standards-Version: 4.0.0 -Vcs-Git: https://anonscm.debian.org/git/collab-maint/gramps.git -Vcs-browser: https://anonscm.debian.org/cgit/collab-maint/gramps.git + debhelper (>= 11) +Standards-Version: 4.1.3 +Vcs-Git: https://salsa.debian.org/debian/gramps.git +Vcs-browser: https://salsa.debian.org/debian/gramps Homepage: https://www.gramps-project.org/ X-Python3-Version: >= 3.2 diff -Nru gramps-4.2.6~dfsg/debian/copyright gramps-4.2.8~dfsg/debian/copyright --- gramps-4.2.6~dfsg/debian/copyright 2017-08-01 18:21:12.000000000 +0000 +++ gramps-4.2.8~dfsg/debian/copyright 2018-02-10 08:28:04.000000000 +0000 @@ -55,7 +55,7 @@ 2009, Gerald W. Britton 2009, Igal Shapira 2009, 2011, John Resig - 2009-2016, Nick Hall + 2009-2018, Nick Hall 2009, Pander Musubi 2009, Robert Ham 2009, Swoon on bug tracker @@ -86,7 +86,8 @@ 2014, Gerald Kunzmann 2015, Lajos Nemeséri 2015, Detlef Wolz - 2016, Paul R. Culley + 2016-2017, Paul Culley + 2017, Mindaugas Baranauskas License: GPL-2+ Files: data/javascript/jquery.flexbox* diff -Nru gramps-4.2.6~dfsg/gramps/cli/plug/__init__.py gramps-4.2.8~dfsg/gramps/cli/plug/__init__.py --- gramps-4.2.6~dfsg/gramps/cli/plug/__init__.py 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/cli/plug/__init__.py 2018-02-09 21:05:56.000000000 +0000 @@ -46,7 +46,8 @@ #------------------------------------------------------------------------- from gramps.gen.plug import BasePluginManager from gramps.gen.plug.docgen import (StyleSheet, StyleSheetList, PaperStyle, - PAPER_PORTRAIT, PAPER_LANDSCAPE, graphdoc) + PAPER_PORTRAIT, PAPER_LANDSCAPE, graphdoc, + treedoc) from gramps.gen.plug.menu import (FamilyOption, PersonOption, NoteOption, MediaOption, PersonListOption, NumberOption, BooleanOption, DestinationOption, StringOption, @@ -54,8 +55,8 @@ from gramps.gen.display.name import displayer as name_displayer from gramps.gen.errors import ReportError, FilterError from gramps.gen.plug.report import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_BOOK, - CATEGORY_GRAPHVIZ, CATEGORY_CODE, - ReportOptions, append_styles) + CATEGORY_GRAPHVIZ, CATEGORY_TREE, + CATEGORY_CODE, ReportOptions, append_styles) from gramps.gen.plug.report._paper import paper_sizes from gramps.gen.const import USER_HOME from gramps.gen.dbstate import DbState @@ -233,6 +234,15 @@ if name not in self.option_class.options_dict: self.option_class.options_dict[name] = \ menu.get_option_by_name(name).get_value() + if category == CATEGORY_TREE: + # Need to include Genealogy Tree options + self.__toptions = treedoc.TreeOptions() + menu = self.option_class.menu + self.__toptions.add_menu_options(menu) + for name in menu.get_all_option_names(): + if name not in self.option_class.options_dict: + self.option_class.options_dict[ + name] = menu.get_option_by_name(name).get_value() self.option_class.load_previous_values() _validate_options(self.option_class, database) self.show = options_str_dict.pop('show', None) @@ -301,6 +311,10 @@ for graph_format in graphdoc.FORMATS: self.options_help['off'][2].append( graph_format["type"] + "\t" + graph_format["descr"] ) + elif self.category == CATEGORY_TREE: + for tree_format in treedoc.FORMATS: + self.options_help['off'][2].append( + tree_format["type"] + "\t" + tree_format["descr"]) else: self.options_help['off'][2] = "NA" @@ -478,6 +492,15 @@ # Pick the first one as the default. self.format = graphdoc.FORMATS[0]["class"] _chosen_format = graphdoc.FORMATS[0]["type"] + elif self.category == CATEGORY_TREE: + for tree_format in treedoc.FORMATS: + if tree_format['type'] == self.options_dict['off']: + if not self.format: # choose the first one, not the last + self.format = tree_format["class"] + if self.format is None: + # Pick the first one as the default. + self.format = tree_format.FORMATS[0]["class"] + _chosen_format = tree_format.FORMATS[0]["type"] else: self.format = None if _chosen_format and _format_str: @@ -640,7 +663,7 @@ clr.selected_style, PaperStyle(clr.paper,clr.orien,clr.marginl, clr.marginr,clr.margint,clr.marginb)) - elif category == CATEGORY_GRAPHVIZ: + elif category in [CATEGORY_GRAPHVIZ, CATEGORY_TREE]: clr.option_class.handler.doc = clr.format( clr.option_class, PaperStyle(clr.paper,clr.orien,clr.marginl, diff -Nru gramps-4.2.6~dfsg/gramps/gen/datehandler/_date_de.py gramps-4.2.8~dfsg/gramps/gen/datehandler/_date_de.py --- gramps-4.2.6~dfsg/gramps/gen/datehandler/_date_de.py 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/gen/datehandler/_date_de.py 2018-02-09 21:05:56.000000000 +0000 @@ -221,7 +221,7 @@ ) # this definition must agree with its "_display_gregorian" method - def _display_gregorian(self, date_val): + def _display_gregorian(self, date_val, **kwargs): """ display gregorian calendar date in different format """ diff -Nru gramps-4.2.6~dfsg/gramps/gen/datehandler/_date_el.py gramps-4.2.8~dfsg/gramps/gen/datehandler/_date_el.py --- gramps-4.2.6~dfsg/gramps/gen/datehandler/_date_el.py 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/gen/datehandler/_date_el.py 2018-02-09 21:05:56.000000000 +0000 @@ -155,7 +155,7 @@ ) # this definition must agree with its "_display_gregorian" method - def _display_gregorian(self, date_val): + def _display_gregorian(self, date_val, **kwargs): """ display gregorian calendar date in different format """ diff -Nru gramps-4.2.6~dfsg/gramps/gen/datehandler/_date_lt.py gramps-4.2.8~dfsg/gramps/gen/datehandler/_date_lt.py --- gramps-4.2.6~dfsg/gramps/gen/datehandler/_date_lt.py 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/gen/datehandler/_date_lt.py 2018-02-09 21:05:56.000000000 +0000 @@ -185,7 +185,7 @@ "mmmm-MM-DD (ISO)", "mmmm m. mėnesio diena d.", "Mėn diena, metai") # this definition must agree with its "_display_gregorian" method - def _display_gregorian(self, date_val): + def _display_gregorian(self, date_val, **kwargs): """ display gregorian calendar date in different format """ diff -Nru gramps-4.2.6~dfsg/gramps/gen/datehandler/_date_nl.py gramps-4.2.8~dfsg/gramps/gen/datehandler/_date_nl.py --- gramps-4.2.6~dfsg/gramps/gen/datehandler/_date_nl.py 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/gen/datehandler/_date_nl.py 2018-02-09 21:05:56.000000000 +0000 @@ -164,7 +164,7 @@ ) # this definition must agree with its "_display_gregorian" method - def _display_gregorian(self, date_val): + def _display_gregorian(self, date_val, **kwargs): """ display gregorian calendar date in different format """ diff -Nru gramps-4.2.6~dfsg/gramps/gen/datehandler/_date_pl.py gramps-4.2.8~dfsg/gramps/gen/datehandler/_date_pl.py --- gramps-4.2.6~dfsg/gramps/gen/datehandler/_date_pl.py 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/gen/datehandler/_date_pl.py 2018-02-09 21:05:56.000000000 +0000 @@ -215,7 +215,7 @@ "XII" ) - def _display_gregorian(self, date_val): + def _display_gregorian(self, date_val, **kwargs): """ display gregorian calendar date in different format """ diff -Nru gramps-4.2.6~dfsg/gramps/gen/datehandler/_date_sr.py gramps-4.2.8~dfsg/gramps/gen/datehandler/_date_sr.py --- gramps-4.2.6~dfsg/gramps/gen/datehandler/_date_sr.py 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/gen/datehandler/_date_sr.py 2018-02-09 21:05:56.000000000 +0000 @@ -240,7 +240,7 @@ "VII", "VIII", "IX", "X", "XI", "XII" ) - def _display_gregorian(self, date_val): + def _display_gregorian(self, date_val, **kwargs): """ display gregorian calendar date in different format """ diff -Nru gramps-4.2.6~dfsg/gramps/gen/lib/familyreltype.py gramps-4.2.8~dfsg/gramps/gen/lib/familyreltype.py --- gramps-4.2.6~dfsg/gramps/gen/lib/familyreltype.py 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/gen/lib/familyreltype.py 2018-02-09 21:05:56.000000000 +0000 @@ -49,11 +49,11 @@ _DEFAULT = MARRIED _DATAMAP = [ - (UNKNOWN, _("Unknown"), "Unknown"), - (CUSTOM, _("Custom"), "Custom"), + (MARRIED, _("Married"), "Married"), + (UNMARRIED, _("Unmarried"), "Unmarried"), (CIVIL_UNION, _("Civil Union"), "Civil Union"), - (UNMARRIED, _("Unmarried"), "Unmarried"), - (MARRIED, _("Married"), "Married"), + (UNKNOWN, _("Unknown"), "Unknown"), + (CUSTOM, _("Custom"), "Custom"), ] def __init__(self, value=None): diff -Nru gramps-4.2.6~dfsg/gramps/gen/plug/docgen/graphdoc.py gramps-4.2.8~dfsg/gramps/gen/plug/docgen/graphdoc.py --- gramps-4.2.6~dfsg/gramps/gen/plug/docgen/graphdoc.py 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/gen/plug/docgen/graphdoc.py 2018-02-09 21:05:56.000000000 +0000 @@ -8,6 +8,8 @@ # Copyright (C) 2007 Brian G. Matherly # Copyright (C) 2009 Benny Malengier # Copyright (C) 2009 Gary Burton +# Copyright (C) 2017 Mindaugas Baranauskas +# Copyright (C) 2017 Paul Culley # # 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 @@ -42,7 +44,7 @@ #------------------------------------------------------------------------------- from ...const import GRAMPS_LOCALE as glocale _ = glocale.translation.gettext -from ...utils.file import search_for +from ...utils.file import search_for, where_is from . import BaseDoc from ..menu import NumberOption, TextOption, EnumeratedListOption, \ BooleanOption @@ -101,13 +103,10 @@ DETACHED_PROCESS = DWORD(0x00000008).value else: _DOT_FOUND = search_for("dot") - - if search_for("gs") == 1: - _GS_CMD = "gs" - else: - _GS_CMD = "" - -#------------------------------------------------------------------------------- + _GS_CMD = where_is("gs") + + +#------------------------------------------------------------------------------ # # GVOptions # @@ -659,6 +658,8 @@ # disappeared. I used 1 inch margins always. # See bug tracker issue 2815 # :cairo does not work with Graphviz 2.26.3 and later See issue 4164 + # recent versions of Graphvis doesn't even try, just puts out a single + # large page. command = 'dot -Tps:cairo -o"%s" "%s"' % (self._filename, tmp_dot) if win(): @@ -670,8 +671,8 @@ dotversion = str(Popen(['dot', '-V'], stderr=PIPE).communicate(input=None)[1]) # Problem with dot 2.26.3 and later and multiple pages, which gives "cairo: out of - # memory" If the :cairo is skipped for these cases it gives acceptable - # result. + # memory" If the :cairo is skipped for these cases it gives bad + # result for non-Latin-1 characters (utf-8). if (dotversion.find('2.26.3') or dotversion.find('2.28.0') != -1) and (self.vpages * self.hpages) > 1: command = command.replace(':cairo','') os.system(command) @@ -921,9 +922,11 @@ # Generate PostScript using dot # Reason for using -Tps:cairo. Needed for Non Latin-1 letters # See bug tracker issue 2815 - # :cairo does not work with Graphviz 2.26.3 and later See issue 4164 - - command = 'dot -Tps:cairo -o"%s" "%s"' % ( tmp_ps, tmp_dot ) + # :cairo does not work with with multi-page See issue 4164 + # recent versions of Graphvis doesn't even try, just puts out a single + # large page, so we use Ghostscript to split it up. + + command = 'dot -Tps:cairo -o"%s" "%s"' % (tmp_ps, tmp_dot) if win(): dotversion = str(Popen(['dot', '-V'], creationflags=DETACHED_PROCESS, @@ -932,26 +935,65 @@ else: dotversion = str(Popen(['dot', '-V'], stderr=PIPE).communicate(input=None)[1]) - - # Problem with dot 2.26.3 and later and multiple pages, which gives "cairo: out - # of memory". If the :cairo is skipped for these cases it gives - # acceptable result. - if (dotversion.find('2.26.3') or dotversion.find('2.28.0') != -1) and (self.vpages * self.hpages) > 1: - command = command.replace(':cairo','') os.system(command) # Add .5 to remove rounding errors. paper_size = self._paper.get_size() - width_pt = int( (paper_size.get_width_inches() * 72) + 0.5 ) - height_pt = int( (paper_size.get_height_inches() * 72) + 0.5 ) - + width_pt = int((paper_size.get_width_inches() * 72) + .5) + height_pt = int((paper_size.get_height_inches() * 72) + .5) + if (self.vpages * self.hpages) == 1: + # -dDEVICEWIDTHPOINTS=%d' -dDEVICEHEIGHTPOINTS=%d + command = '%s -q -sDEVICE=pdfwrite -dNOPAUSE '\ + '-dDEVICEWIDTHPOINTS=%d -dDEVICEHEIGHTPOINTS=%d '\ + '-sOutputFile="%s" "%s" -c quit' % ( + _GS_CMD, width_pt, height_pt, self._filename, tmp_ps) + os.system(command) + os.remove(tmp_ps) + return + # Margins (in centimeters) to pixels 72/2.54=28.345 + MarginT = int(28.345 * self._paper.get_top_margin()) + MarginB = int(28.345 * self._paper.get_bottom_margin()) + MarginR = int(28.345 * self._paper.get_right_margin()) + MarginL = int(28.345 * self._paper.get_left_margin()) + MarginX = MarginL + MarginR + MarginY = MarginT + MarginB # Convert to PDF using ghostscript - command = '%s -q -sDEVICE=pdfwrite -dNOPAUSE -dDEVICEWIDTHPOINTS=%d' \ - ' -dDEVICEHEIGHTPOINTS=%d -sOutputFile="%s" "%s" -c quit' \ - % ( _GS_CMD, width_pt, height_pt, self._filename, tmp_ps ) + list_of_pieces = [] + + x_rng = range(1, self.hpages + 1) if 'L' in self.pagedir \ + else range(self.hpages , 0, -1) + y_rng = range(1, self.vpages + 1) if 'B' in self.pagedir \ + else range(self.vpages , 0, -1) + if self.pagedir[0] in 'TB': + the_list = ((x, y) for y in y_rng for x in x_rng) + else: + the_list = ((x, y) for x in x_rng for y in y_rng) + for x, y in the_list: + # Slit PS file to pieces of PDF + PageOffsetX = (x - 1) * (MarginX - width_pt) + PageOffsetY = (y - 1) * (MarginY - height_pt) + tmp_pdf_piece = "%s_%d_%d.pdf" % (tmp_ps, x, y) + list_of_pieces.append(tmp_pdf_piece) + # Generate Ghostscript code + command = '%s -q -dBATCH -dNOPAUSE -dSAFER -g%dx%d '\ + '-sOutputFile="%s" -r72 -sDEVICE=pdfwrite '\ + '-c "<> '\ + 'setpagedevice" -f "%s"' % ( + _GS_CMD, width_pt + 10, height_pt + 10, tmp_pdf_piece, + MarginL, MarginB, MarginR, MarginT, + PageOffsetX + 5, PageOffsetY + 5, tmp_ps) + # Execute Ghostscript + os.system(command) + # Merge pieces to single multipage PDF ; + command = '%s -q -dBATCH -dNOPAUSE '\ + '-sOUTPUTFILE=%s -r72 -sDEVICE=pdfwrite %s '\ + % (_GS_CMD, self._filename, ' '.join(list_of_pieces)) os.system(command) - + + # Clean temporary files os.remove(tmp_ps) + for tmp_pdf_piece in list_of_pieces: + os.remove(tmp_pdf_piece) os.remove(tmp_dot) #------------------------------------------------------------------------------- diff -Nru gramps-4.2.6~dfsg/gramps/gen/plug/docgen/__init__.py gramps-4.2.8~dfsg/gramps/gen/plug/docgen/__init__.py --- gramps-4.2.6~dfsg/gramps/gen/plug/docgen/__init__.py 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/gen/plug/docgen/__init__.py 2018-02-09 21:05:56.000000000 +0000 @@ -37,3 +37,4 @@ URL_PATTERN, LOCAL_HYPERLINK, LOCAL_TARGET from .drawdoc import DrawDoc from .graphdoc import GVDoc +from .treedoc import TreeDoc diff -Nru gramps-4.2.6~dfsg/gramps/gen/plug/docgen/treedoc.py gramps-4.2.8~dfsg/gramps/gen/plug/docgen/treedoc.py --- gramps-4.2.6~dfsg/gramps/gen/plug/docgen/treedoc.py 1970-01-01 00:00:00.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/gen/plug/docgen/treedoc.py 2018-02-09 21:05:56.000000000 +0000 @@ -0,0 +1,632 @@ +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2017-2018 Nick Hall +# +# 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. +# +""" LaTeX Genealogy Tree adapter for Trees """ +#------------------------------------------------------------------------- +# +# Standard Python modules +# +#------------------------------------------------------------------------- +from abc import ABCMeta, abstractmethod +import os +import shutil +from io import StringIO +import tempfile +import logging + +#------------------------------------------------------------------------- +# +# Gramps modules +# +#------------------------------------------------------------------------- +from ...utils.file import search_for +from ...lib import Person, EventType, EventRoleType, Date +from ...display.place import displayer as _pd +from ...utils.file import media_path_full +from . import BaseDoc, PAPER_PORTRAIT +from ..menu import NumberOption, TextOption, EnumeratedListOption +from ...constfunc import win +from ...config import config +from ...const import GRAMPS_LOCALE as glocale +_ = glocale.translation.gettext + +#------------------------------------------------------------------------- +# +# set up logging +# +#------------------------------------------------------------------------- +LOG = logging.getLogger(".treedoc") + +#------------------------------------------------------------------------- +# +# Private Constants +# +#------------------------------------------------------------------------- +_DETAIL = [{'name': _("Full"), 'value': "full"}, + {'name': _("Medium"), 'value': "medium"}, + {'name': _("Short"), 'value': "short"}] + +_MARRIAGE = [{'name': _("Default"), 'value': ""}, + {'name': _("Above"), 'value': "marriage above"}, + {'name': _("Below"), 'value': "marriage below"}, + {'name': _("Not shown"), 'value': "no marriage"}] + +_COLOR = [{'name': _("None"), 'value': "none"}, + {'name': _("Default"), 'value': "default"}, + {'name': _("Preferences"), 'value': "preferences"}] + +_TIMEFLOW = [{'name': _("Down (↓)"), 'value': ""}, + {'name': _("Up (↑)"), 'value': "up"}, + {'name': _("Right (→)"), 'value': "right"}, + {'name': _("Left (←)"), 'value': "left"}] + +_EDGES = [{'name': _("Perpendicular"), 'value': ""}, + {'name': _("Rounded"), 'value': "rounded", }, + {'name': _("Swing"), 'value': "swing", }, + {'name': _("Mesh"), 'value': 'mesh'}] + +_NOTELOC = [{'name': _("Top"), 'value': "t"}, + {'name': _("Bottom"), 'value': "b"}] + +_NOTESIZE = [{'name': _("Tiny"), 'value': "tiny"}, + {'name': _("Script"), 'value': "scriptsize"}, + {'name': _("Footnote"), 'value': "footnotesize"}, + {'name': _("Small"), 'value': "small"}, + {'name': _("Normal"), 'value': "normalsize"}, + {'name': _("Large"), 'value': "large"}, + {'name': _("Very large"), 'value': "Large"}, + {'name': _("Extra large"), 'value': "LARGE"}, + {'name': _("Huge"), 'value': "huge"}, + {'name': _("Extra huge"), 'value': "Huge"}] + +if win(): + _LATEX_FOUND = search_for("lualatex.exe") +else: + _LATEX_FOUND = search_for("lualatex") + + +#------------------------------------------------------------------------------ +# +# TreeOptions +# +#------------------------------------------------------------------------------ +class TreeOptions: + """ + Defines all of the controls necessary + to configure the genealogy tree reports. + """ + def add_menu_options(self, menu): + """ + Add all graph related options to the menu. + + :param menu: The menu the options should be added to. + :type menu: :class:`.Menu` + :return: nothing + """ + ################################ + category = _("Node Options") + ################################ + + detail = EnumeratedListOption(_("Node detail"), "full") + for item in _DETAIL: + detail.add_item(item["value"], item["name"]) + detail.set_help(_("Detail of information to be shown in a node.")) + menu.add_option(category, "detail", detail) + + marriage = EnumeratedListOption(_("Marriage"), "") + for item in _MARRIAGE: + marriage.add_item(item["value"], item["name"]) + marriage.set_help(_("Position of marriage information.")) + menu.add_option(category, "marriage", marriage) + + nodesize = NumberOption(_("Node size"), 25, 5, 100, 5) + nodesize.set_help(_("One dimension of a node, in mm. If the timeflow " + "is up or down then this is the width, otherwise " + "it is the height.")) + menu.add_option(category, "nodesize", nodesize) + + levelsize = NumberOption(_("Level size"), 35, 5, 100, 5) + levelsize.set_help(_("One dimension of a node, in mm. If the timeflow " + "is up or down then this is the height, otherwise " + "it is the width.")) + menu.add_option(category, "levelsize", levelsize) + + nodecolor = EnumeratedListOption(_("Color"), "none") + for item in _COLOR: + nodecolor.add_item(item["value"], item["name"]) + nodecolor.set_help(_("Node color.")) + menu.add_option(category, "nodecolor", nodecolor) + + ################################ + category = _("Tree Options") + ################################ + + timeflow = EnumeratedListOption(_("Timeflow"), "") + for item in _TIMEFLOW: + timeflow.add_item(item["value"], item["name"]) + timeflow.set_help(_("Direction that the graph will grow over time.")) + menu.add_option(category, "timeflow", timeflow) + + edges = EnumeratedListOption(_("Edge style"), "") + for item in _EDGES: + edges.add_item(item["value"], item["name"]) + edges.set_help(_("Style of the edges between nodes.")) + menu.add_option(category, "edges", edges) + + leveldist = NumberOption(_("Level distance"), 5, 1, 20, 1) + leveldist.set_help(_("The minimum amount of free space, in mm, " + "between levels. For vertical graphs, this " + "corresponds to spacing between rows. For " + "horizontal graphs, this corresponds to spacing " + "between columns.")) + menu.add_option(category, "leveldist", leveldist) + + ################################ + category = _("Note") + ################################ + + note = TextOption(_("Note to add to the tree"), [""]) + note.set_help(_("This text will be added to the tree.")) + menu.add_option(category, "note", note) + + noteloc = EnumeratedListOption(_("Note location"), 't') + for item in _NOTELOC: + noteloc.add_item(item["value"], item["name"]) + noteloc.set_help(_("Whether note will appear on top " + "or bottom of the page.")) + menu.add_option(category, "noteloc", noteloc) + + notesize = EnumeratedListOption(_("Note size"), 'normalsize') + for item in _NOTESIZE: + notesize.add_item(item["value"], item["name"]) + notesize.set_help(_("The size of note text.")) + menu.add_option(category, "notesize", notesize) + + +#------------------------------------------------------------------------------ +# +# TreeDoc +# +#------------------------------------------------------------------------------ +class TreeDoc(metaclass=ABCMeta): + """ + Abstract Interface for genealogy tree document generators. Output formats + for genealogy tree reports must implement this interface to be used by the + report system. + """ + @abstractmethod + def start_tree(self, option_list): + """ + Write the start of a tree. + """ + + @abstractmethod + def end_tree(self): + """ + Write the end of a tree. + """ + + @abstractmethod + def start_subgraph(self, level, subgraph_type, family, option_list=None): + """ + Write the start of a subgraph. + """ + + @abstractmethod + def end_subgraph(self, level): + """ + Write the end of a subgraph. + """ + + @abstractmethod + def write_node(self, db, level, node_type, person, marriage_flag, + option_list=None): + """ + Write the contents of a node. + """ + + +#------------------------------------------------------------------------------ +# +# TreeDocBase +# +#------------------------------------------------------------------------------ +class TreeDocBase(BaseDoc, TreeDoc): + """ + Base document generator for all Graphviz document generators. Classes that + inherit from this class will only need to implement the close function. + The close function will generate the actual file of the appropriate type. + """ + def __init__(self, options, paper_style): + BaseDoc.__init__(self, None, paper_style) + + self._filename = None + self._tex = StringIO() + self._paper = paper_style + + get_option = options.menu.get_option_by_name + + self.detail = get_option('detail').get_value() + self.marriage = get_option('marriage').get_value() + self.nodesize = get_option('nodesize').get_value() + self.levelsize = get_option('levelsize').get_value() + self.nodecolor = get_option('nodecolor').get_value() + + self.timeflow = get_option('timeflow').get_value() + self.edges = get_option('edges').get_value() + self.leveldist = get_option('leveldist').get_value() + + self.note = get_option('note').get_value() + self.noteloc = get_option('noteloc').get_value() + self.notesize = get_option('notesize').get_value() + + def write_start(self): + """ + Write the start of the document. + """ + paper_size = self._paper.get_size() + name = paper_size.get_name().lower() + if name == 'custom size': + width = str(paper_size.get_width()) + height = str(paper_size.get_width()) + paper = 'papersize={%scm,%scm}' % (width, height) + elif name in ('a', 'b', 'c', 'd', 'e'): + paper = 'ansi' + name + 'paper' + else: + paper = name + 'paper' + + if self._paper.get_orientation() == PAPER_PORTRAIT: + orientation = 'portrait' + else: + orientation = 'landscape' + + lmargin = self._paper.get_left_margin() + rmargin = self._paper.get_right_margin() + tmargin = self._paper.get_top_margin() + bmargin = self._paper.get_bottom_margin() + if lmargin == rmargin == tmargin == bmargin: + margin = 'margin=%scm'% lmargin + else: + if lmargin == rmargin: + margin = 'hmargin=%scm' % lmargin + else: + margin = 'hmargin={%scm,%scm}' % (lmargin, rmargin) + if tmargin == bmargin: + margin += ',vmargin=%scm' % tmargin + else: + margin += ',vmargin={%scm,%scm}' % (tmargin, bmargin) + + self.write(0, '\\documentclass[%s]{article}\n' % orientation) + + self.write(0, '\\IfFileExists{libertine.sty}{\n') + self.write(0, ' \\usepackage{libertine}\n') + self.write(0, '}{}\n') + + self.write(0, '\\usepackage[%s,%s]{geometry}\n' % (paper, margin)) + self.write(0, '\\usepackage[all]{genealogytree}\n') + self.write(0, '\\usepackage{color}\n') + self.write(0, '\\begin{document}\n') + + if self.nodecolor == 'preferences': + male_bg = config.get('preferences.color-gender-male-death')[1:] + female_bg = config.get('preferences.color-gender-female-death')[1:] + neuter_bg = config.get('preferences.color-gender-unknown-death')[1:] + self.write(0, '\\definecolor{male-bg}{HTML}{%s}\n' % male_bg) + self.write(0, '\\definecolor{female-bg}{HTML}{%s}\n' % female_bg) + self.write(0, '\\definecolor{neuter-bg}{HTML}{%s}\n' % neuter_bg) + + if ''.join(self.note) != '' and self.noteloc == 't': + for line in self.note: + self.write(0, '{\\%s %s}\\par\n' % (self.notesize, line)) + self.write(0, '\\bigskip\n') + + self.write(0, '\\begin{tikzpicture}\n') + + def start_tree(self, option_list): + self.write(0, '\\genealogytree[\n') + self.write(0, 'processing=database,\n') + if self.marriage: + info = self.detail + ' ' + self.marriage + else: + info = self.detail + self.write(0, 'database format=%s,\n' % info) + if self.timeflow: + self.write(0, 'timeflow=%s,\n' % self.timeflow) + if self.edges: + self.write(0, 'edges=%s,\n' % self.edges) + if self.leveldist != 5: + self.write(0, 'level distance=%smm,\n' % self.leveldist) + if self.nodesize != 25: + self.write(0, 'node size=%smm,\n' % self.nodesize) + if self.levelsize != 35: + self.write(0, 'level size=%smm,\n' % self.levelsize) + if self.nodecolor == 'none': + self.write(0, 'tcbset={male/.style={},\n') + self.write(0, ' female/.style={},\n') + self.write(0, ' neuter/.style={}},\n') + if self.nodecolor == 'preferences': + self.write(0, 'tcbset={male/.style={colback=male-bg},\n') + self.write(0, ' female/.style={colback=female-bg},\n') + self.write(0, ' neuter/.style={colback=neuter-bg}},\n') + + for option in option_list: + self.write(0, '%s,\n' % option) + + self.write(0, ']{\n') + + def end_tree(self): + self.write(0, '}\n') + + def write_end(self): + """ + Write the end of the document. + """ + self.write(0, '\\end{tikzpicture}\n') + + if ''.join(self.note) != '' and self.noteloc == 'b': + self.write(0, '\\bigskip\n') + for line in self.note: + self.write(0, '\\par{\\%s %s}\n' % (self.notesize, line)) + + self.write(0, '\\end{document}\n') + + def start_subgraph(self, level, subgraph_type, family, option_list=None): + options = ['id=%s' % family.gramps_id] + if option_list: + options.extend(option_list) + if subgraph_type == 'sandclock': + self.write(level, 'sandclock{\n') + else: + self.write(level, '%s[%s]{\n' % (subgraph_type, ','.join(options))) + + def end_subgraph(self, level): + self.write(level, '}\n') + + def write_node(self, db, level, node_type, person, marriage_flag, + option_list=None): + options = ['id=%s' % person.gramps_id] + if option_list: + options.extend(option_list) + self.write(level, '%s[%s]{\n' % (node_type, ','.join(options))) + if person.gender == Person.MALE: + self.write(level+1, 'male,\n') + elif person.gender == Person.FEMALE: + self.write(level+1, 'female,\n') + elif person.gender == Person.UNKNOWN: + self.write(level+1, 'neuter,\n') + name = person.get_primary_name() + nick = name.get_nick_name() + surn = name.get_surname() + name_parts = [self.format_given_names(name), + '\\nick{{{}}}'.format(nick) if nick else '', + '\\surn{{{}}}'.format(surn) if surn else ''] + self.write(level+1, 'name = {{{}}},\n'.format( + ' '.join([e for e in name_parts if e]))) + for eventref in person.get_event_ref_list(): + if eventref.role == EventRoleType.PRIMARY: + event = db.get_event_from_handle(eventref.ref) + self.write_event(db, level+1, event) + if marriage_flag: + for handle in person.get_family_handle_list(): + family = db.get_family_from_handle(handle) + for eventref in family.get_event_ref_list(): + if eventref.role == EventRoleType.FAMILY: + event = db.get_event_from_handle(eventref.ref) + self.write_event(db, level+1, event) + for attr in person.get_attribute_list(): + if str(attr.get_type()) == 'Occupation': + self.write(level+1, 'profession = {%s},\n' % attr.get_value()) + if str(attr.get_type()) == 'Comment': + self.write(level+1, 'comment = {%s},\n' % attr.get_value()) + for mediaref in person.get_media_list(): + media = db.get_object_from_handle(mediaref.ref) + path = media_path_full(db, media.get_path()) + if os.path.isfile(path): + self.write(level+1, 'image = {%s},\n' % path) + break # first image only + self.write(level, '}\n') + + def write_event(self, db, level, event): + """ + Write an event. + """ + modifier = None + if event.type == EventType.BIRTH: + event_type = 'birth' + if 'died' in event.description.lower(): + modifier = 'died' + if 'stillborn' in event.description.lower(): + modifier = 'stillborn' + # modifier = 'out of wedlock' + elif event.type == EventType.BAPTISM: + event_type = 'baptism' + elif event.type == EventType.ENGAGEMENT: + event_type = 'engagement' + elif event.type == EventType.MARRIAGE: + event_type = 'marriage' + elif event.type == EventType.DIVORCE: + event_type = 'divorce' + elif event.type == EventType.DEATH: + event_type = 'death' + elif event.type == EventType.BURIAL: + event_type = 'burial' + if 'killed' in event.description.lower(): + modifier = 'killed' + elif event.type == EventType.CREMATION: + event_type = 'burial' + modifier = 'cremated' + else: + return + + date = event.get_date_object() + + if date.get_calendar() == Date.CAL_GREGORIAN: + calendar = 'AD' # GR + elif date.get_calendar() == Date.CAL_JULIAN: + calendar = 'JU' + else: + calendar = '' + + if date.get_modifier() == Date.MOD_ABOUT: + calendar = 'ca' + calendar + + date_str = self.format_iso(date.get_ymd(), calendar) + if date.get_modifier() == Date.MOD_BEFORE: + date_str = '/' + date_str + elif date.get_modifier() == Date.MOD_AFTER: + date_str = date_str + '/' + elif date.is_compound(): + stop_date = self.format_iso(date.get_stop_ymd(), calendar) + date_str = date_str + '/' + stop_date + + place = _pd.display_event(db, event) + + if modifier: + event_type += '+' + self.write(level, '%s = {%s}{%s}{%s},\n' % + (event_type, date_str, place, modifier)) + elif place == '': + event_type += '-' + self.write(level, '%s = {%s},\n' % (event_type, date_str)) + else: + self.write(level, '%s = {%s}{%s},\n' % + (event_type, date_str, place)) + + def format_given_names(self, name): + """ + Format given names. + """ + first = name.get_first_name() + call = name.get_call_name() + if call: + if call in first: + where = first.index(call) + return '{before}\\pref{{{call}}}{after}'.format( + before=first[:where], + call=call, + after=first[where+len(call):]) + else: + # ignore erroneous call name + return first + else: + return first + + def format_iso(self, date_tuple, calendar): + """ + Format an iso date. + """ + year, month, day = date_tuple + if year == 0: + iso_date = '' + elif month == 0: + iso_date = str(year) + elif day == 0: + iso_date = '%s-%s' % (year, month) + else: + iso_date = '%s-%s-%s' % (year, month, day) + if calendar and calendar != 'AD': + iso_date = '(%s)%s' % (calendar, iso_date) + return iso_date + + def write(self, level, text): + """ + Write indented text. + """ + self._tex.write(' '*level + text) + + def open(self, filename): + """ Implement TreeDocBase.open() """ + self._filename = os.path.normpath(os.path.abspath(filename)) + self.write_start() + + def close(self): + """ + This isn't useful by itself. Other classes need to override this and + actually generate a file. + """ + self.write_end() + + +#------------------------------------------------------------------------------ +# +# TreeTexDoc +# +#------------------------------------------------------------------------------ +class TreeTexDoc(TreeDocBase): + """ + TreeTexDoc implementation that generates a .tex file. + """ + + def close(self): + """ Implements TreeDocBase.close() """ + TreeDocBase.close(self) + + # Make sure the extension is correct + if self._filename[-4:] != ".tex": + self._filename += ".tex" + + with open(self._filename, "w") as texfile: + texfile.write(self._tex.getvalue()) + + +#------------------------------------------------------------------------------ +# +# TreePdfDoc +# +#------------------------------------------------------------------------------ +class TreePdfDoc(TreeDocBase): + """ + TreePdfDoc implementation that generates a .pdf file. + """ + + def close(self): + """ Implements TreeDocBase.close() """ + TreeDocBase.close(self) + + # Make sure the extension is correct + if self._filename[-4:] != ".pdf": + self._filename += ".pdf" + + with tempfile.TemporaryDirectory() as tmpdir: + with open(os.path.join(tmpdir, 'temp.tex'), "w") as texfile: + texfile.write(self._tex.getvalue()) + os.system('lualatex -output-directory %s temp.tex >/dev/null' + % tmpdir) + shutil.copy(os.path.join(tmpdir, 'temp.pdf'), self._filename) + + +#------------------------------------------------------------------------------ +# +# Various Genealogy Tree formats. +# +#------------------------------------------------------------------------------ +FORMATS = [] + +if _LATEX_FOUND: + FORMATS += [{'type' : "pdf", + 'ext' : "pdf", + 'descr': _("PDF"), + 'mime' : "application/pdf", + 'class': TreePdfDoc}] + +FORMATS += [{'type' : "tex", + 'ext' : "tex", + 'descr': _("LaTeX File"), + 'mime' : "application/x-latex", + 'class': TreeTexDoc}] diff -Nru gramps-4.2.6~dfsg/gramps/gen/plug/__init__.py gramps-4.2.8~dfsg/gramps/gen/plug/__init__.py --- gramps-4.2.6~dfsg/gramps/gen/plug/__init__.py 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/gen/plug/__init__.py 2018-02-09 21:05:56.000000000 +0000 @@ -27,7 +27,7 @@ from ._plugin import Plugin from ._pluginreg import (PluginData, PluginRegister, REPORT, TOOL, CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE, - CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ, + CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ, CATEGORY_TREE, TOOL_DEBUG, TOOL_ANAL, TOOL_DBPROC, TOOL_DBFIX, TOOL_REVCTL, TOOL_UTILS, CATEGORY_QR_MISC, CATEGORY_QR_PERSON, CATEGORY_QR_FAMILY, CATEGORY_QR_EVENT, CATEGORY_QR_SOURCE, @@ -49,7 +49,7 @@ PluginRegister, BasePluginManager, ImportPlugin, ExportPlugin, DocGenPlugin, REPORT, TOOL, CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE, - CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ, + CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ, CATEGORY_TREE, TOOL_DEBUG, TOOL_ANAL, TOOL_DBPROC, TOOL_DBFIX, TOOL_REVCTL, TOOL_UTILS, CATEGORY_QR_MISC, CATEGORY_QR_PERSON, CATEGORY_QR_FAMILY, CATEGORY_QR_EVENT, CATEGORY_QR_SOURCE, diff -Nru gramps-4.2.6~dfsg/gramps/gen/plug/_pluginreg.py gramps-4.2.8~dfsg/gramps/gen/plug/_pluginreg.py --- gramps-4.2.6~dfsg/gramps/gen/plug/_pluginreg.py 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/gen/plug/_pluginreg.py 2018-02-09 21:05:56.000000000 +0000 @@ -94,8 +94,10 @@ CATEGORY_WEB = 3 CATEGORY_BOOK = 4 CATEGORY_GRAPHVIZ = 5 +CATEGORY_TREE = 6 REPORT_CAT = [ CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE, - CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ] + CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ, + CATEGORY_TREE] #possible tool categories TOOL_DEBUG = -1 TOOL_ANAL = 0 @@ -1009,6 +1011,7 @@ 'CATEGORY_WEB': CATEGORY_WEB, 'CATEGORY_BOOK': CATEGORY_BOOK, 'CATEGORY_GRAPHVIZ': CATEGORY_GRAPHVIZ, + 'CATEGORY_TREE': CATEGORY_TREE, 'TOOL_DEBUG': TOOL_DEBUG, 'TOOL_ANAL': TOOL_ANAL, 'TOOL_DBPROC': TOOL_DBPROC, diff -Nru gramps-4.2.6~dfsg/gramps/gen/plug/report/_book.py gramps-4.2.8~dfsg/gramps/gen/plug/report/_book.py --- gramps-4.2.6~dfsg/gramps/gen/plug/report/_book.py 2017-08-01 09:04:28.000000000 +0000 +++ gramps-4.2.8~dfsg/gramps/gen/plug/report/_book.py 2018-02-09 21:05:56.000000000 +0000 @@ -457,79 +457,98 @@ """ Saves the current BookList to the associated file. """ - f = open(self.file, "w") - f.write("\n") - f.write('\n') - for name in sorted(self.bookmap): # enable a diff of archived copies - book = self.get_book(name) - dbname = book.get_dbname() - f.write('\n' % (name, dbname) ) - for item in book.get_item_list(): - f.write(' \n' % - (item.get_name(),item.get_translated_name() ) ) - options = item.option_class.handler.options_dict - for option_name in sorted(options.keys()): # enable a diff - option_value = options[option_name] - if isinstance(option_value, (list, tuple)): - f.write(' \n') - else: - option_type = type_name(option_value) - value = escape(str(option_value)) - value = value.replace('"', '"') - f.write('