From 367de337a4bdd8e7c4435296ecdd07917efa1dec Mon Sep 17 00:00:00 2001 From: Tim G L Lyons Date: Mon, 12 Aug 2013 16:04:37 +0000 Subject: [PATCH] - Move citeref formatting to gen.utils. Functions now have a db parameter, so they find the template themselves. - Separate out the GEDCOM template creation. It becomes a separate plugin that can be loaded or not as the user chooses (but it is loaded automatically on upgrade). - Fixes to allow templates to work even when no templates are loaded (data is input via the Attributes tab not the source template tab). - Enhance upgrade to include GEDCOM template. The GEDCOM template is automatically loaded when a database that contains sources is upgraded. - Tidy up unused variables and redundant code. svn: r22856 --- gramps/gen/db/upgrade.py | 26 +- gramps/gen/db/write.py | 11 +- gramps/gen/lib/srcattrtype.py | 31 -- gramps/gen/lib/srctemplate.py | 364 +------------- gramps/gen/utils/citeref.py | 448 ++++++++++++++++++ .../editors/displaytabs/citationrefmodel.py | 10 +- .../gui/editors/displaytabs/srctemplatetab.py | 9 +- gramps/gui/editors/editsource.py | 36 +- .../gui/views/treemodels/citationbasemodel.py | 11 +- gramps/gui/views/treemodels/sourcemodel.py | 7 +- gramps/gui/widgets/srctemplatetreeview.py | 4 +- .../plugins/srctemplates/evidenceexplained.py | 1 + .../srctemplates/gedcomtemplate.gpr.py | 41 ++ gramps/plugins/srctemplates/gedcomtemplate.py | 193 ++++++++ gramps/plugins/srctemplates/importcsv.py | 184 ++----- 15 files changed, 788 insertions(+), 588 deletions(-) create mode 100644 gramps/gen/utils/citeref.py create mode 100644 gramps/plugins/srctemplates/gedcomtemplate.gpr.py create mode 100644 gramps/plugins/srctemplates/gedcomtemplate.py diff --git a/gramps/gen/db/upgrade.py b/gramps/gen/db/upgrade.py index 37dd53213..7a8fae2ef 100644 --- a/gramps/gen/db/upgrade.py +++ b/gramps/gen/db/upgrade.py @@ -148,25 +148,39 @@ def gramps_upgrade_17(self): from ..lib.srcattrtype import SrcAttributeType private = False + first = True for handle in self.source_map.keys(): + if first: + from gramps.plugins.srctemplates.gedcomtemplate import build_GEDCOM_template + template = build_GEDCOM_template() + if isinstance(template.handle, UNITYPE): + template.handle = template.handle.encode('utf-8') + teml_handle = template.handle + from gramps.gen.lib.srctemplate import SrcTemplate + template = SrcTemplate.serialize(template) + with BSDDBTxn(self.env, self.template_map) as txn: + txn.put(teml_handle, template) + with BSDDBTxn(self.env, self.metadata) as txn: + txn.put(b'gedcom_template', teml_handle) + first = False + source = self.source_map[handle] (handle, gramps_id, title, author, pubinfo, notelist, medialist, abbrev, change, datamap, reporef_list, taglist, private) = source srcattributelist = upgrade_datamap_17(datamap) if title: - the_type = (SrcAttributeType.TITLE, '') + the_type = (SrcAttributeType.CUSTOM, SrcAttributeType.TITLE) srcattributelist.append((private, the_type, title)) if author: - the_type = (SrcAttributeType.AUTHOR, '') + the_type = (SrcAttributeType.CUSTOM, SrcAttributeType.AUTHOR) srcattributelist.append((private, the_type, author)) if pubinfo: - the_type = (SrcAttributeType.PUB_INFO, '') + the_type = (SrcAttributeType.CUSTOM, SrcAttributeType.PUB_INFO) srcattributelist.append((private, the_type, pubinfo)) name = title - template = 'GEDCOM' - new_source = (handle, gramps_id, name, template, + new_source = (handle, gramps_id, name, teml_handle, notelist, medialist, abbrev, change, srcattributelist, reporef_list, taglist, private) with BSDDBTxn(self.env, self.source_map) as txn: @@ -181,7 +195,7 @@ def gramps_upgrade_17(self): notelist, medialist, datamap, change, taglist, private) = citation srcattributelist = upgrade_datamap_17(datamap) if page: - the_type = (SrcAttributeType.PAGE, '') + the_type = (SrcAttributeType.CUSTOM, SrcAttributeType.PAGE) srcattributelist.append((private, the_type, page)) name = page diff --git a/gramps/gen/db/write.py b/gramps/gen/db/write.py index a3feae345..03037b9ac 100644 --- a/gramps/gen/db/write.py +++ b/gramps/gen/db/write.py @@ -281,6 +281,9 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback): self.brief_name = None self.update_env_version = False self.update_python_version = False + # Whether SrcTemplates need to be loaded. They need to be loaded on + # creating a new database, and on upgrade from schema version 16 to 17. + self.load_templates = False def catch_db_error(func): """ @@ -672,6 +675,7 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback): self.__load_metadata() gstats = self.metadata.get(b'gender_stats', default=None) + self.load_templates = False # Ensure version info in metadata if not self.readonly: @@ -681,6 +685,7 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback): # New database. Set up the current version. #self.metadata.put(b'version', _DBVERSION, txn=the_txn) txn.put(b'version', _DBVERSION) + self.load_templates = True elif b'version' not in self.metadata: # Not new database, but the version is missing. # Use 0, but it is likely to fail anyway. @@ -769,7 +774,7 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback): self.__open_undodb() self.db_is_open = True - if gstats is None: + if self.load_templates: # FIXME gstat is used as a proxy to say whether the database is new # or not, This is not a very clean approach from gramps.plugins.srctemplates.importcsv import load_srctemplates_data @@ -2214,6 +2219,10 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback): upgrade.gramps_upgrade_16(self) if version < 17: upgrade.gramps_upgrade_17(self) + # On upgrade from 16 to 17, SrcTemplate is added, so the templates + # need to be loaded. In the future, on upgrade from 17, the + # templates will already be present and will not need to be loaded + self.load_templates = True self.reset() self.set_total(6) diff --git a/gramps/gen/lib/srcattrtype.py b/gramps/gen/lib/srcattrtype.py index 45bdfed43..98b8ec17f 100644 --- a/gramps/gen/lib/srcattrtype.py +++ b/gramps/gen/lib/srcattrtype.py @@ -40,37 +40,6 @@ _ = glocale.translation.gettext #------------------------------------------------------------------------- from .grampstype import GrampsType -#------------------------------------------------------------------------- -# -# Template constants -# -#------------------------------------------------------------------------- - -REF_TYPE_F = 1 # Full footnote citation to a source -REF_TYPE_S = 2 # Short footnote citation to a source -REF_TYPE_L = 3 # Listed reference of the source (no citation info) - -EMPTY = 0 -# template to GEDCOM field mapping for L reference fields -GED_AUTHOR = 1 -GED_TITLE = 2 -GED_PUBINF = 3 -# template to GEDCOM field mapping for Date in F reference fields -GED_DATE = 4 -GED_PAGE = 5 -# template to a shortening algorithm mapping for predefined algorithms -SHORTERALG_LOC = 1 # reduce a location to a shorter format (typically city level) -SHORTERALG_YEAR = 2 # reduce a date to only the year part -SHORTERALG_ETAL = 3 # reduce an author list to "first author et al." -SHORTERALG_REVERT_TO_DOT = 4 # change a list of first, second, third to - # a list third. second. first. -# template to a style mapping -STYLE_QUOTE = 1 # add quotes around the field -STYLE_QUOTECONT = 2 # add quotes around this field combined with other - # QUOTECONT fields around it -STYLE_EMPH = 3 # emphasize field -STYLE_BOLD = 4 # make field bold - #------------------------------------------------------------------------- # # Classes diff --git a/gramps/gen/lib/srctemplate.py b/gramps/gen/lib/srctemplate.py index e232fdb39..3f5aa508a 100644 --- a/gramps/gen/lib/srctemplate.py +++ b/gramps/gen/lib/srctemplate.py @@ -32,8 +32,7 @@ SrcTemplate class for GRAMPS. # #------------------------------------------------------------------------- from __future__ import print_function -from collections import defaultdict, OrderedDict -import sys +from collections import defaultdict #------------------------------------------------------------------------ # @@ -48,38 +47,11 @@ LOG = logging.getLogger('.template') # GRAMPS modules # #------------------------------------------------------------------------- -from ..const import GRAMPS_LOCALE as glocale -_ = glocale.translation.gettext -from .srcattrtype import * -from .date import Date from .tableobj import TableObject from .secondaryobj import SecondaryObject from .handle import Handle from ..constfunc import cuni -#columns in a csv file defining templates -NRCOL = 0 -CATCOL = 1 -CATTYPECOL = 2 -TYPECOL = 3 -DESCRCOL= 4 -CITETYPECOL = 5 -IDENTCOL = 6 -LDELCOL = 7 # left delimiter -FIELDCOL = 8 -LABELCOL = 9 -RDELCOL = 10 # right delimiter -GEDCOMCOL = 11 -SHORTERCOL = 12 -STYLECOL = 13 -PRIVACYCOL = 14 -OPTCOL = 15 -HINTCOL = 16 -TOOLTIPCOL = 17 - -UNKNOWN = 'UNKNOWN' -DESCR = -10 - #------------------------------------------------------------------------- # # SrcTemplate class @@ -130,7 +102,6 @@ class SrcTemplate(TableObject): 7/ the REF_TYPE_L reference maps to GEDCOM fields on export via this column. GEDCOM contains Title, Author and Pub.Info field """ - UNKNOWN = UNKNOWN def __init__(self, template_key=None): """ @@ -145,9 +116,6 @@ class SrcTemplate(TableObject): self.descr = "" self.template_element_list = [] self.mapdict = defaultdict(str) - self.structure = {REF_TYPE_L: [], REF_TYPE_F: [], - REF_TYPE_S: []} - self.empty() def serialize(self): """ @@ -172,7 +140,7 @@ class SrcTemplate(TableObject): self.name, self.descr, [template_element.serialize() for template_element in self.template_element_list], - self.mapdict, + self.mapdict ) def to_struct(self): @@ -199,7 +167,7 @@ class SrcTemplate(TableObject): "name": cuni(self.name), "descr": cuni(self.descr), "elements": [e.to_struct() for e in self.template_element_list], - "mapdict" : self.mapdict, + "mapdict" : {'dict': self.mapdict} } def unserialize(self, data): @@ -257,332 +225,6 @@ class SrcTemplate(TableObject): def add_template_element(self, template_element): self.template_element_list.append(template_element) - def add_structure_element(self, cite_type, slist): - self.structure[cite_type] += slist - - def get_structure(self): - return self.structure - - def empty(self): - """ - remove all computed data - """ - self.refL = None - self.refF = None - self.refS = None - # attrmap will hold mapping of field to normal value and short value - # short value will be None if not given - # map is field -> (normal value for ref L, - # normal value for ref F/S, short value ref S) - self.attrmap = {} - self.input_dict = defaultdict(str) - - def set_attr_list(self, attr_list, attr_list_citation=None, date_citation=None): - """ - Set the attribute list of this template. Setting once for different - references saves some time. - attr_list should be the source attribute list - If citation given, citation attrib - utes overrule source attributes for - the Full and Short references - The citation date is not stored as attribute, so pass Date() object via - date_citation if a date is known. - """ - self.empty() - self.attrmap = {} - self.input_dict = defaultdict(str) - self.attr_list = attr_list or [] - self.attr_list_cite = attr_list_citation or [] - self.date_citation = date_citation - - # ----------------------------------------------------------------- - # Construct the input dictionary - # First pre-load the dictionary with default settings for citations - if not attr_list_citation: - for te in [x for x in self.get_template_element_list() - if x.get_citation()]: - name = str(SrcAttributeType(te.get_name())).upper().replace(' ', '_') - if te.get_display(): - val = te.get_display().upper().replace(' ', '_') - else: - val = name - self.input_dict[name] = "[" + val + "]" - - # Now get the actual attribute values. store attributes in a dict last - # to first. this overwrites data so first attribute will be the one - # taken if duplicates are present - for input_attr in ((attr_list or []) + (attr_list_citation or []))[::-1]: - typ = input_attr.get_type() - if int(typ) == SrcAttributeType.CUSTOM: - name = str(typ).upper().replace(' ', '_') - else: - name = typ.xml_str().upper().replace(' ', '_') - self.input_dict[name] = input_attr.get_value() - # if we haven't already got a value for the short attribute, we - # store the long attribute in the short attribute - if not name.endswith("(SHORT)"): - short_name = name + "_(SHORT)" - if self.input_dict.get(short_name) is None or \ - (self.input_dict.get(short_name) and \ - self.input_dict[short_name] == ("[" + short_name + "]")): - self.input_dict[short_name] = self.input_dict[name] - - if self.date_citation and (not self.date_citation.is_empty()): - #we store the date of the citation in attrmap - name = SrcAttributeType.DATE.upper().replace(' ', '_') - txt = str(self.date_citation) - self.input_dict[name] = txt - short_name = name + "_(SHORT)" - if self.input_dict.get(short_name) is None or \ - (self.input_dict.get(short_name) and \ - self.input_dict[short_name] == ("[" + short_name + "]")): - self.input_dict[short_name] = txt - - # FIXME: REPOSITORY, REPOSITORY_ADDRESS and REPOSITORY_CALL_NUMBER all - # need to be added to the self.input_dict. See srctemplatetab.py - # _add_repo_entry() - - def reference_L(self, attr_list=None): - """ - Return the list reference based on the passed source attribute list - If attr_list is None, same list as before is used. - """ - if attr_list: - self.set_attr_list(attr_list) - if self.refL is not None: - return self.refL - self.refL = self._reference(REF_TYPE_L) - return self.refL - - def reference_S(self, attr_list=None, attr_list_citation=None, date_citation=None): - """ - Return the short reference based on the passed source attribute list - If attr_list is None, same list as - before is used. - """ - if attr_list or attr_list_citation or date_citation: - self.set_attr_list(attr_list, attr_list_citation, date_citation) - if self.refS is not None: - return self.refS - self.refS = self._reference(REF_TYPE_S) - return self.refS - - def reference_F(self, attr_list=None, attr_list_citation=None, date_citation=None): - """ - Return the full reference based on the passed source attribute list - If attr_list is None, same list as before is used. - """ - if attr_list or attr_list_citation or date_citation: - self.set_attr_list(attr_list, attr_list_citation, date_citation) - if self.refF is not None: - return self.refF - self.refF = self._reference(REF_TYPE_F) - return self.refF - - def _reference(self, reftype, gedcomfield=None): - """ - Compute the reference based on data present. - """ - # http://bugs.python.org/issue6081 - class DefaultBlank(dict): - def __missing__(self, key): - return "" - - class DefaultKey(dict): - def __missing__(self, key): - return "[" + key + "]" - - ged_table = { - GED_AUTHOR : "GEDCOM_A", - GED_TITLE : "GEDCOM_T", - GED_PUBINF : "GEDCOM_P", - GED_DATE : "GEDCOM_D", - GED_PAGE : "GEDCOM_PAGE", - } - if gedcomfield: - return (self.get_map_element(ged_table[gedcomfield]) % - DefaultKey(self.input_dict)) or "" - - use_CSL = False - try: - import citeproc - if sys.version_info[0] >= 3: - use_CSL = True - except: - pass - - if use_CSL: - # ----------------------------------------------------------------- - # Construct the standard output-elements - self.output_dict = OrderedDict() - LOG.debug(self.get_map_dict()) - LOG.debug("input_attributes \n" + - "".join(("%s: %s\n" % item) for item in list(self.input_dict.items()))) - for key, val in list(self.get_map_dict().items()): - if key[0].islower(): - try: - self.output_dict[key] = val % DefaultBlank(self.input_dict) - except: - LOG.warn("key error with key %s; val %s; input_dict %s" % - (key, val, self.input_dict)) - self.output_dict[key] = "" - - LOG.debug("CSL_attributes \n" + - "".join(("%s: %s\n" % item) for item in list(self.output_dict.items()))) - - # Temporary fix for not implemented yet templates - if len(self.output_dict) == 0: - return "" - - # Now fix CSL attributes that need special sub-elements - for name in ["author", "container_author", "some other name"]: - if name in self.output_dict: - self.output_dict[name] = [{"family": self.output_dict[name], - "given": ""}] - # ----------------------------------------------------------------- - # Modify the output-elements to allow the standard Chicago style to - # format the citations close to Evidence Style - - # literal dates are not specially treated. Date accessed is converted to - # a literal publication date to conform to how ESM formats the accessed - # date - if "accessed" in self.output_dict: - self.output_dict["issued"] = {'literal' : "accessed " + self.output_dict['accessed']} - del self.output_dict['accessed'] - # Website is rendered as publisher_place to conform to how ESM renders - # it. - if "url" in self.output_dict: - self.output_dict["publisher_place"] = \ - self.output_dict["publisher_place"] if "publisher_place" in self.output_dict \ - else "" + self.output_dict["url"] - LOG.debug("self.output_dictibutes modified \n" + - "".join((" %s: %s\n" % item) for item in self.output_dict.items())) - - try: - (refF, refS, refL) = self.get_CSL_references(self.output_dict) - if reftype == REF_TYPE_F: - return refF - elif reftype == REF_TYPE_S: - return refS - else: - return refL - except: - print(sys.exc_info()[0], sys.exc_info()[1]) - return "" - - else: - # ----------------------------------------------------------------- - # Construct the standard output-elements - ref_table = { - REF_TYPE_L : "EE_L", - REF_TYPE_F : "EE_F", - REF_TYPE_S : "EE_S", - } - return (self.get_map_element(ref_table[reftype]) % - DefaultKey(self.input_dict)) or "" - - def get_CSL_references(self, CSL_attributes): - # Import the citeproc-py classes we'll use below. - from citeproc import CitationStylesStyle, CitationStylesBibliography - from citeproc import Citation, CitationItem - from citeproc import formatter, Locator - from citeproc.source.json import CiteProcJSON - - # Process the JSON data to generate a citeproc-py BibliographySource. - if 'locator' in CSL_attributes: - loc = Locator("page", CSL_attributes["locator"]) - - import copy - c1 = copy.deepcopy(CSL_attributes) - c2 = copy.deepcopy(CSL_attributes) - - bib_source = {"full": c1, "subs" : c2} - bib_source = {"full": c1} - -# for key, entry in bib_source.items(): -# print(key) -# for name, value in entry.items(): -# print(' {}: {}'.format(name, value)) - - # load a CSL style (from the current directory) - - bib_style = CitationStylesStyle('chicago-fullnote-bibliography-no-ibid.csl') - - # Create the citeproc-py bibliography, passing it the: - # * CitationStylesStyle, - # * BibliographySource (CiteProcJSON in this case), and - # * a formatter (plain, html, or you can write a custom formatter) - - bibliography = CitationStylesBibliography(bib_style, bib_source, formatter.plain) - - - # Processing citations in a document need to be done in two passes as for some - # CSL styles, a citation can depend on the order of citations in the - # bibliography and thus on citations following the current one. - # For this reason, we first need to register all citations with the - # CitationStylesBibliography. - - if loc: - citation1 = Citation([CitationItem('full', locator=loc)]) - citation2 = Citation([CitationItem('subs', locator=loc)]) - else: - citation1 = Citation([CitationItem('full')]) - citation2 = Citation([CitationItem('subs')]) - - citation1 = Citation([CitationItem('full')]) - - bibliography.register(citation1) - bibliography.register(citation2) - - - # In the second pass, CitationStylesBibliography can generate citations. - # CitationStylesBibliography.cite() requires a callback function to be passed - # along to be called in case a CitationItem's key is not present in the - # bilbiography. - - def warn(citation_item): - print("WARNING: Reference with key '{}' not found in the bibliography." - .format(citation_item.key)) - - print('Citations') - print('---------') - - print(bibliography.cite(citation1, warn)) - print(bibliography.cite(citation2, warn)) - - - # And finally, the bibliography can be rendered. - - print('') - print('Bibliography') - print('------------') - - print(bibliography.bibliography()) - - return(bibliography.cite(citation1, warn), - bibliography.cite(citation2, warn), - bibliography.bibliography()) - - def author_gedcom(self, attr_list=None): - if attr_list: - self.set_attr_list(attr_list) - return self._reference(REF_TYPE_L, GED_AUTHOR) - - def title_gedcom(self, attr_list=None): - if attr_list: - self.set_attr_list(attr_list) - return self._reference(REF_TYPE_L, GED_TITLE) - - def pubinfo_gedcom(self, attr_list=None): - if attr_list: - self.set_attr_list(attr_list) - return self._reference(REF_TYPE_L, GED_PUBINF) - - def page_gedcom(self, attr_list=None): - if attr_list: - self.set_attr_list(attr_list) - return self._reference(REF_TYPE_F, GED_PAGE) - class TemplateElement(SecondaryObject): """ TemplateEelement class. diff --git a/gramps/gen/utils/citeref.py b/gramps/gen/utils/citeref.py new file mode 100644 index 000000000..6e9db4f7c --- /dev/null +++ b/gramps/gen/utils/citeref.py @@ -0,0 +1,448 @@ +# -*- coding: utf-8 -*- +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2013 Benny Malengier +# Copyright (C) 2013 Tim G L Lyons +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# $Id$ + +""" +Utility functions to create citation references for Gramps Sources and +Citations. +""" + +#------------------------------------------------------------------------- +# +# Python modules +# +#------------------------------------------------------------------------- +from __future__ import print_function +from collections import defaultdict, OrderedDict +import sys + +#------------------------------------------------------------------------- +# +# GRAMPS modules +# +#------------------------------------------------------------------------- +from ..const import GRAMPS_LOCALE as glocale +_ = glocale.translation.gettext +from gramps.gen.lib.srcattrtype import SrcAttributeType + +#------------------------------------------------------------------------ +# +# Set up logging +# +#------------------------------------------------------------------------ +import logging +LOG = logging.getLogger('.template') + +#------------------------------------------------------------------------- +# +# The functions are passed either a Source object or a Citation object or both. +# They call set_input_dict_and_template to construct a dictionary of template input elements +# to values. This dictionary includes the Date value and any Repository values +# although these are not stored as attributes. +# +# For the GEDCOM fields, the mapping is done immediately. For the bibliographic +# items, 'reference' is called to construct the various citation references. +# +#------------------------------------------------------------------------- + +# The predefined template mappings are given names starting with underscore so +# they can be distinguished from CSL mappings. +REF_TYPE_F = "_full" # Full footnote citation to a source +REF_TYPE_S = "_subsequent" # Short footnote citation to a source +REF_TYPE_L = "_bibliography" # Listed reference of the source (no citation info) +GED_AUTHOR = "_GEDCOM_A" +GED_TITLE = "_GEDCOM_T" +GED_PUBINF = "_GEDCOM_P" +GED_DATE = "_GEDCOM_D" +GED_PAGE = "_GEDCOM_PAGE" + +refL = None +refF = None +refS = None +input_dict = defaultdict(str) +template_cache = None + +def reference_L(db, source=None): + """ + Return the list reference (bibliography entry) based on the passed source + If source is None, the same input_dict as before is used. + """ + global refL + if source: + set_input_dict_and_template(db, source) + if refL is not None: + return refL + refL = _reference(db, REF_TYPE_L) + return refL + +def reference_S(db, source=None, citation=None): + """ + Return the short reference based on the passed source and/or citation + If both source and citation are None, the same list as before is used. + """ + global refS + if source or citation: + set_input_dict_and_template(db, source, citation) + if refS is not None: + return refS + refS = _reference(db, REF_TYPE_S) + return refS + +def reference_F(db, source=None, citation=None): + """ + Return the full reference based on the passed source and/or citation + If both source and citation are None, the same list as before is used. + """ + global refF + if source or citation: + set_input_dict_and_template(db, source, citation) + if refF is not None: + return refF + refF = _reference(db, REF_TYPE_F) + return refF + +def get_gedcom_title(db, source=None): + global template_cache, source_cache + if source: + set_input_dict_and_template(db, source) + if template_cache is None: + if source: + return source.get_name() + else: + return source_cache.get_name() + return (template_cache.get_map_element(GED_TITLE) % + DefaultKey(input_dict)) or "" + +def get_gedcom_author(db, source=None): + global template_cache, source_cache + if source: + set_input_dict_and_template(db, source) + if template_cache is None: + return "author not available" + return (template_cache.get_map_element(GED_AUTHOR) % + DefaultKey(input_dict)) or "" + +def get_gedcom_pubinfo(db, source=None): + global template_cache, source_cache + if source: + set_input_dict_and_template(db, source) + if template_cache is None: + return "pubinfo not available" + return (template_cache.get_map_element(GED_PUBINF) % + DefaultKey(input_dict)) or "" + +def get_gedcom_page(db, citation=None): + global template_cache + if citation: + set_input_dict_and_template(db, source=None, citation=citation) + if template_cache is None: + return "page not available" + return (template_cache.get_map_element(GED_PAGE) % + DefaultKey(input_dict)) or "" + +# http://bugs.python.org/issue6081 +class DefaultBlank(dict): + def __missing__(self, key): + return "" + +class DefaultKey(dict): + def __missing__(self, key): + return "[" + key + "]" + +def empty(): + """ + remove all computed data + """ + global refL, refF, refS, input_dict, template_cache, source_cache + refL = None + refF = None + refS = None + input_dict = defaultdict(str) + template_cache = None + source_cache = None + +def set_input_dict_and_template(db, source=None, citation=None): + """ + Set the attribute dictionary of this template. Setting once for different + references saves some time. + attr_list should be the source attribute list + If citation given, citation attributes overrule source attributes for + the Full and Short references + The citation date is not stored as attribute, so pass Date() object via + date_citation if a date is known. + """ + global refL, refF, refS, input_dict, template_cache, source_cache + empty() + + # Find the template + if not source and not citation: + # No source and no citation + raise NotImplementedError + elif not source: + # Citation and no source + # citation will be used to obtain the source + source_handle = citation.get_reference_handle() + source_cache = db.get_source_from_handle(source_handle) + template_handle = source_cache.get_template() + if template_handle is None: + return + template_cache = db.get_template_from_handle(template_handle) + attr_list = source_cache.get_attribute_list() + citation.get_attribute_list() + date_citation = citation.get_date_object() + elif citation: + #source and citation are given + source_cache = source + # FIXME: as both a source and a citation have been given, they should be + # connected, so a check for that should be made here. However, in + # editsource, the 'refernce_handle' for a new citation to an existing + # source is only set in __base_save when data is saved to the database. + # Hence the check cannot be done at the moment. +# if not (citation.get_reference_handle() == source_cache.handle): +# raise Exception('Citation must be a Citation of the Source being cited') + template_handle = source_cache.get_template() + if template_handle is None: + return + template_cache = db.get_template_from_handle(template_handle) + attr_list = source_cache.get_attribute_list() + citation.get_attribute_list() + date_citation = citation.get_date_object() + else: + # Source and no citation + source_cache = source + template_handle = source_cache.get_template() + if template_handle is None: + return + template_cache = db.get_template_from_handle(template_handle) + attr_list = source_cache.get_attribute_list() + date_citation = None + + # ----------------------------------------------------------------- + # Construct the input dictionary + # First pre-load the dictionary with default settings for citations + if not citation: + for te in [x for x in template_cache.get_template_element_list() + if x.get_citation()]: + name = str(SrcAttributeType(te.get_name())).upper().replace(' ', '_') + if te.get_display(): + val = te.get_display().upper().replace(' ', '_') + else: + val = name + input_dict[name] = "[" + val + "]" + + # Now get the actual attribute values. store attributes in a dict last + # to first. this overwrites data so first attribute will be the one + # taken if duplicates are present + for input_attr in attr_list[::-1]: + typ = input_attr.get_type() + if typ.is_custom(): + name = str(typ).upper().replace(' ', '_') + else: + name = typ.xml_str().upper().replace(' ', '_') + input_dict[name] = input_attr.get_value() + # if we haven't already got a value for the short attribute, we + # store the long attribute in the short attribute + if not name.endswith("(SHORT)"): + short_name = name + "_(SHORT)" + if input_dict.get(short_name) is None or \ + (input_dict.get(short_name) and \ + input_dict[short_name] == ("[" + short_name + "]")): + input_dict[short_name] = input_dict[name] + + if date_citation and (not date_citation.is_empty()): + #we store the date of the citation + name = SrcAttributeType.DATE.upper().replace(' ', '_') + txt = str(date_citation) + input_dict[name] = txt + short_name = name + "_(SHORT)" + if input_dict.get(short_name) is None or \ + (input_dict.get(short_name) and \ + input_dict[short_name] == ("[" + short_name + "]")): + input_dict[short_name] = txt + + # FIXME: REPOSITORY, REPOSITORY_ADDRESS and REPOSITORY_CALL_NUMBER all + # need to be added to the input_dict. See srctemplatetab.py + # _add_repo_entry() + +def _reference(self, reftype): + """ + Compute the reference based on data present. + """ + global refL, refF, refS, input_dict, template_cache + + if template_cache is None: + return "" + + use_CSL = False + try: + import citeproc + if sys.version_info[0] >= 3: + use_CSL = True + except: + pass + + if use_CSL: + # ----------------------------------------------------------------- + # Construct the standard output-elements + self.output_dict = OrderedDict() + LOG.debug(self.get_map_dict()) + LOG.debug("input_attributes \n" + + "".join(("%s: %s\n" % item) for item in list(input_dict.items()))) + for key, val in list(self.get_map_dict().items()): + if not key.startswith("_"): + try: + self.output_dict[key] = val % DefaultBlank(input_dict) + except: + LOG.warn("key error with key %s; val %s; input_dict %s" % + (key, val, input_dict)) + self.output_dict[key] = "" + + LOG.debug("CSL_attributes \n" + + "".join(("%s: %s\n" % item) for item in list(self.output_dict.items()))) + + # Temporary fix for not implemented yet templates + if len(self.output_dict) == 0: + return "" + + # Now fix CSL attributes that need special sub-elements + for name in ["author", "container_author", "some other name"]: + if name in self.output_dict: + self.output_dict[name] = [{"family": self.output_dict[name], + "given": ""}] + # ----------------------------------------------------------------- + # Modify the output-elements to allow the standard Chicago style to + # format the citations close to Evidence Style + + # literal dates are not specially treated. Date accessed is converted to + # a literal publication date to conform to how ESM formats the accessed + # date + if "accessed" in self.output_dict: + self.output_dict["issued"] = {'literal' : "accessed " + self.output_dict['accessed']} + del self.output_dict['accessed'] + # Website is rendered as publisher_place to conform to how ESM renders + # it. + if "url" in self.output_dict: + self.output_dict["publisher_place"] = \ + self.output_dict["publisher_place"] if "publisher_place" in self.output_dict \ + else "" + self.output_dict["url"] + LOG.debug("self.output_dictibutes modified \n" + + "".join((" %s: %s\n" % item) for item in self.output_dict.items())) + + try: + (refF, refS, refL) = self.get_CSL_references(self.output_dict) + if reftype == REF_TYPE_F: + return refF + elif reftype == REF_TYPE_S: + return refS + else: + return refL + except: + print(sys.exc_info()[0], sys.exc_info()[1]) + return "" + + else: + # ----------------------------------------------------------------- + # Construct the standard output-elements + return (template_cache.get_map_element(reftype) % + DefaultKey(input_dict)) or "" + +def get_CSL_references(self, CSL_attributes): + # Import the citeproc-py classes we'll use below. + from citeproc import CitationStylesStyle, CitationStylesBibliography + from citeproc import Citation, CitationItem + from citeproc import formatter, Locator + from citeproc.source.json import CiteProcJSON + + # Process the JSON data to generate a citeproc-py BibliographySource. + if 'locator' in CSL_attributes: + loc = Locator("page", CSL_attributes["locator"]) + + import copy + c1 = copy.deepcopy(CSL_attributes) + c2 = copy.deepcopy(CSL_attributes) + + bib_source = {"full": c1, "subs" : c2} + bib_source = {"full": c1} + +# for key, entry in bib_source.items(): +# print(key) +# for name, value in entry.items(): +# print(' {}: {}'.format(name, value)) + + # load a CSL style (from the current directory) + + bib_style = CitationStylesStyle('chicago-fullnote-bibliography-no-ibid.csl') + + # Create the citeproc-py bibliography, passing it the: + # * CitationStylesStyle, + # * BibliographySource (CiteProcJSON in this case), and + # * a formatter (plain, html, or you can write a custom formatter) + + bibliography = CitationStylesBibliography(bib_style, bib_source, formatter.plain) + + + # Processing citations in a document need to be done in two passes as for some + # CSL styles, a citation can depend on the order of citations in the + # bibliography and thus on citations following the current one. + # For this reason, we first need to register all citations with the + # CitationStylesBibliography. + + if loc: + citation1 = Citation([CitationItem('full', locator=loc)]) + citation2 = Citation([CitationItem('subs', locator=loc)]) + else: + citation1 = Citation([CitationItem('full')]) + citation2 = Citation([CitationItem('subs')]) + + citation1 = Citation([CitationItem('full')]) + + bibliography.register(citation1) + bibliography.register(citation2) + + + # In the second pass, CitationStylesBibliography can generate citations. + # CitationStylesBibliography.cite() requires a callback function to be passed + # along to be called in case a CitationItem's key is not present in the + # bilbiography. + + def warn(citation_item): + print("WARNING: Reference with key '{}' not found in the bibliography." + .format(citation_item.key)) + + print('Citations') + print('---------') + + print(bibliography.cite(citation1, warn)) + print(bibliography.cite(citation2, warn)) + + + # And finally, the bibliography can be rendered. + + print('') + print('Bibliography') + print('------------') + + print(bibliography.bibliography()) + + return(bibliography.cite(citation1, warn), + bibliography.cite(citation2, warn), + bibliography.bibliography()) + diff --git a/gramps/gui/editors/displaytabs/citationrefmodel.py b/gramps/gui/editors/displaytabs/citationrefmodel.py index 1f9b48698..218883a4a 100644 --- a/gramps/gui/editors/displaytabs/citationrefmodel.py +++ b/gramps/gui/editors/displaytabs/citationrefmodel.py @@ -28,6 +28,14 @@ #------------------------------------------------------------------------- from gi.repository import Gtk +#------------------------------------------------------------------------- +# +# GRAMPS modules +# +#------------------------------------------------------------------------- + +from gramps.gen.utils.citeref import get_gedcom_author + #------------------------------------------------------------------------- # # CitationModel @@ -41,6 +49,6 @@ class CitationRefModel(Gtk.ListStore): for handle in citation_list: citation = self.db.get_citation_from_handle(handle) src = self.db.get_source_from_handle(citation.get_reference_handle()) - self.append(row=[src.get_name(), src.get_gedcom_author(), citation.get_name(), + self.append(row=[src.get_name(), get_gedcom_author(self.db, src), citation.get_name(), citation.gramps_id, citation.get_privacy(), handle, ]) diff --git a/gramps/gui/editors/displaytabs/srctemplatetab.py b/gramps/gui/editors/displaytabs/srctemplatetab.py index 005a52262..560373ec3 100644 --- a/gramps/gui/editors/displaytabs/srctemplatetab.py +++ b/gramps/gui/editors/displaytabs/srctemplatetab.py @@ -50,8 +50,7 @@ LOG = logging.getLogger('.template') # Gramps libraries # #------------------------------------------------------------------------- -from gramps.gen.lib.srcattrtype import (SrcAttributeType, REF_TYPE_F, - REF_TYPE_S, REF_TYPE_L, EMPTY) +from gramps.gen.lib.srcattrtype import SrcAttributeType from gramps.gen.lib import SrcAttribute, SrcTemplate from gramps.gen.plug.report.utils import get_address_ref_str from ...autocomp import StandardCustomSelector @@ -60,6 +59,7 @@ from ...widgets import (UndoableEntry, MonitoredEntryIndicator, MonitoredDate, ValidatableMaskedEntry) from .grampstab import GrampsTab from gramps.gen.constfunc import STRTYPE +from gramps.gen.utils.citeref import get_gedcom_title #------------------------------------------------------------------------- # @@ -148,9 +148,7 @@ class SrcTemplateTab(GrampsTab): If title of the source is what we would set with autotitle, we set the checkbox to true. Otherwise to False """ - srctemp = self.db.get_template_from_handle(self.src.get_template()) - srctemp.set_attr_list(self.src.get_attribute_list()) - title = srctemp.title_gedcom() + title = get_gedcom_title(self.dbstate.db, self.src) if self.src.get_title() == title: self.autoset_title = True else: @@ -311,7 +309,6 @@ class TemplateFields(object): Note srcattrtype should actually be the English name of the type! """ self.gridfields.insert_row(row) - field = srcattrtype #setup label if alt_label: label = _(alt_label) diff --git a/gramps/gui/editors/editsource.py b/gramps/gui/editors/editsource.py index a7c3d4375..204d88203 100644 --- a/gramps/gui/editors/editsource.py +++ b/gramps/gui/editors/editsource.py @@ -44,7 +44,7 @@ from gi.repository import Gtk, Gdk # gramps modules # #------------------------------------------------------------------------- -from gramps.gen.lib import NoteType, Source, SrcTemplate, Citation +from gramps.gen.lib import NoteType, Source, Citation from gramps.gen.db import DbTxn from gramps.gen.utils.file import media_path_full from ..thumbnails import get_thumbnail_image @@ -61,6 +61,10 @@ from ..widgets import (MonitoredEntry, PrivacyButton, MonitoredTagList, from ..dialog import ErrorDialog, QuestionDialog2 from ..utils import is_right_click, open_file_with_default_application from ..glade import Glade +from gramps.gen.utils.citeref import (set_input_dict_and_template, reference_L, + reference_S, reference_F, + get_gedcom_title, get_gedcom_author, + get_gedcom_pubinfo) #------------------------------------------------------------------------- # @@ -83,7 +87,6 @@ class EditSource(EditPrimary): nothing made!) """ self.db = dbstate.db - self.srctemp = None self.citation = citation self.template_tab = None self.attr_tab = None @@ -107,6 +110,8 @@ class EditSource(EditPrimary): self.citation_loaded = False #we put an empty base citation ready. self.citation = Citation() + if source.get_template() is None: + source.set_template(dbstate.db.get_GEDCOM_template_handle()) self.callertitle = callertitle self.citation_ready = False @@ -350,28 +355,19 @@ class EditSource(EditPrimary): """ Reaction to update on attributes """ - if self.srctemp is None or \ - self.obj.get_template() != self.srctemp.get_name(): - self.srctemp = self.db.get_template_from_handle(self.obj.get_template()) - - #set new attrlist in template if self.citation_loaded: - citeattr = self.citation.get_attribute_list() - citedate = self.citation.get_date_object() + citation = self.citation else: - citeattr = None - citedate = None - self.srctemp.set_attr_list(self.obj.get_attribute_list(), citeattr, - citedate) - + citation = None + set_input_dict_and_template(self.db, self.obj, citation) #set fields with the template - self.refL.set_markup(self.srctemp.reference_L()) - self.refF.set_markup(self.srctemp.reference_F()) - self.refS.set_markup(self.srctemp.reference_S()) - self.author.set_markup(self.srctemp.author_gedcom()) - self.pubinfo.set_markup(self.srctemp.pubinfo_gedcom()) + self.refL.set_markup(reference_L(self.db)) + self.refF.set_markup(reference_F(self.db)) + self.refS.set_markup(reference_S(self.db)) + self.author.set_markup(get_gedcom_author(self.db)) + self.pubinfo.set_markup(get_gedcom_pubinfo(self.db)) if self.template_tab and self.template_tab.autoset_title: - title = self.srctemp.title_gedcom() + title = get_gedcom_title(self.db) self.obj.set_name(title) self.title.update() #lastly update the window title diff --git a/gramps/gui/views/treemodels/citationbasemodel.py b/gramps/gui/views/treemodels/citationbasemodel.py index bd40eb26c..9346855f7 100644 --- a/gramps/gui/views/treemodels/citationbasemodel.py +++ b/gramps/gui/views/treemodels/citationbasemodel.py @@ -2,7 +2,7 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000-2006 Donald N. Allingham -# Copyright (C) 2011 Tim G L Lyons, Nick Hall +# Copyright (C) 2011-2013 Tim G L Lyons, 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 @@ -45,6 +45,7 @@ from gramps.gen.utils.string import confidence from gramps.gen.config import config from gramps.gen.constfunc import cuni from gramps.gen.const import GRAMPS_LOCALE as glocale +from gramps.gen.utils.citeref import get_gedcom_author, get_gedcom_pubinfo #------------------------------------------------------------------------- # @@ -184,7 +185,7 @@ class CitationBaseModel(object): source_handle = data[COLUMN_SOURCE] try: source = self.db.get_source_from_handle(source_handle) - return cuni(source.get_gedcom_author()) + return cuni(get_gedcom_author(self.db, source)) except: return '' @@ -201,7 +202,7 @@ class CitationBaseModel(object): source_handle = data[COLUMN_SOURCE] try: source = self.db.get_source_from_handle(source_handle) - return cuni(source.get_gedcom_publication_info()) + return cuni(get_gedcom_pubinfo(self.db, source)) except: return '' @@ -247,14 +248,14 @@ class CitationBaseModel(object): def source_src_auth(self, data): source = self.db.get_source_from_handle(data[COLUMN2_HANDLE]) - return cuni(source.get_gedcom_author()) + return cuni(get_gedcom_author(self.db, source)) def source_src_abbr(self, data): return cuni(data[COLUMN2_ABBREV]) def source_src_pinfo(self, data): source = self.db.get_source_from_handle(data[COLUMN2_HANDLE]) - return cuni(source.get_gedcom_publication_info()) + return cuni(get_gedcom_pubinfo(self.db, source)) def source_src_private(self, data): if data[COLUMN2_PRIV]: diff --git a/gramps/gui/views/treemodels/sourcemodel.py b/gramps/gui/views/treemodels/sourcemodel.py index 16b5830fe..b1a21d601 100644 --- a/gramps/gui/views/treemodels/sourcemodel.py +++ b/gramps/gui/views/treemodels/sourcemodel.py @@ -2,6 +2,7 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000-2006 Donald N. Allingham +# Copyright (C) 2013 Tim G L Lyons # # 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 @@ -43,6 +44,8 @@ from gramps.gen.datehandler import format_time from gramps.gen.constfunc import cuni from .flatbasemodel import FlatBaseModel from gramps.gen.const import GRAMPS_LOCALE as glocale +from gramps.gen.utils.citeref import (get_gedcom_title, get_gedcom_author, + get_gedcom_pubinfo) COLUMN_HANDLE = 0 @@ -117,7 +120,7 @@ class SourceModel(FlatBaseModel): def column_author(self, data): source = self.db.get_source_from_handle(data[COLUMN_HANDLE]) - return cuni(source.get_gedcom_author()) + return cuni(get_gedcom_author(self.db, source)) def column_template(self, data): return cuni(data[COLUMN_TEMPLATE]) @@ -130,7 +133,7 @@ class SourceModel(FlatBaseModel): def column_pubinfo(self, data): source = self.db.get_source_from_handle(data[COLUMN_HANDLE]) - return cuni(source.get_gedcom_publication_info()) + return cuni(get_gedcom_pubinfo(self.db, source)) def column_private(self, data): if data[COLUMN_PRIV]: diff --git a/gramps/gui/widgets/srctemplatetreeview.py b/gramps/gui/widgets/srctemplatetreeview.py index cf142e1bb..7ac99d092 100644 --- a/gramps/gui/widgets/srctemplatetreeview.py +++ b/gramps/gui/widgets/srctemplatetreeview.py @@ -71,7 +71,9 @@ class SrcTemplateTreeView(Gtk.TreeView): self.make_columns() self.selection = self.get_selection() self.set_model(self.model) - self.goto(default_key) + if default_key: + # The default key, normally the GEDCOM template, is available + self.goto(default_key) # set up selection and fields on click self.connect('button-release-event', self._on_button_release) self.connect('key_press_event', self._on_key_press_event) diff --git a/gramps/plugins/srctemplates/evidenceexplained.py b/gramps/plugins/srctemplates/evidenceexplained.py index f6d39c9a2..5786c3389 100644 --- a/gramps/plugins/srctemplates/evidenceexplained.py +++ b/gramps/plugins/srctemplates/evidenceexplained.py @@ -43,6 +43,7 @@ csvfile = path_csv('evidence_style.csv') #name of this style style = 'EE' +input_type = 'csv' #strings to translate #following translations are generated with extract_trans_csv.py diff --git a/gramps/plugins/srctemplates/gedcomtemplate.gpr.py b/gramps/plugins/srctemplates/gedcomtemplate.gpr.py new file mode 100644 index 000000000..73b6105ff --- /dev/null +++ b/gramps/plugins/srctemplates/gedcomtemplate.gpr.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2013 Tim G L Lyons +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# $Id$ + +""" +Registering srctemplates for GRAMPS. +""" + +# +# SrcTemplates distributed with Gramps +# + +# GEDCOM +plg = newplugin() +plg.id = 'GEDCOM styles' +plg.name = _("GEDCOM Source Templates") +plg.description = _("Defines source templates corresponding with GEDCOM.") +plg.version = '1.0' +plg.gramps_target_version = '4.1' +plg.status = STABLE +plg.fname = 'gedcomtemplate.py' +plg.ptype = SRCTEMPLATE diff --git a/gramps/plugins/srctemplates/gedcomtemplate.py b/gramps/plugins/srctemplates/gedcomtemplate.py new file mode 100644 index 000000000..4ada18428 --- /dev/null +++ b/gramps/plugins/srctemplates/gedcomtemplate.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- +# +# Gramps - a GTK+/GNOME based genealogy program +# +# Copyright (C) 2013 Tim G L Lyons +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +# $Id$ + +""" +Registering GEDCOM srctemplates for GRAMPS. + +N.B. This is used both from creating a new database (when the database is in its +normal state), and +""" + +#------------------------------------------------------------------------- +# +# Python modules +# +#------------------------------------------------------------------------- + +from __future__ import print_function + +#------------------------------------------------------------------------- +# +# GRAMPS modules +# +#------------------------------------------------------------------------- +from gramps.gen.const import GRAMPS_LOCALE as glocale +_ = glocale.translation.gettext + +from gramps.gen.db import DbTxn + +from gramps.gen.utils.id import create_id +from gramps.gen.lib.srctemplate import SrcTemplate, TemplateElement +from gramps.gen.utils.citeref import (REF_TYPE_L, REF_TYPE_S, REF_TYPE_F, + GED_TITLE, GED_AUTHOR, GED_PUBINF, + GED_DATE, GED_PAGE) + +#------------------------------------------------------------------------ +# +# Set up logging +# +#------------------------------------------------------------------------ +import logging +LOG = logging.getLogger('.template') + +# +# GEDCOM SrcTemplates distributed with Gramps +# + +#name of this style +style = 'GEDCOM' +input_type = 'code' + +def load_template(db): + # Don't load the GEDCOM template twice + if db.get_GEDCOM_template_handle() is None: + template = build_GEDCOM_template() + msg = _("Add template (%s)") % template.get_name() + with DbTxn(msg, db) as trans: + db.commit_template(template, trans) + db.set_GEDCOM_template_handle(template.get_handle()) + +def build_GEDCOM_template(): + """ + Builds the GEDCOM template. This does not commit the template to the + database. For Upgrade commit is done in the upgrade code. For new databases, + commit is done by load_template function. + """ + EMPTY = 0 + DESCR = -10 + # template to GEDCOM field mapping for L reference fields + # template to a style mapping + STYLE_QUOTE = 1 # add quotes around the field + + DEFAULTS = { + "Author" : ("Doe, D.P. & Cameron, E." , "Give names in following form:'FirstAuthorSurname, Given Names & SecondAuthorSurname, Given Names'. Like this Gramps can parse the name and shorten as needed."), + "Date" : ("17 Sep 1745" , "The date that this event data was entered into the original source document. ."), + "Page" : ("5; or 4,6-8, ..." , "Specific location with in the information referenced. For a published work, this could include the volume of a multi-volume work and the page number(s). For a periodical, it could include volume, issue, and page numbers. For a newspaper, it could include a column number and page number. For an unpublished source, this could be a sheet number, page number, frame number, etc. A census record might have a line number or dwelling and family numbers in addition to the page number. "), + "Pub_info" : ("Springer, Berlin, 2014" , "When and where the record was created. For published works, this includes information such as the city of publication, name of the publisher, and year of publication."), + "Title" : ("Diary Title, Message Title, Bible Name, Article Title, ..." , "The title of the work, record, or item and, when appropriate, the title of the larger work or series of which it is a part."), + } + + TEMPLATES = { + 'GEDCOM': { + REF_TYPE_L: [ + ('', "Author", '', '.', EMPTY, False, False, EMPTY, GED_AUTHOR, + None, None), + ('', "Title", '', '.', STYLE_QUOTE, False, False, EMPTY, GED_TITLE, + None, None), + ('', "Pub_info", '', '', EMPTY, False, False, EMPTY, GED_PUBINF, + None, None), + ], + REF_TYPE_F: [ + ('', "Author", '', ',', EMPTY, False, False, EMPTY, EMPTY, + None, None), + ('', "Title", '', ',', STYLE_QUOTE, False, False, EMPTY, EMPTY, + None, None), + ('', "Pub_info", '', '.', EMPTY, False, False, EMPTY, EMPTY, + None, None), + ('', "Date", '', ' -', EMPTY, False, False, EMPTY, EMPTY, + None, None), + ('', "Page", 'Page(s)', '.', EMPTY, False, False, EMPTY, EMPTY, + None, None), + ], + REF_TYPE_S: [ + ('', "Author", '', ',', EMPTY, False, False, EMPTY, EMPTY, + None, None), + ('', "Date", '', ' -', EMPTY, False, False, EMPTY, EMPTY, + None, None), + ('', "Page", 'Page(s)', '.', EMPTY, False, False, EMPTY, EMPTY, + None, None), + ], + DESCR: '%(first)s - %(sec)s - %(third)s' % { 'first': _('Basic'), 'sec': _('GEDCOM Style'), 'third': _('')}, + }, + } + + template = SrcTemplate() + template.set_name('GEDCOM') + template.set_descr('%(first)s - %(sec)s - %(third)s' % { 'first': _('Basic'), 'sec': _('GEDCOM Style'), 'third': _('')}) + handle = create_id() + template.set_handle(handle) + + for (cite_type, slist) in list(TEMPLATES['GEDCOM'].items()): + if cite_type != DESCR: + for struct in slist: + if cite_type == REF_TYPE_L or cite_type == REF_TYPE_F: + elem = [x for x in template.get_template_element_list() + if x.get_name()==struct[1] and x.get_short()==False] + if elem: + te = elem[0] + else: + te = TemplateElement() + template.add_template_element(te) + elif cite_type == REF_TYPE_S: + te = TemplateElement() + template.add_template_element(te) + ldel = struct[0] + field_type = struct[1] + field_label = struct[2] + rdel = struct[3] + style = struct[4] + private = struct[5] + optional = struct[6] + shorteralg = struct[7] + gedcommap = struct[8] + hint = struct[9] + tooltip = struct[10] + te.set_name(field_type) + te.set_display(field_label) + if DEFAULTS.get(field_type): + te.set_hint(hint or (DEFAULTS[field_type][0] or "")) + te.set_tooltip(tooltip or (DEFAULTS[field_type][1] or "")) + else: + te.set_hint("") + te.set_tooltip("") + if cite_type == REF_TYPE_S: + te.set_short(True) + if field_type.lower().endswith(' (short)'): + te.set_name(field_type) + else: + te.set_name(field_type + ' (Short)') + if field_type == "Page" or \ + field_type == "Date": + te.set_citation(True) + + template.set_map_element(GED_AUTHOR, "%(AUTHOR)s") + template.set_map_element(GED_TITLE, "%(TITLE)s") + template.set_map_element(GED_PUBINF, "%(PUB_INFO)s") + template.set_map_element(GED_DATE, "%(DATE)s") + template.set_map_element(GED_PAGE, "%(PAGE)s") + + template.set_map_element(REF_TYPE_L, "%(AUTHOR)s. %(TITLE)s. %(PUB_INFO)s") + template.set_map_element(REF_TYPE_F, "%(AUTHOR)s, %(TITLE)s, %(PUB_INFO)s. %(DATE)s - %(PAGE)s") + template.set_map_element(REF_TYPE_S, "%(AUTHOR_(SHORT))s, %(DATE_(SHORT))s - %(PAGE_(SHORT))s.") + + return template diff --git a/gramps/plugins/srctemplates/importcsv.py b/gramps/plugins/srctemplates/importcsv.py index ca6026103..ed1c08d4e 100644 --- a/gramps/plugins/srctemplates/importcsv.py +++ b/gramps/plugins/srctemplates/importcsv.py @@ -49,6 +49,9 @@ from gramps.gen.utils.id import create_id from gramps.gen.lib.srcattrtype import * from gramps.gen.lib.date import Date from gramps.gen.lib.srctemplate import SrcTemplate, TemplateElement +from gramps.gen.utils.citeref import (REF_TYPE_L, REF_TYPE_S, REF_TYPE_F, + GED_TITLE, GED_AUTHOR, GED_PUBINF, + GED_DATE, GED_PAGE) #------------------------------------------------------------------------ # @@ -184,9 +187,6 @@ def load_srctemplates_data(db): Loads the srctemplates defined, and returns a dict with template data """ LOG.debug("**** load_srctemplate_data. Starting") - load_srctemplate_gedcom(db) - LOG.debug("**** load_srctemplate_data. GEDCOM and UNKNOWN loaded") - from gramps.gen.plug import BasePluginManager bpmgr = BasePluginManager.get_instance() @@ -195,16 +195,20 @@ def load_srctemplates_data(db): for plugin in pdatas: mod = bpmgr.load_plugin(plugin) if mod: - csvfilename = mod.csvfile - LOG.debug("**** load_srctemplate_data. Loading csv from %s" % csvfilename) - if sys.version_info[0] <3: - with open(csvfilename, 'rb') as csvfile: - load_srctemplate_csv(csvfile, db) - else: - with open(csvfilename, 'r') as csvfile: - load_srctemplate_csv(csvfile, db) - - LOG.debug("**** load_srctemplate_data. csv data loaded") + if mod.input_type == 'csv': + csvfilename = mod.csvfile + LOG.debug("**** load_srctemplate_data. Loading csv from %s" % csvfilename) + if sys.version_info[0] <3: + with open(csvfilename, 'rb') as csvfile: + load_srctemplate_csv(csvfile, db) + else: + with open(csvfilename, 'r') as csvfile: + load_srctemplate_csv(csvfile, db) + + LOG.debug("**** load_srctemplate_data. csv data loaded") + elif mod.input_type == 'code': + mod.load_template(db) + LOG.debug("**** load_srctemplate_data. GEDCOM loaded") for handle in db.get_template_handles(): LOG.debug("handle %s" % handle) @@ -223,144 +227,6 @@ def load_srctemplates_data(db): (template.get_name(), target, template.get_map_element(target))) LOG.debug("**** load_srctemplate_data. finished") -def load_srctemplate_gedcom(db): - """ - Loads the GEDCOM and UNKNOWN templates which are always pre-defined - """ - global DEFAULTS - TEMPLATES = { - 'GEDCOM': { - REF_TYPE_L: [ - ('', "Author", '', '.', EMPTY, False, False, EMPTY, GED_AUTHOR, - None, None), - ('', "Title", '', '.', STYLE_QUOTE, False, False, EMPTY, GED_TITLE, - None, None), - ('', "Pub_info", '', '', EMPTY, False, False, EMPTY, GED_PUBINF, - None, None), - ], - REF_TYPE_F: [ - ('', "Author", '', ',', EMPTY, False, False, EMPTY, EMPTY, - None, None), - ('', "Title", '', ',', STYLE_QUOTE, False, False, EMPTY, EMPTY, - None, None), - ('', "Pub_info", '', '.', EMPTY, False, False, EMPTY, EMPTY, - None, None), - ('', "Date", '', ' -', EMPTY, False, False, EMPTY, EMPTY, - None, None), - ('', "Page", 'Page(s)', '.', EMPTY, False, False, EMPTY, EMPTY, - None, None), - ], - REF_TYPE_S: [ - ('', "Author", '', ',', EMPTY, False, False, EMPTY, EMPTY, - None, None), - ('', "Date", '', ' -', EMPTY, False, False, EMPTY, EMPTY, - None, None), - ('', "Page", 'Page(s)', '.', EMPTY, False, False, EMPTY, EMPTY, - None, None), - ], - DESCR: '%(first)s - %(sec)s - %(third)s' % { 'first': _('Basic'), 'sec': _('GEDCOM Style'), 'third': _('')}, - }, - UNKNOWN: { - REF_TYPE_L: [ - ], - REF_TYPE_F: [ - ], - REF_TYPE_S: [ - ], - DESCR: _("Unrecognized Template. Download it's definition."), - }, - } - - template = SrcTemplate() - template.set_name('GEDCOM') - template.set_descr('%(first)s - %(sec)s - %(third)s' % { 'first': _('Basic'), 'sec': _('GEDCOM Style'), 'third': _('')}) - handle = create_id() - template.set_handle(handle) - - for (cite_type, slist) in list(TEMPLATES['GEDCOM'].items()): - if cite_type != DESCR: - for struct in slist: - if cite_type == REF_TYPE_L or cite_type == REF_TYPE_F: - elem = [x for x in template.get_template_element_list() - if x.get_name()==struct[1] and x.get_short()==False] - if elem: - te = elem[0] - else: - te = TemplateElement() - template.add_template_element(te) - elif cite_type == REF_TYPE_S: - te = TemplateElement() - template.add_template_element(te) - ldel = struct[0] - field_type = struct[1] - field_label = struct[2] - rdel = struct[3] - style = struct[4] - private = struct[5] - optional = struct[6] - shorteralg = struct[7] - gedcommap = struct[8] - hint = struct[9] - tooltip = struct[10] - te.set_name(field_type) - te.set_display(field_label) - if DEFAULTS.get(field_type): - te.set_hint(hint or (DEFAULTS[field_type][0] or "")) - te.set_tooltip(tooltip or (DEFAULTS[field_type][1] or "")) - else: - te.set_hint("") - te.set_tooltip("") - if cite_type == REF_TYPE_S: - te.set_short(True) - if field_type.lower().endswith(' (short)'): - te.set_name(field_type) - else: - te.set_name(field_type + ' (Short)') - if field_type == "Page" or \ - field_type == "Date": - te.set_citation(True) - template.add_structure_element(cite_type, [(ldel, field_type, - field_label, rdel, style, private, optional, - shorteralg, gedcommap, hint, tooltip)]) - - template.set_map_element("GEDCOM_A", "%(AUTHOR)s") - template.set_map_element("GEDCOM_T", "%(TITLE)s") - template.set_map_element("GEDCOM_P", "%(PUB_INFO)s") - template.set_map_element("GEDCOM_D", "%(DATE)s") - template.set_map_element("GEDCOM_PAGE", "%(PAGE)s") - - template.set_map_element("EE_L", "%(AUTHOR)s. %(TITLE)s. %(PUB_INFO)s") - template.set_map_element("EE_F", "%(AUTHOR)s, %(TITLE)s, %(PUB_INFO)s. %(DATE)s - %(PAGE)s") - template.set_map_element("EE_S", "%(AUTHOR_(SHORT))s, %(DATE_(SHORT))s - %(PAGE_(SHORT))s.") - msg = _("Add template (%s)") % template.get_name() - with DbTxn(msg, db) as trans: - db.commit_template(template, trans) - db.set_GEDCOM_template_handle(template.get_handle()) -# for handle in db.get_template_handles(): -# template = db.get_template_from_handle(handle) -# LOG.debug("source_type: %s; handle %s" % (template.get_name(), template.get_handle())) -# for te in template.get_template_element_list(): -# LOG.debug(" name: %s; display: %s; hint: %s; tooltip: %s; citation %s; " -# "short %s; short_alg %s" % -# (te.get_name(), -# te.get_display(), te.get_hint(), -# te.get_tooltip(), te.get_citation(), -# te.get_short(), te.get_short_alg() -# )) - - # Now load the UNKNOWN template - template = SrcTemplate() - template.set_name(UNKNOWN) - template.set_descr(_("Unrecognized Template. Download it's definition.")) - handle = create_id() - template.set_handle(handle) - msg = _("Add template (%s)") % template.get_name() - with DbTxn(msg, db) as trans: - db.commit_template(template, trans) - - for cite_type in (REF_TYPE_F, REF_TYPE_L, REF_TYPE_S): - template.add_structure_element(cite_type, []) - def load_srctemplate_csv(csvfile, db): """ Loads a template csvfile, and returns a dict with template data @@ -373,6 +239,19 @@ def load_srctemplate_csv(csvfile, db): CITE_TYPES = {'F': REF_TYPE_F, 'L': REF_TYPE_L, 'S': REF_TYPE_S} GEDCOMFIELDS = {'A': GED_AUTHOR, 'T': GED_TITLE, 'P': GED_PUBINF, 'D': GED_DATE} + EMPTY = 0 + # template to a shortening algorithm mapping for predefined algorithms + SHORTERALG_LOC = 1 # reduce a location to a shorter format (typically city level) + SHORTERALG_YEAR = 2 # reduce a date to only the year part + SHORTERALG_ETAL = 3 # reduce an author list to "first author et al." + SHORTERALG_REVERT_TO_DOT = 4 # change a list of first, second, third to + # a list third. second. first. + # template to a style mapping + STYLE_QUOTE = 1 # add quotes around the field + STYLE_QUOTECONT = 2 # add quotes around this field combined with other + # QUOTECONT fields around it + STYLE_EMPH = 3 # emphasize field + STYLE_BOLD = 4 # make field bold SHORTERALG = {'LOC': SHORTERALG_LOC, 'YEAR': SHORTERALG_YEAR, 'ETAL': SHORTERALG_ETAL, 'REV.': SHORTERALG_REVERT_TO_DOT} STYLES = {'Quoted': STYLE_QUOTE, 'Italics': STYLE_EMPH, @@ -494,9 +373,6 @@ def load_srctemplate_csv(csvfile, db): 'normal_version_label': lblval}) template.add_template_element(te) TYPE2FIELDS[source_type][cite_type].append(field_type) - template.add_structure_element(cite_type, [(row[LDELCOL], field_type, - field_label, row[RDELCOL], style, private, optional, - shorteralg, gedcommap, hint, tooltip)]) # Setup the mapping. A typical mapping would look like: # ('EE_Full' : '%(COMPILER)s, "%(TITLE)s", %(TYPE)s, %(WEBSITE CREATOR/OWNER)s, %(WEBSITE)s, (%(URL (DIGITAL LOCATION))s: accessed %(DATE ACCESSED)s), %(ITEM OF INTEREST)s; %(CREDIT LINE)s.')