Code Search for Developers
 
 
  

_WriteGedcom.py from gramps at Krugle


Show _WriteGedcom.py syntax highlighted

#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007  Donald N. Allingham
#
# 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: _WriteGedcom.py 8922 2007-09-01 22:26:23Z dallingham $

"Export to GEDCOM"

#-------------------------------------------------------------------------
#
# Standard Python Modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
import os
import time
import re
import shutil
import string

import logging
log = logging.getLogger(".WriteGedcom")

#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import RelLib
import const
import _GedcomInfo as GedcomInfo
import Errors
import Utils
import ExportOptions
from QuestionDialog import ErrorDialog, WarningDialog
from BasicUtils import UpdateCallback, name_displayer

try:
    import Config
    HAVE_CONFIG = True
except:
    log.warn("No Config module available using defaults.")
    HAVE_CONFIG = False

#-------------------------------------------------------------------------
#
# GEDCOM tags representing attributes that may take a parameter, value or
# description on the same line as the tag
#
#-------------------------------------------------------------------------
personalAttributeTakesParam = set(
    ["CAST", "DSCR", "EDUC", "IDNO", "NATI", "NCHI", 
     "NMR",  "OCCU", "PROP", "RELI", "SSN",  "TITL"])

#-------------------------------------------------------------------------
#
# Calendar month names
#
#-------------------------------------------------------------------------
 
_hmonth = [
    "", "ELUL", "TSH", "CSH", "KSL", "TVT", "SHV", "ADR", 
    "ADS", "NSN", "IYR", "SVN", "TMZ", "AAV", "ELL" ]

_fmonth = [
    "",     "VEND", "BRUM", "FRIM", "NIVO", "PLUV", "VENT", 
    "GERM", "FLOR", "PRAI", "MESS", "THER", "FRUC", "COMP"]

_month = [
    "",    "JAN", "FEB", "MAR", "APR", "MAY", "JUN", 
    "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" ]

_calmap = {
    RelLib.Date.CAL_HEBREW : (_hmonth, '@#DHEBREW@'), 
    RelLib.Date.CAL_FRENCH : (_fmonth, '@#DFRENCH R@'), 
    RelLib.Date.CAL_JULIAN : (_month, '@#DJULIAN@'), 
    }

_caldef = {
    RelLib.Date.MOD_ABOUT : "ABT", 
    RelLib.Date.MOD_BEFORE : "BEF", 
    RelLib.Date.MOD_AFTER : "AFT", 
    }

lds_ord_name = {
    RelLib.LdsOrd.BAPTISM         : 'BAPL', 
    RelLib.LdsOrd.ENDOWMENT       : 'ENDL', 
    RelLib.LdsOrd.SEAL_TO_PARENTS : 'SLGC', 
    RelLib.LdsOrd.SEAL_TO_SPOUSE  : 'SGLS', 
    RelLib.LdsOrd.CONFIRMATION    : 'CONL', 
    }

lds_status = {
    RelLib.LdsOrd.STATUS_BIC        : "BIC", 
    RelLib.LdsOrd.STATUS_CANCELED   : "CANCELED", 
    RelLib.LdsOrd.STATUS_CHILD      : "CHILD", 
    RelLib.LdsOrd.STATUS_CLEARED    : "CLEARED", 
    RelLib.LdsOrd.STATUS_COMPLETED  : "COMPLETED", 
    RelLib.LdsOrd.STATUS_DNS        : "DNS", 
    RelLib.LdsOrd.STATUS_INFANT     : "INFANT", 
    RelLib.LdsOrd.STATUS_PRE_1970   : "PRE-1970", 
    RelLib.LdsOrd.STATUS_QUALIFIED  : "QUALIFIED", 
    RelLib.LdsOrd.STATUS_DNS_CAN    : "DNS/CAN", 
    RelLib.LdsOrd.STATUS_STILLBORN  : "STILLBORN", 
    RelLib.LdsOrd.STATUS_SUBMITTED  : "SUBMITTED" , 
    RelLib.LdsOrd.STATUS_UNCLEARED  : "UNCLEARED", 
    }

LANGUAGES = {
    'cs' : 'Czech',     'da' : 'Danish',    'nl' : 'Dutch',
    'en' : 'English',   'eo' : 'Esperanto', 'fi' : 'Finnish',
    'fr' : 'French',    'de' : 'German',    'hu' : 'Hungarian',
    'it' : 'Italian',   'lt' : 'Latvian',   'lv' : 'Lithuanian',
    'no' : 'Norwegian', 'po' : 'Polish',    'pt' : 'Portuguese',
    'ro' : 'Romanian',  'sk' : 'Slovak',    'es' : 'Spanish',
    'sv' : 'Swedish',   'ru' : 'Russian',    
    }

#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
_get_int = re.compile('([0-9]+)')

mime2ged = {
    "image/bmp"   : "bmp", 
    "image/gif"   : "gif", 
    "image/jpeg"  : "jpeg", 
    "image/x-pcx" : "pcx", 
    "image/tiff"  : "tiff", 
    "audio/x-wav" : "wav"
    }

quay_map = {
    RelLib.SourceRef.CONF_VERY_HIGH : 3, 
    RelLib.SourceRef.CONF_HIGH      : 2, 
    RelLib.SourceRef.CONF_LOW       : 1, 
    RelLib.SourceRef.CONF_VERY_LOW  : 0, 
    }

#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
def sort_by_gramps_id(first, second):
    return cmp(first.gramps_id, second.gramps_id)

#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
def make_date(subdate, calendar, mode):
    retval = ""
    (day, mon, year, sl) = subdate
    
    (mmap, prefix) = _calmap.get(calendar, (_month, ""))

    if year < 0:
        year = -year
        bc = " B.C."
    else:
        bc = ""
        
    if day == 0:
        try:
            if mon == 0:
                retval = '%d%s' % (year, bc)
            elif year == 0:
                retval = '(%s)' % mmap[mon]
            else:
                retval = "%s %d%s" % (mmap[mon], year, bc)
        except IndexError:
            print "Month index error - %d" % mon
            retval = '%d%s' % (year, bc)
    elif mon == 0:
        retval = '%d%s' % (year, bc)
    else:
        try:
            month = mmap[mon]
            if year == 0:
                retval = "(%d %s)" % (day, month)
            else:
                retval = "%d %s %d%s" % (day, month, year, bc)
        except IndexError:
            print "Month index error - %d" % mon
            retval = "%d%s" % (year, bc)

    if prefix:
        retval = "%s %s" % (prefix, retval)

    if _caldef.has_key(mode):
        retval = "%s %s"  % (_caldef[mode], retval)
        
    return retval

#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
def writeData(database, person):
    GedcomWriter(database, person)

def breakup(txt, limit):
    """
    Breaks a line of text into a list of strings that conform to the 
    maximum length specified, while breaking words in the middle of a word
    to avoid issues with spaces.
    """
    data = []
    original = txt
    while limit < len(txt)+1:
        idx = limit-1
        while txt[idx-1] in string.whitespace or txt[idx] in string.whitespace :
            idx -= 1
        data.append(txt[:idx])
        txt = txt[idx:]
    if len(txt) > 0:
        data.append(txt)
    return data

#-------------------------------------------------------------------------
#
# GedcomWriter class
#
#-------------------------------------------------------------------------
class GedcomWriter(UpdateCallback):
    def __init__(self, database, person, cl=0, filename="", option_box=None, 
                 callback=None):
        UpdateCallback.__init__(self, callback)

        self.db = database
        self.person = person
        self.option_box = option_box
        self.cl = cl
        self.filename = filename
        
        self.slist = set()
        self.rlist = set()
        self.nlist = set()

        if option_box:
            setup_func = self.gui_setup
        else:
            setup_func = self.cli_setup

        # Run setup, bail out if status is not Ture
        if not setup_func():
            return

    def __writeln(self, level, token, textlines="", limit=72):
        assert(token)
        if textlines:
            textlist = textlines.split('\n')
            token_level = level
            for text in textlist:
                if limit:
                    prefix = "\n%d CONC " % (level + 1)
                    txt = prefix.join(breakup(text, limit))
                else:
                    txt = text
                self.g.write("%d %s %s\n" % (token_level, token, txt))
                token_level = level+1
                token = "CONT"
        else:
            self.g.write("%d %s\n" % (level, token))
    
    def gui_setup(self):
        # Get settings from the options store/dialog
        self.option_box.parse_options()

        self.restrict = self.option_box.restrict
        self.private = self.option_box.private

        if self.private:
            from _PrivateProxyDb import PrivateProxyDb
            self.db = PrivateProxyDb(self.db)

        if self.restrict:
            from _LivingProxyDb import LivingProxyDb
            self.db = LivingProxyDb(self.db, LivingProxyDb.MODE_RESTRICT)

        if not self.option_box.cfilter.is_empty():
            from _FilterProxyDb import FilterProxyDb
            self.db = FilterProxyDb(self.db, self.option_box.cfilter)

    def cli_setup(self):
        # use default settings
        self.restrict = 0
        self.private = 0
        return True

    def export_data(self, filename):

        self.dirname = os.path.dirname (filename)
        try:
            self.g = open(filename, "w")
        except IOError, msg:
            msg2 = _("Could not create %s") % filename
            ErrorDialog(msg2, str(msg))
            return 0
        except:
            ErrorDialog(_("Could not create %s") % filename)
            return 0

        self.__write_header(filename)
        self.__write_submitter()
        self.__write_individuals()
        self.__write_families()
        self.__write_sources()
        self.__write_repos()
        self.__write_notes()

        self.__writeln(0, "TRLR")
        self.g.close()
        return 1

    def __write_header(self, filename):
        """
        Writes the GEDCOM header. 

          HEADER:=
          n HEAD {1:1}
          +1 SOUR <APPROVED_SYSTEM_ID> {1:1} 
          +2 VERS <VERSION_NUMBER> {0:1} 
          +2 NAME <NAME_OF_PRODUCT> {0:1} 
          +2 CORP <NAME_OF_BUSINESS> {0:1}           # Not used
          +3 <<ADDRESS_STRUCTURE>> {0:1}             # Not used
          +2 DATA <NAME_OF_SOURCE_DATA> {0:1}        # Not used
          +3 DATE <PUBLICATION_DATE> {0:1}           # Not used
          +3 COPR <COPYRIGHT_SOURCE_DATA> {0:1}      # Not used
          +1 DEST <RECEIVING_SYSTEM_NAME> {0:1*}     # Not used
          +1 DATE <TRANSMISSION_DATE> {0:1} 
          +2 TIME <TIME_VALUE> {0:1} 
          +1 SUBM @XREF:SUBM@ {1:1} 
          +1 SUBN @XREF:SUBN@ {0:1} 
          +1 FILE <FILE_NAME> {0:1} 
          +1 COPR <COPYRIGHT_GEDCOM_FILE> {0:1} 
          +1 GEDC {1:1}
          +2 VERS <VERSION_NUMBER> {1:1} 
          +2 FORM <GEDCOM_FORM> {1:1} 
          +1 CHAR <CHARACTER_SET> {1:1} 
          +2 VERS <VERSION_NUMBER> {0:1} 
          +1 LANG <LANGUAGE_OF_TEXT> {0:1} 
          +1 PLAC {0:1}
          +2 FORM <PLACE_HIERARCHY> {1:1} 
          +1 NOTE <GEDCOM_CONTENT_DESCRIPTION> {0:1} 
          +2 [CONT|CONC] <GEDCOM_CONTENT_DESCRIPTION> {0:M}
        """
        (year, mon, day, hour, min, sec, x, y, z) = time.localtime(time.time())
        date_str = "%d %s %d" % (day, _month[mon], year)
        time_str = "%02d:%02d:%02d" % (hour, min, sec)
        rname = self.db.get_researcher().get_name()

        self.__writeln(0, "HEAD")
        self.__writeln(1, "SOUR", "GRAMPS")
        self.__writeln(2, "VERS",  const.version)
        self.__writeln(2, "NAME", "GRAMPS")
        self.__writeln(1, "DATE", date_str)
        self.__writeln(2, "TIME", time_str)
        self.__writeln(1, "SUBM", "@SUBM@")
        self.__writeln(1, "FILE", filename)
        self.__writeln(1, "COPR", 'Copyright (c) %d %s.' % (year, rname))
        self.__writeln(1, "GEDC")
        self.__writeln(2, "VERS", "5.5")
        self.__writeln(2, "FORM", 'LINEAGE-LINKED')
        self.__writeln(1, "CHAR", "UTF-8")
        
        # write the language string if the current LANG variable 
        # matches something we know about.

        lang = os.getenv('LANG')
        if lang and len(lang) >= 2:
            lang_code = LANGUAGES.get(lang[0:2])
            if lang_code:
                self.__writeln(1, 'LANG', lang_code)

    def __write_submitter(self):
        """
          n @<XREF:SUBM>@ SUBM {1:1}
          +1 NAME <SUBMITTER_NAME> {1:1} 
          +1 <<ADDRESS_STRUCTURE>> {0:1}
          +1 <<MULTIMEDIA_LINK>> {0:M}              # not used
          +1 LANG <LANGUAGE_PREFERENCE> {0:3}       # not used
          +1 RFN <SUBMITTER_REGISTERED_RFN> {0:1}   # not used
          +1 RIN <AUTOMATED_RECORD_ID> {0:1}        # not used
          +1 <<CHANGE_DATE>> {0:1}                  # not used
        """
        owner = self.db.get_researcher()
        (name, addr, city, stae, ctry, post, phon, mail) = owner.get()
        if not name : 
            name = u'Not Provided'
        if not addr : 
            addr = u'Not Provided'
        
        self.__writeln(0, "@SUBM@", "SUBM")
        self.__writeln(1, "NAME", name)
        self.__writeln(1, "ADDR", addr)
        if city and stae and post:
            self.__writeln(2, "CONT", "%s, %s %s" % (city, stae, post))
        else:
            self.__writeln(2, "CONT", u"Not Provided")
        if city:
            self.__writeln(2, "CITY", city)
        if stae:
            self.__writeln(2, "STAE", stae)
        if post:
            self.__writeln(2, "POST", post)
        if ctry:
            self.__writeln(2, "CTRY", ctry)
        if phon:
            self.__writeln(1, "PHON", phon)

    def __write_individuals(self):
        """
        INDIVIDUAL RECORDS
        """

        phandles = self.db.get_person_handles()

        hcnt = len(phandles)

        self.reset(_("Sorting"))
        self.set_total(hcnt)
        sorted = []
        for handle in phandles:
            person = self.db.get_person_from_handle (handle)
            data = (person.get_gramps_id (), handle)
            sorted.append (data)
            self.update()
        sorted.sort()

        self.set_total(hcnt + len(self.db.get_family_handles()))
        self.reset(_("Writing"))
        for data in sorted:
            self.__write_person(self.db.get_person_from_handle(data[1]))
            self.update()

    def __write_person(self, person):
        """
        Writes out a single person

          n @XREF:INDI@ INDI {1:1}
          +1 RESN <RESTRICTION_NOTICE> {0:1}            # not used
          +1 <<PERSONAL_NAME_STRUCTURE>> {0:M}          
          +1 SEX <SEX_VALUE> {0:1} 
          +1 <<INDIVIDUAL_EVENT_STRUCTURE>> {0:M} 
          +1 <<INDIVIDUAL_ATTRIBUTE_STRUCTURE>> {0:M} 
          +1 <<LDS_INDIVIDUAL_ORDINANCE>> {0:M} 
          +1 <<CHILD_TO_FAMILY_LINK>> {0:M} 
          +1 <<SPOUSE_TO_FAMILY_LINK>> {0:M} 
          +1 SUBM @<XREF:SUBM>@ {0:M} 
          +1 <<ASSOCIATION_STRUCTURE>> {0:M} 
          +1 ALIA @<XREF:INDI>@ {0:M} 
          +1 ANCI @<XREF:SUBM>@ {0:M} 
          +1 DESI @<XREF:SUBM>@ {0:M} 
          +1 <<SOURCE_CITATION>> {0:M} 
          +1 <<MULTIMEDIA_LINK>> {0:M} ,*
          +1 <<NOTE_STRUCTURE>> {0:M} 
          +1 RFN <PERMANENT_RECORD_FILE_NUMBER> {0:1} 
          +1 AFN <ANCESTRAL_FILE_NUMBER> {0:1} 
          +1 REFN <USER_REFERENCE_NUMBER> {0:M} 
          +2 TYPE <USER_REFERENCE_TYPE> {0:1} 
          +1 RIN <AUTOMATED_RECORD_ID> {0:1} 
          +1 <<CHANGE_DATE>> {0:1} 
        """
        self.__writeln(0, "@%s@" % person.get_gramps_id(),  "INDI")

        self.__write_names(person)
        self.__write_gender(person)
        self.__write_person_event_ref('BIRT', person.get_birth_ref())
        self.__write_person_event_ref('DEAT', person.get_death_ref())
        self.__write_remaining_events(person)
        self.__write_attributes(person)
        self.__write_lds_ords(person, 1)
        self.__write_child_families(person)
        self.__write_parent_families(person)
        self.__write_assoc(person, 1)
        self.__write_person_sources(person)
        self.__write_addresses(person)
        self.__write_photos(person.get_media_list(), 1)
        self.__write_url_list(person, 1)
        self.__write_note_references(person.get_note_list(), 1)
        self.__write_change(person.get_change_time(), 1)

    def __write_assoc(self, person, level):
        """
          n ASSO @<XREF:INDI>@ {0:M} 
          +1 TYPE <RECORD_TYPE> {1:1}
          +1 RELA <RELATION_IS_DESCRIPTOR> {1:1}
          +1 <<NOTE_STRUCTURE>> {0:M} 
          +1 <<SOURCE_CITATION>> {0:M} 
        """
        for ref in person.get_person_ref_list():
            person = self.db.get_person_from_handle(ref.ref)
            self.__writeln(level, "ASSO", "@%s@" % person.get_gramps_id())
            self.__writeln(level+1, "TYPE", ref.get_relation())
            self.__write_note_references(ref.get_note_list(), level+1)
            self.__write_source_references(ref.get_source_references, level+1)

    def __write_note_references(self, notelist, level):
        for note_handle in notelist:
            note = self.db.get_note_from_handle(note_handle)
            self.__writeln(level, 'NOTE', '@%s@' % note.get_gramps_id())
            self.nlist.add(note_handle)

    def __write_names(self, person):
        nicknames = [ attr.get_value() for attr in person.get_attribute_list()
                      if int(attr.get_type()) == RelLib.AttributeType.NICKNAME ]
        if len(nicknames) > 0:
            nickname = nicknames[0]
        else:
            nickname = ""

        self.__write_person_name(person.get_primary_name(), nickname)
        for name in person.get_alternate_names():
            self.__write_person_name(name, "")

    def __write_gender(self, person):
        if person.get_gender() == RelLib.Person.MALE:
            self.__writeln(1, "SEX", "M")
        elif person.get_gender() == RelLib.Person.FEMALE:
            self.__writeln(1, "SEX", "F")

    def __write_lds_ords(self, obj, level):
        for lds_ord in obj.get_lds_ord_list():
            self.write_ord(lds_ord, level)

    def __write_remaining_events(self, person):

        ad = False
        for event_ref in person.get_event_ref_list():
            event = self.db.get_event_from_handle(event_ref.ref)
            etype = int(event.get_type())

            if etype in (RelLib.EventType.BIRTH, RelLib.EventType.DEATH):
                continue
                
            val = GedcomInfo.personalConstantEvents.get(etype, "")
                        
            if val and val.strip():
                if val in personalAttributeTakesParam:
                    if event.get_description().strip():
                        self.__writeln(1, val, event.get_description())
                    else:
                        self.__writeln(1, val)
                else:
                    if (not event.get_date_object().is_empty()) \
                            or event.get_place_handle():
                        self.__writeln(1, val)
                    else:
                        self.__writeln(1, val, 'Y')
                    if event.get_description().strip():
                        self.__writeln(2, 'TYPE', event.get_description())
            else:
                self.__writeln(1, 'EVEN')
                if val.strip():
                    self.__writeln(2, 'TYPE', val)
                else:
                    self.__writeln(2, 'TYPE', str(event.get_type()))
                descr = event.get_description()
                if descr:
                    self.__writeln(2, 'NOTE', "Description: " + descr)

            self.dump_event_stats(event, event_ref)

        self.__write_adoption_record(person)

    def __write_adoption_record(self, person):
        
        adopt_records = []

        for family in [ self.db.get_family_from_handle(fh) 
                        for fh in person.get_parent_family_handle_list() ]:
            for child_ref in family.get_child_ref_list():
                if child_ref.ref == person.handle:
                    if child_ref.mrel == RelLib.ChildRefType.ADOPTED \
                            or child_ref.frel == RelLib.ChildRefType.ADOPTED:
                        adopt_records.append((family, child_ref.frel, child_ref.mrel))

        for (fam, frel, mrel) in adopt_records:
            self.__writeln(1, 'ADOP', 'Y')
            self.__writeln(2, 'FAMC', '@%s@' % fam.get_gramps_id())
            if mrel == frel:
                self.__writeln(3, 'ADOP', 'BOTH')
            elif mrel == RelLib.ChildRefType.ADOPTED:
                self.__writeln(3, 'ADOP', 'WIFE')
            else:
                self.__writeln(3, 'ADOP', 'HUSB')

    def __write_attributes(self, person):
        
        # filter out the Nicknames, since they have already been
        # processed.

        attr_list = [ attr for attr in person.get_attribute_list()
                      if attr.get_type() != RelLib.AttributeType.NICKNAME ]

        for attr in attr_list:

            t = int(attr.get_type())
            name = GedcomInfo.personalConstantAttributes.get(t)
            key = str(attr.get_type())
            value = attr.get_value().strip().replace('\r', ' ')
            
            if key in ("AFN", "RFN", "REFN", "_UID"):
                self.__writeln(1, key, value)
                continue

            if key == "RESN":
                self.__writeln(1, 'RESN')
                continue

            if name and name.strip():
                self.__writeln(1, name, value)
            elif value:
                self.__writeln(1, 'FACT', value)
                self.__writeln(2, 'TYPE', key)
            else:
                continue
            self.__write_note_references(attr.get_note_list(), 2)
            self.__write_source_references(attr.get_source_references(), 2)

    def __write_source_references(self, ref_list, level):
        for srcref in ref_list:
            self.write_source_ref(level, srcref)

    def __write_addresses(self, person):
        for addr in person.get_address_list():
            self.__writeln(1, 'RESI')
            self.print_date(2, addr.get_date_object())
            self.__writeln(2, "ADDR", addr.get_street())
            if addr.get_city():
                self.__writeln(3, 'CITY', addr.get_city())
            if addr.get_state():
                self.__writeln(3, 'STAE', addr.get_state())
            if addr.get_postal_code():
                self.__writeln(3, 'POST', addr.get_postal_code())
            if addr.get_country():
                self.__writeln(3, 'CTRY', addr.get_country())
            if addr.get_phone():
                self.__writeln(2, 'PHON', addr.get_phone())

            self.__write_note_references(addr.get_note_list(), 2)
            self.__write_source_references(addr.get_source_references(), 2)

    def __write_photos(self, media_list, level):
        for photo in media_list:
            self.__write_photo(photo, level)

    def __write_child_families(self, person):
        hndl_list = [ hndl for hndl in person.get_parent_family_handle_list() ]

        for family_handle in hndl_list:
            family = self.db.get_family_from_handle(family_handle)
            family_id = family.get_gramps_id()
            self.__writeln(1, 'FAMC', '@%s@' % family_id)

    def __write_parent_families(self, person):
        for family_handle in person.get_family_handle_list():
            family = self.db.get_family_from_handle(family_handle)
            self.__writeln(1, 'FAMS', '@%s@' % family.get_gramps_id())

    def __write_person_sources(self, person):
        for srcref in person.get_source_references():
            self.write_source_ref(1, srcref)

    def __write_url_list(self, obj, level):
        """
          n OBJE {1:1}
          +1 FORM <MULTIMEDIA_FORMAT> {1:1} 
          +1 TITL <DESCRIPTIVE_TITLE> {0:1} 
          +1 FILE <MULTIMEDIA_FILE_REFERENCE> {1:1}
          +1 <<NOTE_STRUCTURE>> {0:M}
        """
        for url in obj.get_url_list():
            self.__writeln(level, 'OBJE')
            self.__writeln(level+1, 'FORM', 'URL')
            if url.get_description():
                self.__writeln(level+1, 'TITL', url.get_description())
            if url.get_path():
                self.__writeln(level+1, 'FILE', url.get_path())

    def __write_families(self):
        sorted = []

        for family_handle in self.db.get_family_handles():
            family = self.db.get_family_from_handle(family_handle)
            data = (family.get_gramps_id(), family_handle)
            sorted.append (data)
        sorted.sort ()

        for (gramps_id, family_handle) in sorted:
            family = self.db.get_family_from_handle(family_handle)
            self.__write_family(family)

    def __write_family_reference(self, token, person_handle):
        if person_handle:
            person = self.db.get_person_from_handle(person_handle)
            gramps_id = person.get_gramps_id()
            self.__writeln(1, token, '@%s@' % gramps_id)

    def __write_family(self, family):

        gramps_id = family.get_gramps_id()
        family_handle = family.get_handle()

        self.__writeln(0, '@%s@' % gramps_id, 'FAM' )

        self.__write_family_reference('HUSB', family.get_father_handle())
        self.__write_family_reference('WIFE', family.get_mother_handle())

        self.__write_lds_ords(family, 1)
        self.__write_family_events(family)

        self.__write_family_attributes(family.get_attribute_list(), 1)

        
        child_list = [ self.db.get_person_from_handle(cref.ref).get_gramps_id()
                       for cref in family.get_child_ref_list() ]
        child_list.sort()

        for gid in child_list:
            self.__writeln(1, 'CHIL', '@%s@' % gid)

        self.__write_source_references(family.get_source_references(), 1)
        self.__write_photos(family.get_media_list(), 1)
        self.__write_note_references(family.get_note_list(), 1)
        self.__write_change(family.get_change_time(), 1)
        self.update()

    def __write_family_events(self, family):

        for event_ref in [ ref for ref in family.get_event_ref_list()]:
            event = self.db.get_event_from_handle(event_ref.ref)
            if not event:
                continue

            etype = int(event.get_type())
            val = GedcomInfo.familyConstantEvents.get(etype)
            
            if val:
                if (not event.get_date_object().is_empty()) \
                        or event.get_place_handle():
                    self.__writeln(1, val)
                else:
                    self.__writeln(1, val, 'Y')

                if event.get_type() == RelLib.EventType.MARRIAGE:
                    ftype = family.get_relationship()
                    if ftype != RelLib.FamilyRelType.MARRIED and str(ftype):
                        self.__writeln(2, 'TYPE', str(ftype))

                    self.__write_family_event_attrs(event.get_attribute_list(), 2) 
                elif event.get_description().strip() != "":
                    self.__writeln(2, 'TYPE', event.get_description())
            else:
                self.__writeln(1, 'EVEN')
                the_type = str(event.get_type())
                if the_type:
                    self.__writeln(2, 'TYPE', the_type)
                descr = event.get_description()
                if descr:
                    self.__writeln(2, 'NOTE', "Description: " + descr)

            self.dump_event_stats(event, event_ref)


    def __write_family_event_attrs(self, attr_list, level):
        for attr in attr_list:
            if attr.get_type() == RelLib.AttributeType.FATHER_AGE:
                self.__writeln(level, 'HUSB')
                self.__writeln(level+1, 'AGE', attr.get_value())
            elif attr.get_type() == RelLib.AttributeType.MOTHER_AGE:
                self.__writeln(level, 'WIFE')
                self.__writeln(level+1, 'AGE', attr.get_value())

    def __write_family_attributes(self, attr_list, level):

        for attr in attr_list:
            
            t = int(attr.get_type())
            name = GedcomInfo.familyConstantAttributes.get(t)
            value = attr.get_value().replace('\r', ' ')

            if t in ("AFN", "RFN", "REFN", "_UID"):
                self.__writeln(1, t, value)
                continue
            
            if name and name.strip():
                self.__writeln(1, name, value)
                continue
            else:
                the_name = str(attr.get_type())
                self.__writeln(level, 'EVEN')
                if value:
                    self.__writeln(level+1, 'TYPE', '%s %s' % (the_name, value))
                else:
                    self.__writeln(level+1, 'TYPE', the_name)

            self.__write_note_references(attr.get_note_list(), level+1)
            self.__write_source_references(attr.get_source_references(), level+1)

    def __write_sources(self):
        sorted = []
        for handle in self.slist:
            source = self.db.get_source_from_handle(handle)
            if not source:
                continue
            data = (source.get_gramps_id(), handle)
            sorted.append (data)
        sorted.sort ()

        for (source_id, handle) in sorted:
            source = self.db.get_source_from_handle(handle)
            self.__writeln(0, '@%s@' % source_id, 'SOUR')
            if source.get_title():
                self.__writeln(1, 'TITL', source.get_title())

            if source.get_author():
                self.__writeln(1, "AUTH", source.get_author())

            if source.get_publication_info():
                self.__writeln(1, "PUBL", source.get_publication_info())

            if source.get_abbreviation():
                self.__writeln(1, 'ABBR', source.get_abbreviation())

            self.__write_photos(source.get_media_list(), 1)

            for reporef in source.get_reporef_list():
                self.write_reporef(reporef, 1)
                break

            self.__write_note_references(source.get_note_list(), 1)
            self.__write_change(source.get_change_time(), 1)

    def __write_notes(self):
        sorted = []
        for handle in self.nlist:
            note = self.db.get_note_from_handle(handle)
            data = (note.get_gramps_id(), handle)
            sorted.append (data)
        sorted.sort ()

        for (node_id, note_handle) in sorted:
            note = self.db.get_note_from_handle(note_handle)
            self.__write_note_record(note)
            
    def __write_note_record(self, note):
        """
          n @<XREF:NOTE>@ NOTE <SUBMITTER_TEXT> {1:1} 
          +1 [ CONC | CONT] <SUBMITTER_TEXT> {0:M}
          +1 <<SOURCE_CITATION>> {0:M} 
          +1 REFN <USER_REFERENCE_NUMBER> {0:M} 
          +2 TYPE <USER_REFERENCE_TYPE> {0:1} 
          +1 RIN <AUTOMATED_RECORD_ID> {0:1} 
          +1 <<CHANGE_DATE>> {0:1} 
        """

        self.__writeln(0, '@%s@' % note.get_gramps_id(),  'NOTE ' + note.get())

    def __write_repos(self):
        sorted = []
        for handle in self.rlist:
            repo = self.db.get_repository_from_handle(handle)
            repo_id = repo.get_gramps_id()
            sorted.append((repo_id, handle))

        sorted.sort()

        slist = set()

        # GEDCOM only allows for a single repository per source

        for (repo_id, handle) in sorted:
            repo = self.db.get_repository_from_handle(handle)
            self.__writeln(0, '@%s@' % repo_id, 'REPO' )
            if repo.get_name():
                self.__writeln(1, 'NAME', repo.get_name())
            for addr in repo.get_address_list():
                self.__writeln(1, "ADDR", addr.get_street())
                if addr.get_city():
                    self.__writeln(2, 'CITY', addr.get_city())
                if addr.get_state():
                    self.__writeln(2, 'STAE', addr.get_state())
                if addr.get_postal_code():
                    self.__writeln(2, 'POST', addr.get_postal_code())
                if addr.get_country():
                    self.__writeln(2, 'CTRY', addr.get_country())
                if addr.get_phone():
                    self.__writeln(1, 'PHON', addr.get_phone())
            self.__write_note_references(repo.get_note_list(), 1)

    def write_reporef(self, reporef, level):

        if reporef.ref == None:
            return

        # Append handle to the list for exporting REPOs later
        self.rlist.add(reporef.ref)

        repo = self.db.get_repository_from_handle(reporef.ref)
        repo_id = repo.get_gramps_id()

        self.__writeln(level, 'REPO', '@%s@' % repo_id )

        self.__write_note_references(reporef.get_note_list(), level+1)

        if reporef.get_call_number():
            self.__writeln(level+1, 'CALN', reporef.get_call_number() )
            if reporef.get_media_type():
                self.__writeln(level+2, 'MEDI', str(reporef.get_media_type()))

    def __write_person_event_ref(self, key, event_ref):

        if event_ref:
            event = self.db.get_event_from_handle(event_ref.ref)
            if (not event.get_date_object().is_empty()) \
                    or event.get_place_handle():
                self.__writeln(1, key)
            else:
                self.__writeln(1, key, 'Y')
            if event.get_description().strip() != "":
                self.__writeln(2, 'TYPE', event.get_description())
            self.dump_event_stats(event, event_ref)

    def __write_change(self, timeval, level):
        self.__writeln(level, 'CHAN')
        time_val = time.localtime(timeval)
        self.__writeln(level+1, 'DATE', '%d %s %d' % (
                time_val[2], _month[time_val[1]], time_val[0]))
        self.__writeln(level+2, 'TIME', '%02d:%02d:%02d' % (
                time_val[3], time_val[4], time_val[5]))

    def dump_event_stats(self, event, event_ref):
        dateobj = event.get_date_object()
        self.print_date(2, dateobj)
        place = None

        if event.get_place_handle():
            place = self.db.get_place_from_handle(event.get_place_handle())
            self.write_place(place, 2)

        for attr in event.get_attribute_list():
            t = attr.get_type()
            if t == RelLib.AttributeType.CAUSE:
                self.__writeln(2, 'CAUS', attr.get_value())
            elif t == RelLib.AttributeType.AGENCY:
                self.__writeln(2, 'AGNC', attr.get_value())

        for attr in event_ref.get_attribute_list():
            t = attr.get_type()
            if t == RelLib.AttributeType.AGE:
                self.__writeln(2, 'AGE', attr.get_value())
            elif t == RelLib.AttributeType.FATHER_AGE:
                self.__writeln(2, 'HUSB')
                self.__writeln(3, 'AGE', attr.get_value())
            elif t == RelLib.AttributeType.MOTHER_AGE:
                self.__writeln(2, 'WIFE')
                self.__writeln(3, 'AGE', attr.get_value())

        self.__write_note_references(event.get_note_list(), 2)
        self.__write_source_references(event.get_source_references(), 2)

        self.__write_photos(event.get_media_list(), 2)
        if place:
            self.__write_photos(place.get_media_list(), 2)

    def write_ord(self, ord, index):
        self.__writeln(index, lds_ord_name[ord.get_type()])
        self.print_date(index + 1, ord.get_date_object())
        if ord.get_family_handle():
            family_handle = ord.get_family_handle()
            family = self.db.get_family_from_handle(family_handle)
            if family:
                self.__writeln(index+1, 'FAMC', '@%s@' % family.get_gramps_id())
        if ord.get_temple():
            self.__writeln(index+1, 'TEMP', ord.get_temple())
        if ord.get_place_handle():
            self.write_place(
                self.db.get_place_from_handle(ord.get_place_handle()), 2)
        if ord.get_status() != RelLib.LdsOrd.STATUS_NONE:
            self.__writeln(2, 'STAT', lds_status[ord.get_status()])
        
        self.__write_note_references(ord.get_note_list(), index+1)
        self.__write_source_references(ord.get_source_references(), index+1)

    def print_date(self, level, date):
        start = date.get_start_date()
        if start != RelLib.Date.EMPTY:
            cal = date.get_calendar()
            mod = date.get_modifier()
            if date.get_modifier() == RelLib.Date.MOD_SPAN:
                val = "FROM %s TO %s" % (
                    make_date(start, cal, mod), 
                    make_date(date.get_stop_date(), cal, mod))
            elif date.get_modifier() == RelLib.Date.MOD_RANGE:
                val = "BET %s AND %s" % (
                    make_date(start, cal, mod), 
                    make_date(date.get_stop_date(), cal, mod))
            else:
                val = make_date(start, cal, mod)
            self.__writeln(level, 'DATE', val)
        elif date.get_text():
            self.__writeln(level, 'DATE', date.get_text())

    def __write_person_name(self, name, nick):
        """
          n NAME <NAME_PERSONAL> {1:1} 
          +1 NPFX <NAME_PIECE_PREFIX> {0:1} 
          +1 GIVN <NAME_PIECE_GIVEN> {0:1} 
          +1 NICK <NAME_PIECE_NICKNAME> {0:1} 
          +1 SPFX <NAME_PIECE_SURNAME_PREFIX {0:1} 
          +1 SURN <NAME_PIECE_SURNAME> {0:1} 
          +1 NSFX <NAME_PIECE_SUFFIX> {0:1} 
          +1 <<SOURCE_CITATION>> {0:M} 
          +1 <<NOTE_STRUCTURE>> {0:M} 
        """
        firstname = name.get_first_name().strip()
        patron = name.get_patronymic().strip()
        if patron:
            firstname = "%s %s" % (firstname, patron)

        surname = name.get_surname().replace('/', '?')
        surprefix = name.get_surname_prefix().replace('/', '?')
        suffix = name.get_suffix()
        title = name.get_title()
        if suffix == "":
            if surprefix == "":
                self.__writeln(1, 'NAME', '%s/%s/' % (firstname, surname))
            else:
                self.__writeln(1, 'NAME', '%s/%s %s/' % (firstname, surprefix, surname))
        else:
            if surprefix == "":
                self.__writeln(1, 'NAME', '%s/%s/ %s' % (firstname, surname, suffix))
            else:
                self.__writeln(1, 'NAME', '%s/%s %s/ %s' % (firstname, surprefix, 
                                                            surname, suffix))

        if firstname:
            self.__writeln(2, 'GIVN', firstname)
        if surprefix:
            self.__writeln(2, 'SPFX', surprefix)
        if surname:
            self.__writeln(2, 'SURN', surname)
                
        if name.get_suffix():
            self.__writeln(2, 'NSFX', suffix)
        if name.get_title():
            self.__writeln(2, 'NPFX', title)
        if nick:
            self.__writeln(2, 'NICK', nick)

        self.__write_source_references(name.get_source_references(), 2)
        self.__write_note_references(name.get_note_list(), 2)

    def write_source_ref(self, level, ref):
        """
          n SOUR @<XREF:SOUR>@ /* pointer to source record */ {1:1} 
          +1 PAGE <WHERE_WITHIN_SOURCE> {0:1} 
          +1 EVEN <EVENT_TYPE_CITED_FROM> {0:1} 
          +2 ROLE <ROLE_IN_EVENT> {0:1} 
          +1 DATA {0:1}
          +2 DATE <ENTRY_RECORDING_DATE> {0:1} 
          +2 TEXT <TEXT_FROM_SOURCE> {0:M} 
          +3 [ CONC | CONT ] <TEXT_FROM_SOURCE> {0:M}
          +1 QUAY <CERTAINTY_ASSESSMENT> {0:1} 
          +1 <<MULTIMEDIA_LINK>> {0:M} ,*
          +1 <<NOTE_STRUCTURE>> {0:M} 
        """

        src_handle = ref.get_reference_handle()
        if src_handle == None:
            return

        src = self.db.get_source_from_handle(src_handle)
        self.slist.add(src_handle)

        # Reference to the source
        self.__writeln(level, "SOUR", "@%s@" % src.get_gramps_id())
        if ref.get_page() != "":
            self.__writeln(level+1, 'PAGE', ref.get_page())

        conf = min(ref.get_confidence_level(), RelLib.SourceRef.CONF_VERY_HIGH)
        if conf != RelLib.SourceRef.CONF_NORMAL and conf != -1:
            self.__writeln(level+1, "QUAY", str(quay_map[conf]))

        if len(ref.get_note_list()) > 0:

            note_list = [ self.db.get_note_from_handle(h) for h in ref.get_note_list() ]
            note_list = [ n for n in note_list 
                          if n.get_type() == RelLib.NoteType.SOURCE_TEXT]

            if note_list:
                ref_text = note_list[0].get()
            else:
                ref_text = ""

            if ref_text != "" or not ref.get_date_object().is_empty():
                self.__writeln(level+1, 'DATA')
                if ref_text != "":
                    self.__writeln(level+2, "TEXT", ref_text)
                self.print_date(level+2, ref.get_date_object())

            note_list = [ self.db.get_note_from_handle(h) for h in ref.get_note_list() ]
            note_list = [ n.handle for n in note_list 
                          if n.get_type() != RelLib.NoteType.SOURCE_TEXT]
            self.__write_note_references(note_list, level+1)

    def __write_photo(self, photo, level):
        """
          n OBJE {1:1}
          +1 FORM <MULTIMEDIA_FORMAT> {1:1} 
          +1 TITL <DESCRIPTIVE_TITLE> {0:1} 
          +1 FILE <MULTIMEDIA_FILE_REFERENCE> {1:1}
          +1 <<NOTE_STRUCTURE>> {0:M}
        """
        photo_obj_id = photo.get_reference_handle()
        photo_obj = self.db.get_object_from_handle(photo_obj_id)
        if photo_obj:
            mime = photo_obj.get_mime_type()
            form = mime2ged.get(mime, mime)
            path = photo_obj.get_path()
            imgdir = path
            if not os.path.isfile(path):
                return
            self.__writeln(level, 'OBJE')
            if form:
                self.__writeln(level+1, 'FORM', form)
            self.__writeln(level+1, 'TITL', photo_obj.get_description())
            self.__writeln(level+1, 'FILE', path)

            self.__write_note_references(photo_obj.get_note_list(), level+1)

    def write_place(self, place, level):
        place_name = place.get_title()
        self.__writeln(level, "PLAC", place_name.replace('\r', ' '))
        long = place.get_longitude()
        lat = place.get_latitude()
        if long and lat:
            self.__writeln(level+1, "MAP")
            self.__writeln(level+2, 'LATI', lat)
            self.__writeln(level+2, 'LONG', long)

#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
def exportData(database, filename, person, option_box, callback=None):
    ret = 0
    try:
        gw = GedcomWriter(database, person, 0, filename, option_box, callback)
        ret = gw.export_data(filename)
    except Errors.DatabaseError, msg:
        ErrorDialog(_("Export failed"), str(msg))
    return ret

#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
_title = _('GE_DCOM')
_description = _('GEDCOM is used to transfer data between genealogy programs. '
        'Most genealogy software will accept a GEDCOM file as input. ')
_config = (_('GEDCOM export options'), ExportOptions.WriterOptionBox)
_filename = 'ged'

from PluginUtils import register_export
register_export(exportData, _title, _description, _config, _filename)




See more files for this project here

gramps

GRAMPS is a GNOME genealogy program for Linux and FreeBSD that allows you to easily build\r\nand keep track of your family tree.

Project homepage: http://sourceforge.net/projects/gramps
Programming language(s): Python
License: other

  Makefile.am
  _Backup.py
  _FilterProxyDb.py
  _GedcomChar.py
  _GedcomInfo.py
  _GedcomLex.py
  _GedcomParse.py
  _GedcomTokens.py
  _GedcomUtils.py
  _GrampsDbWRFactories.py
  _LivingProxyDb.py
  _PrivateProxyDb.py
  _ProxyDbBase.py
  _ReadGedcom.py
  _ReadXML.py
  _WriteGedcom.py
  _WriteGrdb.py
  _WriteXML.py
  __init__.py
  gedcomimport.glade