Added tagging on import for GEDCOM, XML, and CSV. Also fixed CSV iterator issue with next. Default tag is set in Preferences using time.strftime codes (eg, %Y, %m, etc). Noticed that adding source on input is only for GEDCOM, so adjusted the text description for it. Tagging on input supports all taggable items (notes, media, family, person --- although csv does not import media). Will add to gramps40 if all ok.

svn: r20914
This commit is contained in:
Doug Blank 2012-12-31 20:07:36 +00:00
parent 1c240f9bef
commit 771ae761e2
7 changed files with 147 additions and 27 deletions

View File

@ -279,6 +279,8 @@ register('preferences.date-format', 0)
register('preferences.calendar-format-report', 0)
register('preferences.cprefix', 'C%04d')
register('preferences.default-source', False)
register('preferences.tag-on-import', False)
register('preferences.tag-on-import-format', _("Imported %Y/%m/%d %H:%M:%S"))
register('preferences.eprefix', 'E%04d')
register('preferences.family-warn', True)
register('preferences.fprefix', 'F%04d')

View File

@ -327,13 +327,18 @@ class ConfigureDialog(ManagedWindow):
config = self.__config
if not callback:
callback = self.update_entry
lwidget = BasicLabel("%s: " % label)
if label:
lwidget = BasicLabel("%s: " % label)
entry = Gtk.Entry()
entry.set_text(config.get(constant))
entry.connect('changed', callback, constant)
table.attach(lwidget, col_attach, col_attach+1, index, index+1, yoptions=0,
xoptions=Gtk.AttachOptions.FILL)
table.attach(entry, col_attach+1, col_attach+2, index, index+1, yoptions=0)
if label:
table.attach(lwidget, col_attach, col_attach+1, index, index+1, yoptions=0,
xoptions=Gtk.AttachOptions.FILL)
table.attach(entry, col_attach+1, col_attach+2, index, index+1, yoptions=0)
else:
table.attach(entry, col_attach, col_attach+1, index, index+1, yoptions=0)
return entry
def add_pos_int_entry(self, table, label, index, constant, callback=None,
config=None, col_attach=1):
@ -1101,6 +1106,11 @@ class GrampsPreferences(ConfigureDialog):
config.set('behavior.do-not-show-previously-seen-updates',
bool(active))
def toggle_tag_on_import(self, obj):
active = obj.get_active()
config.set('preferences.tag-on-import', bool(active))
self.tag_format_entry.set_sensitive(bool(active))
def check_for_updates_changed(self, obj):
active = obj.get_active()
config.set('behavior.check-for-updates', active)
@ -1153,27 +1163,49 @@ class GrampsPreferences(ConfigureDialog):
table.set_col_spacings(6)
table.set_row_spacings(6)
current_line = 0
self.add_checkbox(table,
_('Add default source on import'),
0, 'preferences.default-source')
_('Add default source on GEDCOM import'),
current_line, 'preferences.default-source')
current_line += 1
checkbutton = Gtk.CheckButton(_("Add tag on import"))
checkbutton.set_active(config.get('preferences.tag-on-import'))
checkbutton.connect("toggled", self.toggle_tag_on_import)
table.attach(checkbutton, 1, 2, current_line, current_line+1, yoptions=0)
self.tag_format_entry = self.add_entry(table, None, current_line,
'preferences.tag-on-import-format',
col_attach=2)
self.tag_format_entry.set_sensitive(config.get('preferences.tag-on-import'))
current_line += 1
self.add_checkbox(table,
_('Enable spelling checker'),
1, 'behavior.spellcheck')
current_line, 'behavior.spellcheck')
current_line += 1
self.add_checkbox(table,
_('Display Tip of the Day'),
2, 'behavior.use-tips')
current_line, 'behavior.use-tips')
current_line += 1
self.add_checkbox(table,
_('Remember last view displayed'),
3, 'preferences.use-last-view')
current_line, 'preferences.use-last-view')
current_line += 1
self.add_spinner(table,
_('Max generations for relationships'),
4, 'behavior.generation-depth', (5, 50), self.update_gendepth)
current_line, 'behavior.generation-depth', (5, 50), self.update_gendepth)
current_line += 1
self.path_entry = Gtk.Entry()
self.add_path_box(table,
_('Base path for relative media paths'),
5, self.path_entry, self.dbstate.db.get_mediapath(),
current_line, self.path_entry, self.dbstate.db.get_mediapath(),
self.set_mediapath, self.select_mediapath)
current_line += 1
# Check for updates:
obox = Gtk.ComboBoxText()
formats = [_("Never"),
@ -1186,9 +1218,10 @@ class GrampsPreferences(ConfigureDialog):
obox.set_active(active)
obox.connect('changed', self.check_for_updates_changed)
lwidget = BasicLabel("%s: " % _('Check for updates'))
table.attach(lwidget, 1, 2, 6, 7, yoptions=0)
table.attach(obox, 2, 3, 6, 7, yoptions=0)
table.attach(lwidget, 1, 2, current_line, current_line+1, yoptions=0)
table.attach(obox, 2, 3, current_line, current_line+1, yoptions=0)
current_line += 1
self.whattype_box = Gtk.ComboBoxText()
formats = [_("Updated addons only"),
_("New addons only"),
@ -1203,21 +1236,23 @@ class GrampsPreferences(ConfigureDialog):
self.whattype_box.set_active(0)
self.whattype_box.connect('changed', self.check_for_type_changed)
lwidget = BasicLabel("%s: " % _('What to check'))
table.attach(lwidget, 1, 2, 7, 8, yoptions=0)
table.attach(self.whattype_box, 2, 3, 7, 8, yoptions=0)
table.attach(lwidget, 1, 2, current_line, current_line+1, yoptions=0)
table.attach(self.whattype_box, 2, 3, current_line, current_line+1, yoptions=0)
self.add_entry(table, _('Where to check'), 8, 'behavior.addons-url', col_attach=1)
current_line += 1
self.add_entry(table, _('Where to check'), current_line, 'behavior.addons-url', col_attach=1)
current_line += 1
checkbutton = Gtk.CheckButton(
_("Do not ask about previously notified addons"))
checkbutton.set_active(config.get('behavior.do-not-show-previously-seen-updates'))
checkbutton.connect("toggled", self.toggle_hide_previous_addons)
table.attach(checkbutton, 0, 3, 9, 10, yoptions=0)
table.attach(checkbutton, 0, 3, current_line, current_line+1, yoptions=0)
button = Gtk.Button(_("Check now"))
button.connect("clicked", lambda obj: \
self.uistate.viewmanager.check_for_updates(force=True))
table.attach(button, 3, 4, 9, 10, yoptions=0)
table.attach(button, 3, 4, current_line, current_line+1, yoptions=0)
return _('General'), table

View File

@ -50,7 +50,7 @@ LOG = logging.getLogger(".ImportCSV")
#-------------------------------------------------------------------------
from gramps.gen.ggettext import sgettext as _
from gramps.gen.ggettext import ngettext
from gramps.gen.lib import ChildRef, Citation, Event, EventRef, EventType, Family, FamilyRelType, Name, NameType, Note, NoteType, Person, Place, Source, Surname
from gramps.gen.lib import ChildRef, Citation, Event, EventRef, EventType, Family, FamilyRelType, Name, NameType, Note, NoteType, Person, Place, Source, Surname, Tag
from gramps.gen.db import DbTxn
from gramps.gen.plug.utils import OpenFileOrStdin
from gramps.gen.datehandler import parser as _dp
@ -59,6 +59,7 @@ from gramps.gen.utils.id import create_id
from gramps.gui.utils import ProgressMeter
from gramps.gen.lib.eventroletype import EventRoleType
from gramps.gen.constfunc import cuni, conv_to_unicode, STRTYPE
from gramps.gen.config import config
#-------------------------------------------------------------------------
#
@ -95,6 +96,8 @@ class UTF8Recoder(object):
"Encode the next line of the file."
return self.reader.next().encode("utf-8")
next = __next__
class UnicodeReader(object):
"""
A CSV reader which will iterate over lines in the CSV file,
@ -120,6 +123,8 @@ class UnicodeReader(object):
def __iter__(self):
return self
next = __next__
#-------------------------------------------------------------------------
#
# Support and main functions
@ -141,7 +146,8 @@ def rd(line_number, row, col, key, default = None):
def importData(dbase, filename, user):
"""Function called by Gramps to import data on persons in CSV format."""
parser = CSVParser(dbase, user)
parser = CSVParser(dbase, user, (config.get('preferences.tag-on-import-format') if
config.get('preferences.tag-on-import') else None))
try:
with OpenFileOrStdin(filename, 'b') as filehandle:
parser.parse(filehandle)
@ -157,7 +163,7 @@ def importData(dbase, filename, user):
#-------------------------------------------------------------------------
class CSVParser(object):
"""Class to read data in CSV format from a file object."""
def __init__(self, dbase, user):
def __init__(self, dbase, user, default_tag_format=None):
self.db = dbase
self.user = user
self.trans = None
@ -235,6 +241,16 @@ class CSVParser(object):
for val in column2label[key]:
lab2col_dict.append((val, key))
self.label2column = dict(lab2col_dict)
if default_tag_format:
name = time.strftime(default_tag_format)
tag = self.db.get_tag_from_name(name)
if tag:
self.default_tag = tag
else:
self.default_tag = Tag()
self.default_tag.set_name(name)
else:
self.default_tag = None
def cleanup_column_name(self, column):
"""Handle column aliases for CSV spreadsheet import and SQL."""
@ -313,6 +329,8 @@ class CSVParser(object):
tym = time.time()
self.db.disable_signals()
with DbTxn(_("CSV import"), self.db, batch=True) as self.trans:
if self.default_tag and self.default_tag.handle is None:
self.db.add_tag(self.default_tag, self.trans)
self._parse_csv_data(data, progress)
self.db.enable_signals()
self.db.request_rebuild()
@ -432,6 +450,8 @@ class CSVParser(object):
new_note.handle = create_id()
new_note.type.set(NoteType.EVENT)
new_note.set(note)
if self.default_tag:
new_note.add_tag(self.default_tag.handle)
self.db.add_note(new_note, self.trans)
marriage.add_note(new_note.handle)
self.db.commit_event(marriage, self.trans)
@ -709,6 +729,8 @@ class CSVParser(object):
if wife.get_handle() != fam_wife_handle:
# this wife is not the same old one! Add her!
family.set_mother_handle(wife.get_handle())
if self.default_tag:
family.add_tag(self.default_tag.handle)
LOG.debug(" returning existing family")
return family
# if not, create one:
@ -775,6 +797,8 @@ class CSVParser(object):
def create_person(self):
""" Used to create a new person we know doesn't exist """
person = Person()
if self.default_tag:
person.add_tag(self.default_tag.handle)
self.db.add_person(person, self.trans)
self.indi_count += 1
return person

View File

@ -115,8 +115,10 @@ def importData(database, filename, user):
stage_one.set_encoding(code_set)
ifile.seek(0)
gedparse = libgedcom.GedcomParser(
database, ifile, filename, user, stage_one,
config.get('preferences.default-source'))
database, ifile, filename, user, stage_one,
config.get('preferences.default-source'),
(config.get('preferences.tag-on-import-format') if
config.get('preferences.tag-on-import') else None))
except IOError as msg:
user.notify_error(_("%s could not be opened\n") % filename, str(msg))
return

View File

@ -94,6 +94,7 @@ def impData(database, name, user):
importer = importData
info = importer(database, imp_db_name, user)
newmediapath = database.get_mediapath()
#import of gpkg should not change media path as all media has new paths!
if not oldmediapath == newmediapath :

View File

@ -67,6 +67,7 @@ from gramps.gen.db.dbconst import (PERSON_KEY, FAMILY_KEY, SOURCE_KEY,
CITATION_KEY)
from gramps.gen.updatecallback import UpdateCallback
from gramps.gen.const import VERSION
from gramps.gen.config import config
#import gramps.plugins.lib.libgrampsxml
from gramps.plugins.lib import libgrampsxml
@ -123,7 +124,9 @@ def importData(database, filename, user):
change = time.time()
else:
change = os.path.getmtime(filename)
parser = GrampsParser(database, user, change)
parser = GrampsParser(database, user, change,
(config.get('preferences.tag-on-import-format') if
config.get('preferences.tag-on-import') else None))
if filename != '-':
linecounter = LineParser(filename)
@ -457,7 +460,7 @@ class ImportOpenFileContextManager:
#-------------------------------------------------------------------------
class GrampsParser(UpdateCallback):
def __init__(self, database, user, change):
def __init__(self, database, user, change, default_tag_format=None):
UpdateCallback.__init__(self, user.callback)
self.user = user
self.__gramps_version = 'unknown'
@ -564,6 +567,17 @@ class GrampsParser(UpdateCallback):
self.eidswap = {}
self.import_handles = {}
if default_tag_format:
name = time.strftime(default_tag_format)
tag = self.db.get_tag_from_name(name)
if tag:
self.default_tag = tag
else:
self.default_tag = Tag()
self.default_tag.set_name(name)
else:
self.default_tag = None
self.func_map = {
#name part
"name": (self.start_name, self.stop_name),
@ -895,6 +909,9 @@ class GrampsParser(UpdateCallback):
self.db.disable_signals()
if self.default_tag and self.default_tag.handle is None:
self.db.add_tag(self.default_tag, self.trans)
self.p = ParserCreate()
self.p.StartElementHandler = self.startElement
self.p.EndElementHandler = self.endElement
@ -1384,6 +1401,8 @@ class GrampsParser(UpdateCallback):
self.person.change = int(attrs.get('change', self.change))
self.info.add('new-object', PERSON_KEY, self.person)
self.convert_marker(attrs, self.person)
if self.default_tag:
self.person.add_tag(self.default_tag.handle)
return self.person
def start_people(self, attrs):
@ -1520,6 +1539,8 @@ class GrampsParser(UpdateCallback):
if 'type' in attrs:
self.family.type.set_from_xml_str(attrs["type"])
self.convert_marker(attrs, self.family)
if self.default_tag:
self.family.add_tag(self.default_tag.handle)
return self.family
def start_rel(self, attrs):
@ -1833,6 +1854,8 @@ class GrampsParser(UpdateCallback):
#set correct change time
self.db.commit_note(self.note, self.trans, self.change)
self.info.add('new-object', NOTE_KEY, self.note)
if self.default_tag:
self.note.add_tag(self.default_tag.handle)
return self.note
def start_noteref(self, attrs):
@ -2088,6 +2111,8 @@ class GrampsParser(UpdateCallback):
src = attrs.get("src", '')
if src:
self.object.path = src
if self.default_tag:
self.object.add_tag(self.default_tag.handle)
return self.object
def start_repo(self, attrs):

View File

@ -127,7 +127,7 @@ from gramps.gen.lib import (Address, Attribute, AttributeType, ChildRef,
ChildRefType, Citation, Date, Event, EventRef, EventRoleType,
EventType, Family, FamilyRelType, LdsOrd, Location, MediaObject,
MediaRef, Name, NameType, Note, NoteType, Person, PersonRef, Place,
RepoRef, Repository, RepositoryType, Researcher, Source,
RepoRef, Repository, RepositoryType, Researcher, Source, Tag,
SourceMediaType, Surname, Url, UrlType)
from gramps.gen.db import DbTxn
from gramps.gen.updatecallback import UpdateCallback
@ -1807,7 +1807,7 @@ class GedcomParser(UpdateCallback):
return name
def __init__(self, dbase, ifile, filename, user, stage_one,
default_source):
default_source, default_tag_format=None):
UpdateCallback.__init__(self, user.callback)
self.user = user
self.set_total(stage_one.get_line_count())
@ -1835,6 +1835,16 @@ class GedcomParser(UpdateCallback):
self.def_src = Source()
fname = os.path.basename(filename).split('\\')[-1]
self.def_src.set_title(_("Import from GEDCOM (%s)") % fname)
if default_tag_format:
name = time.strftime(default_tag_format)
tag = self.dbase.get_tag_from_name(name)
if tag:
self.default_tag = tag
else:
self.default_tag = Tag()
self.default_tag.set_name(name)
else:
self.default_tag = None
self.dir_path = os.path.dirname(filename)
self.is_ftw = False
self.groups = None
@ -2594,6 +2604,8 @@ class GedcomParser(UpdateCallback):
self.want_parse_warnings = True
if self.use_def_src:
self.dbase.add_source(self.def_src, self.trans)
if self.default_tag and self.default_tag.handle is None:
self.dbase.add_tag(self.default_tag, self.trans)
self.__parse_record()
self.__parse_trailer()
for title, handle in self.inline_srcs.items():
@ -3318,6 +3330,9 @@ class GedcomParser(UpdateCallback):
# Add the default reference if no source has found
self.__add_default_source(person)
# Add a default tag if provided
self.__add_default_tag(person)
self.__check_msgs(_("INDI (individual) Gramps ID %s") %
person.get_gramps_id(), state, person)
# commit the person to the database
@ -4579,6 +4594,9 @@ class GedcomParser(UpdateCallback):
# add default reference if no reference exists
self.__add_default_source(family)
# Add a default tag if provided
self.__add_default_tag(family)
self.__check_msgs(_("FAM (family) Gramps ID %s") % family.get_gramps_id(),
state, family)
# commit family to database
@ -6118,6 +6136,9 @@ class GedcomParser(UpdateCallback):
# Add the default reference if no source has found
self.__add_default_source(media)
# Add a default tag if provided
self.__add_default_tag(media)
self.__check_msgs(_("OBJE (multi-media object) Gramps ID %s") %
media.get_gramps_id(), state, media)
# commit the person to the database
@ -6931,6 +6952,9 @@ class GedcomParser(UpdateCallback):
self.__undefined)
state.msg += sub_state.msg
# Add a default tag if provided
self.__add_default_tag(new_note)
self.dbase.commit_note(new_note, self.trans, new_note.change)
obj.add_note(new_note.get_handle())
@ -7255,6 +7279,13 @@ class GedcomParser(UpdateCallback):
self.dbase.add_citation(citation, self.trans)
obj.add_citation(citation.handle)
def __add_default_tag(self, obj):
"""
Add the default tag to the object.
"""
if self.default_tag:
obj.add_tag(self.default_tag.handle)
def __subm_name(self, line, state):
"""
@param line: The current line in GedLine format