1#
2# Gramps - a GTK+/GNOME based genealogy program
3#
4# Copyright (C) 2003-2006, 2008  Donald N. Allingham
5# Copyright (C) 2008       Brian G. Matherly
6# Copyright (C) 2010       Jakim Friant
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21#
22
23"Export to Web Family Tree"
24
25#-------------------------------------------------------------------------
26#
27# standard python modules
28#
29#-------------------------------------------------------------------------
30
31#------------------------------------------------------------------------
32#
33# Set up logging
34#
35#------------------------------------------------------------------------
36import logging
37from collections import abc
38log = logging.getLogger(".WriteFtree")
39
40#-------------------------------------------------------------------------
41#
42# Gramps modules
43#
44#-------------------------------------------------------------------------
45# keep the following line even though not obviously used (works on import)
46from gramps.gui.plug.export import WriterOptionBox
47from gramps.gui.dialog import ErrorDialog
48from gramps.gen.const import GRAMPS_LOCALE as glocale
49_ = glocale.translation.gettext
50
51
52#-------------------------------------------------------------------------
53#
54# writeData
55#
56#-------------------------------------------------------------------------
57def writeData(database, filename, user, option_box=None):
58    """ function to export Web Family Tree file """
59    writer = FtreeWriter(database, filename, user, option_box)
60    return writer.export_data()
61
62
63#-------------------------------------------------------------------------
64#
65# FtreeWriter
66#
67#-------------------------------------------------------------------------
68class FtreeWriter:
69    """ Export a Web Family Tree format file """
70    def __init__(self, database, filename, user, option_box=None):
71        self.db = database
72        self.filename = filename
73        self.user = user
74        self.option_box = option_box
75        # is callback is really callable?
76        if isinstance(self.user.callback, abc.Callable):
77            self.update = self.update_real
78        else:
79            self.update = self.update_empty
80
81        if option_box:
82            self.option_box.parse_options()
83            self.db = option_box.get_filtered_database(self.db)
84
85        self.plist = self.db.get_person_handles()
86        self.plist.sort()
87        # the following are used to update the progress meter
88        self.total = 2 * len(self.plist)
89        self.count = 0
90        self.oldval = 0  # we only update when percentage changes
91
92    def update_empty(self):
93        """ used when no callback is present """
94        pass
95
96    def update_real(self):
97        """ Progress update """
98        self.count += 1
99        newval = int(100 * self.count / self.total)
100        if newval != self.oldval:
101            self.user.callback(newval)
102            self.oldval = newval
103
104    def export_data(self):
105        """ main export processing """
106        name_map = {}
107        id_map = {}
108        id_name = {}
109
110        for key in self.plist:
111            self.update()
112            pnam = self.db.get_person_from_handle(key).get_primary_name()
113            snam = pnam.get_surname()
114            items = pnam.get_first_name().split()
115            nam = ("%s %s" % (items[0], snam)) if items else snam
116
117            count = -1
118            if nam in name_map:
119                count = 0
120                while 1:
121                    nam_num = "%s%d" % (nam, count)
122                    if nam_num not in name_map:
123                        break
124                    count += 1
125                name_map[nam_num] = key
126                id_map[key] = nam_num
127            else:
128                name_map[nam] = key
129                id_map[key] = nam
130            id_name[key] = get_name(pnam, snam, count)
131
132        try:
133            with open(self.filename, "w", encoding='utf_8') as file:
134                return self._export_data(file, id_name, id_map)
135        except IOError as msg:
136            msg2 = _("Could not create %s") % self.filename
137            ErrorDialog(msg2, str(msg), parent=self.option_box.window)
138            return False
139
140    def _export_data(self, file, id_name, id_map):
141        """ file export processing """
142        for key in self.plist:
143            self.update()
144            pers = self.db.get_person_from_handle(key)
145            name = id_name[key]
146            father = mother = email = web = ""
147
148            family_handle = pers.get_main_parents_family_handle()
149            if family_handle:
150                family = self.db.get_family_from_handle(family_handle)
151                if family.get_father_handle() and \
152                        family.get_father_handle() in id_map:
153                    father = id_map[family.get_father_handle()]
154                if family.get_mother_handle() and \
155                        family.get_mother_handle() in id_map:
156                    mother = id_map[family.get_mother_handle()]
157
158            #
159            # Calculate Date
160            #
161            birth_ref = pers.get_birth_ref()
162            death_ref = pers.get_death_ref()
163            if birth_ref:
164                birth_event = self.db.get_event_from_handle(birth_ref.ref)
165                birth = birth_event.get_date_object()
166            else:
167                birth = None
168            if death_ref:
169                death_event = self.db.get_event_from_handle(death_ref.ref)
170                death = death_event.get_date_object()
171            else:
172                death = None
173
174            #if self.restrict:
175            #    alive = probably_alive(pers, self.db)
176            #else:
177            #    alive = 0
178
179            if birth:
180                if death:
181                    dates = "%s-%s" % (fdate(birth), fdate(death))
182                else:
183                    dates = fdate(birth)
184            else:
185                if death:
186                    dates = fdate(death)
187                else:
188                    dates = ""
189
190            file.write('%s;%s;%s;%s;%s;%s\n' %
191                       (name, father, mother, email, web, dates))
192
193        return True
194
195
196def fdate(val):
197    """ return properly formatted date """
198    if val.get_year_valid():
199        if val.get_month_valid():
200            if val.get_day_valid():
201                return "%d/%d/%d" % (val.get_day(), val.get_month(),
202                                     val.get_year())
203            return "%d/%d" % (val.get_month(), val.get_year())
204        return "%d" % val.get_year()
205    return ""
206
207
208def get_name(name, surname, count):
209    """returns a name string built from the components of the Name
210    instance, in the form of Firstname Surname"""
211
212    return (name.first_name + ' ' +
213            surname +
214            (str(count) if count != -1 else '') +
215            (', ' + name.suffix if name.suffix else ''))
216