From dd43cde20e96426261ebcf35195574f39f67ac9d Mon Sep 17 00:00:00 2001 From: Paul Culley Date: Wed, 28 Nov 2018 16:28:56 -0600 Subject: [PATCH] Gedcom export, upgrade OBJE handling to Gedcom 5.5.1 style (#702) Fixes #10797 --- data/tests/exp_sample_ged.ged | 22 ++++---- gramps/plugins/export/exportgedcom.py | 74 +++++++++++++++++++++------ gramps/plugins/test/exports_test.py | 20 +++++--- 3 files changed, 83 insertions(+), 33 deletions(-) diff --git a/data/tests/exp_sample_ged.ged b/data/tests/exp_sample_ged.ged index 47d7a2998..cce2ab1bc 100644 --- a/data/tests/exp_sample_ged.ged +++ b/data/tests/exp_sample_ged.ged @@ -1,12 +1,12 @@ 0 HEAD 1 SOUR Gramps -2 VERS 5.0.0-alpha2 +2 VERS 5.0.1 2 NAME Gramps -1 DATE 1 SEP 2017 -2 TIME 12:10:38 +1 DATE 7 NOV 2018 +2 TIME 16:03:33 1 SUBM @SUBM@ 1 FILE C:\Users\prc\AppData\Roaming\gramps\temp\exp_sample_ged.ged -1 COPR Copyright (c) 2017 Alex Roitman,,,. +1 COPR Copyright (c) 2018 Alex Roitman,,,. 1 GEDC 2 VERS 5.5.1 2 FORM LINEAGE-LINKED @@ -786,11 +786,7 @@ 3 ADOP BOTH 1 FAMC @F0005@ 2 PEDI adopted -1 OBJE -2 FORM jpeg -2 TITL Michael O'Toole 2015-11 -2 FILE c:\grampsaio64-5.0.0\share\gramps\tests\O0.jpg -2 NOTE @N0019@ +1 OBJE @O0000@ 1 NOTE @N0007@ 1 CHAN 2 DATE 18 JUN 2016 @@ -1423,4 +1419,12 @@ 0 @N0017@ NOTE A citation Note Source text 0 @N0018@ NOTE Another Citation Note 0 @N0019@ NOTE A bad photo for sure +0 @O0000@ OBJE +1 FILE c:\users\prc\workspace\grampsm\main\data\tests\O0.jpg +2 FORM jpeg +2 TITL Michael O'Toole 2015-11 +1 NOTE @N0019@ +1 CHAN +2 DATE 29 OCT 2016 +3 TIME 15:23:37 0 TRLR diff --git a/gramps/plugins/export/exportgedcom.py b/gramps/plugins/export/exportgedcom.py index e9eb39034..9ce4cc206 100644 --- a/gramps/plugins/export/exportgedcom.py +++ b/gramps/plugins/export/exportgedcom.py @@ -259,6 +259,7 @@ class GedcomWriter(UpdateCallback): self._sources() self._repos() self._notes() + self._all_media() self._writeln(0, "TRLR") @@ -1421,27 +1422,68 @@ class GedcomWriter(UpdateCallback): def _photo(self, photo, level): """ - n OBJE {1:1} - +1 FORM {1:1} - +1 TITL {0:1} - +1 FILE {1:1} - +1 <> {0:M} + n OBJE @@ {1:1} """ photo_obj_id = photo.get_reference_handle() photo_obj = self.dbase.get_media_from_handle(photo_obj_id) if photo_obj: - mime = photo_obj.get_mime_type() - form = MIME2GED.get(mime, mime) - path = media_path_full(self.dbase, photo_obj.get_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, limit=255) + # if not os.path.isfile(path): + # return + self._writeln(level, 'OBJE @%s@' % photo_obj.get_gramps_id()) - self._note_references(photo_obj.get_note_list(), level + 1) + def _all_media(self): + """ + Write out the list of media, sorting by Gramps ID. + """ + self.set_text(_("Writing media")) + # generate a list of (GRAMPS_ID, HANDLE) pairs. This list + # can then be sorted by the sort routine, which will use the + # first value of the tuple as the sort key. + sorted_list = sort_handles_by_id(self.dbase.get_media_handles(), + self.dbase.get_media_from_handle) + + # loop through the sorted list, pulling of the handle. This list + # has already been sorted by GRAMPS_ID + for media_handle in [hndl[1] for hndl in sorted_list]: + self.update() + self._media(self.dbase.get_media_from_handle(media_handle)) + + def _media(self, media): + """ + n @XREF:OBJE@ OBJE {1:1} + +1 FILE {1:M} + +2 FORM {1:1} + +3 TYPE {0:1} + +2 TITL {0:1} p.48 + +1 REFN {0:M} + +2 TYPE {0:1} + +1 RIN {0:1} + +1 <> {0:M} + +1 <> {0:M} + +1 <> {0:1} + """ + if media is None: + return + gramps_id = media.get_gramps_id() + + self._writeln(0, '@%s@' % gramps_id, 'OBJE') + mime = media.get_mime_type() + form = MIME2GED.get(mime, mime) + path = media_path_full(self.dbase, media.get_path()) + self._writeln(1, 'FILE', path, limit=255) + if form: + self._writeln(2, 'FORM', form) + self._writeln(2, 'TITL', media.get_description()) + + for attr in media.get_attribute_list(): + key = str(attr.get_type()) + value = attr.get_value().replace('\r', ' ') + if key in ("RIN", "RFN", "REFN"): + self._writeln(1, key, value) + continue + self._note_references(media.get_note_list(), 1) + self._source_references(media.get_citation_list(), 1) + self._change(media.get_change_time(), 1) def _place(self, place, dateobj, level): """ diff --git a/gramps/plugins/test/exports_test.py b/gramps/plugins/test/exports_test.py index 6c39113fe..dcda87d89 100644 --- a/gramps/plugins/test/exports_test.py +++ b/gramps/plugins/test/exports_test.py @@ -93,6 +93,10 @@ def gedfilt(line): The differences are not functional, but are related to changes in Gramps version, file date/time and filename. """ + def get_prev_token(back): + if back > gedfilt.indx: + return None + return gedfilt.prev[gedfilt.indx - back][0] #pylint: disable=unsubscriptable-object if line.startswith('@@'): gedfilt.prev = [None] * 8 @@ -112,13 +116,13 @@ def gedfilt(line): # save the line for later if needed to figure out the data element gedfilt.prev[gedfilt.indx] = token, level, line gedfilt.indx = (gedfilt.indx + 1) % 8 - if token == "VERS" and gedfilt.prev[gedfilt.indx-2][0] == "SOUR": + if token == "VERS" and get_prev_token(2) == "SOUR": # we must have a header with Gramps version retval = False - elif token == "DATE" and gedfilt.prev[gedfilt.indx-2][0] == "NAME": + elif token == "DATE" and get_prev_token(2) == "NAME": # we must have a header with file date retval = False - elif token == "TIME" and gedfilt.prev[gedfilt.indx-2][0] == "DATE": + elif token == "TIME" and get_prev_token(2) == "DATE": # probably have a header with file time retval = False elif token == "FILE" and line.endswith('.ged\n'): @@ -131,15 +135,15 @@ def gedfilt(line): # probably have a copyright line with year retval = False else: # this is an addition - if token == "VERS" and gedfilt.prev[gedfilt.indx-1][0] == "VERS": + if token == "VERS" and get_prev_token(1) == "VERS": # we must have a header with Gramps version retval = False - elif token == "DATE" and (gedfilt.prev[gedfilt.indx-2][0] == "NAME" or - gedfilt.prev[gedfilt.indx-3][0] == "NAME"): + elif token == "DATE" and (get_prev_token(2) == "NAME" or + get_prev_token(3) == "NAME"): # we must have a header with file date retval = False - elif token == "TIME" and (gedfilt.prev[gedfilt.indx-2][0] == "DATE" or - gedfilt.prev[gedfilt.indx-3][0] == "DATE"): + elif token == "TIME" and (get_prev_token(2) == "DATE" or + get_prev_token(3) == "DATE"): # probably have a header with file time retval = False elif token == "FILE" and line.endswith('.ged\n'):