GEPS 011: Tagging - Add XML import and export

svn: r15938
This commit is contained in:
Nick Hall
2010-09-29 22:25:52 +00:00
parent 8b675ed1f2
commit 6b6da7dafe
6 changed files with 364 additions and 160 deletions

View File

@@ -198,9 +198,10 @@ 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()
total_steps = person_len + family_len + event_len + source_len \
+ place_len + repo_len + obj_len + note_len
+ place_len + repo_len + obj_len + note_len + tag_len
self.set_total(total_steps)
@@ -233,6 +234,16 @@ class GrampsXmlWriter(UpdateCallback):
# by the time we get to person's names
self.write_name_formats()
# Write table objects
if tag_len > 0:
self.g.write(" <tags>\n")
for key in self.db.get_tag_handles():
tag = self.db.get_tag_from_handle(key)
self.write_tag(tag, 2)
self.update()
self.g.write(" </tags>\n")
# Write primary objects
if event_len > 0:
self.g.write(" <events>\n")
for handle in self.db.get_event_handles():
@@ -384,6 +395,19 @@ class GrampsXmlWriter(UpdateCallback):
escxml(name), escxml(fmt_str), int(active)) )
self.g.write(" </name-formats>\n")
def write_tag(self, tag, index=2):
"""
Write a tag definition.
"""
if not tag:
return
self.write_table_tag('tag', tag, index, close=False)
self.g.write(' name="%s"' % escxml(tag.get_name()))
self.g.write(' color="%s"' % tag.get_color())
self.g.write(' priority="%d"' % tag.get_priority())
self.g.write('/>\n')
def fix(self,line):
try:
l = unicode(line)
@@ -426,7 +450,7 @@ class GrampsXmlWriter(UpdateCallback):
name = tag.name.xml_str()
value = tag.value
self.g.write(' ' * index + '<tag name="%s"' % name)
self.g.write(' ' * index + '<style name="%s"' % name)
if value:
self.g.write(' value="%s"' % escxml(str(value)))
self.g.write('>\n')
@@ -435,7 +459,7 @@ class GrampsXmlWriter(UpdateCallback):
self.g.write((' ' * (index + 1)) +
'<range start="%d" end="%d"/>\n' % (start, end))
self.g.write(' ' * index + '</tag>\n')
self.g.write(' ' * index + '</style>\n')
def write_text(self, val, text, indent=0):
if not text:
@@ -488,6 +512,10 @@ class GrampsXmlWriter(UpdateCallback):
for s in person.get_source_references():
self.dump_source_ref(s,index+2)
for tag_handle in person.get_tag_list():
self.write_ref("tagref", tag_handle, index+1)
self.g.write("%s</person>\n" % sp)
def write_family(self,family,index=1):
@@ -711,22 +739,37 @@ class GrampsXmlWriter(UpdateCallback):
self.g.write('%s<%s hlink="_%s"%s%s>\n'
% (sp,tagname, handle,extra_text,close_tag))
def write_primary_tag(self,tagname, obj,index=1,close=True):
def write_primary_tag(self, tagname, obj, index=1, close=True):
"""
Write the tag attributes common to all primary objects.
"""
if not obj:
return
sp = " "*index
marker = obj.get_marker().xml_str()
if marker:
marker_text = ' marker="%s"' % escxml(marker)
else:
marker_text = ''
priv_text = conf_priv(obj)
change_text = ' change="%d"' % obj.get_change_time()
handle_id_text = ' id="%s" handle="_%s"' % (escxml(obj.gramps_id), obj.handle)
obj_text = '%s<%s' % (sp,tagname)
id_text = ' id="%s"' % escxml(obj.gramps_id)
self.g.write(obj_text + handle_id_text + priv_text + marker_text +
change_text)
self.write_table_tag(tagname, obj, index, False)
self.g.write(id_text + priv_text + marker_text)
if close:
self.g.write('>\n')
def write_table_tag(self, tagname, obj, index=1, close=True):
"""
Write the tag attributes common to all table objects.
"""
if not obj:
return
sp = " " * index
change_text = ' change="%d"' % obj.get_change_time()
handle_text = ' handle="_%s"' % obj.get_handle()
obj_text = '%s<%s' % (sp, tagname)
self.g.write(obj_text + handle_text + change_text)
if close:
self.g.write('>\n')

View File

@@ -46,7 +46,8 @@ import Utils
import DateHandler
from gen.display.name import displayer as name_displayer
from gen.db.dbconst import (PERSON_KEY, FAMILY_KEY, SOURCE_KEY, EVENT_KEY,
MEDIA_KEY, PLACE_KEY, REPOSITORY_KEY, NOTE_KEY)
MEDIA_KEY, PLACE_KEY, REPOSITORY_KEY, NOTE_KEY,
TAG_KEY)
from gen.updatecallback import UpdateCallback
import const
import libgrampsxml
@@ -198,7 +199,7 @@ 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]
PLACE_KEY, REPOSITORY_KEY, NOTE_KEY, TAG_KEY]
key2data = {
PERSON_KEY : 0,
FAMILY_KEY : 1,
@@ -207,7 +208,8 @@ class ImportInfo(object):
MEDIA_KEY: 4,
PLACE_KEY: 5,
REPOSITORY_KEY: 6,
NOTE_KEY: 7
NOTE_KEY: 7,
TAG_KEY: 8
}
def __init__(self):
@@ -216,8 +218,8 @@ class ImportInfo(object):
This creates the datastructures to hold info
"""
self.data_mergeoverwrite = [{},{},{},{},{},{},{},{}]
self.data_newobject = [0,0,0,0,0,0,0,0]
self.data_mergeoverwrite = [{}] * 9
self.data_newobject = [0] * 9
self.data_relpath = False
@@ -257,6 +259,8 @@ class ImportInfo(object):
return _(" Repository %(id)s\n") % {'id': obj.gramps_id}
elif key == NOTE_KEY:
return _(" Note %(id)s\n") % {'id': obj.gramps_id}
elif key == TAG_KEY:
return _(" Tag %(name)s\n") % {'name': obj.get_name()}
def info_text(self):
"""
@@ -271,6 +275,7 @@ class ImportInfo(object):
PLACE_KEY : _(' Places: %d\n'),
REPOSITORY_KEY : _(' Repositories: %d\n'),
NOTE_KEY : _(' Notes: %d\n'),
TAG_KEY : _(' Tags: %d\n'),
}
txt = _("Number of new objects imported:\n")
for key in self.keyorder:
@@ -373,6 +378,7 @@ class GrampsParser(UpdateCallback):
self.in_note = 0
self.in_stext = 0
self.in_scomments = 0
self.note = None
self.note_text = None
self.note_tags = []
self.in_witness = False
@@ -529,8 +535,11 @@ class GrampsParser(UpdateCallback):
"stext": (None, self.stop_stext),
"stitle": (None, self.stop_stitle),
"street": (None, self.stop_street),
"style": (self.start_style, None),
"suffix": (None, self.stop_suffix),
"tag": (self.start_tag, None),
"tagref": (self.start_tagref, None),
"tags": (None, None),
"text": (None, self.stop_text),
"title": (None, self.stop_title),
"url": (self.start_url, None),
@@ -1321,7 +1330,10 @@ class GrampsParser(UpdateCallback):
self.name.prefix = attrs.get('prefix', '')
self.name.group_as = attrs.get('group', '')
def start_tag(self, attrs):
def start_style(self, attrs):
"""
Styled text tag in notes (v1.4.0 onwards).
"""
tagtype = gen.lib.StyledTextTagType()
tagtype.set_from_xml_str(attrs['name'])
@@ -1334,6 +1346,42 @@ class GrampsParser(UpdateCallback):
return
self.note_tags.append(gen.lib.StyledTextTag(tagtype, tagvalue))
def start_tag(self, attrs):
"""
Tag definition.
"""
if self.note is not None:
# Styled text tag in notes (prior to v1.4.0)
self.start_style(attrs)
return
# Tag defintion
self.tag, new = self.db.find_tag_from_handle(
attrs['handle'].replace('_', ''), self.trans)
if new:
#keep change time from xml file
self.tag.change = int(attrs.get('change', self.change))
self.info.add('new-object', TAG_KEY, self.tag)
else:
self.tag.change = self.change
self.info.add('merge-overwrite', TAG_KEY, self.tag)
self.tag.set_name(attrs['name'])
self.tag.set_color(attrs['color'])
self.tag.set_priority(int(attrs['priority']))
self.db.commit_tag(self.tag, self.trans, self.tag.get_change_time())
def start_tagref(self, attrs):
"""
Tag reference in a primary object.
"""
handle = attrs['hlink'].replace('_', '')
self.db.check_tag_from_handle(handle, self.trans)
if self.person:
self.person.add_tag(handle)
def start_range(self, attrs):
self.note_tags[-1].ranges.append((int(attrs['start']),

View File

@@ -35,5 +35,5 @@
# Public Constants
#
#------------------------------------------------------------------------
GRAMPS_XML_VERSION = "1.3.0"
GRAMPS_XML_VERSION = "1.4.0"

View File

@@ -29,8 +29,8 @@ Mixin for DbDir to enable find_from_handle and check_from_handle methods.
# Gramps Modules
#
#------------------------------------------------------------------------------
from gen.lib import (GenderStats, Person, Family, Event, Place, Source,
MediaObject, Repository, Note)
from gen.lib import (Person, Family, Event, Place, Source,
MediaObject, Repository, Note, Tag)
#------------------------------------------------------------------------------
#
@@ -50,10 +50,11 @@ class DbMixin(object):
where "database" is the object name of your instance of the gramps
database.
"""
def find_from_handle(self, handle, transaction, class_type, dmap,
def __find_primary_from_handle(self, handle, transaction, class_type, dmap,
add_func):
"""
Find a object of class_type in the database from the passed handle.
Find a primary object of class_type in the database from the passed
handle.
If no object exists, a new object is added to the database.
@@ -74,14 +75,57 @@ class DbMixin(object):
add_func(obj, transaction)
return obj, new
def __check_from_handle(self, handle, transaction, class_type, dmap,
def __find_table_from_handle(self, handle, transaction, class_type, dmap,
add_func):
"""
Find a table object of class_type in the database from the passed
handle.
If no object exists, a new object is added to the database.
@return: Returns a tuple, first the object, second a bool which is True
if the object is new
@rtype: tuple
"""
obj = class_type()
handle = str(handle)
if handle in dmap:
obj.unserialize(dmap.get(handle))
return obj, False
else:
obj.set_handle(handle)
add_func(obj, transaction)
return obj, True
def __check_primary_from_handle(self, handle, transaction, class_type, dmap,
add_func, set_gid=True):
"""
Check whether a primary object of class_type with the passed handle
exists in the database.
If no such object exists, a new object is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
handle = str(handle)
if handle not in dmap:
obj = class_type()
obj.set_handle(handle)
add_func(obj, transaction, set_gid=set_gid)
def __check_table_from_handle(self, handle, transaction, class_type, dmap,
add_func):
"""
Check whether a table object of class_type with the passed handle exists
in the database.
If no such object exists, a new object is added to the database.
"""
handle = str(handle)
if handle not in dmap:
obj = class_type()
obj.set_handle(handle)
add_func(obj, transaction)
def find_person_from_handle(self, handle, transaction):
"""
Find a Person in the database from the passed handle.
@@ -92,7 +136,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Person,
return self.__find_primary_from_handle(handle, transaction, Person,
self.person_map, self.add_person)
def find_source_from_handle(self, handle, transaction):
@@ -105,7 +149,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Source,
return self.__find_primary_from_handle(handle, transaction, Source,
self.source_map, self.add_source)
def find_event_from_handle(self, handle, transaction):
@@ -118,7 +162,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Event,
return self.__find_primary_from_handle(handle, transaction, Event,
self.event_map, self.add_event)
def find_object_from_handle(self, handle, transaction):
@@ -131,7 +175,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, MediaObject,
return self.__find_primary_from_handle(handle, transaction, MediaObject,
self.media_map, self.add_object)
def find_place_from_handle(self, handle, transaction):
@@ -144,7 +188,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Place,
return self.__find_primary_from_handle(handle, transaction, Place,
self.place_map, self.add_place)
def find_family_from_handle(self, handle, transaction):
@@ -157,7 +201,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Family,
return self.__find_primary_from_handle(handle, transaction, Family,
self.family_map, self.add_family)
def find_repository_from_handle(self, handle, transaction):
@@ -170,7 +214,7 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Repository,
return self.__find_primary_from_handle(handle, transaction, Repository,
self.repository_map, self.add_repository)
def find_note_from_handle(self, handle, transaction):
@@ -183,9 +227,22 @@ class DbMixin(object):
if the object is new
@rtype: tuple
"""
return self.find_from_handle(handle, transaction, Note,
return self.__find_primary_from_handle(handle, transaction, Note,
self.note_map, self.add_note)
def find_tag_from_handle(self, handle, transaction):
"""
Find a Tag in the database from the passed handle.
If no such Tag exists, a new Tag is added to the database.
@return: Returns a tuple, first the object, second a bool which is True
if the object is new
@rtype: tuple
"""
return self.__find_table_from_handle(handle, transaction, Tag,
self.tag_map, self.add_tag)
def check_person_from_handle(self, handle, transaction, set_gid=True):
"""
Check whether a Person with the passed handle exists in the database.
@@ -193,7 +250,7 @@ class DbMixin(object):
If no such Person exists, a new Person is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Person,
self.__check_primary_from_handle(handle, transaction, Person,
self.person_map, self.add_person,
set_gid = set_gid)
@@ -204,7 +261,7 @@ class DbMixin(object):
If no such Source exists, a new Source is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Source,
self.__check_primary_from_handle(handle, transaction, Source,
self.source_map, self.add_source,
set_gid=set_gid)
@@ -215,7 +272,7 @@ class DbMixin(object):
If no such Event exists, a new Event is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Event,
self.__check_primary_from_handle(handle, transaction, Event,
self.event_map, self.add_event,
set_gid=set_gid)
@@ -228,7 +285,7 @@ class DbMixin(object):
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, MediaObject,
self.__check_primary_from_handle(handle, transaction, MediaObject,
self.media_map, self.add_object,
set_gid=set_gid)
@@ -239,7 +296,7 @@ class DbMixin(object):
If no such Place exists, a new Place is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Place,
self.__check_primary_from_handle(handle, transaction, Place,
self.place_map, self.add_place,
set_gid=set_gid)
@@ -250,7 +307,7 @@ class DbMixin(object):
If no such Family exists, a new Family is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Family,
self.__check_primary_from_handle(handle, transaction, Family,
self.family_map, self.add_family,
set_gid=set_gid)
@@ -262,7 +319,7 @@ class DbMixin(object):
If no such Repository exists, a new Repository is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Repository,
self.__check_primary_from_handle(handle, transaction, Repository,
self.repository_map, self.add_repository,
set_gid=set_gid)
@@ -273,6 +330,15 @@ class DbMixin(object):
If no such Note exists, a new Note is added to the database.
If set_gid then a new gramps_id is created, if not, None is used.
"""
self.__check_from_handle(handle, transaction, Note,
self.__check_primary_from_handle(handle, transaction, Note,
self.note_map, self.add_note,
set_gid=set_gid)
def check_tag_from_handle(self, handle, transaction):
"""
Check whether a Tag with the passed handle exists in the database.
If no such Tag exists, a new Tag is added to the database.
"""
self.__check_table_from_handle(handle, transaction, Tag,
self.tag_map, self.add_tag)