From 9037f827a51cdef92de7cfe4e5a88121dfddb54d Mon Sep 17 00:00:00 2001 From: Tim G L Lyons Date: Mon, 19 Aug 2013 22:31:52 +0000 Subject: [PATCH] - update exportxml and importxml for templates, - move TemplateElement into separate module, - remove redundant srctemplatelist module, - fix editsource so source attribute tab updates when template fields are input, - fix importcsv so it uses map names defined in citeref module, svn: r22880 --- gramps/gen/db/read.py | 5 + gramps/gen/db/write.py | 22 +- gramps/gen/lib/__init__.py | 1 + gramps/gen/lib/src.py | 2 - gramps/gen/lib/srctemplate.py | 190 +------------- gramps/gen/lib/srctemplatelist.py | 116 --------- gramps/gen/lib/templateelement.py | 244 ++++++++++++++++++ gramps/gui/editors/editsource.py | 23 +- gramps/plugins/export/exportxml.py | 74 +++++- gramps/plugins/importer/importxml.py | 124 ++++++++- gramps/plugins/srctemplates/gedcomtemplate.py | 3 +- gramps/plugins/srctemplates/importcsv.py | 24 +- 12 files changed, 469 insertions(+), 359 deletions(-) delete mode 100644 gramps/gen/lib/srctemplatelist.py create mode 100644 gramps/gen/lib/templateelement.py diff --git a/gramps/gen/db/read.py b/gramps/gen/db/read.py index 4a540282d..4159ece21 100644 --- a/gramps/gen/db/read.py +++ b/gramps/gen/db/read.py @@ -1859,6 +1859,11 @@ class DbBsddbRead(DbReadBase, Callback): return self.metadata.get(b'mediapath', None) return None + def set_GEDCOM_template_handle(self, handle): + """Set the default GEDCOM template handle for database""" + if (self.metadata is not None) and (not self.readonly): + self.metadata[b'gedcom_template'] = handle + def find_backlink_handles(self, handle, include_classes=None): """ Find all objects that hold a reference to the object handle. diff --git a/gramps/gen/db/write.py b/gramps/gen/db/write.py index 03037b9ac..ed7a42d7a 100644 --- a/gramps/gen/db/write.py +++ b/gramps/gen/db/write.py @@ -393,17 +393,6 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback): txn.put(b'default', handle) self.emit('home-person-changed') - @catch_db_error - def set_GEDCOM_template_handle(self, handle): - """Set the handle of the GEDCOM template to the passed instance.""" - #we store a byte string! - if isinstance(handle, UNITYPE): - handle = handle.encode('utf-8') - if not self.readonly: - # Start transaction - with BSDDBTxn(self.env, self.metadata) as txn: - txn.put(b'gedcom_template', handle) - @catch_db_error def get_default_person(self): """Return the default Person of the database.""" @@ -416,6 +405,17 @@ class DbBsddb(DbBsddbRead, DbWriteBase, UpdateCallback): txn.put(b'default', None) return None + @catch_db_error + def set_GEDCOM_template_handle(self, handle): + """Set the handle of the GEDCOM template to the passed instance.""" + #we store a byte string! + if isinstance(handle, UNITYPE): + handle = handle.encode('utf-8') + if not self.readonly: + # Start transaction + with BSDDBTxn(self.env, self.metadata) as txn: + txn.put(b'gedcom_template', handle) + def set_mediapath(self, path): """Set the default media path for database, path should be utf-8.""" if self.metadata and not self.readonly: diff --git a/gramps/gen/lib/__init__.py b/gramps/gen/lib/__init__.py index cf2cd3433..b74ab3f00 100644 --- a/gramps/gen/lib/__init__.py +++ b/gramps/gen/lib/__init__.py @@ -79,6 +79,7 @@ from .markertype import MarkerType from .nameorigintype import NameOriginType from .notetype import NoteType from .styledtexttagtype import StyledTextTagType +from .templateelement import TemplateElement # Text from .styledtexttag import StyledTextTag diff --git a/gramps/gen/lib/src.py b/gramps/gen/lib/src.py index d4ce284e7..7dbd52d2e 100644 --- a/gramps/gen/lib/src.py +++ b/gramps/gen/lib/src.py @@ -36,8 +36,6 @@ from .mediabase import MediaBase from .notebase import NoteBase from .tagbase import TagBase from .srcattrbase import SrcAttributeBase -from .srctemplate import SrcTemplate -from .srctemplatelist import SrcTemplateList from .reporef import RepoRef from .const import DIFFERENT, EQUAL, IDENTICAL from ..constfunc import cuni, deprecated diff --git a/gramps/gen/lib/srctemplate.py b/gramps/gen/lib/srctemplate.py index 3f5aa508a..a25cad08f 100644 --- a/gramps/gen/lib/srctemplate.py +++ b/gramps/gen/lib/srctemplate.py @@ -48,9 +48,9 @@ LOG = logging.getLogger('.template') # #------------------------------------------------------------------------- from .tableobj import TableObject -from .secondaryobj import SecondaryObject from .handle import Handle from ..constfunc import cuni +from .templateelement import TemplateElement #------------------------------------------------------------------------- # @@ -224,191 +224,3 @@ class SrcTemplate(TableObject): def add_template_element(self, template_element): self.template_element_list.append(template_element) - -class TemplateElement(SecondaryObject): - """ - TemplateEelement class. - - This class is for keeping information about each template-element. - - TemplateElement: - - - template_element_name - English name of the element exactly as it appears - in Yates e.g. [WRITER FIRST] - - - name to be displayed in the user interface e.g. 'Name of the first - author' - - - hint e.g. "Doe, D.P. & Cameron, E." - - - tooltip e.g. "Give names in following form: 'FirstAuthorSurname, Given - Names & SecondAuthorSurname, Given Names'. Like this Gramps can parse the - name and shorten as needed." - - - citation - True if this element appears in a citation (false for a source - element) - - - short - True if this element is an optional short element - - - short_alg - algorithm to shorten the field. - - - list of Mappings - there would always be a GEDCOM mapping. Also we would - expect a CSL mapping - - """ - - def __init__(self, source=None): - """ - Create a new TemplateEelement instance, copying from the source if present. - """ - if source: - self.name = source.name - self.display = source.display - self.hint = source.hint - self.tooltip = source.tooltip - self.citation = source.citation - self.short - source.short - self.short_alg = source.short_alg - else: - self.name = "" - self.display = "" - self.hint = "" - self.tooltip = "" - self.citation = False - self.short = False - self.short_alg = "" - - def serialize(self): - """ - Convert the object to a serialized tuple of data. - """ - return (self.name, - self.display, - self.hint, - self.tooltip, - self.citation, - self.short, - self.short_alg - ) - - def to_struct(self): - """ - Convert the data held in this object to a structure (eg, - struct) that represents all the data elements. - - This method is used to recursively convert the object into a - self-documenting form that can easily be used for various - purposes, including diffs and queries. - - These structures may be primitive Python types (string, - integer, boolean, etc.) or complex Python types (lists, - tuples, or dicts). If the return type is a dict, then the keys - of the dict match the fieldname of the object. If the return - struct (or value of a dict key) is a list, then it is a list - of structs. Otherwise, the struct is just the value of the - attribute. - - :returns: Returns a struct containing the data of the object. - :rtype: dict - """ - return {"name": cuni(self.name), - "display": cuni(self.display), - "hint": cuni(self.hint), - "tooltip": cuni(self.tooltip), - "citation": cuni(self.citation), - "short": cuni(self.short), - "short_alg": cuni(self.short_alg), - } - - def unserialize(self, data): - """ - Convert a serialized tuple of data to an object. - """ - (self.name, self.display, self.hint, self.tooltip, self.citation, - self.short, self.short_alg) = data - return self - - def get_name(self): - """ - Return the name for the Template element. - """ - return self.name - - def set_name(self, name): - """ - Set the name for the Template element according to the given argument. - """ - self.name = name - - def get_hint(self): - """ - Return the hint for the Template element. - """ - return self.hint - - def set_hint(self, hint): - """ - Set the hint for the Template element according to the given argument. - """ - self.hint = hint - - def get_display(self): - """ - Return the display form for the Template element. - """ - return self.display - - def set_display(self, display): - """ - Set the display form for the Template element according to the given - argument. - """ - self.display = display - - def get_tooltip(self): - """ - Return the tooltip for the Template element. - """ - return self.tooltip - - def set_tooltip(self, tooltip): - """ - Set the tooltip for the Template element according to the given argument. - """ - self.tooltip = tooltip - - def get_citation(self): - """ - Return the citation for the Template element. - """ - return self.citation - - def set_citation(self, citation): - """ - Set the citation for the Template element according to the given argument. - """ - self.citation = citation - - def get_short(self): - """ - Return the short for the Template element. - """ - return self.short - - def set_short(self, short): - """ - Set the short for the Template element according to the given argument. - """ - self.short = short - - def get_short_alg(self): - """ - Return the short_alg for the Template element. - """ - return self.short_alg - - def set_short_alg(self, short_alg): - """ - Set the short_alg for the Template element according to the given argument. - """ - self.short_alg = short_alg diff --git a/gramps/gen/lib/srctemplatelist.py b/gramps/gen/lib/srctemplatelist.py deleted file mode 100644 index 58e552a40..000000000 --- a/gramps/gen/lib/srctemplatelist.py +++ /dev/null @@ -1,116 +0,0 @@ -# -*- 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$ - -""" -SrcTemplateList class for GRAMPS. -""" - -from __future__ import print_function - -#------------------------------------------------------------------------- -# -# Python modules -# -#------------------------------------------------------------------------- -import sys - -#------------------------------------------------------------------------ -# -# Set up logging -# -#------------------------------------------------------------------------ -import logging -LOG = logging.getLogger('.template') - -#------------------------------------------------------------------------- -# -# GRAMPS modules -# -#------------------------------------------------------------------------- - -# Pattern from http://stackoverflow.com/questions/13789235/how-to-initialize-singleton-derived-object-once -class Singleton(type): - _instances = {} - def __call__(cls, *args, **kwargs): - if cls not in cls._instances: - cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) - return cls._instances[cls] - -# See http://stackoverflow.com/questions/17237857/python3-singleton-metaclass- -# method-not-working the syntax has changed - -# http://mikewatkins.ca/2008/11/29/python-2-and-3-metaclasses/ -# http://stackoverflow.com/questions/6760685/creating-a-singleton-in-python/17840539 -STL = Singleton('STL', (object, ), {}) - -class SrcTemplateList(STL): - """ - Manages a singleton list of the source templates. - - This should be replaced by access to the database when the templates are - stored in the database. - - I would expect the TemplateList object to contain a dictionary of Template - objects, with the template ID as a key. It needs a method to return a list - of keys, and another method to return the Template object for a given key. - In this way it would act like a database table. - """ -# __metaclass__ = Singleton - def __init__(self): - self.clear() - - def clear(self): - self.template_list = {} - self.GEDCOM_handle = None - self.UNKNOWN_handle = None - - def add_template(self, handle, template): - self.template_list[handle] = template - -# def get_template_from_handle(self, handle): -# if handle in self.template_list: -# return self.template_list[handle] -# else: -# return self.template_list[self.get_UNKNOWN_handle()] - -# def get_template_list(self): -# return self.template_list -# -# def template_defined(self, handle): -# if self.get_template_from_handle(handle) is None: -# return False -# else: -# return True -# -# def set_GEDCOM_handle(self, handle): -# self.GEDCOM_handle = handle -# -# def get_GEDCOM_handle(self): -# return self.GEDCOM_handle -# -# def set_UNKNOWN_handle(self, handle): -# self.UNKNOWN_handle = handle -# -# def get_UNKNOWN_handle(self): -# return self.UNKNOWN_handle diff --git a/gramps/gen/lib/templateelement.py b/gramps/gen/lib/templateelement.py new file mode 100644 index 000000000..d4713b821 --- /dev/null +++ b/gramps/gen/lib/templateelement.py @@ -0,0 +1,244 @@ +# -*- 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$ + +""" +SrcTemplate class for GRAMPS. +""" + +#------------------------------------------------------------------------- +# +# Python modules +# +#------------------------------------------------------------------------- +from __future__ import print_function + +#------------------------------------------------------------------------ +# +# Set up logging +# +#------------------------------------------------------------------------ +import logging +LOG = logging.getLogger('.template') + +#------------------------------------------------------------------------- +# +# GRAMPS modules +# +#------------------------------------------------------------------------- +from .secondaryobj import SecondaryObject +from ..constfunc import cuni + +#------------------------------------------------------------------------- +# +# TemplateElement class +# +#------------------------------------------------------------------------- + +class TemplateElement(SecondaryObject): + """ + TemplateEelement class. + + This class is for keeping information about each template-element. + + TemplateElement: + + - template_element_name - English name of the element exactly as it appears + in Yates e.g. [WRITER FIRST] + + - name to be displayed in the user interface e.g. 'Name of the first + author' + + - hint e.g. "Doe, D.P. & Cameron, E." + + - tooltip e.g. "Give names in following form: 'FirstAuthorSurname, Given + Names & SecondAuthorSurname, Given Names'. Like this Gramps can parse the + name and shorten as needed." + + - citation - True if this element appears in a citation (false for a source + element) + + - short - True if this element is an optional short element + + - short_alg - algorithm to shorten the field. + + - list of Mappings - there would always be a GEDCOM mapping. Also we would + expect a CSL mapping + + """ + + def __init__(self, source=None): + """ + Create a new TemplateEelement instance, copying from the source if present. + """ + if source: + self.name = source.name + self.display = source.display + self.hint = source.hint + self.tooltip = source.tooltip + self.citation = source.citation + self.short - source.short + self.short_alg = source.short_alg + else: + self.name = "" + self.display = "" + self.hint = "" + self.tooltip = "" + self.citation = False + self.short = False + self.short_alg = "" + + def serialize(self): + """ + Convert the object to a serialized tuple of data. + """ + return (self.name, + self.display, + self.hint, + self.tooltip, + self.citation, + self.short, + self.short_alg + ) + + def to_struct(self): + """ + Convert the data held in this object to a structure (eg, + struct) that represents all the data elements. + + This method is used to recursively convert the object into a + self-documenting form that can easily be used for various + purposes, including diffs and queries. + + These structures may be primitive Python types (string, + integer, boolean, etc.) or complex Python types (lists, + tuples, or dicts). If the return type is a dict, then the keys + of the dict match the fieldname of the object. If the return + struct (or value of a dict key) is a list, then it is a list + of structs. Otherwise, the struct is just the value of the + attribute. + + :returns: Returns a struct containing the data of the object. + :rtype: dict + """ + return {"name": cuni(self.name), + "display": cuni(self.display), + "hint": cuni(self.hint), + "tooltip": cuni(self.tooltip), + "citation": cuni(self.citation), + "short": cuni(self.short), + "short_alg": cuni(self.short_alg), + } + + def unserialize(self, data): + """ + Convert a serialized tuple of data to an object. + """ + (self.name, self.display, self.hint, self.tooltip, self.citation, + self.short, self.short_alg) = data + return self + + def get_name(self): + """ + Return the name for the Template element. + """ + return self.name + + def set_name(self, name): + """ + Set the name for the Template element according to the given argument. + """ + self.name = name + + def get_hint(self): + """ + Return the hint for the Template element. + """ + return self.hint + + def set_hint(self, hint): + """ + Set the hint for the Template element according to the given argument. + """ + self.hint = hint + + def get_display(self): + """ + Return the display form for the Template element. + """ + return self.display + + def set_display(self, display): + """ + Set the display form for the Template element according to the given + argument. + """ + self.display = display + + def get_tooltip(self): + """ + Return the tooltip for the Template element. + """ + return self.tooltip + + def set_tooltip(self, tooltip): + """ + Set the tooltip for the Template element according to the given argument. + """ + self.tooltip = tooltip + + def get_citation(self): + """ + Return the citation for the Template element. + """ + return self.citation + + def set_citation(self, citation): + """ + Set the citation for the Template element according to the given argument. + """ + self.citation = citation + + def get_short(self): + """ + Return the short for the Template element. + """ + return self.short + + def set_short(self, short): + """ + Set the short for the Template element according to the given argument. + """ + self.short = short + + def get_short_alg(self): + """ + Return the short_alg for the Template element. + """ + return self.short_alg + + def set_short_alg(self, short_alg): + """ + Set the short_alg for the Template element according to the given argument. + """ + self.short_alg = short_alg diff --git a/gramps/gui/editors/editsource.py b/gramps/gui/editors/editsource.py index 204d88203..836ad60a4 100644 --- a/gramps/gui/editors/editsource.py +++ b/gramps/gui/editors/editsource.py @@ -89,7 +89,8 @@ class EditSource(EditPrimary): self.db = dbstate.db self.citation = citation self.template_tab = None - self.attr_tab = None + self.citn_attr_tab = None + self.src_attr_tab = None self.citation_loaded = True if not source and not citation: raise NotImplementedError @@ -381,8 +382,10 @@ class EditSource(EditPrimary): if templatechanged and self.tmplfields: #the citation template fields must be changed! self.tmplfields.reset_template_fields(self.obj.get_template()) - if self.attr_tab: - self.attr_tab.rebuild_callback() + if self.citn_attr_tab: + self.citn_attr_tab.rebuild_callback() + if self.src_attr_tab: + self.src_attr_tab.rebuild_callback() self.update_attr() def callback_cite_changed(self): @@ -451,12 +454,12 @@ class EditSource(EditPrimary): self._add_tab(notebook, self.repo_tab) self.track_ref_for_deletion("repo_tab") - self.attr_tab = SrcAttrEmbedList(self.dbstate, + self.src_attr_tab = SrcAttrEmbedList(self.dbstate, self.uistate, self.track, self.obj.get_attribute_list()) - self._add_tab(notebook, self.attr_tab) - self.track_ref_for_deletion("attr_tab") + self._add_tab(notebook, self.src_attr_tab) + self.track_ref_for_deletion("src_attr_tab") self.citedin_tab = CitedInTab(self.dbstate, self.uistate, self.track, self.obj, self.cite_apply_callback, @@ -509,10 +512,10 @@ class EditSource(EditPrimary): self._add_tab(notebook_ref, self.gallery_tab) self.track_ref_for_deletion("gallery_tab") - self.attr_tab = SrcAttrEmbedList(self.dbstate, self.uistate, self.track, + self.citn_attr_tab = SrcAttrEmbedList(self.dbstate, self.uistate, self.track, self.citation.get_attribute_list()) - self._add_tab(notebook_ref, self.attr_tab) - self.track_ref_for_deletion("attr_tab") + self._add_tab(notebook_ref, self.citn_attr_tab) + self.track_ref_for_deletion("citn_attr_tab") self.citationref_list = CitationBackRefList(self.dbstate, self.uistate, self.track, @@ -837,7 +840,7 @@ class EditSource(EditPrimary): #trigger update of the tab fields self.comment_tab.rebuild_callback(self.citation.get_note_list()) self.gallery_tab.rebuild_callback(self.citation.get_media_list()) - self.attr_tab.rebuild_callback(self.citation.get_attribute_list()) + self.citn_attr_tab.rebuild_callback(self.citation.get_attribute_list()) self.citationref_list.rebuild_callback( self.db.find_backlink_handles(self.citation.handle)) diff --git a/gramps/plugins/export/exportxml.py b/gramps/plugins/export/exportxml.py index fd5292e71..61d1443d4 100644 --- a/gramps/plugins/export/exportxml.py +++ b/gramps/plugins/export/exportxml.py @@ -208,11 +208,12 @@ class GrampsXmlWriter(UpdateCallback): repo_len = self.db.get_number_of_repositories() obj_len = self.db.get_number_of_media_objects() note_len = self.db.get_number_of_notes() - tag_len = self.db.get_number_of_tags() + tag_len = self.db.get_number_of_tags() + template_len = self.db.get_number_of_templates() total_steps = (person_len + family_len + event_len + citation_len + source_len + place_len + repo_len + obj_len + note_len + - tag_len + tag_len + template_len ) self.set_total(total_steps) @@ -256,6 +257,14 @@ class GrampsXmlWriter(UpdateCallback): self.update() self.g.write(" \n") + if template_len > 0: + self.g.write(" \n") + for key in sorted(self.db.get_template_handles()): + template = self.db.get_template_from_handle(key) + self.write_template(template, 2) + self.update() + self.g.write(" \n") + # Write primary objects if event_len > 0: self.g.write(" \n") @@ -350,6 +359,9 @@ class GrampsXmlWriter(UpdateCallback): mediapath= self.db.get_mediapath() if mediapath is not None: self.write_line("mediapath", mediapath, 2) + gedcom_handle = self.db.get_GEDCOM_template_handle() + if gedcom_handle is not None: + self.write_line("gedcom_template", gedcom_handle, 2) def write_namemaps(self): group_map = self.db.get_name_group_keys() @@ -435,6 +447,22 @@ class GrampsXmlWriter(UpdateCallback): self.g.write(' priority="%d"' % tag.get_priority()) self.g.write('/>\n') + def write_template(self, template, index=2): + """ + Write a template definition. + """ + if not template: + return + + sp = " "*index + self.write_template_tag('template', template, index) + self.write_force_line("tname", template.get_name(), index+1) + self.write_line("tdescription", template.get_descr(), index+1) + self.write_map_list(template.get_map_dict(), index+1) + self.write_te_list(template.get_template_element_list(), index+1) + + self.g.write("%s\n" % sp) + def fix(self,line): try: l = cuni(line) @@ -595,7 +623,7 @@ class GrampsXmlWriter(UpdateCallback): sp = " "*index self.write_primary_tag("source", source, index) self.write_force_line("sname", source.get_name(), index+1) - self.write_line("stemplate", source.get_template(), index+1) + self.write_ref("stemplate", source.get_template(), index+1) self.write_line("sabbrev", source.get_abbreviation(), index+1) self.write_note_list(source.get_note_list(), index+1) self.write_media_list(source.get_media_list(), index+1) @@ -809,6 +837,25 @@ class GrampsXmlWriter(UpdateCallback): if close: self.g.write('>\n') + def write_template_tag(self, templatename, obj, index=1, close=True): + """ + Write the template attributes common to all table objects. + """ + if not obj: + return + sp = " " * index + try: + change_text = ' change="%d"' % obj.get_change_time() + except: + change_text = ' change="%d"' % 0 + + handle_text = ' handle="_%s"' % obj.get_handle() + + obj_text = '%s<%s' % (sp, templatename) + self.g.write(obj_text + handle_text + change_text) + if close: + self.g.write('>\n') + def write_family_handle(self,family,index=1): sp = " "*index self.write_primary_tag('family',family,index) @@ -1174,6 +1221,27 @@ class GrampsXmlWriter(UpdateCallback): ) ) + def write_map_list(self, map_dict, indent=3): + sp = ' ' * indent + for (key, value) in list(map_dict.items()): + self.g.write('%s\n') + + def write_te_list(self, te_list, index=1): + sp = " "*index + for te in te_list: + self.g.write('%s\n' % + (sp, te.get_citation(), te.get_short(), te.get_short_alg()) + ) + self.write_line("tename", te.get_name(), index+1) + self.write_line("Display", te.get_display(), index+1) + self.write_line("Hint", te.get_hint(), index+1) + self.write_line("Tooltip", te.get_tooltip(), index+1) + self.g.write('%s\n' % sp) + pass + def write_place_obj(self, place, index=1): self.write_primary_tag("placeobj", place, index) diff --git a/gramps/plugins/importer/importxml.py b/gramps/plugins/importer/importxml.py index b447674f2..1d000b3f7 100644 --- a/gramps/plugins/importer/importxml.py +++ b/gramps/plugins/importer/importxml.py @@ -55,7 +55,7 @@ from gramps.gen.lib import (Address, Attribute, AttributeType, ChildRef, Place, RepoRef, Repository, Researcher, Source, SrcAttribute, SrcAttributeType, StyledText, StyledTextTag, StyledTextTagType, - Surname, Tag, Url) + Surname, Tag, Url, SrcTemplate, TemplateElement) from gramps.gen.db import DbTxn from gramps.gen.db.write import CLASS_TO_KEY_MAP from gramps.gen.errors import GrampsImportError @@ -67,7 +67,7 @@ from gramps.gen.display.name import displayer as name_displayer from gramps.gen.db.dbconst import (PERSON_KEY, FAMILY_KEY, SOURCE_KEY, EVENT_KEY, MEDIA_KEY, PLACE_KEY, REPOSITORY_KEY, NOTE_KEY, TAG_KEY, - CITATION_KEY) + CITATION_KEY, TEMPLATE_KEY) from gramps.gen.updatecallback import UpdateCallback from gramps.version import VERSION from gramps.gen.config import config @@ -215,7 +215,8 @@ class ImportInfo(object): Class object that can hold information about the import """ keyorder = [PERSON_KEY, FAMILY_KEY, SOURCE_KEY, EVENT_KEY, MEDIA_KEY, - PLACE_KEY, REPOSITORY_KEY, NOTE_KEY, TAG_KEY, CITATION_KEY] + PLACE_KEY, REPOSITORY_KEY, NOTE_KEY, TAG_KEY, CITATION_KEY, + TEMPLATE_KEY] key2data = { PERSON_KEY : 0, FAMILY_KEY : 1, @@ -226,7 +227,8 @@ class ImportInfo(object): REPOSITORY_KEY: 6, NOTE_KEY: 7, TAG_KEY: 8, - CITATION_KEY: 9 + CITATION_KEY: 9, + TEMPLATE_KEY: 10 } def __init__(self): @@ -235,9 +237,9 @@ class ImportInfo(object): This creates the datastructures to hold info """ - self.data_mergecandidate = [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}] - self.data_newobject = [0] * 10 - self.data_unknownobject = [0] * 10 + self.data_mergecandidate = [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}] + self.data_newobject = [0] * 11 + self.data_unknownobject = [0] * 11 self.data_families = '' self.expl_note = '' self.data_relpath = False @@ -315,6 +317,7 @@ class ImportInfo(object): NOTE_KEY : _(' Notes: %d\n'), TAG_KEY : _(' Tags: %d\n'), CITATION_KEY : _(' Citations: %d\n'), + TEMPLATE_KEY : _(' Source Templates; %d\n'), } txt = _("Number of new objects imported:\n") for key in self.keyorder: @@ -537,6 +540,7 @@ class GrampsParser(UpdateCallback): self.attribute = None self.srcattribute = None self.placeobj = None + self.template = None self.locations = 0 self.place_map = {} @@ -708,18 +712,28 @@ class GrampsParser(UpdateCallback): "source": (self.start_source, self.stop_source), "sourceref": (self.start_sourceref, self.stop_sourceref), "sources": (None, None), + "SourceTemplates": (None, None), "spage": (None, self.stop_spage), #deprecated "spubinfo": (None, self.stop_spubinfo), #deprecated in 1.6.0 "state": (None, self.stop_state), "stext": (None, self.stop_stext), "stitle": (None, self.stop_stitle), #deprecated in 1.6.0 "sname": (None, self.stop_sname), #new in 1.6.0 - "stemplate": (None, self.stop_stemplate), #new in 1.6.0 + "stemplate": (self.start_stemplate, None), #new in 1.6.0 "street": (None, self.stop_street), "style": (self.start_style, None), "tag": (self.start_tag, self.stop_tag), "tagref": (self.start_tagref, None), "tags": (None, None), + "tdescription": (None, self.stop_tdescription), + "tefield": (self.start_tefield, self.stop_tefield), + "tename": (None, self.stop_tename), + "tedisplay": (None, self.stop_tedisplay), + "tehint": (None, self.stop_tehint), + "tetooltip": (None, self.stop_tetooltip), + "template": (self.start_template, self.stop_template), + "tmap": (self.start_tmap, None), + "tname": (None, self.stop_tname), # Template name "text": (None, self.stop_text), "url": (self.start_url, None), "repository": (self.start_repo, self.stop_repo), @@ -767,7 +781,8 @@ class GrampsParser(UpdateCallback): "repository": self.db.get_raw_repository_data, "media": self.db.get_raw_object_data, "note": self.db.get_raw_note_data, - "tag": self.db.get_raw_tag_data}[target] + "tag": self.db.get_raw_tag_data, + "template": self.db.get_raw_template_data}[target] raw = get_raw_obj_data(handle) prim_obj.unserialize(raw) self.import_handles[orig_handle][target][INSTANTIATED] = True @@ -795,7 +810,8 @@ class GrampsParser(UpdateCallback): "repository": self.db.has_repository_handle, "media": self.db.has_object_handle, "note": self.db.has_note_handle, - "tag": self.db.has_tag_handle}[target] + "tag": self.db.has_tag_handle, + "template": self.db.has_template_handle}[target] while has_handle_func(handle): handle = create_id() self.import_handles[orig_handle] = {target: [handle, False]} @@ -806,6 +822,8 @@ class GrampsParser(UpdateCallback): prim_obj.set_handle(handle) if target == "tag": self.db.add_tag(prim_obj, self.trans) + elif target == "template": + self.db.add_template(prim_obj, self.trans) else: add_func = {"person": self.db.add_person, "family": self.db.add_family, @@ -1807,6 +1825,68 @@ class GrampsParser(UpdateCallback): self.note_tags[-1].ranges.append((int(attrs['start']), int(attrs['end']))) + def start_template(self, attrs): + """ + Template definition. + """ + # Tag defintion + self.template = SrcTemplate() + self.inaugurate(attrs['handle'], "template", self.template) + self.template.change = int(attrs.get('change', self.change)) + self.info.add('new-object', TEMPLATE_KEY, self.template) + self.template.set_name(attrs.get('tname', _('Unknown when imported'))) + self.template.set_descr(attrs.get('tdescription', _('Unknown when imported'))) + return self.template + + def stop_template(self, *tag): + self.db.commit_template(self.template, self.trans, self.template.get_change_time()) + self.template = None + + def stop_tname(self, tag): + self.template.set_name(tag) + + def stop_tdescription(self, tag): + self.template.set_descr(tag) + + def start_tmap(self, attrs): + self.template.set_map_element(attrs["key"], attrs["value"]) + + @staticmethod + def _conv_bool(val, default): + """ + Converts a string attribute to True or False. If the attribute is absent + (val is None) the default value is returned. If the value is "True" then + True is returned and vice-versa for False + """ + if val is None: + return default + if val == "True": + return True + else: + return False + + def start_tefield(self, attrs): + self.template_element = TemplateElement() + self.template_element.set_citation(self._conv_bool(attrs.get("citation"), False)) + self.template_element.set_short(self._conv_bool(attrs.get("short"), False)) + self.template_element.set_short_alg(attrs.get("short_alg", None)) + + def stop_tename(self, tag): + self.template_element.set_name(tag) + + def stop_tedisplay(self, tag): + self.template_element.set_display(tag) + + def stop_tehint(self, tag): + self.template_element.set_hint(tag) + + def stop_tetooltip(self, tag): + self.template_element.set_tooltip(tag) + + def stop_tefield(self, tag): + self.template.add_template_element(self.template_element) + self.template_element = None + def start_note(self, attrs): """ Add a note to db if it doesn't exist yet and assign @@ -2083,6 +2163,7 @@ class GrampsParser(UpdateCallback): self.inaugurate_id(attrs.get('id'), SOURCE_KEY, self.source) self.source.private = bool(attrs.get("priv")) self.source.change = int(attrs.get('change', self.change)) + self.source.template = None self.info.add('new-object', SOURCE_KEY, self.source) return self.source @@ -2732,10 +2813,13 @@ class GrampsParser(UpdateCallback): #store descriptive name of the source self.source.name = tag - def stop_stemplate(self, tag): - #store template of the source - self.source.template = tag - + def start_stemplate(self, attrs): + """ + Add a template reference to the source object currently being processed + """ + handle = self.inaugurate(attrs['hlink'], "template", SrcTemplate) + self.source.set_template(handle) + def stop_stitle(self, tag): #title was deprecated and converted to name and attribute TITLE in 1.6.0 if not self.source.name: @@ -2754,6 +2838,18 @@ class GrampsParser(UpdateCallback): self.in_old_sourceref = False def stop_source(self, *tag): + # Template are new at 1.6.0. Prior to 1.6.0, sources (and citations) wll + # be GEDCOM style, so the template needs to be set to GEDCOM - if the + # GEDCOM template has not alraedy been defined, it needs to be built. + if self.__xml_version < '1.6.0': + gedcom_handle = self.db.get_GEDCOM_template_handle() + if gedcom_handle is None: + from gramps.plugins.srctemplates.gedcomtemplate import load_template + load_template(self.db) + gedcom_handle = self.db.get_GEDCOM_template_handle() + self.source.set_template(gedcom_handle) + # From xml version 1.6.0, if the template is None, this is intentional, + # and there is no template defined. self.db.commit_source(self.source, self.trans, self.source.get_change_time()) self.source = None diff --git a/gramps/plugins/srctemplates/gedcomtemplate.py b/gramps/plugins/srctemplates/gedcomtemplate.py index 4ada18428..4d8900f8c 100644 --- a/gramps/plugins/srctemplates/gedcomtemplate.py +++ b/gramps/plugins/srctemplates/gedcomtemplate.py @@ -47,7 +47,8 @@ _ = 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.lib.srctemplate import SrcTemplate +from gramps.gen.lib.templateelement import 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) diff --git a/gramps/plugins/srctemplates/importcsv.py b/gramps/plugins/srctemplates/importcsv.py index ed1c08d4e..94eb0bc25 100644 --- a/gramps/plugins/srctemplates/importcsv.py +++ b/gramps/plugins/srctemplates/importcsv.py @@ -48,7 +48,8 @@ from gramps.gen.db import DbTxn 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.lib.srctemplate import SrcTemplate +from gramps.gen.lib.templateelement import 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) @@ -335,7 +336,7 @@ def load_srctemplate_csv(csvfile, db): optional = True shorteralg = SHORTERALG.get(row[SHORTERCOL].strip()) or EMPTY gedcom_type_text = row[GEDCOMCOL].strip() - gedcommap = GEDCOMFIELDS.get(row[GEDCOMCOL].strip()) or EMPTY + gedcommap = GEDCOMFIELDS.get(row[GEDCOMCOL].strip()) style = STYLES.get(row[STYLECOL].strip()) or EMPTY if source_type in TYPE2TEMPLATEMAP: @@ -376,7 +377,6 @@ def load_srctemplate_csv(csvfile, db): # 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.') - target = "EE_" + cite_type_text if te.get_short(): if field_type.lower().endswith(' (short)'): txt = field_type @@ -392,8 +392,8 @@ def load_srctemplate_csv(csvfile, db): if style == STYLE_QUOTE: txt = '"' + txt + '"' elif style == STYLE_QUOTECONT: - if template.get_map_element(target)[-1] == '"': - template.set_map_element(target, template.get_map_element(target)[:-1]) + if template.get_map_element(cite_type)[-1] == '"': + template.set_map_element(cite_type, template.get_map_element(cite_type)[:-1]) txt = txt + '"' else: txt = '"' + txt + '"' @@ -401,15 +401,14 @@ def load_srctemplate_csv(csvfile, db): txt = "" + txt + "" elif style == STYLE_BOLD: txt = "" + txt + "" - template.set_map_element(target, template.get_map_element(target) + txt) + template.set_map_element(cite_type, template.get_map_element(cite_type) + txt) # Setup the GEDCOM fields. These are only stored in the L template if cite_type == REF_TYPE_L and gedcom_type_text: - target = "GEDCOM_" + gedcom_type_text if style == STYLE_QUOTECONT: - if template.get_map_element(target) and template.get_map_element(target)[-1] == '"': - template.set_map_element(target, template.get_map_element(target)[:-1]) - template.set_map_element(target, template.get_map_element(target) + txt) + if template.get_map_element(gedcommap) and template.get_map_element(gedcommap)[-1] == '"': + template.set_map_element(gedcommap, template.get_map_element(gedcommap)[:-1]) + template.set_map_element(gedcommap, template.get_map_element(gedcommap) + txt) msg = _("Add template (%s)") % template.get_name() with DbTxn(msg, db) as trans: @@ -455,9 +454,8 @@ def load_srctemplate_csv(csvfile, db): template = TYPE2TEMPLATEMAP[source_type] for te in [x for x in template.get_template_element_list() if x.get_citation() and not x.get_short()]: - target = "GEDCOM_PAGE" - template.set_map_element(target, - ", ".join((template.get_map_element(target), txt))) + template.set_map_element(GED_PAGE, + ", ".join((template.get_map_element(GED_PAGE), txt))) msg = _("Add template (%s)") % template.get_name() with DbTxn(msg, db) as trans: db.commit_template(template, trans)