Start of a new (unsupported) plugin to import from Pro-Gen.
* src/plugins/ImportProGen.py svn: r10639
This commit is contained in:
parent
141c38cde3
commit
09246035b3
887
src/plugins/ImportProGen.py
Normal file
887
src/plugins/ImportProGen.py
Normal file
@ -0,0 +1,887 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2008-2008 Kees Bakker
|
||||
#
|
||||
# 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:$
|
||||
|
||||
"Import from Pro-Gen"
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# standard python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import re
|
||||
from gettext import gettext as _
|
||||
import os
|
||||
import struct
|
||||
|
||||
import time
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Set up logging
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import logging
|
||||
log = logging.getLogger('.ImportProGen')
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GRAMPS modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import Errors
|
||||
import Utils
|
||||
import gen.lib
|
||||
import const
|
||||
from QuestionDialog import ErrorDialog
|
||||
from PluginUtils import register_import
|
||||
|
||||
|
||||
class ProgenError(Exception):
|
||||
"""Error used to report Progen errors."""
|
||||
def __init__(self, value=""):
|
||||
Exception.__init__(self)
|
||||
self.value = value
|
||||
|
||||
def __str__(self):
|
||||
return self.value
|
||||
|
||||
|
||||
def _importData(database, filename, cb=None):
|
||||
|
||||
try:
|
||||
g = ProgenParser(database, filename)
|
||||
except IOError, msg:
|
||||
ErrorDialog(_("%s could not be opened") % filename, str(msg))
|
||||
return
|
||||
|
||||
try:
|
||||
status = g.parse_progen_file()
|
||||
except ProgenError, msg:
|
||||
ErrorDialog(_("Pro-Gen data error"), str(msg))
|
||||
return
|
||||
except IOError, msg:
|
||||
ErrorDialog(_("%s could not be opened") % filename, str(msg))
|
||||
return
|
||||
|
||||
|
||||
def _find_from_handle(gramps_id, table):
|
||||
"""
|
||||
Find a handle corresponding to the specified GRAMPS ID.
|
||||
|
||||
The passed table contains the mapping. If the value is found, we return
|
||||
it, otherwise we create a new handle, store it, and return it.
|
||||
|
||||
"""
|
||||
intid = table.get(gramps_id)
|
||||
if not intid:
|
||||
intid = Utils.create_id()
|
||||
table[gramps_id] = intid
|
||||
return intid
|
||||
|
||||
|
||||
def _read_mem(bname):
|
||||
'''
|
||||
Each record is 32 bytes. First a 4 byte reference to the next record
|
||||
followed by 28 bytes of text.
|
||||
The information forms a chain of records, that stops when a reference is 0
|
||||
or smaller.
|
||||
There are two special sequences:
|
||||
<ESC> <CR> hard return
|
||||
<ESC> <^Z> end of the memo field
|
||||
'''
|
||||
f = open(bname + '.mem')
|
||||
recfmt = "i28s"
|
||||
reclen = struct.calcsize( recfmt )
|
||||
#print "# reclen = %d" % reclen
|
||||
|
||||
mems = []
|
||||
while 1:
|
||||
buf = f.read(reclen)
|
||||
if not buf:
|
||||
break
|
||||
(recno, text) = struct.unpack(recfmt, buf)
|
||||
mems.append([recno, text])
|
||||
return mems
|
||||
|
||||
|
||||
def _read_recs(table, bname):
|
||||
'Read records from .PER or .REL file.'
|
||||
f = open(bname + table.fileext)
|
||||
recfmt = table.recfmt
|
||||
log.info("# %s - recfmt = %s" % (table['name1'], recfmt))
|
||||
reclen = struct.calcsize( recfmt )
|
||||
log.info("# %s - reclen = %d" % (table['name1'], reclen))
|
||||
|
||||
recs = []
|
||||
while 1:
|
||||
buf = f.read(reclen)
|
||||
if not buf:
|
||||
break
|
||||
tups = struct.unpack(recfmt, buf)
|
||||
recs.append(tups)
|
||||
|
||||
log.info("# length %s.recs[] = %d" % (table['name1'], len(recs)))
|
||||
return recs
|
||||
|
||||
|
||||
def _get_defname(fname):
|
||||
'''
|
||||
Get the name of the PG30 DEF file by looking at the user DEF file. And return
|
||||
the name of the DEF file. fname is expected to be somewhere in the PG30 tree.
|
||||
|
||||
Contents of <fname> is something like:
|
||||
=> \0
|
||||
=> C:\PG30\NL\PG30-1.DEF
|
||||
|
||||
We will strip the C: and convert the rest to a native pathname. Next, this pathname
|
||||
is compared with <fname>.
|
||||
'''
|
||||
lines = open( fname ).readlines()
|
||||
if not lines[0].startswith(r'\0') or len(lines) < 2:
|
||||
raise ProgenError(_("Not a Pro-Gen file"))
|
||||
return None, '?'
|
||||
|
||||
defname = lines[1].lower()
|
||||
defname = defname.strip()
|
||||
# Strip drive, if any
|
||||
defname = re.sub( r'^\w:', '', defname )
|
||||
defname = defname.replace('\\', os.sep)
|
||||
# Strip leading slash, if any.
|
||||
if defname.startswith(os.sep):
|
||||
defname = defname[1:]
|
||||
|
||||
# Using the directory of <fname>, go to the parent directory until
|
||||
# the DEF is found.
|
||||
dir_, f = os.path.split(os.path.abspath(fname))
|
||||
while dir_:
|
||||
newdefname = os.path.join(dir_, defname)
|
||||
if os.path.exists(newdefname):
|
||||
return newdefname, defname
|
||||
dir_, f = os.path.split(dir_)
|
||||
|
||||
return None, defname
|
||||
|
||||
|
||||
esc_ctrlz_pat = re.compile(r'\033\032.*')
|
||||
def _get_mem_text(mems, i):
|
||||
'Notice that Pro-Gen starts the mem numbering at 1.'
|
||||
if i <= 0:
|
||||
return ''
|
||||
|
||||
i = i - 1
|
||||
recno = mems[i][0]
|
||||
text = mems[i][1].decode('cp850')
|
||||
if recno != 0:
|
||||
text += _get_mem_text(mems, recno)
|
||||
# ESC-^M is newline
|
||||
text = text.replace('\033\r', '\n')
|
||||
# ESC-^Z is end of string
|
||||
text = esc_ctrlz_pat.sub('', text)
|
||||
|
||||
# TODO. Strip trailing empty lines.
|
||||
#print text.encode('utf-8')
|
||||
return text
|
||||
|
||||
|
||||
|
||||
# Example field:
|
||||
# ['Voornaam', '47', '64', '4', '2', '15', '""', '""']
|
||||
# item 0
|
||||
# item 1 is a number indicating the fieldtype
|
||||
# item 2
|
||||
# item 3 is the size of the field
|
||||
class PG30_Def_Table_Field:
|
||||
'This class represents a field in one of the tables in the DEF file.'
|
||||
def __init__(self, name, value):
|
||||
self.fieldname = name
|
||||
self.fields = value.split(',')
|
||||
self.fields = [p.strip() for p in self.fields]
|
||||
self.name = self.fields[0]
|
||||
self.type_ = int(self.fields[1])
|
||||
self.size = int(self.fields[3])
|
||||
|
||||
def __repr__(self):
|
||||
return self.fieldname + ' -> ' + ', '.join(self.fields)
|
||||
|
||||
|
||||
class PG30_Def_Table:
|
||||
'This class represents a table in the DEF file.'
|
||||
def __init__(self, name, lines):
|
||||
self.name = name
|
||||
self.parms = {}
|
||||
self.recfmt = None
|
||||
# Example line:
|
||||
#f02=Persoon gewijzigd ,32,10,10, 1,68,"","INDI CHAN DATE"
|
||||
line_pat = re.compile(r'(\w+) = (.*)', re.VERBOSE)
|
||||
for l in lines:
|
||||
#print l
|
||||
m = line_pat.match(l)
|
||||
if m:
|
||||
# TODO. Catch duplicates?
|
||||
self.parms[m.group(1)] = m.group(2)
|
||||
|
||||
self.fileext = self.parms.get('fileext', None)
|
||||
if self.fileext:
|
||||
self.fileext = self.fileext.lower()
|
||||
#self.name1 = self.parms.get('name1', None)
|
||||
|
||||
# If there is a n_fields entry then this is a table that
|
||||
# has details about the record format of another file (PER or REL).
|
||||
if self.parms.has_key('n_fields'):
|
||||
self.get_fields()
|
||||
self.recfmt = self.get_recfmt()
|
||||
self.nam2fld = {}
|
||||
self.nam2idx = {}
|
||||
self.recflds = [] # list of fields that use up space in a record
|
||||
j = 0
|
||||
for i, f in enumerate(self.flds):
|
||||
#print "# field %s" % f
|
||||
nam = f.name
|
||||
self.nam2fld[nam] = f
|
||||
if f.size != 0:
|
||||
self.nam2idx[nam] = j
|
||||
#print "# %s <= %d" % (f[0], j)
|
||||
self.recflds.append(f)
|
||||
j = j + 1
|
||||
|
||||
def __getitem__(self, i):
|
||||
return self.parms.get(i, None)
|
||||
|
||||
def get_recfmt(self):
|
||||
'Get the record format for struct.unpack'
|
||||
# Example field:
|
||||
# ['Voornaam', '47', '64', '4', '2', '15', '""', '""']
|
||||
# item 0
|
||||
# item 1 is a number indicating the fieldtype
|
||||
# item 2
|
||||
# item 3 is the size of the field
|
||||
# ...
|
||||
flds = self.flds
|
||||
fmt = '='
|
||||
for f in flds:
|
||||
fldtyp = f.type_
|
||||
if fldtyp == 2 or fldtyp == 3 or fldtyp == 22 or fldtyp == 23:
|
||||
fmt += 'i'
|
||||
elif fldtyp == 31:
|
||||
pass
|
||||
elif fldtyp == 32 or fldtyp == 44 or fldtyp == 45:
|
||||
fmt += '%ds' % f.size
|
||||
elif fldtyp == 41:
|
||||
fmt += 'h'
|
||||
elif fldtyp == 42 or fldtyp == 43 or fldtyp == 46 or fldtyp == 47:
|
||||
fmt += 'i'
|
||||
else:
|
||||
pass # ???? Do we want to know?
|
||||
return fmt
|
||||
|
||||
def get_fields(self):
|
||||
# For example from pg30-1.def
|
||||
#n_fields=58
|
||||
#f01=Persoon record ,31, 6, 0, 1,17,"","INDI RFN"
|
||||
#f02=Persoon gewijzigd ,32,10,10, 1,68,"","INDI CHAN DATE"
|
||||
#f03=Voornaam ,47,64, 4, 2,15,"",""
|
||||
|
||||
n_fields = int(self.parms['n_fields'])
|
||||
flds = []
|
||||
for i in range(n_fields):
|
||||
fld_name = 'f%02d' % (i+1)
|
||||
fld = self.parms.get(fld_name, None)
|
||||
flds.append(PG30_Def_Table_Field(fld_name, fld))
|
||||
self.flds = flds
|
||||
|
||||
def get_record_field_index(self, fldname):
|
||||
'Return the index number in the record tuple, based on the name.'
|
||||
if not fldname in self.nam2idx:
|
||||
raise ProgenError(_("Field '%(fldname)s' not found") % locals())
|
||||
return self.nam2idx[fldname]
|
||||
|
||||
def convert_record_to_list(self, rec, mems):
|
||||
flds = []
|
||||
for i in range(len(rec)):
|
||||
if self.field_ix_is_record_number(i):
|
||||
flds.append("%d" % rec[i])
|
||||
elif self.field_ix_is_mem_type(i):
|
||||
flds.append(_get_mem_text(mems, rec[i]))
|
||||
else:
|
||||
# Not a record number, not a mem number. It must be just text.
|
||||
fld = rec[i].strip()
|
||||
# Convert to unicode
|
||||
fld = fld.decode('cp850')
|
||||
flds.append(fld)
|
||||
#print ', '.join([f.encode('utf-8') for f in flds])
|
||||
return flds
|
||||
|
||||
def get_field_names(self):
|
||||
ret = []
|
||||
for f in self.flds:
|
||||
if f.size != 0:
|
||||
ret.append(f.name)
|
||||
return ret
|
||||
|
||||
def field_is_mem_type(self, fldname):
|
||||
if not fldname in self.nam2fld:
|
||||
return None
|
||||
typ = self.nam2fld[fldname].type_
|
||||
if typ == 46 or typ == 47:
|
||||
return True
|
||||
return False
|
||||
|
||||
# TODO. Integrate this into field_is_mem_type()
|
||||
def field_ix_is_mem_type(self, ix):
|
||||
typ = self.recflds[ix].type_
|
||||
if typ == 46 or typ == 47:
|
||||
return True
|
||||
return False
|
||||
|
||||
def field_ix_is_record_number(self, ix):
|
||||
typ = self.recflds[ix].type_
|
||||
if typ == 2 or typ == 3 or typ == 22 or typ == 23:
|
||||
return True
|
||||
return False
|
||||
|
||||
def diag(self):
|
||||
txt = self.name + '\n'
|
||||
if self.parms.has_key('n_fields'):
|
||||
txt += 'n_fields = %s\n' % self.parms['n_fields']
|
||||
# Just grab a field
|
||||
f = self.flds[1]
|
||||
txt += '"%s"\n' % f
|
||||
txt += 'recfmt = %s (length=%d)' % (self.recfmt, struct.calcsize(self.recfmt))
|
||||
return txt
|
||||
|
||||
|
||||
class PG30_Def:
|
||||
'''
|
||||
Utility class to read PG30-1.DEF and to get certain information
|
||||
from it.
|
||||
|
||||
The contents of the DEF file is separated in sections that start
|
||||
with [<section name>]. For example:
|
||||
[general]
|
||||
dateformat=DD-MM-YYYY
|
||||
pointerlength=4
|
||||
tables=2
|
||||
|
||||
'''
|
||||
def __init__(self, fname):
|
||||
#print fname
|
||||
fname, deffname = _get_defname(fname)
|
||||
if not fname:
|
||||
raise ProgenError(_("Cannot find DEF file: %(deffname)s") % locals())
|
||||
|
||||
# This can throw a IOError
|
||||
lines = open(fname).readlines()
|
||||
lines = [l.strip() for l in lines]
|
||||
content = '\n'.join(lines)
|
||||
parts = re.split(r'\n(?=\[)', content)
|
||||
self.parts = {}
|
||||
self.tables = {}
|
||||
for p in parts:
|
||||
lines = p.splitlines()
|
||||
# Get section name
|
||||
k = re.sub(r'\[(.*)\]', r'\1', lines[0])
|
||||
# Store section contents in a hashtable using that section name
|
||||
self.parts[k] = lines[1:]
|
||||
self.tables[k] = PG30_Def_Table(k, self.parts[k])
|
||||
|
||||
# Some sections are special: Table_1 and Table_2
|
||||
|
||||
def __getitem__(self, i):
|
||||
return self.tables.get(i, None)
|
||||
|
||||
# TODO. Maybe rename to __repr__
|
||||
def diag(self):
|
||||
return '\n\n'.join([self.tables[t].diag() for t in self.tables])
|
||||
|
||||
|
||||
class ProgenParser:
|
||||
def __init__(self, dbase, file_):
|
||||
self.bname, ext = os.path.splitext(file_)
|
||||
if ext.lower() != '.def':
|
||||
raise ProgenError(_("Expecting a file with .def extension"))
|
||||
self.db = dbase
|
||||
self.fname = file_
|
||||
|
||||
self.gid2id = {} # Maps person id
|
||||
self.fid2id = {} # Maps family id
|
||||
self.pkeys = {} # Caching place handles
|
||||
|
||||
def parse_progen_file(self):
|
||||
self.progress = Utils.ProgressMeter(_("Import from Pro-Gen"), '')
|
||||
|
||||
self.def_ = PG30_Def(self.fname)
|
||||
#print self.def_.diag()
|
||||
|
||||
self.mems = _read_mem(self.bname)
|
||||
self.pers = _read_recs(self.def_['Table_1'], self.bname)
|
||||
self.rels = _read_recs(self.def_['Table_2'], self.bname)
|
||||
|
||||
self.trans = self.db.transaction_begin('', batch=True)
|
||||
self.db.disable_signals()
|
||||
|
||||
self.create_persons()
|
||||
self.create_families()
|
||||
#self.add_children()
|
||||
|
||||
self.db.transaction_commit(self.trans, _("Pro-Gen import"))
|
||||
self.db.enable_signals()
|
||||
self.db.request_rebuild()
|
||||
self.progress.close()
|
||||
|
||||
|
||||
def __find_person_handle(self, gramps_id):
|
||||
"""
|
||||
Return the database handle associated with the person's GRAMPS ID
|
||||
"""
|
||||
return _find_from_handle(gramps_id, self.gid2id)
|
||||
|
||||
def __find_family_handle(self, gramps_id):
|
||||
"""
|
||||
Return the database handle associated with the family's GRAMPS ID
|
||||
"""
|
||||
return _find_from_handle(gramps_id, self.fid2id)
|
||||
|
||||
def __find_or_create_person(self, gramps_id):
|
||||
"""
|
||||
Finds or creates a person based on the GRAMPS ID. If the ID is
|
||||
already used (is in the db), we return the item in the db. Otherwise,
|
||||
we create a new person, assign the handle and GRAMPS ID.
|
||||
"""
|
||||
person = gen.lib.Person()
|
||||
intid = self.gid2id.get(gramps_id)
|
||||
if self.db.has_person_handle(intid):
|
||||
person.unserialize(self.db.get_raw_person_data(intid))
|
||||
else:
|
||||
intid = _find_from_handle(gramps_id, self.gid2id)
|
||||
person.set_handle(intid)
|
||||
person.set_gramps_id(gramps_id)
|
||||
return person
|
||||
|
||||
def __find_or_create_family(self, gramps_id):
|
||||
"""
|
||||
Finds or creates a family based on the GRAMPS ID. If the ID is
|
||||
already used (is in the db), we return the item in the db. Otherwise,
|
||||
we create a new family, assign the handle and GRAMPS ID.
|
||||
"""
|
||||
family = gen.lib.Family()
|
||||
intid = self.fid2id.get(gramps_id)
|
||||
if self.db.has_family_handle(intid):
|
||||
family.unserialize(self.db.get_raw_family_data(intid))
|
||||
else:
|
||||
intid = _find_from_handle(gramps_id, self.fid2id)
|
||||
family.set_handle(intid)
|
||||
family.set_gramps_id(gramps_id)
|
||||
return family
|
||||
|
||||
def __get_or_create_place(self, place_name):
|
||||
if not place_name:
|
||||
return None
|
||||
place = None
|
||||
if place_name in self.pkeys:
|
||||
place = self.db.get_place_from_handle(self.pkeys[place_name])
|
||||
else:
|
||||
# Create a new Place
|
||||
place = gen.lib.Place()
|
||||
place.set_title(place_name)
|
||||
self.db.add_place(place, self.trans)
|
||||
self.db.commit_place(place, self.trans)
|
||||
self.pkeys[place_name] = place.get_handle()
|
||||
return place
|
||||
|
||||
def __create_event_and_ref(self, type_, desc=None, date=None, place=None, source=None):
|
||||
event = gen.lib.Event()
|
||||
event.set_type(gen.lib.EventType(type_))
|
||||
if desc:
|
||||
event.set_description(desc)
|
||||
if date:
|
||||
event.set_date_object(date)
|
||||
if place:
|
||||
event.set_place_handle(place.get_handle())
|
||||
if source:
|
||||
event.add_source_reference(source)
|
||||
self.db.add_event(event,self.trans)
|
||||
self.db.commit_event(event,self.trans)
|
||||
event_ref = gen.lib.EventRef()
|
||||
event_ref.set_reference_handle(event.get_handle())
|
||||
return event, event_ref
|
||||
|
||||
__date_pat1 = re.compile(r'(?P<day>\d{1,2}) (-|=) (?P<month>\d{1,2}) (-|=) (?P<year>\d{2,4})', re.VERBOSE)
|
||||
__date_pat2 = re.compile(r'(?P<month>\d{1,2}) (-|=) (?P<year>\d{4})', re.VERBOSE)
|
||||
__date_pat3 = re.compile(r'(?P<year>\d{4})', re.VERBOSE)
|
||||
__date_pat4 = re.compile(ur'(v|vóór|voor|na|circa|ca|rond) \s* (?P<year>\d{4})', re.VERBOSE)
|
||||
__date_pat5 = re.compile(r'(oo) (-|=) (oo) (-|=) (?P<year>\d{2,4})', re.VERBOSE)
|
||||
def __create_date_from_text(self, txt, diag_msg=None):
|
||||
'''
|
||||
Pro-Gen has a text field for the date. It can be anything. Mostly it will be dd-mm-yyyy,
|
||||
but we have seen:
|
||||
yyyy
|
||||
mm-yyyy
|
||||
voor yyyy
|
||||
dd=mm-yyyy (typo I guess)
|
||||
00-00-yyyy
|
||||
oo-oo-yyyy
|
||||
dd-mm-00 (does this mean we do not know about the year?)
|
||||
|
||||
This function tries to parse the text and create a proper Gramps Date() object.
|
||||
If all else fails we create a MOD_TEXTONLY Date() object.
|
||||
'''
|
||||
date = gen.lib.Date()
|
||||
|
||||
# dd-mm-yyyy
|
||||
m = self.__date_pat1.match(txt)
|
||||
if m:
|
||||
day = int(m.group('day'))
|
||||
month = int(m.group('month'))
|
||||
year = int(m.group('year'))
|
||||
if day and month and year:
|
||||
date.set_yr_mon_day(year, month, day)
|
||||
else:
|
||||
date.set(gen.lib.Date.QUAL_NONE, gen.lib.Date.MOD_ABOUT, gen.lib.Date.CAL_GREGORIAN, (day, month, year, None))
|
||||
return date
|
||||
|
||||
# mm-yyyy
|
||||
m = self.__date_pat2.match(txt)
|
||||
if m:
|
||||
month = int(m.group('month'))
|
||||
year = int(m.group('year'))
|
||||
date.set(gen.lib.Date.QUAL_NONE, gen.lib.Date.MOD_ABOUT, gen.lib.Date.CAL_GREGORIAN, (0, month, year, None))
|
||||
return date
|
||||
|
||||
# yyyy
|
||||
m = self.__date_pat3.match(txt)
|
||||
if m:
|
||||
year = int(m.group('year'))
|
||||
date.set(gen.lib.Date.QUAL_NONE, gen.lib.Date.MOD_ABOUT, gen.lib.Date.CAL_GREGORIAN, (0, 0, year, None))
|
||||
return date
|
||||
|
||||
# voor|na|... yyyy
|
||||
m = self.__date_pat4.match(txt)
|
||||
if m:
|
||||
year = int(m.group('year'))
|
||||
if m.group(1) == 'voor' or m.group(1) == 'v' or m.group(1) == u'vóór':
|
||||
date.set(gen.lib.Date.QUAL_NONE, gen.lib.Date.MOD_BEFORE, gen.lib.Date.CAL_GREGORIAN, (0, 0, year, None))
|
||||
elif m.group(1) == 'na':
|
||||
date.set(gen.lib.Date.QUAL_NONE, gen.lib.Date.MOD_AFTER, gen.lib.Date.CAL_GREGORIAN, (0, 0, year, None))
|
||||
else:
|
||||
date.set(gen.lib.Date.QUAL_NONE, gen.lib.Date.MOD_ABOUT, gen.lib.Date.CAL_GREGORIAN, (0, 0, year, None))
|
||||
return date
|
||||
|
||||
# oo-oo-yyyy
|
||||
m = self.__date_pat5.match(txt)
|
||||
if m:
|
||||
year = int(m.group('year'))
|
||||
date.set(gen.lib.Date.QUAL_NONE, gen.lib.Date.MOD_ABOUT, gen.lib.Date.CAL_GREGORIAN, (0, 0, year, None))
|
||||
return date
|
||||
|
||||
log.warning(_("date did not match: '%s' (%s)") % (txt.encode('utf-8'), diag_msg or ''))
|
||||
# Hmmm. Just use the plain text.
|
||||
date.set_as_text(txt)
|
||||
return date
|
||||
|
||||
def create_persons(self):
|
||||
self.progress.set_pass(_('Importing individuals'), len(self.pers))
|
||||
table = self.def_['Table_1']
|
||||
|
||||
# Records in the PER file using PG30-1.DEF contain the following fields:
|
||||
# (Note. We want this to be computed just once.
|
||||
|
||||
#log.info(table.get_field_names())
|
||||
|
||||
# I'm sure I can find a better way to do this through the local() dict)
|
||||
first_name_ix = table.get_record_field_index('Voornaam')
|
||||
surname_ix = table.get_record_field_index('Achternaam')
|
||||
gender_ix = table.get_record_field_index('Geslacht')
|
||||
patron_ix = table.get_record_field_index('Patroniem')
|
||||
call_name_ix = table.get_record_field_index('Roepnaam')
|
||||
alias_ix = table.get_record_field_index('Alias')
|
||||
percode_ix = table.get_record_field_index('Persoon code')
|
||||
title1_ix = table.get_record_field_index('Titel1')
|
||||
title2_ix = table.get_record_field_index('Titel2')
|
||||
title3_ix = table.get_record_field_index('Titel3')
|
||||
father_ix = table.get_record_field_index('Vader')
|
||||
mother_ix = table.get_record_field_index('Moeder')
|
||||
occu_ix = table.get_record_field_index('Beroep')
|
||||
|
||||
per_klad_ix = table.get_record_field_index('Persoon klad')
|
||||
per_info_ix = table.get_record_field_index('Persoon info')
|
||||
|
||||
addr_date_ix = table.get_record_field_index('Adres datum')
|
||||
addr_street_ix = table.get_record_field_index('Adres straat')
|
||||
addr_postal_ix = table.get_record_field_index('Adres postcode')
|
||||
addr_place_ix = table.get_record_field_index('Adres plaats')
|
||||
addr_country_ix = table.get_record_field_index('Adres land')
|
||||
addr_tel_ix = table.get_record_field_index('Adres telefoon')
|
||||
addr_info_ix = table.get_record_field_index('Adres info')
|
||||
|
||||
birth_date_ix = table.get_record_field_index('Geboorte datum')
|
||||
birth_place_ix = table.get_record_field_index('Geboorte plaats')
|
||||
birth_time_ix = table.get_record_field_index('Geboorte tijd')
|
||||
birth_source_ix = table.get_record_field_index('Geboorte bron')
|
||||
birth_cert_ix = table.get_record_field_index('Geboorte akte')
|
||||
birth_source_text_ix = table.get_record_field_index('Geboorte brontekst')
|
||||
birth_info_ix = table.get_record_field_index('Geboorte info')
|
||||
|
||||
bapt_date_ix = table.get_record_field_index('Doop datum')
|
||||
bapt_place_ix = table.get_record_field_index('Doop plaats')
|
||||
bapt_reli_ix = table.get_record_field_index('Gezindte')
|
||||
bapt_wit_ix = table.get_record_field_index('Doop getuigen')
|
||||
bapt_source_ix = table.get_record_field_index('Doop bron')
|
||||
bapt_cert_ix = table.get_record_field_index('Doop akte')
|
||||
bapt_source_text_ix = table.get_record_field_index('Doop brontekst')
|
||||
bapt_info_ix = table.get_record_field_index('Doop info')
|
||||
|
||||
death_date_ix = table.get_record_field_index('Overlijden datum')
|
||||
death_place_ix = table.get_record_field_index('Overlijden plaats')
|
||||
death_time_ix = table.get_record_field_index('Overlijden tijd')
|
||||
death_source_ix = table.get_record_field_index('Overlijden bron')
|
||||
death_cert_ix = table.get_record_field_index('Overlijden akte')
|
||||
death_source_text_ix = table.get_record_field_index('Overlijden brontekst')
|
||||
death_info_ix = table.get_record_field_index('Overlijden info')
|
||||
|
||||
crem_date_ix = table.get_record_field_index('Crematie datum')
|
||||
crem_place_ix = table.get_record_field_index('Crematie plaats')
|
||||
crem_source_ix = table.get_record_field_index('Crematie bron')
|
||||
crem_cert_ix = table.get_record_field_index('Crematie akte')
|
||||
crem_source_text_ix = table.get_record_field_index('Crematie brontekst')
|
||||
crem_info_ix = table.get_record_field_index('Crematie info')
|
||||
|
||||
bur_date_ix = table.get_record_field_index('Begrafenis datum')
|
||||
bur_place_ix = table.get_record_field_index('Begrafenis plaats')
|
||||
bur_source_ix = table.get_record_field_index('Begrafenis bron')
|
||||
bur_cert_ix = table.get_record_field_index('Begrafenis akte')
|
||||
bur_source_text_ix = table.get_record_field_index('Begrafenis brontekst')
|
||||
bur_info_ix = table.get_record_field_index('Begrafenis info')
|
||||
|
||||
# The records are numbered 1..N
|
||||
for i, rec in enumerate(self.pers):
|
||||
pers_id = i + 1
|
||||
father = rec[father_ix]
|
||||
mother = rec[mother_ix]
|
||||
if father >= 0 and mother >= 0:
|
||||
recflds = table.convert_record_to_list(rec, self.mems)
|
||||
|
||||
first_name = recflds[first_name_ix]
|
||||
surname = recflds[surname_ix]
|
||||
gender = recflds[gender_ix]
|
||||
if gender == 'M':
|
||||
gender = gen.lib.Person.MALE
|
||||
elif gender == 'V':
|
||||
gender = gen.lib.Person.FEMALE
|
||||
else:
|
||||
gender = gen.lib.Person.UNKNOWN
|
||||
|
||||
person = self.__find_or_create_person("I%d" % pers_id)
|
||||
diag_msg = "I%d: %s %s" % (pers_id, first_name.encode('utf-8'), surname.encode('utf-8'))
|
||||
#log.info(diag_msg)
|
||||
|
||||
name = gen.lib.Name()
|
||||
name.set_type(gen.lib.NameType.BIRTH)
|
||||
name.set_surname(surname)
|
||||
name.set_first_name(first_name)
|
||||
if recflds[call_name_ix]:
|
||||
name.set_call_name(recflds[call_name_ix])
|
||||
person.set_primary_name(name)
|
||||
person.set_gender(gender)
|
||||
|
||||
if recflds[alias_ix]:
|
||||
# Alias skipped. Not sure if it is used.
|
||||
# TODO. Log it
|
||||
pass
|
||||
|
||||
if recflds[patron_ix]:
|
||||
# Patronym skipped. Not sure if it is used.
|
||||
# TODO. Log it
|
||||
pass
|
||||
|
||||
if recflds[percode_ix]:
|
||||
# Person code skipped. Not sure if it is used.
|
||||
# TODO. Log it
|
||||
pass
|
||||
|
||||
if recflds[occu_ix]:
|
||||
event, event_ref = self.__create_event_and_ref(gen.lib.EventType.OCCUPATION, recflds[occu_ix])
|
||||
person.add_event_ref(event_ref)
|
||||
|
||||
if recflds[birth_date_ix]:
|
||||
place = self.__get_or_create_place(recflds[birth_place_ix])
|
||||
time = recflds[birth_time_ix]
|
||||
source = recflds[birth_source_ix]
|
||||
cert = recflds[birth_cert_ix]
|
||||
source_text = recflds[birth_source_text_ix]
|
||||
info = recflds[birth_info_ix]
|
||||
|
||||
date = self.__create_date_from_text(recflds[birth_date_ix], diag_msg)
|
||||
event, birth_ref = self.__create_event_and_ref(gen.lib.EventType.BIRTH, info, date, place)
|
||||
person.set_birth_ref(birth_ref)
|
||||
|
||||
if recflds[bapt_date_ix]:
|
||||
place = self.__get_or_create_place(recflds[bapt_place_ix])
|
||||
reli = recflds[bapt_reli_ix]
|
||||
witness = recflds[bapt_wit_ix]
|
||||
source = recflds[bapt_source_ix]
|
||||
cert = recflds[bapt_cert_ix]
|
||||
source_text = recflds[bapt_source_text_ix]
|
||||
info = recflds[bapt_info_ix]
|
||||
|
||||
date = self.__create_date_from_text(recflds[bapt_date_ix], diag_msg)
|
||||
event, bapt_ref = self.__create_event_and_ref(gen.lib.EventType.BAPTISM, info, date, place)
|
||||
# ???? reli
|
||||
# ???? witness
|
||||
person.add_event_ref(bapt_ref)
|
||||
|
||||
if recflds[death_date_ix]:
|
||||
place = self.__get_or_create_place(recflds[death_place_ix])
|
||||
time = recflds[death_time_ix]
|
||||
source = recflds[death_source_ix]
|
||||
cert = recflds[death_cert_ix]
|
||||
source_text = recflds[death_source_text_ix]
|
||||
info = recflds[death_info_ix]
|
||||
|
||||
date = self.__create_date_from_text(recflds[death_date_ix], diag_msg)
|
||||
event, death_ref = self.__create_event_and_ref(gen.lib.EventType.DEATH, info, date, place)
|
||||
person.set_death_ref(death_ref)
|
||||
|
||||
if recflds[bur_date_ix]:
|
||||
place = self.__get_or_create_place(recflds[bur_place_ix])
|
||||
source = recflds[bur_source_ix]
|
||||
cert = recflds[bur_cert_ix]
|
||||
source_text = recflds[bur_source_text_ix]
|
||||
info = recflds[bur_info_ix]
|
||||
|
||||
date = self.__create_date_from_text(recflds[bur_date_ix], diag_msg)
|
||||
event, burial_ref = self.__create_event_and_ref(gen.lib.EventType.BURIAL, info, date, place)
|
||||
person.add_event_ref(burial_ref)
|
||||
|
||||
elif recflds[crem_date_ix]:
|
||||
place = self.__get_or_create_place(recflds[crem_place_ix])
|
||||
source = recflds[crem_source_ix]
|
||||
cert = recflds[crem_cert_ix]
|
||||
source_text = recflds[crem_source_text_ix]
|
||||
info = recflds[crem_info_ix]
|
||||
|
||||
date = self.__create_date_from_text(recflds[crem_date_ix], diag_msg)
|
||||
event, cremation_ref = self.__create_event_and_ref(gen.lib.EventType.CREMATION, info, date, place)
|
||||
person.add_event_ref(cremation_ref)
|
||||
|
||||
self.db.commit_person(person, self.trans)
|
||||
self.progress.step()
|
||||
|
||||
def create_families(self):
|
||||
self.progress.set_pass(_('Importing families'), len(self.rels))
|
||||
table = self.def_['Table_2']
|
||||
|
||||
# Records in the REL file using PG30-1.DEF contain the following fields:
|
||||
# (Note. We want this to be computed just once.
|
||||
|
||||
#log.info(table.get_field_names())
|
||||
|
||||
man_ix = table.get_record_field_index('Man')
|
||||
vrouw_ix = table.get_record_field_index('Vrouw')
|
||||
f05 = table.get_record_field_index('Relatie code')
|
||||
f06 = table.get_record_field_index('Relatie klad')
|
||||
f07 = table.get_record_field_index('Relatie info')
|
||||
f08 = table.get_record_field_index('Samenwonen datum')
|
||||
f09 = table.get_record_field_index('Samenwonen plaats')
|
||||
f10 = table.get_record_field_index('Samenwonen bron')
|
||||
f11 = table.get_record_field_index('Samenwonen akte')
|
||||
f12 = table.get_record_field_index('Samenwonen brontekst')
|
||||
f13 = table.get_record_field_index('Samenwonen info')
|
||||
f14 = table.get_record_field_index('Ondertrouw datum')
|
||||
f15 = table.get_record_field_index('Ondertrouw plaats')
|
||||
f16 = table.get_record_field_index('Ondertrouw getuigen')
|
||||
f17 = table.get_record_field_index('Ondertrouw bron')
|
||||
f18 = table.get_record_field_index('Ondertrouw akte')
|
||||
f19 = table.get_record_field_index('Ondertrouw brontekst')
|
||||
f20 = table.get_record_field_index('Ondertrouw info')
|
||||
f21 = table.get_record_field_index('Wettelijk datum')
|
||||
f22 = table.get_record_field_index('Wettelijk plaats')
|
||||
f23 = table.get_record_field_index('Wettelijk getuigen')
|
||||
f24 = table.get_record_field_index('Wettelijk bron')
|
||||
f25 = table.get_record_field_index('Wettelijk akte')
|
||||
f26 = table.get_record_field_index('Wettelijk brontekst')
|
||||
f27 = table.get_record_field_index('Wettelijk info')
|
||||
f28 = table.get_record_field_index('Kerkelijk datum')
|
||||
f29 = table.get_record_field_index('Kerkelijk plaats')
|
||||
f30 = table.get_record_field_index('Kerk')
|
||||
f31 = table.get_record_field_index('Kerkelijk getuigen')
|
||||
f32 = table.get_record_field_index('Kerkelijk bron')
|
||||
f33 = table.get_record_field_index('Kerkelijk akte')
|
||||
f34 = table.get_record_field_index('Kerkelijk brontekst')
|
||||
f35 = table.get_record_field_index('Kerkelijk info')
|
||||
f36 = table.get_record_field_index('Scheiding datum')
|
||||
f37 = table.get_record_field_index('Scheiding plaats')
|
||||
f38 = table.get_record_field_index('Scheiding bron')
|
||||
f39 = table.get_record_field_index('Scheiding akte')
|
||||
f40 = table.get_record_field_index('Scheiding brontekst')
|
||||
f41 = table.get_record_field_index('Scheiding info')
|
||||
|
||||
# The records are numbered 1..N
|
||||
self.progress.set_pass(_('Adding families'), len(self.rels))
|
||||
for i, rec in enumerate(self.rels):
|
||||
fam_id = i + 1
|
||||
husband = rec[man_ix]
|
||||
wife = rec[vrouw_ix]
|
||||
if husband > 0 or wife > 0:
|
||||
fam = self.__find_or_create_family("F%d" % fam_id)
|
||||
if husband > 0:
|
||||
husband_handle = self.__find_person_handle("I%d" % husband)
|
||||
fam.set_father_handle(husband_handle)
|
||||
husband_person = self.db.get_person_from_handle(husband_handle)
|
||||
husband_person.add_family_handle(fam.get_handle())
|
||||
self.db.commit_person(husband_person,self.trans)
|
||||
if wife > 0:
|
||||
wife_handle = self.__find_person_handle("I%d" % wife)
|
||||
fam.set_mother_handle(wife_handle)
|
||||
wife_person = self.db.get_person_from_handle(wife_handle)
|
||||
wife_person.add_family_handle(fam.get_handle())
|
||||
self.db.commit_person(wife_person,self.trans)
|
||||
self.db.commit_family(fam, self.trans)
|
||||
|
||||
self.progress.step()
|
||||
|
||||
def add_children():
|
||||
# Once more to record the father and mother
|
||||
# The records are numbered 1..N
|
||||
self.progress.set_pass(_('Adding children'), len(self.pers))
|
||||
for i, rec in enumerate(self.pers):
|
||||
pers_id = i + 1
|
||||
father = rec[father_ix]
|
||||
mother = rec[mother_ix]
|
||||
if father > 0 or mother > 0:
|
||||
person = self.__find_or_create_person("I%d" % pers_id)
|
||||
if father > 0:
|
||||
father_handle = self.__find_person("I%d" % father)
|
||||
if mother > 0:
|
||||
mother_handle = self.__find_person("I%d" % mother)
|
||||
self.progress.step()
|
||||
|
||||
|
||||
|
||||
_mime_type = "application/x-progen"
|
||||
import gtk
|
||||
_filter = gtk.FileFilter()
|
||||
_filter.set_name(_('Pro-Gen files'))
|
||||
_filter.add_mime_type(_mime_type)
|
||||
_format_name = _('Pro-Gen')
|
||||
|
||||
register_import(_importData, _filter, [_mime_type], 0, _format_name)
|
Loading…
Reference in New Issue
Block a user