Plugins Restructure: Move export plugins into plugins/export.
svn: r11640
This commit is contained in:
313
src/plugins/export/ExportCd.py
Normal file
313
src/plugins/export/ExportCd.py
Normal file
@@ -0,0 +1,313 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2000-2008 Donald N. Allingham
|
||||
# Copyright (C) 2008 Brian G. Matherly
|
||||
#
|
||||
# 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:WriteCD.py 9912 2008-01-22 09:17:46Z acraphae $
|
||||
|
||||
"Export to CD (nautilus)."
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# standard python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import os
|
||||
import sys
|
||||
from gettext import gettext as _
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Set up logging
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import logging
|
||||
log = logging.getLogger(".WriteCD")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GNOME/GTK modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gtk
|
||||
import Errors
|
||||
|
||||
#This is a GNOME only plugin
|
||||
_gnome_session = os.getenv('GNOME_DESKTOP_SESSION_ID')
|
||||
if not _gnome_session:
|
||||
raise Errors.UnavailableError(
|
||||
_("WriteCD is a GNOME plugin and you are not running GNOME"))
|
||||
|
||||
try:
|
||||
import gnome
|
||||
except ImportError:
|
||||
raise Errors.UnavailableError(
|
||||
_("Cannot be loaded because python bindings "
|
||||
"for GNOME are not installed"))
|
||||
|
||||
try:
|
||||
from gnomevfs import (URI, create, OPEN_WRITE, make_directory,
|
||||
FileExistsError)
|
||||
except:
|
||||
from gnome.vfs import (URI, create, OPEN_WRITE, make_directory,
|
||||
FileExistsError)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GRAMPS modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from ExportXml import XmlWriter
|
||||
from Utils import media_path_full
|
||||
from QuestionDialog import ErrorDialog, MissingMediaDialog
|
||||
from gen.plug import PluginManager, ExportPlugin
|
||||
|
||||
_title_string = _("Export to CD")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# writeData
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
def writeData(database, filename, option_box=None, callback=None):
|
||||
writer = PackageWriter(database, filename, callback)
|
||||
return writer.export()
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# PackageWriter
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class PackageWriter:
|
||||
|
||||
def __init__(self, database, filename="", cl=0, callback=None):
|
||||
self.db = database
|
||||
self.cl = cl
|
||||
self.filename = filename
|
||||
self.callback = callback
|
||||
|
||||
def export(self):
|
||||
if self.cl:
|
||||
return self.cl_run()
|
||||
else:
|
||||
return self.gui_run()
|
||||
|
||||
def cl_run(self):
|
||||
base = os.path.basename(self.filename)
|
||||
|
||||
try:
|
||||
uri = URI('burn:///%s' % base)
|
||||
make_directory(uri, OPEN_WRITE)
|
||||
except FileExistsError, msg:
|
||||
ErrorDialog(_("CD export preparation failed"),
|
||||
"1 %s " % str(msg))
|
||||
return False
|
||||
except:
|
||||
uri_name = "burn:///" + base
|
||||
ErrorDialog("CD export preparation failed",
|
||||
'Could not create %s' % uri_name)
|
||||
return False
|
||||
|
||||
for obj_id in self.db.get_media_object_handles():
|
||||
obj = self.db.get_object_from_handle(obj_id)
|
||||
oldfile = media_path_full(self.db, obj.get_path())
|
||||
root = os.path.basename(oldfile)
|
||||
if os.path.isfile(oldfile):
|
||||
self.copy_file(oldfile, 'burn:///%s/%s' % (base, root))
|
||||
else:
|
||||
print "Warning: media file %s was not found, " % root, \
|
||||
"so it was ignored."
|
||||
|
||||
# Write XML now
|
||||
g = create('burn:///%s/data.gramps' % base, OPEN_WRITE )
|
||||
gfile = XmlWriter(self.db, None, 2)
|
||||
gfile.write_handle(g)
|
||||
g.close()
|
||||
return True
|
||||
|
||||
def gui_run(self):
|
||||
missmedia_action = 0
|
||||
|
||||
base = os.path.basename(self.filename)
|
||||
|
||||
try:
|
||||
uri = URI('burn:///%s' % base)
|
||||
make_directory(uri, OPEN_WRITE)
|
||||
except FileExistsError:
|
||||
ErrorDialog(_("CD export preparation failed"),
|
||||
"File already exists")
|
||||
return False
|
||||
except:
|
||||
uri_name = "burn:///" + base
|
||||
ErrorDialog(_("CD export preparation failed"),
|
||||
_('Could not create %s') % uri_name)
|
||||
return False
|
||||
|
||||
try:
|
||||
uri = URI('burn:///%s/.thumb' % base)
|
||||
make_directory(uri, OPEN_WRITE)
|
||||
except FileExistsError, msg:
|
||||
ErrorDialog("CD export preparation failed",
|
||||
"4 %s " % str(msg))
|
||||
return False
|
||||
except:
|
||||
uri_name = "burn:///" + base + "/.thumb"
|
||||
ErrorDialog(_("CD export preparation failed"),
|
||||
_('Could not create %s') % uri_name)
|
||||
return False
|
||||
|
||||
#--------------------------------------------------------
|
||||
def remove_clicked():
|
||||
# File is lost => remove all references and the object itself
|
||||
for p_id in self.db.get_family_handles():
|
||||
p = self.db.get_family_from_handle(p_id)
|
||||
nl = p.get_media_list()
|
||||
for o in nl:
|
||||
if o.get_reference_handle() == self.object_handle:
|
||||
nl.remove(o)
|
||||
p.set_media_list(nl)
|
||||
self.db.commit_family(p, None)
|
||||
|
||||
for key in self.db.get_person_handles(sort_handles=False):
|
||||
p = self.db.get_person_from_handle(key)
|
||||
nl = p.get_media_list()
|
||||
for o in nl:
|
||||
if o.get_reference_handle() == self.object_handle:
|
||||
nl.remove(o)
|
||||
p.set_media_list(nl)
|
||||
self.db.commit_person(p, None)
|
||||
for key in self.db.get_source_handles():
|
||||
p = self.db.get_source_from_handle(key)
|
||||
nl = p.get_media_list()
|
||||
for o in nl:
|
||||
if o.get_reference_handle() == self.object_handle:
|
||||
nl.remove(o)
|
||||
p.set_media_list(nl)
|
||||
self.db.commit_source(p, None)
|
||||
for key in self.db.get_place_handles():
|
||||
p = self.db.get_place_from_handle(key)
|
||||
nl = p.get_media_list()
|
||||
for o in nl:
|
||||
if o.get_reference_handle() == self.object_handle:
|
||||
nl.remove(o)
|
||||
p.set_media_list(nl)
|
||||
self.db.commit_place(p, None)
|
||||
for key in self.db.get_event_handles():
|
||||
p = self.db.get_event_from_handle(key)
|
||||
nl = p.get_media_list()
|
||||
for o in nl:
|
||||
if o.get_reference_handle() == self.object_handle:
|
||||
nl.remove(o)
|
||||
p.set_media_list(nl)
|
||||
self.db.commit_event(p, None)
|
||||
self.db.remove_object(self.object_handle, None)
|
||||
|
||||
def leave_clicked():
|
||||
# File is lost => do nothing, leave as is
|
||||
pass
|
||||
|
||||
def select_clicked():
|
||||
# File is lost => select a file to replace the lost one
|
||||
def fs_close_window(obj):
|
||||
pass
|
||||
|
||||
def fs_ok_clicked(obj):
|
||||
newfile = unicode(fs_top.get_filename(),
|
||||
sys.getfilesystemencoding())
|
||||
if os.path.isfile(newfile):
|
||||
self.copy_file(newfile, 'burn:///%s/%s' % (base, obase))
|
||||
|
||||
fs_top = gtk.FileSelection("%s - GRAMPS" % _("Select file"))
|
||||
fs_top.hide_fileop_buttons()
|
||||
fs_top.ok_button.connect('clicked', fs_ok_clicked)
|
||||
fs_top.cancel_button.connect('clicked', fs_close_window)
|
||||
fs_top.run()
|
||||
fs_top.destroy()
|
||||
|
||||
#----------------------------------------------------------
|
||||
|
||||
# Write media files first, since the database may be modified
|
||||
# during the process (i.e. when removing object)
|
||||
|
||||
for obj_id in self.db.get_media_object_handles():
|
||||
obj = self.db.get_object_from_handle(obj_id)
|
||||
oldfile = media_path_full(self.db, obj.get_path())
|
||||
root = os.path.basename(oldfile)
|
||||
if os.path.isfile(oldfile):
|
||||
self.copy_file(oldfile, 'burn:///%s/%s' % (base, root))
|
||||
else:
|
||||
# File is lost => ask what to do
|
||||
self.object_handle = obj.get_handle()
|
||||
if missmedia_action == 0:
|
||||
mmd = MissingMediaDialog(_("Media object could not be found"),
|
||||
_("%(file_name)s is referenced in the database, but no longer exists. "
|
||||
"The file may have been deleted or moved to a different location. "
|
||||
"You may choose to either remove the reference from the database, "
|
||||
"keep the reference to the missing file, or select a new file."
|
||||
) % { 'file_name' : oldfile },
|
||||
remove_clicked, leave_clicked, select_clicked)
|
||||
missmedia_action = mmd.default_action
|
||||
elif missmedia_action == 1:
|
||||
remove_clicked()
|
||||
elif missmedia_action == 2:
|
||||
leave_clicked()
|
||||
elif missmedia_action == 3:
|
||||
select_clicked()
|
||||
|
||||
# Write XML now
|
||||
uri = 'burn:///%s/data.gramps' % base
|
||||
uri = uri.encode('utf8')
|
||||
g = create(uri, OPEN_WRITE)
|
||||
gfile = XmlWriter(self.db, self.callback, 2)
|
||||
gfile.write_handle(g)
|
||||
g.close()
|
||||
os.system("nautilus --no-desktop burn:///")
|
||||
return True
|
||||
|
||||
def copy_file(self, src, dest):
|
||||
original = open(src, "r")
|
||||
destobj = URI(dest)
|
||||
target = create(destobj, OPEN_WRITE)
|
||||
done = 0
|
||||
while 1:
|
||||
buf = original.read(2048)
|
||||
if buf == '':
|
||||
break
|
||||
else:
|
||||
target.write(buf)
|
||||
target.close()
|
||||
original.close()
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Register the plugin
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
_description = _('Exporting to CD copies all your data and media object files '
|
||||
'to the CD Creator. You may later burn the CD with this data, '
|
||||
'and that copy will be completely portable across different '
|
||||
'machines and binary architectures.')
|
||||
|
||||
pmgr = PluginManager.get_instance()
|
||||
plugin = ExportPlugin(name = _('_Export to CD (portable XML)'),
|
||||
description = _description,
|
||||
export_function = writeData,
|
||||
extension = "burn",
|
||||
config = None )
|
||||
pmgr.register_plugin(plugin)
|
||||
355
src/plugins/export/ExportCsv.glade
Normal file
355
src/plugins/export/ExportCsv.glade
Normal file
@@ -0,0 +1,355 @@
|
||||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<glade-interface>
|
||||
<requires lib="gnome"/>
|
||||
|
||||
<widget class="GtkDialog" id="csvExport">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes"></property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="default_width">400</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="focus_on_map">True</property>
|
||||
<property name="urgency_hint">False</property>
|
||||
<property name="has_separator">False</property>
|
||||
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">8</property>
|
||||
|
||||
<child internal-child="action_area">
|
||||
<widget class="GtkHButtonBox" id="dialog-action_area1">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="destroy_passed_object" object="gedcomExport"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="ok">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_ok_clicked" object="gedcomExport"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="button1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-help</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">-11</property>
|
||||
<signal name="clicked" handler="on_help_clicked" last_modification_time="Tue, 02 Dec 2003 01:53:26 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEventBox" id="eventbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="visible_window">True</property>
|
||||
<property name="above_child">False</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTable" id="table3">
|
||||
<property name="border_width">12</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">4</property>
|
||||
<property name="n_columns">3</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label9">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"><b>Options</b></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Filt_er:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">filter</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkOptionMenu" id="filter">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="history">-1</property>
|
||||
|
||||
<child internal-child="menu">
|
||||
<widget class="GtkMenu" id="convertwidget1">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTable" id="table4">
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">5</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="marriages">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">_Marriages</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="children">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Chil_dren</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="individuals">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">I_ndividuals</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkDrawingArea" id="drawingarea1">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">shrink|fill</property>
|
||||
<property name="y_options">fill</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="translate_headers">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Translate _Headers</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="bottom_attach">5</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
<property name="x_options">fill</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label10">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Export:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">filter</property>
|
||||
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
|
||||
<property name="width_chars">-1</property>
|
||||
<property name="single_line_mode">False</property>
|
||||
<property name="angle">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
</glade-interface>
|
||||
499
src/plugins/export/ExportCsv.py
Normal file
499
src/plugins/export/ExportCsv.py
Normal file
@@ -0,0 +1,499 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2007-2008 Douglas S. Blank
|
||||
# Copyright (C) 2004-2007 Donald N. Allingham
|
||||
# Copyright (C) 2008 Brian G. Matherly
|
||||
#
|
||||
# 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$
|
||||
|
||||
"Export to CSV Spreadsheet."
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Standard Python Modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import os
|
||||
from gettext import gettext as _
|
||||
import csv
|
||||
import cStringIO
|
||||
import codecs
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GNOME/GTK modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gtk import glade
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Set up logging
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import logging
|
||||
log = logging.getLogger(".ExportCSV")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GRAMPS modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gen.lib
|
||||
from Filters import GenericFilter, Rules, build_filter_menu
|
||||
import Utils
|
||||
from QuestionDialog import ErrorDialog
|
||||
from gen.plug import PluginManager, ExportPlugin
|
||||
import gen.proxy
|
||||
import DateHandler
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# The function that does the exporting
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
def exportData(database, filename, option_box=None, callback=None):
|
||||
gw = CSVWriter(database, filename, option_box, callback)
|
||||
return gw.export_data()
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Support Functions
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
def sortable_string_representation(text):
|
||||
numeric = ""
|
||||
alpha = ""
|
||||
for s in text:
|
||||
if s.isdigit():
|
||||
numeric += s
|
||||
else:
|
||||
alpha += s
|
||||
return alpha + (("0" * 10) + numeric)[-10:]
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Encoding support for CSV, from http://docs.python.org/lib/csv-examples.html
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class UTF8Recoder:
|
||||
"""Iterator that reads an encoded stream and reencodes the input to UTF-8."""
|
||||
def __init__(self, f, encoding):
|
||||
self.reader = codecs.getreader(encoding)(f)
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
return self.reader.next().encode("utf-8")
|
||||
|
||||
class UnicodeReader:
|
||||
"""
|
||||
A CSV reader which will iterate over lines in the CSV file "f", which is
|
||||
encoded in the given encoding.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, f, encoding="utf-8", **kwds):
|
||||
f = UTF8Recoder(f, encoding)
|
||||
self.reader = csv.reader(f, **kwds)
|
||||
|
||||
def next(self):
|
||||
row = self.reader.next()
|
||||
return [unicode(s, "utf-8") for s in row]
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
class UnicodeWriter:
|
||||
"""
|
||||
A CSV writer which will write rows to CSV file "f", which is encoded in
|
||||
the given encoding.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, f, encoding="utf-8", **kwds):
|
||||
# Redirect output to a queue
|
||||
self.queue = cStringIO.StringIO()
|
||||
self.writer = csv.writer(self.queue, **kwds)
|
||||
self.stream = f
|
||||
self.encoder = codecs.getencoder(encoding)
|
||||
|
||||
def writerow(self, row):
|
||||
self.writer.writerow([s.encode('utf-8') for s in row])
|
||||
# Fetch UTF-8 output from the queue ...
|
||||
data = self.queue.getvalue()
|
||||
data = data.decode('utf-8')
|
||||
# ... and reencode it into the target encoding
|
||||
data, length = self.encoder(data)
|
||||
# write to the target stream
|
||||
self.stream.write(data)
|
||||
# empty queue
|
||||
self.queue.truncate(0)
|
||||
|
||||
def writerows(self, rows):
|
||||
for row in rows:
|
||||
self.writerow(row)
|
||||
|
||||
def close(self):
|
||||
self.stream.close()
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# CSVWriter Options
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class CSVWriterOptionBox:
|
||||
"""
|
||||
Create a VBox with the option widgets and define methods to retrieve
|
||||
the options.
|
||||
|
||||
"""
|
||||
def __init__(self,person):
|
||||
self.person = person
|
||||
self.include_individuals = 1
|
||||
self.include_marriages = 1
|
||||
self.include_children = 1
|
||||
self.translate_headers = 1
|
||||
|
||||
def get_option_box(self):
|
||||
glade_file = os.path.join(os.path.dirname(__file__), "ExportCsv.glade")
|
||||
|
||||
self.topDialog = glade.XML(glade_file,"csvExport","gramps")
|
||||
filter_obj = self.topDialog.get_widget("filter")
|
||||
|
||||
all = GenericFilter()
|
||||
all.set_name(_("Entire Database"))
|
||||
all.add_rule(Rules.Person.Everyone([]))
|
||||
|
||||
the_filters = [all]
|
||||
|
||||
if self.person:
|
||||
des = GenericFilter()
|
||||
des.set_name(_("Descendants of %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
des.add_rule(Rules.Person.IsDescendantOf(
|
||||
[self.person.get_gramps_id(),1]))
|
||||
|
||||
ans = GenericFilter()
|
||||
ans.set_name(_("Ancestors of %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
ans.add_rule(Rules.Person.IsAncestorOf(
|
||||
[self.person.get_gramps_id(),1]))
|
||||
|
||||
com = GenericFilter()
|
||||
com.set_name(_("People with common ancestor with %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
com.add_rule(Rules.Person.HasCommonAncestorWith(
|
||||
[self.person.get_gramps_id()]))
|
||||
|
||||
the_filters += [des,ans,com]
|
||||
|
||||
from Filters import CustomFilters
|
||||
the_filters.extend(CustomFilters.get_filters('Person'))
|
||||
self.filter_menu = build_filter_menu(the_filters)
|
||||
filter_obj.set_menu(self.filter_menu)
|
||||
|
||||
the_box = self.topDialog.get_widget('vbox1')
|
||||
the_parent = self.topDialog.get_widget('dialog-vbox1')
|
||||
the_parent.remove(the_box)
|
||||
self.topDialog.get_widget("csvExport").destroy()
|
||||
return the_box
|
||||
|
||||
def parse_options(self):
|
||||
self.include_individuals = self.topDialog.get_widget("individuals").get_active()
|
||||
self.include_marriages = self.topDialog.get_widget("marriages").get_active()
|
||||
self.include_children = self.topDialog.get_widget("children").get_active()
|
||||
self.translate_headers = self.topDialog.get_widget("translate_headers").get_active()
|
||||
self.cfilter = self.filter_menu.get_active().get_data("filter")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# CSVWriter class
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class CSVWriter:
|
||||
def __init__(self, database, filename, option_box=None, callback=None):
|
||||
self.db = database
|
||||
self.option_box = option_box
|
||||
self.filename = filename
|
||||
self.callback = callback
|
||||
if callable(self.callback): # callback is really callable
|
||||
self.update = self.update_real
|
||||
else:
|
||||
self.update = self.update_empty
|
||||
|
||||
self.plist = {}
|
||||
self.flist = {}
|
||||
|
||||
self.persons_details_done = []
|
||||
self.persons_notes_done = []
|
||||
self.person_ids = {}
|
||||
|
||||
if not option_box:
|
||||
self.include_individuals = 1
|
||||
self.include_marriages = 1
|
||||
self.include_children = 1
|
||||
self.translate_headers = 1
|
||||
else:
|
||||
self.option_box.parse_options()
|
||||
|
||||
self.include_individuals = self.option_box.include_individuals
|
||||
self.include_marriages = self.option_box.include_marriages
|
||||
self.include_children = self.option_box.include_children
|
||||
self.translate_headers = self.option_box.translate_headers
|
||||
|
||||
if not option_box.cfilter.is_empty():
|
||||
self.db = gen.proxy.FilterProxyDb(self.db, option_box.cfilter)
|
||||
|
||||
for p in self.db.get_person_handles(sort_handles=False):
|
||||
self.plist[p] = 1
|
||||
# get the families for which these people are spouses:
|
||||
self.flist = {}
|
||||
for key in self.plist:
|
||||
p = self.db.get_person_from_handle(key)
|
||||
for family_handle in p.get_family_handle_list():
|
||||
self.flist[family_handle] = 1
|
||||
# now add the families for which these people are a child:
|
||||
family_handles = self.db.get_family_handles()
|
||||
for family_handle in family_handles:
|
||||
family = self.db.get_family_from_handle(family_handle)
|
||||
for child_ref in family.get_child_ref_list():
|
||||
child_handle = child_ref.ref
|
||||
if child_handle in self.plist.keys():
|
||||
self.flist[family_handle] = 1
|
||||
|
||||
def update_empty(self):
|
||||
pass
|
||||
|
||||
def update_real(self):
|
||||
self.count += 1
|
||||
newval = int(100*self.count/self.total)
|
||||
if newval != self.oldval:
|
||||
self.callback(newval)
|
||||
self.oldval = newval
|
||||
|
||||
def writeln(self):
|
||||
self.g.writerow([])
|
||||
|
||||
def write_csv(self, *items):
|
||||
self.g.writerow(items)
|
||||
|
||||
def export_data(self):
|
||||
self.dirname = os.path.dirname (self.filename)
|
||||
try:
|
||||
self.g = open(self.filename,"w")
|
||||
self.fp = open(self.filename, "wb")
|
||||
self.g = UnicodeWriter(self.fp)
|
||||
except IOError,msg:
|
||||
msg2 = _("Could not create %s") % self.filename
|
||||
ErrorDialog(msg2,str(msg))
|
||||
return False
|
||||
except:
|
||||
ErrorDialog(_("Could not create %s") % self.filename)
|
||||
return False
|
||||
######################### initialize progress bar
|
||||
self.count = 0
|
||||
self.total = 0
|
||||
self.oldval = 0
|
||||
if self.include_individuals:
|
||||
self.total += len(self.plist)
|
||||
if self.include_marriages:
|
||||
self.total += len(self.flist)
|
||||
if self.include_children:
|
||||
self.total += len(self.flist)
|
||||
########################
|
||||
print "Possible people to export:", len(self.plist)
|
||||
print "Possible families to export:", len(self.flist)
|
||||
########################### sort:
|
||||
sortorder = []
|
||||
for key in self.plist:
|
||||
person = self.db.get_person_from_handle(key)
|
||||
if person:
|
||||
primary_name = person.get_primary_name()
|
||||
first_name = primary_name.get_first_name()
|
||||
surname = primary_name.get_surname()
|
||||
sortorder.append( (surname, first_name, key) )
|
||||
sortorder.sort() # will sort on tuples
|
||||
plist = [data[2] for data in sortorder]
|
||||
###########################
|
||||
if self.include_individuals:
|
||||
if self.translate_headers:
|
||||
self.write_csv(_("Person"), _("Surname"), _("Given"),
|
||||
_("Call"), _("Suffix"), _("Prefix"),
|
||||
_("Title"), _("Gender"), _("Birth date"),
|
||||
_("Birth place"), _("Birth source"),
|
||||
_("Death date"), _("Death place"),
|
||||
_("Death source"), _("Note"))
|
||||
else:
|
||||
self.write_csv("Person", "Surname", "Given",
|
||||
"Call", "Suffix", "Prefix",
|
||||
"Title", "Gender", "Birth date",
|
||||
"Birth place", "Birth source",
|
||||
"Death date", "Death place",
|
||||
"Death source", "Note")
|
||||
for key in plist:
|
||||
person = self.db.get_person_from_handle(key)
|
||||
if person:
|
||||
primary_name = person.get_primary_name()
|
||||
first_name = primary_name.get_first_name()
|
||||
surname = primary_name.get_surname()
|
||||
prefix = primary_name.get_surname_prefix()
|
||||
suffix = primary_name.get_suffix()
|
||||
title = primary_name.get_title()
|
||||
grampsid = person.get_gramps_id()
|
||||
grampsid_ref = ""
|
||||
if grampsid != "":
|
||||
grampsid_ref = "[" + grampsid + "]"
|
||||
note = '' # don't export notes or source
|
||||
callname = primary_name.get_call_name()
|
||||
gender = person.get_gender()
|
||||
if gender == gen.lib.Person.MALE:
|
||||
gender = Utils.gender[gen.lib.Person.MALE]
|
||||
elif gender == gen.lib.Person.FEMALE:
|
||||
gender = Utils.gender[gen.lib.Person.FEMALE]
|
||||
else:
|
||||
gender = Utils.gender[gen.lib.Person.UNKNOWN]
|
||||
# Birth:
|
||||
birthdate = ""
|
||||
birthplace = ""
|
||||
birth_ref = person.get_birth_ref()
|
||||
if birth_ref:
|
||||
birth = self.db.get_event_from_handle(birth_ref.ref)
|
||||
if birth:
|
||||
birthdate = self.format_date( birth)
|
||||
place_handle = birth.get_place_handle()
|
||||
if place_handle:
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
birthplace = place.get_title()
|
||||
# Death:
|
||||
deathdate = ""
|
||||
deathplace = ""
|
||||
death_ref = person.get_death_ref()
|
||||
if death_ref:
|
||||
death = self.db.get_event_from_handle(death_ref.ref)
|
||||
if death:
|
||||
deathdate = self.format_date( death)
|
||||
place_handle = death.get_place_handle()
|
||||
if place_handle:
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
deathplace = place.get_title()
|
||||
self.write_csv(grampsid_ref, surname, first_name, callname,
|
||||
suffix, prefix, title, gender,
|
||||
birthdate, birthplace, "",
|
||||
deathdate, deathplace, "",
|
||||
note)
|
||||
self.update()
|
||||
self.writeln()
|
||||
########################### sort:
|
||||
sortorder = []
|
||||
for key in self.flist:
|
||||
family = self.db.get_family_from_handle(key)
|
||||
if family:
|
||||
marriage_id = family.get_gramps_id()
|
||||
sortorder.append( (sortable_string_representation(marriage_id), key) )
|
||||
sortorder.sort() # will sort on tuples
|
||||
flist = [data[1] for data in sortorder]
|
||||
###########################
|
||||
if self.include_marriages:
|
||||
if self.translate_headers:
|
||||
self.write_csv(_("Marriage"), _("Husband"), _("Wife"),
|
||||
_("Date"), _("Place"), _("Source"), _("Note"))
|
||||
else:
|
||||
self.write_csv("Marriage", "Husband", "Wife",
|
||||
"Date", "Place", "Source", "Note")
|
||||
for key in flist:
|
||||
family = self.db.get_family_from_handle(key)
|
||||
if family:
|
||||
marriage_id = family.get_gramps_id()
|
||||
if marriage_id != "":
|
||||
marriage_id = "[" + marriage_id + "]"
|
||||
mother_id = ''
|
||||
father_id = ''
|
||||
father_handle = family.get_father_handle()
|
||||
if father_handle:
|
||||
father = self.db.get_person_from_handle(father_handle)
|
||||
father_id = father.get_gramps_id()
|
||||
if father_id != "":
|
||||
father_id = "[" + father_id + "]"
|
||||
mother_handle = family.get_mother_handle()
|
||||
if mother_handle:
|
||||
mother = self.db.get_person_from_handle(mother_handle)
|
||||
mother_id = mother.get_gramps_id()
|
||||
if mother_id != "":
|
||||
mother_id = "[" + mother_id + "]"
|
||||
# get mdate, mplace
|
||||
mdate, mplace = '', ''
|
||||
event_ref_list = family.get_event_ref_list()
|
||||
for event_ref in event_ref_list:
|
||||
event = self.db.get_event_from_handle(event_ref.ref)
|
||||
if event.get_type() == gen.lib.EventType.MARRIAGE:
|
||||
mdate = self.format_date( event)
|
||||
place_handle = event.get_place_handle()
|
||||
if place_handle:
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
mplace = place.get_title()
|
||||
# m_source = self.get_primary_source( event.get_source_references())
|
||||
source, note = '', ''
|
||||
self.write_csv(marriage_id, father_id, mother_id, mdate,
|
||||
mplace, source, note)
|
||||
self.update()
|
||||
self.writeln()
|
||||
if self.include_children:
|
||||
if self.translate_headers:
|
||||
self.write_csv(_("Family"), _("Child"))
|
||||
else:
|
||||
self.write_csv("Family", "Child")
|
||||
for key in flist:
|
||||
family = self.db.get_family_from_handle(key)
|
||||
if family:
|
||||
family_id = family.get_gramps_id()
|
||||
if family_id != "":
|
||||
family_id = "[" + family_id + "]"
|
||||
for child_ref in family.get_child_ref_list():
|
||||
child_handle = child_ref.ref
|
||||
child = self.db.get_person_from_handle(child_handle)
|
||||
grampsid = child.get_gramps_id()
|
||||
grampsid_ref = ""
|
||||
if grampsid != "":
|
||||
grampsid_ref = "[" + grampsid + "]"
|
||||
self.write_csv(family_id, grampsid_ref)
|
||||
self.update()
|
||||
self.writeln()
|
||||
self.g.close()
|
||||
return True
|
||||
|
||||
def format_date(self, date):
|
||||
return DateHandler.get_date(date)
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Register the plugin
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
_name = _('Comma _Separated Values Spreadsheet (CSV)')
|
||||
_description = _('CSV is a common spreadsheet format.')
|
||||
_config = (_('CSV spreadsheet options'),CSVWriterOptionBox)
|
||||
|
||||
pmgr = PluginManager.get_instance()
|
||||
plugin = ExportPlugin(name = _name,
|
||||
description = _description,
|
||||
export_function = exportData,
|
||||
extension = "csv",
|
||||
config = _config )
|
||||
pmgr.register_plugin(plugin)
|
||||
229
src/plugins/export/ExportFtree.glade
Normal file
229
src/plugins/export/ExportFtree.glade
Normal file
@@ -0,0 +1,229 @@
|
||||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkDialog" id="top">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes"></property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="default_width">480</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="has_separator">False</property>
|
||||
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">8</property>
|
||||
|
||||
<child internal-child="action_area">
|
||||
<widget class="GtkHButtonBox" id="dialog-action_area1">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="destroy_passed_object" object="gedcomExport"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="ok">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_ok_clicked" object="gedcomExport"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="button1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-help</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">-11</property>
|
||||
<signal name="clicked" handler="on_help_clicked" last_modification_time="Tue, 02 Dec 2003 02:01:12 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="title">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_CENTER</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0.5</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">6</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTable" id="table3">
|
||||
<property name="border_width">12</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">3</property>
|
||||
<property name="n_columns">3</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label9">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"><b>Options</b></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Filt_er:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">filter</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">shrink|fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkOptionMenu" id="filter">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="history">-1</property>
|
||||
|
||||
<child internal-child="menu">
|
||||
<widget class="GtkMenu" id="convertwidget1">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="restrict">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">_Restrict data on living people</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
</glade-interface>
|
||||
316
src/plugins/export/ExportFtree.py
Normal file
316
src/plugins/export/ExportFtree.py
Normal file
@@ -0,0 +1,316 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2003-2006, 2008 Donald N. Allingham
|
||||
# Copyright (C) 2008 Brian G. Matherly
|
||||
#
|
||||
# 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$
|
||||
|
||||
"Export to Web Family Tree"
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# standard python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import os
|
||||
from gettext import gettext as _
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Set up logging
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import logging
|
||||
log = logging.getLogger(".WriteFtree")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GNOME/GTK modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gtk import glade
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GRAMPS modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import Utils
|
||||
from Filters import GenericFilter, Rules, build_filter_menu
|
||||
import Errors
|
||||
from QuestionDialog import ErrorDialog
|
||||
from gen.plug import PluginManager, ExportPlugin
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# writeData
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
def writeData(database, filename, option_box=None, callback=None):
|
||||
writer = FtreeWriter(database, filename, option_box, callback)
|
||||
return writer.export_data()
|
||||
|
||||
class FtreeWriterOptionBox:
|
||||
"""
|
||||
Create a VBox with the option widgets and define methods to retrieve
|
||||
the options.
|
||||
"""
|
||||
def __init__(self, person):
|
||||
self.person = person
|
||||
self.restrict = True
|
||||
|
||||
def get_option_box(self):
|
||||
glade_file = os.path.join(os.path.dirname(__file__),
|
||||
"ExportFtree.glade")
|
||||
|
||||
self.top = glade.XML(glade_file, "top", "gramps")
|
||||
|
||||
filter_obj = self.top.get_widget("filter")
|
||||
|
||||
all = GenericFilter()
|
||||
all.set_name(_("Entire Database"))
|
||||
all.add_rule(Rules.Person.Everyone([]))
|
||||
|
||||
the_filters = [all]
|
||||
|
||||
if self.person:
|
||||
des = GenericFilter()
|
||||
des.set_name(_("Descendants of %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
des.add_rule(Rules.Person.IsDescendantOf(
|
||||
[self.person.get_gramps_id(),1]))
|
||||
|
||||
ans = GenericFilter()
|
||||
ans.set_name(_("Ancestors of %s")
|
||||
% self.person.get_primary_name().get_name())
|
||||
ans.add_rule(Rules.Person.IsAncestorOf(
|
||||
[self.person.get_gramps_id(),1]))
|
||||
|
||||
com = GenericFilter()
|
||||
com.set_name(_("People with common ancestor with %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
com.add_rule(Rules.Person.HasCommonAncestorWith(
|
||||
[self.person.get_gramps_id()]))
|
||||
|
||||
the_filters += [des, ans, com]
|
||||
|
||||
from Filters import CustomFilters
|
||||
the_filters.extend(CustomFilters.get_filters('Person'))
|
||||
self.filter_menu = build_filter_menu(the_filters)
|
||||
filter_obj.set_menu(self.filter_menu)
|
||||
|
||||
the_box = self.top.get_widget("vbox1")
|
||||
the_parent = self.top.get_widget('dialog-vbox1')
|
||||
the_parent.remove(the_box)
|
||||
self.top.get_widget("top").destroy()
|
||||
return the_box
|
||||
|
||||
def parse_options(self):
|
||||
self.restrict = self.top.get_widget("restrict").get_active()
|
||||
self.cfilter = self.filter_menu.get_active().get_data("filter")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# FtreeWriter
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class FtreeWriter:
|
||||
|
||||
def __init__(self, database, filename="", option_box=None,
|
||||
callback = None):
|
||||
self.db = database
|
||||
self.option_box = option_box
|
||||
self.filename = filename
|
||||
self.callback = callback
|
||||
if callable(self.callback): # callback is really callable
|
||||
self.update = self.update_real
|
||||
else:
|
||||
self.update = self.update_empty
|
||||
|
||||
self.plist = {}
|
||||
|
||||
if not option_box:
|
||||
self.cl_setup()
|
||||
else:
|
||||
self.option_box.parse_options()
|
||||
|
||||
self.restrict = self.option_box.restrict
|
||||
if self.option_box.cfilter is None:
|
||||
for p in self.db.get_person_handles(sort_handles=False):
|
||||
self.plist[p] = 1
|
||||
else:
|
||||
try:
|
||||
for p in self.option_box.cfilter.apply(self.db, self.db.get_person_handles(sort_handles=False)):
|
||||
self.plist[p] = 1
|
||||
except Errors.FilterError, msg:
|
||||
(m1, m2) = msg.messages()
|
||||
ErrorDialog(m1, m2)
|
||||
return
|
||||
|
||||
def update_empty(self):
|
||||
pass
|
||||
|
||||
def update_real(self):
|
||||
self.count += 1
|
||||
newval = int(100*self.count/self.total)
|
||||
if newval != self.oldval:
|
||||
self.callback(newval)
|
||||
self.oldval = newval
|
||||
|
||||
def cl_setup(self):
|
||||
self.restrict = True
|
||||
for p in self.db.get_person_handles(sort_handles=False):
|
||||
self.plist[p] = 1
|
||||
|
||||
def export_data(self):
|
||||
name_map = {}
|
||||
id_map = {}
|
||||
id_name = {}
|
||||
self.count = 0
|
||||
self.oldval = 0
|
||||
self.total = 2*len(self.plist)
|
||||
|
||||
for key in self.plist:
|
||||
self.update()
|
||||
pn = self.db.get_person_from_handle(key).get_primary_name()
|
||||
sn = pn.get_surname()
|
||||
items = pn.get_first_name().split()
|
||||
if len(items) > 0:
|
||||
n = "%s %s" % (items[0], sn)
|
||||
else:
|
||||
n = sn
|
||||
|
||||
count = -1
|
||||
if n in name_map:
|
||||
count = 0
|
||||
while 1:
|
||||
nn = "%s%d" % (n, count)
|
||||
if nn not in name_map:
|
||||
break;
|
||||
count += 1
|
||||
name_map[nn] = key
|
||||
id_map[key] = nn
|
||||
else:
|
||||
name_map[n] = key
|
||||
id_map[key] = n
|
||||
id_name[key] = get_name(pn, count)
|
||||
|
||||
f = open(self.filename,"w")
|
||||
|
||||
for key in self.plist:
|
||||
self.update()
|
||||
p = self.db.get_person_from_handle(key)
|
||||
name = id_name[key]
|
||||
father = ""
|
||||
mother = ""
|
||||
email = ""
|
||||
web = ""
|
||||
|
||||
family_handle = p.get_main_parents_family_handle()
|
||||
if family_handle:
|
||||
family = self.db.get_family_from_handle(family_handle)
|
||||
if family.get_father_handle() and family.get_father_handle() in id_map:
|
||||
father = id_map[family.get_father_handle()]
|
||||
if family.get_mother_handle() and family.get_mother_handle() in id_map:
|
||||
mother = id_map[family.get_mother_handle()]
|
||||
|
||||
#
|
||||
# Calculate Date
|
||||
#
|
||||
birth_ref = p.get_birth_ref()
|
||||
death_ref = p.get_death_ref()
|
||||
if birth_ref:
|
||||
birth_event = self.db.get_event_from_handle(birth_ref.ref)
|
||||
birth = birth_event.get_date_object()
|
||||
else:
|
||||
birth = None
|
||||
if death_ref:
|
||||
death_event = self.db.get_event_from_handle(death_ref.ref)
|
||||
death = death_event.get_date_object()
|
||||
else:
|
||||
death = None
|
||||
|
||||
if self.restrict:
|
||||
alive = Utils.probably_alive(p, self.db)
|
||||
else:
|
||||
alive = 0
|
||||
|
||||
if birth and not alive:
|
||||
if death and not alive :
|
||||
dates = "%s-%s" % (fdate(birth), fdate(death))
|
||||
else:
|
||||
dates = fdate(birth)
|
||||
else:
|
||||
if death and not alive:
|
||||
dates = fdate(death)
|
||||
else:
|
||||
dates = ""
|
||||
|
||||
f.write('%s;%s;%s;%s;%s;%s\n' % (name, father, mother, email, web,
|
||||
dates))
|
||||
|
||||
f.close()
|
||||
return True
|
||||
|
||||
def fdate(val):
|
||||
if val.get_year_valid():
|
||||
if val.get_month_valid():
|
||||
if val.get_day_valid():
|
||||
return "%d/%d/%d" % (val.get_day(), val.get_month(),
|
||||
val.get_year())
|
||||
else:
|
||||
return "%d/%d" % (val.get_month(), val.get_year())
|
||||
else:
|
||||
return "%d" % val.get_year()
|
||||
else:
|
||||
return ""
|
||||
|
||||
def get_name(name, count):
|
||||
"""returns a name string built from the components of the Name
|
||||
instance, in the form of Firstname Surname"""
|
||||
if count == -1:
|
||||
val = ""
|
||||
else:
|
||||
val = str(count)
|
||||
|
||||
if (name.suffix == ""):
|
||||
if name.prefix:
|
||||
return "%s %s %s%s" % (name.first_name, name.prefix, name.surname, val)
|
||||
else:
|
||||
return "%s %s%s" % (name.first_name, name.surname, val)
|
||||
else:
|
||||
if name.prefix:
|
||||
return "%s %s %s%s, %s" % (name.first_name, name.prefix, name.surname, val, name.suffix)
|
||||
else:
|
||||
return "%s %s%s, %s" % (name.first_name, name.surname, val, name.suffix)
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Register with the plugin system
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
_config = (_('Web Family Tree export options'), FtreeWriterOptionBox)
|
||||
|
||||
pmgr = PluginManager.get_instance()
|
||||
plugin = ExportPlugin(name = _('_Web Family Tree'),
|
||||
description = _('Web Family Tree format.'),
|
||||
export_function = writeData,
|
||||
extension = "wft",
|
||||
config = _config )
|
||||
pmgr.register_plugin(plugin)
|
||||
1537
src/plugins/export/ExportGedcom.py
Normal file
1537
src/plugins/export/ExportGedcom.py
Normal file
File diff suppressed because it is too large
Load Diff
386
src/plugins/export/ExportGeneWeb.glade
Normal file
386
src/plugins/export/ExportGeneWeb.glade
Normal file
@@ -0,0 +1,386 @@
|
||||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkDialog" id="genewebExport">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes"></property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="default_width">400</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="has_separator">False</property>
|
||||
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">8</property>
|
||||
|
||||
<child internal-child="action_area">
|
||||
<widget class="GtkHButtonBox" id="dialog-action_area1">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="destroy_passed_object" object="gedcomExport"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="ok">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_ok_clicked" object="gedcomExport"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="button1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-help</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">-11</property>
|
||||
<signal name="clicked" handler="on_help_clicked" last_modification_time="Tue, 02 Dec 2003 01:53:26 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTable" id="table3">
|
||||
<property name="border_width">12</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">6</property>
|
||||
<property name="n_columns">3</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label9">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"><b>Options</b></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Filt_er:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">filter</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkOptionMenu" id="filter">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="history">-1</property>
|
||||
|
||||
<child internal-child="menu">
|
||||
<widget class="GtkMenu" id="convertwidget1">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="private">
|
||||
<property name="border_width">3</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">_Do not include records marked private</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="restrict">
|
||||
<property name="border_width">3</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">_Restrict data on living people</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<signal name="toggled" handler="on_restrict_toggled" last_modification_time="Tue, 22 Jul 2003 09:50:16 GMT"/>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">3</property>
|
||||
<property name="bottom_attach">4</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTable" id="table4">
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">3</property>
|
||||
<property name="n_columns">2</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="notes">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Exclude _notes</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="sources">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Exclude _sources</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">2</property>
|
||||
<property name="bottom_attach">3</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="living">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Use _Living as first name</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">True</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkDrawingArea" id="drawingarea1">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">shrink|fill</property>
|
||||
<property name="y_options">fill</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">4</property>
|
||||
<property name="bottom_attach">5</property>
|
||||
<property name="x_options">fill</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkHBox" id="hbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkCheckButton" id="images">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label" translatable="yes">Reference i_mages from path: </property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="active">False</property>
|
||||
<property name="inconsistent">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkEntry" id="images_path">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="editable">True</property>
|
||||
<property name="visibility">True</property>
|
||||
<property name="max_length">0</property>
|
||||
<property name="text" translatable="yes">media</property>
|
||||
<property name="has_frame">True</property>
|
||||
<property name="invisible_char" translatable="yes">*</property>
|
||||
<property name="activates_default">False</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">5</property>
|
||||
<property name="bottom_attach">6</property>
|
||||
<property name="x_options">fill</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
</glade-interface>
|
||||
627
src/plugins/export/ExportGeneWeb.py
Normal file
627
src/plugins/export/ExportGeneWeb.py
Normal file
@@ -0,0 +1,627 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2004 Martin Hawlisch
|
||||
# Copyright (C) 2004-2006, 2008 Donald N. Allingham
|
||||
# Copyright (C) 2008 Brian G. Matherly
|
||||
#
|
||||
# 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:WriteGeneWeb.py 9912 2008-01-22 09:17:46Z acraphae $
|
||||
|
||||
"Export to GeneWeb."
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Standard Python Modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import os
|
||||
from gettext import gettext as _
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GNOME/GTK modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gtk import glade
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Set up logging
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import logging
|
||||
log = logging.getLogger(".WriteGeneWeb")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GRAMPS modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gen.lib
|
||||
from Filters import GenericFilter, Rules, build_filter_menu
|
||||
#import const
|
||||
import Utils
|
||||
from QuestionDialog import ErrorDialog
|
||||
from gen.plug import PluginManager, ExportPlugin
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class GeneWebWriterOptionBox:
|
||||
"""
|
||||
Create a VBox with the option widgets and define methods to retrieve
|
||||
the options.
|
||||
|
||||
"""
|
||||
def __init__(self, person):
|
||||
self.person = person
|
||||
|
||||
def get_option_box(self):
|
||||
self.restrict = 1
|
||||
self.private = 1
|
||||
|
||||
glade_file = os.path.join(os.path.dirname(__file__),
|
||||
"ExportGeneWeb.glade")
|
||||
|
||||
self.topDialog = glade.XML(glade_file, "genewebExport", "gramps")
|
||||
self.topDialog.signal_autoconnect({
|
||||
"on_restrict_toggled": self.on_restrict_toggled
|
||||
})
|
||||
|
||||
filter_obj = self.topDialog.get_widget("filter")
|
||||
self.copy = 0
|
||||
|
||||
all = GenericFilter()
|
||||
all.set_name(_("Entire Database"))
|
||||
all.add_rule(Rules.Person.Everyone([]))
|
||||
|
||||
the_filters = [all]
|
||||
|
||||
if self.person:
|
||||
des = GenericFilter()
|
||||
des.set_name(_("Descendants of %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
des.add_rule(Rules.Person.IsDescendantOf(
|
||||
[self.person.get_gramps_id(),1]))
|
||||
|
||||
ans = GenericFilter()
|
||||
ans.set_name(_("Ancestors of %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
ans.add_rule(Rules.Person.IsAncestorOf(
|
||||
[self.person.get_gramps_id(),1]))
|
||||
|
||||
com = GenericFilter()
|
||||
com.set_name(_("People with common ancestor with %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
com.add_rule(Rules.Person.HasCommonAncestorWith(
|
||||
[self.person.get_gramps_id()]))
|
||||
|
||||
the_filters += [des, ans, com]
|
||||
|
||||
from Filters import CustomFilters
|
||||
the_filters.extend(CustomFilters.get_filters('Person'))
|
||||
self.filter_menu = build_filter_menu(the_filters)
|
||||
filter_obj.set_menu(self.filter_menu)
|
||||
|
||||
the_box = self.topDialog.get_widget('vbox1')
|
||||
the_parent = self.topDialog.get_widget('dialog-vbox1')
|
||||
the_parent.remove(the_box)
|
||||
self.topDialog.get_widget("genewebExport").destroy()
|
||||
return the_box
|
||||
|
||||
def on_restrict_toggled(self, restrict):
|
||||
active = restrict.get_active ()
|
||||
for x in [self.topDialog.get_widget("living"),
|
||||
self.topDialog.get_widget("notes"),
|
||||
self.topDialog.get_widget("sources")]:
|
||||
x.set_sensitive(active)
|
||||
|
||||
def parse_options(self):
|
||||
self.restrict = self.topDialog.get_widget("restrict").get_active()
|
||||
self.living = (self.restrict and
|
||||
self.topDialog.get_widget("living").get_active())
|
||||
self.exclnotes = (self.restrict and
|
||||
self.topDialog.get_widget("notes").get_active())
|
||||
self.exclsrcs = (self.restrict and
|
||||
self.topDialog.get_widget("sources").get_active())
|
||||
self.private = self.topDialog.get_widget("private").get_active()
|
||||
|
||||
self.cfilter = self.filter_menu.get_active().get_data("filter")
|
||||
|
||||
self.images = self.topDialog.get_widget ("images").get_active ()
|
||||
if self.images:
|
||||
images_path = self.topDialog.get_widget ("images_path")
|
||||
self.images_path = unicode(images_path.get_text ())
|
||||
else:
|
||||
self.images_path = ""
|
||||
|
||||
class GeneWebWriter:
|
||||
def __init__(self, database, filename="", option_box=None,
|
||||
callback=None):
|
||||
self.db = database
|
||||
self.option_box = option_box
|
||||
self.filename = filename
|
||||
self.callback = callback
|
||||
if callable(self.callback): # callback is really callable
|
||||
self.update = self.update_real
|
||||
else:
|
||||
self.update = self.update_empty
|
||||
|
||||
self.plist = {}
|
||||
self.flist = {}
|
||||
|
||||
self.persons_details_done = []
|
||||
self.persons_notes_done = []
|
||||
self.person_ids = {}
|
||||
|
||||
if not option_box:
|
||||
self.restrict = 0
|
||||
self.private = 0
|
||||
self.copy = 0
|
||||
self.images = 0
|
||||
else:
|
||||
self.option_box.parse_options()
|
||||
|
||||
self.restrict = self.option_box.restrict
|
||||
self.living = self.option_box.living
|
||||
self.exclnotes = self.option_box.exclnotes
|
||||
self.exclsrcs = self.option_box.exclsrcs
|
||||
self.private = self.option_box.private
|
||||
self.copy = self.option_box.copy
|
||||
self.images = self.option_box.images
|
||||
self.images_path = self.option_box.images_path
|
||||
|
||||
if not option_box.cfilter.is_empty():
|
||||
self.db = gen.proxy.FilterProxyDb(self.db, option_box.cfilter)
|
||||
|
||||
for p in self.db.get_person_handles(sort_handles=False):
|
||||
self.plist[p] = 1
|
||||
|
||||
self.flist = {}
|
||||
for key in self.plist:
|
||||
p = self.db.get_person_from_handle(key)
|
||||
for family_handle in p.get_family_handle_list():
|
||||
self.flist[family_handle] = 1
|
||||
|
||||
# remove families that dont contain father AND mother
|
||||
# because GeneWeb requires both to be present
|
||||
templist = self.flist
|
||||
self.flist = {}
|
||||
for family_handle in templist:
|
||||
family = self.db.get_family_from_handle(family_handle)
|
||||
if family:
|
||||
father_handle = family.get_father_handle()
|
||||
mother_handle = family.get_mother_handle()
|
||||
if father_handle and mother_handle:
|
||||
self.flist[family_handle] = 1
|
||||
|
||||
|
||||
def update_empty(self):
|
||||
pass
|
||||
|
||||
def update_real(self):
|
||||
self.count += 1
|
||||
newval = int(100*self.count/self.total)
|
||||
if newval != self.oldval:
|
||||
self.callback(newval)
|
||||
self.oldval = newval
|
||||
|
||||
def writeln(self, text):
|
||||
self.g.write(self.iso8859('%s\n' % (text)))
|
||||
|
||||
def export_data(self):
|
||||
|
||||
self.dirname = os.path.dirname (self.filename)
|
||||
try:
|
||||
self.g = open(self.filename, "w")
|
||||
except IOError,msg:
|
||||
msg2 = _("Could not create %s") % self.filename
|
||||
ErrorDialog(msg2, str(msg))
|
||||
return False
|
||||
except:
|
||||
ErrorDialog(_("Could not create %s") % self.filename)
|
||||
return False
|
||||
|
||||
if len(self.flist) < 1:
|
||||
ErrorDialog(_("No families matched by selected filter"))
|
||||
return False
|
||||
|
||||
self.count = 0
|
||||
self.oldval = 0
|
||||
self.total = len(self.flist)
|
||||
for key in self.flist:
|
||||
self.write_family(key)
|
||||
self.writeln("")
|
||||
|
||||
self.g.close()
|
||||
return True
|
||||
|
||||
def write_family(self, family_handle):
|
||||
family = self.db.get_family_from_handle(family_handle)
|
||||
if family:
|
||||
self.update()
|
||||
father_handle = family.get_father_handle()
|
||||
if father_handle:
|
||||
father = self.db.get_person_from_handle(father_handle)
|
||||
mother_handle = family.get_mother_handle()
|
||||
if mother_handle:
|
||||
mother = self.db.get_person_from_handle(mother_handle)
|
||||
self.writeln("fam %s %s +%s %s %s" % (self.get_ref_name(father), self.get_full_person_info_fam(father), self.get_wedding_data(family), self.get_ref_name(mother), self.get_full_person_info_fam(mother)))
|
||||
self.write_witness( family)
|
||||
self.write_sources( family.get_source_references())
|
||||
self.write_children( family, father)
|
||||
self.write_notes( family, father, mother)
|
||||
if not (self.restrict and self.exclnotes):
|
||||
notelist = family.get_note_list()
|
||||
note = ""
|
||||
for notehandle in notelist:
|
||||
noteobj = self.db.get_note_from_handle(notehandle)
|
||||
note += noteobj.get(False)
|
||||
note += " "
|
||||
if note and note != "":
|
||||
note = note.replace('\n\r',' ')
|
||||
note = note.replace('\r\n',' ')
|
||||
note = note.replace('\n',' ')
|
||||
note = note.replace('\r',' ')
|
||||
self.writeln("comm %s" % note)
|
||||
|
||||
def write_witness(self, family):
|
||||
# FIXME: witnesses are not in events anymore
|
||||
return
|
||||
|
||||
if self.restrict:
|
||||
return
|
||||
event_ref_list = family.get_event_ref_list()
|
||||
for event_ref in event_ref:
|
||||
event = self.db.get_event_from_handle(event_ref.ref)
|
||||
if event.type == gen.lib.EventType.MARRIAGE:
|
||||
w_list = event.get_witness_list()
|
||||
if w_list:
|
||||
for witness in w_list:
|
||||
if witness and witness.type == gen.lib.Event.ID:
|
||||
person = self.db.get_person_from_handle(witness.get_value())
|
||||
if person:
|
||||
gender = ""
|
||||
if person.get_gender() == gen.lib.Person.MALE:
|
||||
gender = "h"
|
||||
elif person.get_gender() == gen.lib.Person.FEMALE:
|
||||
gender = "f"
|
||||
self.writeln("wit %s %s %s" % (gender, self.get_ref_name(person), self.get_full_person_info_fam(person)))
|
||||
|
||||
|
||||
def write_sources(self,reflist):
|
||||
if self.restrict and self.exclnotes:
|
||||
return
|
||||
|
||||
if reflist:
|
||||
for sr in reflist:
|
||||
sbase = sr.get_reference_handle()
|
||||
if sbase:
|
||||
source = self.db.get_source_from_handle(sbase)
|
||||
if source:
|
||||
self.writeln( "src %s" % (self.rem_spaces(source.get_title())))
|
||||
|
||||
def write_children(self,family, father):
|
||||
father_lastname = father.get_primary_name().get_surname()
|
||||
child_ref_list = family.get_child_ref_list()
|
||||
if child_ref_list:
|
||||
self.writeln("beg")
|
||||
for child_ref in child_ref_list:
|
||||
child = self.db.get_person_from_handle(child_ref.ref)
|
||||
if child:
|
||||
gender = ""
|
||||
if child.get_gender() == gen.lib.Person.MALE:
|
||||
gender = "h"
|
||||
elif child.get_gender() == gen.lib.Person.FEMALE:
|
||||
gender = "f"
|
||||
self.writeln("- %s %s %s" % (gender, self.get_child_ref_name(child, father_lastname), self.get_full_person_info_child(child)))
|
||||
self.writeln("end")
|
||||
|
||||
def write_notes(self,family, father, mother):
|
||||
if self.restrict and self.exclnotes:
|
||||
return
|
||||
|
||||
self.write_note_of_person(father)
|
||||
self.write_note_of_person(mother)
|
||||
child_ref_list = family.get_child_ref_list()
|
||||
if child_ref_list:
|
||||
for child_ref in child_ref_list:
|
||||
child = self.db.get_person_from_handle(child_ref.ref)
|
||||
if child:
|
||||
self.write_note_of_person(child)
|
||||
# FIXME: witnesses do not exist in events anymore
|
||||
## event_ref_list = family.get_event_ref_list()
|
||||
## for event_ref in event_ref_list:
|
||||
## event = self.db.get_event_from_handle(event_ref.ref)
|
||||
## if int(event.get_type()) == gen.lib.EventType.MARRIAGE:
|
||||
## w_list = event.get_witness_list()
|
||||
## if w_list:
|
||||
## for witness in w_list:
|
||||
## if witness and witness.type == gen.lib.Event.ID:
|
||||
## person = self.db.get_person_from_handle(witness.get_value())
|
||||
## if person:
|
||||
## self.write_note_of_person(person)
|
||||
|
||||
def write_note_of_person(self,person):
|
||||
if self.persons_notes_done.count(person.get_handle()) == 0:
|
||||
self.persons_notes_done.append(person.get_handle())
|
||||
|
||||
notelist = person.get_note_list()
|
||||
note = ""
|
||||
for notehandle in notelist:
|
||||
noteobj = self.db.get_note_from_handle(notehandle)
|
||||
note += noteobj.get()
|
||||
note += " "
|
||||
|
||||
if note and note != "":
|
||||
self.writeln("")
|
||||
self.writeln("notes %s" % self.get_ref_name(person))
|
||||
self.writeln("beg")
|
||||
self.writeln(note)
|
||||
self.writeln("end notes")
|
||||
|
||||
def get_full_person_info(self, person):
|
||||
if self.restrict:
|
||||
return "0 "
|
||||
|
||||
retval = ""
|
||||
|
||||
b_date = "0"
|
||||
b_place = ""
|
||||
birth_ref = person.get_birth_ref()
|
||||
if birth_ref:
|
||||
birth = self.db.get_event_from_handle(birth_ref.ref)
|
||||
if birth:
|
||||
b_date = self.format_date( birth.get_date_object())
|
||||
place_handle = birth.get_place_handle()
|
||||
if place_handle:
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
b_place = place.get_title()
|
||||
|
||||
if Utils.probably_alive(person,self.db):
|
||||
d_date = ""
|
||||
else:
|
||||
d_date = "0"
|
||||
d_place = ""
|
||||
death_ref = person.get_death_ref()
|
||||
if death_ref:
|
||||
death = self.db.get_event_from_handle(death_ref.ref)
|
||||
if death:
|
||||
d_date = self.format_date( death.get_date_object())
|
||||
place_handle = death.get_place_handle()
|
||||
if place_handle:
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
d_place = place.get_title()
|
||||
|
||||
retval = retval + "%s " % b_date
|
||||
if b_place != "":
|
||||
retval = retval + "#bp %s " % self.rem_spaces(b_place)
|
||||
retval = retval + "%s " % d_date
|
||||
if d_place != "":
|
||||
retval = retval + "#dp %s " % self.rem_spaces(d_place)
|
||||
return retval
|
||||
|
||||
def get_full_person_info_fam(self, person):
|
||||
"""Output full person data of a family member.
|
||||
|
||||
This is only done if the person is not listed as a child.
|
||||
|
||||
"""
|
||||
retval = ""
|
||||
if self.persons_details_done.count(person.get_handle()) == 0:
|
||||
is_child = 0
|
||||
pf_list = person.get_parent_family_handle_list()
|
||||
if pf_list:
|
||||
for family_handle in pf_list:
|
||||
if family_handle in self.flist:
|
||||
is_child = 1
|
||||
if is_child == 0:
|
||||
self.persons_details_done.append(person.get_handle())
|
||||
retval = self.get_full_person_info(person)
|
||||
return retval
|
||||
|
||||
|
||||
def get_full_person_info_child(self, person):
|
||||
"""Output full person data for a child, if not printed somewhere else."""
|
||||
retval = ""
|
||||
if self.persons_details_done.count(person.get_handle()) == 0:
|
||||
self.persons_details_done.append(person.get_handle())
|
||||
retval = self.get_full_person_info(person)
|
||||
return retval
|
||||
|
||||
def rem_spaces(self,str):
|
||||
return str.replace(' ','_')
|
||||
|
||||
def get_ref_name(self,person):
|
||||
surname = self.rem_spaces( person.get_primary_name().get_surname())
|
||||
firstname = _("Living")
|
||||
if not (Utils.probably_alive(person,self.db) and self.restrict and self.living):
|
||||
firstname = self.rem_spaces( person.get_primary_name().get_first_name())
|
||||
if person.get_handle() not in self.person_ids:
|
||||
self.person_ids[person.get_handle()] = len(self.person_ids)
|
||||
ret = "%s %s.%d" % (surname, firstname, self.person_ids[person.get_handle()])
|
||||
return ret
|
||||
|
||||
def get_child_ref_name(self,person,father_lastname):
|
||||
surname = self.rem_spaces( person.get_primary_name().get_surname())
|
||||
firstname = _("Living")
|
||||
if not (Utils.probably_alive(person,self.db) and self.restrict and self.living):
|
||||
firstname = self.rem_spaces( person.get_primary_name().get_first_name())
|
||||
if person.get_handle() not in self.person_ids:
|
||||
self.person_ids[person.get_handle()] = len(self.person_ids)
|
||||
if surname != father_lastname:
|
||||
ret = "%s.%d %s" % (firstname, self.person_ids[person.get_handle()], surname)
|
||||
else:
|
||||
ret = "%s.%d" % (firstname, self.person_ids[person.get_handle()])
|
||||
return ret
|
||||
|
||||
def get_wedding_data(self,family):
|
||||
ret = "";
|
||||
event_ref_list = family.get_event_ref_list()
|
||||
m_date = ""
|
||||
m_place = ""
|
||||
m_source = ""
|
||||
married = 0
|
||||
eng_date = ""
|
||||
eng_place = ""
|
||||
eng_source = ""
|
||||
engaged = 0
|
||||
div_date = ""
|
||||
divorced = 0
|
||||
for event_ref in event_ref_list:
|
||||
event = self.db.get_event_from_handle(event_ref.ref)
|
||||
if event.get_type() == gen.lib.EventType.MARRIAGE:
|
||||
married = 1
|
||||
m_date = self.format_date( event.get_date_object())
|
||||
place_handle = event.get_place_handle()
|
||||
if place_handle:
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
m_place = place.get_title()
|
||||
m_source = self.get_primary_source( event.get_source_references())
|
||||
if event.get_type() == gen.lib.EventType.ENGAGEMENT:
|
||||
engaged = 1
|
||||
eng_date = self.format_date( event.get_date_object())
|
||||
place_handle = event.get_place_handle()
|
||||
if place_handle:
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
eng_place = place.get_title()
|
||||
eng_source = self.get_primary_source( event.get_source_references())
|
||||
if event.get_type() == gen.lib.EventType.DIVORCE:
|
||||
divorced = 1
|
||||
div_date = self.format_date( event.get_date_object())
|
||||
if married == 1:
|
||||
if m_date != "":
|
||||
ret = ret + m_date
|
||||
ret = ret + " "
|
||||
|
||||
if m_place != "":
|
||||
ret = ret + "#mp %s " % self.rem_spaces( m_place)
|
||||
|
||||
if m_source != "":
|
||||
ret = ret + "#ms %s " % self.rem_spaces( m_source)
|
||||
elif engaged == 1:
|
||||
"""Geneweb only supports either Marriage or engagement"""
|
||||
if eng_date != "":
|
||||
ret = ret + eng_date
|
||||
ret = ret + " "
|
||||
|
||||
if eng_place != "":
|
||||
ret = ret + "#mp %s " % self.rem_spaces( m_place)
|
||||
|
||||
if eng_source != "":
|
||||
ret = ret + "#ms %s " % self.rem_spaces( m_source)
|
||||
else:
|
||||
if family.get_relationship() != gen.lib.FamilyRelType.MARRIED:
|
||||
"""Not married or engaged"""
|
||||
ret = ret + " #nm "
|
||||
|
||||
if divorced == 1:
|
||||
if div_date != "":
|
||||
ret = ret + "-%s " %div_date
|
||||
else:
|
||||
ret = ret + "-0 "
|
||||
|
||||
return ret
|
||||
|
||||
def get_primary_source(self,reflist):
|
||||
ret = ""
|
||||
if reflist:
|
||||
for sr in reflist:
|
||||
sbase = sr.get_reference_handle()
|
||||
if sbase:
|
||||
source = self.db.get_source_from_handle(sbase)
|
||||
if source:
|
||||
if ret != "":
|
||||
ret = ret + ", "
|
||||
ret = ret + source.get_title()
|
||||
return ret
|
||||
|
||||
def format_single_date(self, subdate, cal, mode):
|
||||
retval = ""
|
||||
(day, month, year, sl) = subdate
|
||||
|
||||
cal_type = ""
|
||||
if cal == gen.lib.Date.CAL_HEBREW:
|
||||
cal_type = "H"
|
||||
elif cal == gen.lib.Date.CAL_FRENCH:
|
||||
cal_type = "F"
|
||||
elif cal == gen.lib.Date.CAL_JULIAN:
|
||||
cal_type = "J"
|
||||
|
||||
mode_prefix = ""
|
||||
if mode == gen.lib.Date.MOD_ABOUT:
|
||||
mode_prefix = "~"
|
||||
elif mode == gen.lib.Date.MOD_BEFORE:
|
||||
mode_prefix = "<"
|
||||
elif mode == gen.lib.Date.MOD_AFTER:
|
||||
mode_prefix = ">"
|
||||
|
||||
if year > 0:
|
||||
if month > 0:
|
||||
if day > 0:
|
||||
retval = "%s%s/%s/%s%s" % (mode_prefix,day,month,year,cal_type)
|
||||
else:
|
||||
retval = "%s%s/%s%s" % (mode_prefix,month,year,cal_type)
|
||||
else:
|
||||
retval = "%s%s%s" % (mode_prefix,year,cal_type)
|
||||
return retval
|
||||
|
||||
|
||||
def format_date(self,date):
|
||||
retval = ""
|
||||
if date.get_modifier() == gen.lib.Date.MOD_TEXTONLY:
|
||||
retval = "0(%s)" % self.rem_spaces(date.get_text())
|
||||
elif not date.is_empty():
|
||||
mod = date.get_modifier()
|
||||
cal = cal = date.get_calendar()
|
||||
if mod == gen.lib.Date.MOD_SPAN or mod == gen.lib.Date.MOD_RANGE:
|
||||
retval = "%s..%s" % (
|
||||
self.format_single_date(date.get_start_date(), cal,mod),
|
||||
self.format_single_date(date.get_stop_date(),cal,mod))
|
||||
else:
|
||||
retval = self.format_single_date(date.get_start_date(),cal,mod)
|
||||
return retval
|
||||
|
||||
def iso8859(self,s):
|
||||
return s.encode('iso-8859-1','xmlcharrefreplace')
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
def exportData(database, filename, option_box=None, callback=None):
|
||||
gw = GeneWebWriter(database, filename, option_box, callback)
|
||||
return gw.export_data()
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Register with the plugin system
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
_description = _('GeneWeb is a web based genealogy program.')
|
||||
_config = (_('GeneWeb export options'), GeneWebWriterOptionBox)
|
||||
|
||||
pmgr = PluginManager.get_instance()
|
||||
plugin = ExportPlugin(name = _('_GeneWeb'),
|
||||
description = _description,
|
||||
export_function = exportData,
|
||||
extension = "gw",
|
||||
config = _config )
|
||||
pmgr.register_plugin(plugin)
|
||||
245
src/plugins/export/ExportPkg.py
Normal file
245
src/plugins/export/ExportPkg.py
Normal file
@@ -0,0 +1,245 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2000-2008 Donald N. Allingham
|
||||
# Copyright (C) 2008 Brian G. Matherly
|
||||
# Copyright (C) 2008 Gary Burton
|
||||
# Copyright (C) 2008 Robert Cheramy <robert@cheramy.net>
|
||||
#
|
||||
# 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$
|
||||
|
||||
"Export to GRAMPS package"
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# standard python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import tarfile
|
||||
from cStringIO import StringIO
|
||||
from gettext import gettext as _
|
||||
import ExportOptions
|
||||
#from BasicUtils import UpdateCallback
|
||||
import gen.proxy
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Set up logging
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import logging
|
||||
log = logging.getLogger(".WritePkg")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GNOME/GTK modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gtk
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GRAMPS modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from ExportXml import XmlWriter
|
||||
from gen.plug import PluginManager, ExportPlugin
|
||||
import Utils
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# writeData
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
def writeData(database, filename, option_box=None, callback=None):
|
||||
if option_box:
|
||||
option_box.parse_options()
|
||||
|
||||
if option_box.private:
|
||||
database = gen.proxy.PrivateProxyDb(database)
|
||||
|
||||
if option_box.restrict:
|
||||
database = gen.proxy.LivingProxyDb(
|
||||
database, gen.proxy.LivingProxyDb.MODE_INCLUDE_LAST_NAME_ONLY)
|
||||
|
||||
# Apply the Person Filter
|
||||
if not option_box.cfilter.is_empty():
|
||||
database = gen.proxy.FilterProxyDb(database, option_box.cfilter)
|
||||
|
||||
# Apply the Note Filter
|
||||
if not option_box.nfilter.is_empty():
|
||||
database = gen.proxy.FilterProxyDb(
|
||||
database, note_filter=option_box.nfilter)
|
||||
|
||||
# Apply the ReferencedProxyDb to remove any objects not referenced
|
||||
# after any of the other proxies have been applied
|
||||
if option_box.unlinked:
|
||||
database = gen.proxy.ReferencedProxyDb(database)
|
||||
|
||||
writer = PackageWriter(database, filename, callback)
|
||||
return writer.export()
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# PackageWriter
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class PackageWriter:
|
||||
|
||||
def __init__(self, database, filename, callback=None):
|
||||
self.db = database
|
||||
self.callback = callback
|
||||
self.filename = filename
|
||||
|
||||
def export(self):
|
||||
# missmedia_action = 0
|
||||
#--------------------------------------------------------------
|
||||
def remove_clicked():
|
||||
# File is lost => remove all references and the object itself
|
||||
for p_id in self.db.get_family_handles():
|
||||
p = self.db.get_family_from_handle(p_id)
|
||||
nl = p.get_media_list()
|
||||
for o in nl:
|
||||
if o.get_reference_handle() == m_id:
|
||||
nl.remove(o)
|
||||
p.set_media_list(nl)
|
||||
self.db.commit_family(p,None)
|
||||
for key in self.db.get_person_handles(sort_handles=False):
|
||||
p = self.db.get_person_from_handle(key)
|
||||
nl = p.get_media_list()
|
||||
for o in nl:
|
||||
if o.get_reference_handle() == m_id:
|
||||
nl.remove(o)
|
||||
p.set_media_list(nl)
|
||||
self.db.commit_person(p,None)
|
||||
for key in self.db.get_source_handles():
|
||||
p = self.db.get_source_from_handle(key)
|
||||
nl = p.get_media_list()
|
||||
for o in nl:
|
||||
if o.get_reference_handle() == m_id:
|
||||
nl.remove(o)
|
||||
p.set_media_list(nl)
|
||||
self.db.commit_source(p,None)
|
||||
for key in self.db.get_place_handles():
|
||||
p = self.db.get_place_from_handle(key)
|
||||
nl = p.get_media_list()
|
||||
for o in nl:
|
||||
if o.get_reference_handle() == m_id:
|
||||
nl.remove(o)
|
||||
p.set_media_list(nl)
|
||||
self.db.commit_place(p,None)
|
||||
for key in self.db.get_event_handles():
|
||||
p = self.db.get_event_from_handle(key)
|
||||
nl = p.get_media_list()
|
||||
for o in nl:
|
||||
if o.get_reference_handle() == m_id:
|
||||
nl.remove(o)
|
||||
p.set_media_list(nl)
|
||||
self.db.commit_event(p,None)
|
||||
self.db.remove_object(m_id,None)
|
||||
|
||||
def leave_clicked():
|
||||
# File is lost => do nothing, leave as is
|
||||
pass
|
||||
|
||||
def select_clicked():
|
||||
# File is lost => select a file to replace the lost one
|
||||
def fs_close_window(obj):
|
||||
pass
|
||||
|
||||
def fs_ok_clicked(obj):
|
||||
name = unicode(fs_top.get_filename(),
|
||||
sys.getfilesystemencoding())
|
||||
if os.path.isfile(name):
|
||||
archive.add(name)
|
||||
|
||||
fs_top = gtk.FileSelection("%s - GRAMPS" % _("Select file"))
|
||||
fs_top.hide_fileop_buttons()
|
||||
fs_top.ok_button.connect('clicked',fs_ok_clicked)
|
||||
fs_top.cancel_button.connect('clicked',fs_close_window)
|
||||
fs_top.run()
|
||||
fs_top.destroy()
|
||||
#---------------------------------------------------------------
|
||||
|
||||
archive = tarfile.open(self.filename,'w:gz')
|
||||
|
||||
# Write media files first, since the database may be modified
|
||||
# during the process (i.e. when removing object)
|
||||
for m_id in self.db.get_media_object_handles():
|
||||
mobject = self.db.get_object_from_handle(m_id)
|
||||
filename = str(Utils.media_path_full(self.db, mobject.get_path()))
|
||||
archname = str(mobject.get_path())
|
||||
if os.path.isfile(filename):
|
||||
archive.add(filename, archname)
|
||||
# else:
|
||||
# # File is lost => ask what to do
|
||||
# if missmedia_action == 0:
|
||||
# mmd = MissingMediaDialog(
|
||||
# _("Media object could not be found"),
|
||||
# _("%(file_name)s is referenced in the database, "
|
||||
# "but no longer exists. The file may have been "
|
||||
# "deleted or moved to a different location. "
|
||||
# "You may choose to either remove the reference "
|
||||
# "from the database, keep the reference to the "
|
||||
# "missing file, or select a new file."
|
||||
# ) % { 'file_name' : filename },
|
||||
# remove_clicked, leave_clicked, select_clicked)
|
||||
# missmedia_action = mmd.default_action
|
||||
# elif missmedia_action == 1:
|
||||
# remove_clicked()
|
||||
# elif missmedia_action == 2:
|
||||
# leave_clicked()
|
||||
# elif missmedia_action == 3:
|
||||
# select_clicked()
|
||||
|
||||
# Write XML now
|
||||
g = StringIO()
|
||||
gfile = XmlWriter(self.db, self.callback, 2)
|
||||
gfile.write_handle(g)
|
||||
tarinfo = tarfile.TarInfo('data.gramps')
|
||||
tarinfo.size = len(g.getvalue())
|
||||
tarinfo.mtime = time.time()
|
||||
if os.sys.platform != "win32":
|
||||
tarinfo.uid = os.getuid()
|
||||
tarinfo.gid = os.getgid()
|
||||
g.seek(0)
|
||||
archive.addfile(tarinfo, g)
|
||||
archive.close()
|
||||
g.close()
|
||||
|
||||
return True
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Register with the plugin system
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
_description = _('GRAMPS package is an archived XML database together '
|
||||
'with the media object files.')
|
||||
_config = (_('GRAMPS package export options'), ExportOptions.WriterOptionBox)
|
||||
|
||||
pmgr = PluginManager.get_instance()
|
||||
plugin = ExportPlugin(name = _('GRAM_PS package (portable XML)'),
|
||||
description = _description,
|
||||
export_function = writeData,
|
||||
extension = "gpkg",
|
||||
config = _config )
|
||||
pmgr.register_plugin(plugin)
|
||||
188
src/plugins/export/ExportVCalendar.glade
Normal file
188
src/plugins/export/ExportVCalendar.glade
Normal file
@@ -0,0 +1,188 @@
|
||||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkDialog" id="calendarExport">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes"></property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="default_width">400</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="has_separator">False</property>
|
||||
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">8</property>
|
||||
|
||||
<child internal-child="action_area">
|
||||
<widget class="GtkHButtonBox" id="dialog-action_area1">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="destroy_passed_object" object="gedcomExport"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="ok">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_ok_clicked" object="gedcomExport"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="button1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-help</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">-11</property>
|
||||
<signal name="clicked" handler="on_help_clicked" last_modification_time="Tue, 02 Dec 2003 01:53:26 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTable" id="table3">
|
||||
<property name="border_width">12</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">2</property>
|
||||
<property name="n_columns">3</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label9">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"><b>Options</b></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Filt_er:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">filter</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkOptionMenu" id="filter">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="history">-1</property>
|
||||
|
||||
<child internal-child="menu">
|
||||
<widget class="GtkMenu" id="convertwidget1">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
</glade-interface>
|
||||
362
src/plugins/export/ExportVCalendar.py
Normal file
362
src/plugins/export/ExportVCalendar.py
Normal file
@@ -0,0 +1,362 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2004 Martin Hawlisch
|
||||
# Copyright (C) 2005-2006, 2008 Donald N. Allingham
|
||||
# Copyright (C) 2008 Brian G. Matherly
|
||||
#
|
||||
# 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$
|
||||
|
||||
"Export Events to vCalendar."
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Standard Python Modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import os
|
||||
import sys
|
||||
from time import localtime
|
||||
from gettext import gettext as _
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GNOME/GTK modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gtk
|
||||
from gtk import glade
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Set up logging
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import logging
|
||||
log = logging.getLogger(".ExportVCal")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GRAMPS modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from Filters import GenericFilter, Rules, build_filter_menu
|
||||
import Utils
|
||||
from gen.lib import Date, EventType
|
||||
import Errors
|
||||
from QuestionDialog import ErrorDialog
|
||||
from gen.plug import PluginManager, ExportPlugin
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class CalendarWriterOptionBox:
|
||||
"""
|
||||
Create a VBox with the option widgets and define methods to retrieve
|
||||
the options.
|
||||
|
||||
"""
|
||||
def __init__(self, person):
|
||||
self.person = person
|
||||
|
||||
glade_file = os.path.join(os.path.dirname(__file__),
|
||||
"ExportVCalendar.glade")
|
||||
|
||||
self.topDialog = glade.XML(glade_file, "calendarExport", "gramps")
|
||||
self.copy = 0
|
||||
self.filter_menu = gtk.Menu()
|
||||
|
||||
def get_option_box(self):
|
||||
filter_obj = self.topDialog.get_widget("filter")
|
||||
|
||||
everyone_filter = GenericFilter()
|
||||
everyone_filter.set_name(_("Entire Database"))
|
||||
everyone_filter.add_rule(Rules.Person.Everyone([]))
|
||||
|
||||
the_filters = [everyone_filter]
|
||||
|
||||
if self.person:
|
||||
des = GenericFilter()
|
||||
des.set_name(_("Descendants of %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
des.add_rule(Rules.Person.IsDescendantOf(
|
||||
[self.person.get_gramps_id(),1]))
|
||||
|
||||
ans = GenericFilter()
|
||||
ans.set_name(_("Ancestors of %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
ans.add_rule(Rules.Person.IsAncestorOf(
|
||||
[self.person.get_gramps_id(),1]))
|
||||
|
||||
com = GenericFilter()
|
||||
com.set_name(_("People with common ancestor with %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
com.add_rule(Rules.Person.HasCommonAncestorWith(
|
||||
[self.person.get_gramps_id()]))
|
||||
|
||||
the_filters += [des, ans, com]
|
||||
|
||||
from Filters import CustomFilters
|
||||
the_filters.extend(CustomFilters.get_filters('Person'))
|
||||
self.filter_menu = build_filter_menu(the_filters)
|
||||
filter_obj.set_menu(self.filter_menu)
|
||||
|
||||
the_box = self.topDialog.get_widget('vbox1')
|
||||
the_parent = self.topDialog.get_widget('dialog-vbox1')
|
||||
the_parent.remove(the_box)
|
||||
self.topDialog.get_widget("calendarExport").destroy()
|
||||
return the_box
|
||||
|
||||
def parse_options(self):
|
||||
self.cfilter = self.filter_menu.get_active().get_data("filter")
|
||||
|
||||
|
||||
class CalendarWriter:
|
||||
def __init__(self, database, cl=0, filename="", option_box=None,
|
||||
callback=None):
|
||||
self.db = database
|
||||
self.option_box = option_box
|
||||
self.cl = cl
|
||||
self.filename = filename
|
||||
self.callback = callback
|
||||
if callable(self.callback): # callback is really callable
|
||||
self.update = self.update_real
|
||||
else:
|
||||
self.update = self.update_empty
|
||||
|
||||
self.plist = {}
|
||||
self.flist = {}
|
||||
|
||||
self.count = 0
|
||||
self.oldval = 0
|
||||
|
||||
self.persons_details_done = []
|
||||
self.persons_notes_done = []
|
||||
self.person_ids = {}
|
||||
|
||||
if not option_box:
|
||||
self.cl_setup()
|
||||
else:
|
||||
self.option_box.parse_options()
|
||||
|
||||
if self.option_box.cfilter is None:
|
||||
for p in self.db.get_person_handles(sort_handles=False):
|
||||
self.plist[p] = 1
|
||||
else:
|
||||
try:
|
||||
for p in self.option_box.cfilter.apply(self.db, self.db.get_person_handles(sort_handles=False)):
|
||||
self.plist[p] = 1
|
||||
except Errors.FilterError, msg:
|
||||
(m1, m2) = msg.messages()
|
||||
ErrorDialog(m1, m2)
|
||||
return
|
||||
|
||||
self.flist = {}
|
||||
for key in self.plist:
|
||||
p = self.db.get_person_from_handle(key)
|
||||
for family_handle in p.get_family_handle_list():
|
||||
self.flist[family_handle] = 1
|
||||
|
||||
def update_empty(self):
|
||||
pass
|
||||
|
||||
def update_real(self):
|
||||
self.count += 1
|
||||
newval = int(100 * self.count / self.total)
|
||||
if newval != self.oldval:
|
||||
self.callback(newval)
|
||||
self.oldval = newval
|
||||
|
||||
def cl_setup(self):
|
||||
for p in self.db.get_person_handles(sort_handles=False):
|
||||
self.plist[p] = 1
|
||||
|
||||
self.flist = {}
|
||||
|
||||
for key in self.plist:
|
||||
p = self.db.get_person_from_handle(key)
|
||||
for family_handle in p.get_family_handle_list():
|
||||
self.flist[family_handle] = 1
|
||||
|
||||
def writeln(self, text):
|
||||
#self.g.write('%s\n' % (text.encode('iso-8859-1')))
|
||||
self.g.write('%s\n' % (text.encode(sys.getfilesystemencoding())))
|
||||
|
||||
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 False
|
||||
except:
|
||||
ErrorDialog(_("Could not create %s") % filename)
|
||||
return False
|
||||
|
||||
self.writeln("BEGIN:VCALENDAR")
|
||||
self.writeln("PRODID:-//GNU//Gramps//EN")
|
||||
self.writeln("VERSION:1.0")
|
||||
|
||||
self.total = len(self.plist) + len(self.flist)
|
||||
for key in self.plist:
|
||||
self.write_person(key)
|
||||
self.update()
|
||||
|
||||
for key in self.flist:
|
||||
self.write_family(key)
|
||||
self.update()
|
||||
|
||||
self.writeln("")
|
||||
self.writeln("END:VCALENDAR")
|
||||
|
||||
self.g.close()
|
||||
return True
|
||||
|
||||
def write_family(self, family_handle):
|
||||
family = self.db.get_family_from_handle(family_handle)
|
||||
if family:
|
||||
for event_ref in family.get_event_ref_list():
|
||||
event = self.db.get_event_from_handle(event_ref.ref)
|
||||
if event.get_type() == EventType.MARRIAGE:
|
||||
m_date = event.get_date_object()
|
||||
place_handle = event.get_place_handle()
|
||||
text = _("Marriage of %s") % Utils.family_name(family,
|
||||
self.db)
|
||||
if place_handle:
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
self.write_vevent( text, m_date, place.get_title())
|
||||
else:
|
||||
self.write_vevent( text, m_date)
|
||||
|
||||
def write_person(self, person_handle):
|
||||
person = self.db.get_person_from_handle(person_handle)
|
||||
if person:
|
||||
birth_ref = person.get_birth_ref()
|
||||
if birth_ref:
|
||||
birth = self.db.get_event_from_handle(birth_ref.ref)
|
||||
if birth:
|
||||
b_date = birth.get_date_object()
|
||||
place_handle = birth.get_place_handle()
|
||||
if place_handle:
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
self.write_vevent(_("Birth of %s") % person.get_primary_name().get_name(), b_date, place.get_title())
|
||||
else:
|
||||
self.write_vevent(_("Birth of %s")
|
||||
% person.get_primary_name().get_name(), b_date)
|
||||
|
||||
death_ref = person.get_death_ref()
|
||||
if death_ref:
|
||||
death = self.db.get_event_from_handle(death_ref.ref)
|
||||
if death:
|
||||
d_date = death.get_date_object()
|
||||
place_handle = death.get_place_handle()
|
||||
if place_handle:
|
||||
place = self.db.get_place_from_handle(place_handle)
|
||||
self.write_vevent(_("Death of %s") % person.get_primary_name().get_name(), d_date, place.get_title())
|
||||
else:
|
||||
self.write_vevent(_("Death of %s") % person.get_primary_name().get_name(), d_date)
|
||||
|
||||
|
||||
def format_single_date(self, subdate, thisyear, cal):
|
||||
retval = ""
|
||||
(day, month, year, sl) = subdate
|
||||
|
||||
if thisyear:
|
||||
year = localtime().tm_year
|
||||
|
||||
if not cal == Date.CAL_GREGORIAN:
|
||||
return ""
|
||||
|
||||
if year > 0:
|
||||
if month > 0:
|
||||
if day > 0:
|
||||
retval = "%s%02d%02d" % (year, month, day)
|
||||
return retval
|
||||
|
||||
|
||||
def format_date(self, date, thisyear=0):
|
||||
retval = ""
|
||||
if date.get_modifier() == Date.MOD_TEXTONLY:
|
||||
return ""
|
||||
elif not date.is_empty():
|
||||
mod = date.get_modifier()
|
||||
cal = cal = date.get_calendar()
|
||||
if mod == Date.MOD_SPAN or mod == Date.MOD_RANGE:
|
||||
start = self.format_single_date(date.get_start_date(),
|
||||
thisyear, cal)
|
||||
end = self.format_single_date(date.get_stop_date(),
|
||||
thisyear, cal)
|
||||
if start and end:
|
||||
retval = "DTSTART:%sT000001\nDTEND:%sT235959" % (start,
|
||||
end)
|
||||
elif mod == Date.MOD_NONE:
|
||||
start = self.format_single_date(date.get_start_date(),
|
||||
thisyear, cal)
|
||||
if start:
|
||||
retval = "DTSTART:%sT000001\nDTEND:%sT235959" % (start,
|
||||
start)
|
||||
return retval
|
||||
|
||||
def write_vevent(self, event_text, date, location=""):
|
||||
date_string = self.format_date(date)
|
||||
if date_string is not "":
|
||||
self.writeln("")
|
||||
self.writeln("BEGIN:VEVENT")
|
||||
self.writeln("SUMMARY:%s" % event_text)
|
||||
if location:
|
||||
self.writeln("LOCATION:%s" % location)
|
||||
self.writeln(date_string)
|
||||
self.writeln("END:VEVENT")
|
||||
|
||||
date_string = self.format_date(date, 1)
|
||||
self.writeln("")
|
||||
self.writeln("BEGIN:VEVENT")
|
||||
self.writeln("SUMMARY:"+_("Anniversary: %s") % event_text)
|
||||
if location:
|
||||
self.writeln("LOCATION:%s" % location)
|
||||
self.writeln("RRULE:YD1 #0")
|
||||
self.writeln(date_string)
|
||||
self.writeln("END:VEVENT")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
def exportData(database, filename, option_box=None, callback=None):
|
||||
cw = CalendarWriter(database, 0, filename, option_box, callback)
|
||||
return cw.export_data(filename)
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Register with the plugin system
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
_description = _('vCalendar is used in many calendaring and pim applications.')
|
||||
_config = (_('vCalendar export options'), CalendarWriterOptionBox)
|
||||
|
||||
pmgr = PluginManager.get_instance()
|
||||
plugin = ExportPlugin(name = _('vC_alendar'),
|
||||
description = _description,
|
||||
export_function = exportData,
|
||||
extension = "vcs",
|
||||
config = _config )
|
||||
pmgr.register_plugin(plugin)
|
||||
188
src/plugins/export/ExportVCard.glade
Normal file
188
src/plugins/export/ExportVCard.glade
Normal file
@@ -0,0 +1,188 @@
|
||||
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
|
||||
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
|
||||
|
||||
<glade-interface>
|
||||
|
||||
<widget class="GtkDialog" id="vcardExport">
|
||||
<property name="visible">True</property>
|
||||
<property name="title" translatable="yes"></property>
|
||||
<property name="type">GTK_WINDOW_TOPLEVEL</property>
|
||||
<property name="window_position">GTK_WIN_POS_NONE</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="default_width">400</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="destroy_with_parent">False</property>
|
||||
<property name="decorated">True</property>
|
||||
<property name="skip_taskbar_hint">False</property>
|
||||
<property name="skip_pager_hint">False</property>
|
||||
<property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
|
||||
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
|
||||
<property name="has_separator">False</property>
|
||||
|
||||
<child internal-child="vbox">
|
||||
<widget class="GtkVBox" id="dialog-vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">8</property>
|
||||
|
||||
<child internal-child="action_area">
|
||||
<widget class="GtkHButtonBox" id="dialog-action_area1">
|
||||
<property name="visible">True</property>
|
||||
<property name="layout_style">GTK_BUTTONBOX_END</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="cancel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="destroy_passed_object" object="gedcomExport"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="ok">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-ok</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">0</property>
|
||||
<signal name="clicked" handler="on_ok_clicked" object="gedcomExport"/>
|
||||
</widget>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkButton" id="button1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="label">gtk-help</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="relief">GTK_RELIEF_NORMAL</property>
|
||||
<property name="focus_on_click">True</property>
|
||||
<property name="response_id">-11</property>
|
||||
<signal name="clicked" handler="on_help_clicked" last_modification_time="Tue, 02 Dec 2003 01:53:26 GMT"/>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkVBox" id="vbox1">
|
||||
<property name="visible">True</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="spacing">0</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkTable" id="table3">
|
||||
<property name="border_width">12</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="n_rows">2</property>
|
||||
<property name="n_columns">3</property>
|
||||
<property name="homogeneous">False</property>
|
||||
<property name="row_spacing">6</property>
|
||||
<property name="column_spacing">12</property>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label9">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes"><b>Options</b></property>
|
||||
<property name="use_underline">False</property>
|
||||
<property name="use_markup">True</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">0</property>
|
||||
<property name="bottom_attach">1</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="label" translatable="yes">Filt_er:</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_markup">False</property>
|
||||
<property name="justify">GTK_JUSTIFY_LEFT</property>
|
||||
<property name="wrap">False</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="yalign">0.5</property>
|
||||
<property name="xpad">0</property>
|
||||
<property name="ypad">0</property>
|
||||
<property name="mnemonic_widget">filter</property>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="right_attach">2</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<widget class="GtkOptionMenu" id="filter">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="history">-1</property>
|
||||
|
||||
<child internal-child="menu">
|
||||
<widget class="GtkMenu" id="convertwidget1">
|
||||
<property name="visible">True</property>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
<property name="right_attach">3</property>
|
||||
<property name="top_attach">1</property>
|
||||
<property name="bottom_attach">2</property>
|
||||
<property name="x_options">fill</property>
|
||||
<property name="y_options"></property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">GTK_PACK_END</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
<packing>
|
||||
<property name="padding">0</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</widget>
|
||||
</child>
|
||||
</widget>
|
||||
|
||||
</glade-interface>
|
||||
277
src/plugins/export/ExportVCard.py
Normal file
277
src/plugins/export/ExportVCard.py
Normal file
@@ -0,0 +1,277 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2004 Martin Hawlisch
|
||||
# Copyright (C) 2005-2008 Donald N. Allingham
|
||||
# Copyright (C) 2008 Brian G. Matherly
|
||||
#
|
||||
# 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$
|
||||
|
||||
"Export Persons to vCard."
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Standard Python Modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import os
|
||||
import sys
|
||||
from gettext import gettext as _
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Set up logging
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
import logging
|
||||
log = logging.getLogger(".ExportVCard")
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GNOME/GTK modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gtk import glade
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GRAMPS modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from Filters import GenericFilter, Rules, build_filter_menu
|
||||
from gen.lib import Date
|
||||
import Errors
|
||||
from QuestionDialog import ErrorDialog
|
||||
from gen.plug import PluginManager, ExportPlugin
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class CardWriterOptionBox:
|
||||
"""
|
||||
Create a VBox with the option widgets and define methods to retrieve
|
||||
the options.
|
||||
|
||||
"""
|
||||
def __init__(self, person):
|
||||
self.person = person
|
||||
|
||||
def get_option_box(self):
|
||||
|
||||
glade_file = os.path.join(os.path.dirname(__file__),
|
||||
"ExportVCard.glade")
|
||||
|
||||
self.topDialog = glade.XML(glade_file,"vcardExport","gramps")
|
||||
|
||||
filter_obj = self.topDialog.get_widget("filter")
|
||||
self.copy = 0
|
||||
|
||||
all = GenericFilter()
|
||||
all.set_name(_("Entire Database"))
|
||||
all.add_rule(Rules.Person.Everyone([]))
|
||||
|
||||
the_filters = [all]
|
||||
|
||||
if self.person:
|
||||
des = GenericFilter()
|
||||
des.set_name(_("Descendants of %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
des.add_rule(Rules.Person.IsDescendantOf(
|
||||
[self.person.get_gramps_id(),1]))
|
||||
|
||||
ans = GenericFilter()
|
||||
ans.set_name(_("Ancestors of %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
ans.add_rule(Rules.Person.IsAncestorOf(
|
||||
[self.person.get_gramps_id(),1]))
|
||||
|
||||
com = GenericFilter()
|
||||
com.set_name(_("People with common ancestor with %s") %
|
||||
self.person.get_primary_name().get_name())
|
||||
com.add_rule(Rules.Person.HasCommonAncestorWith(
|
||||
[self.person.get_gramps_id()]))
|
||||
|
||||
the_filters += [des, ans, com]
|
||||
|
||||
from Filters import CustomFilters
|
||||
the_filters.extend(CustomFilters.get_filters('Person'))
|
||||
self.filter_menu = build_filter_menu(the_filters)
|
||||
filter_obj.set_menu(self.filter_menu)
|
||||
|
||||
the_box = self.topDialog.get_widget('vbox1')
|
||||
the_parent = self.topDialog.get_widget('dialog-vbox1')
|
||||
the_parent.remove(the_box)
|
||||
self.topDialog.get_widget("vcardExport").destroy()
|
||||
return the_box
|
||||
|
||||
def parse_options(self):
|
||||
self.cfilter = self.filter_menu.get_active().get_data("filter")
|
||||
|
||||
class CardWriter:
|
||||
def __init__(self, database, cl=0, filename="", option_box=None,
|
||||
callback=None):
|
||||
self.db = database
|
||||
self.option_box = option_box
|
||||
self.cl = cl
|
||||
self.filename = filename
|
||||
self.callback = callback
|
||||
if callable(self.callback): # callback is really callable
|
||||
self.update = self.update_real
|
||||
else:
|
||||
self.update = self.update_empty
|
||||
|
||||
self.plist = {}
|
||||
|
||||
if not option_box:
|
||||
self.cl_setup()
|
||||
else:
|
||||
self.option_box.parse_options()
|
||||
|
||||
if self.option_box.cfilter is None:
|
||||
for p in self.db.get_person_handles(sort_handles=False):
|
||||
self.plist[p] = 1
|
||||
else:
|
||||
try:
|
||||
for p in self.option_box.cfilter.apply(self.db,
|
||||
self.db.get_person_handles(sort_handles=False)):
|
||||
self.plist[p] = 1
|
||||
except Errors.FilterError, msg:
|
||||
(m1, m2) = msg.messages()
|
||||
ErrorDialog(m1, m2)
|
||||
return
|
||||
|
||||
def update_empty(self):
|
||||
pass
|
||||
|
||||
def update_real(self):
|
||||
self.count += 1
|
||||
newval = int(100*self.count/self.total)
|
||||
if newval != self.oldval:
|
||||
self.callback(newval)
|
||||
self.oldval = newval
|
||||
|
||||
def cl_setup(self):
|
||||
for p in self.db.get_person_handles(sort_handles=False):
|
||||
self.plist[p] = 1
|
||||
|
||||
def writeln(self, text):
|
||||
#self.g.write('%s\n' % (text.encode('iso-8859-1')))
|
||||
self.g.write('%s\n' % (text.encode(sys.getfilesystemencoding())))
|
||||
|
||||
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 False
|
||||
except:
|
||||
ErrorDialog(_("Could not create %s") % filename)
|
||||
return False
|
||||
|
||||
self.count = 0
|
||||
self.oldval = 0
|
||||
self.total = len(self.plist)
|
||||
for key in self.plist:
|
||||
self.write_person(key)
|
||||
self.update()
|
||||
|
||||
self.g.close()
|
||||
return True
|
||||
|
||||
def write_person(self, person_handle):
|
||||
person = self.db.get_person_from_handle(person_handle)
|
||||
if person:
|
||||
self.writeln("BEGIN:VCARD");
|
||||
prname = person.get_primary_name()
|
||||
|
||||
self.writeln("FN:%s" % prname.get_regular_name())
|
||||
self.writeln("N:%s;%s;%s;%s;%s" % (prname.get_surname(), prname.get_first_name(), person.get_nick_name(), prname.get_surname_prefix(), prname.get_suffix()))
|
||||
if prname.get_title():
|
||||
self.writeln("TITLE:%s" % prname.get_title())
|
||||
|
||||
birth_ref = person.get_birth_ref()
|
||||
if birth_ref:
|
||||
birth = self.db.get_event_from_handle(birth_ref.ref)
|
||||
if birth:
|
||||
b_date = birth.get_date_object()
|
||||
mod = b_date.get_modifier()
|
||||
if (mod != Date.MOD_TEXTONLY and
|
||||
not b_date.is_empty() and
|
||||
not mod == Date.MOD_SPAN and
|
||||
not mod == Date.MOD_RANGE):
|
||||
(day, month, year, sl) = b_date.get_start_date()
|
||||
if day > 0 and month > 0 and year > 0:
|
||||
self.writeln("BDAY:%s-%02d-%02d" % (year, month,
|
||||
day))
|
||||
|
||||
address_list = person.get_address_list()
|
||||
for address in address_list:
|
||||
postbox = ""
|
||||
ext = ""
|
||||
street = address.get_street()
|
||||
city = address.get_city()
|
||||
state = address.get_state()
|
||||
zip = address.get_postal_code()
|
||||
country = address.get_country()
|
||||
if street or city or state or zip or country:
|
||||
self.writeln("ADR:%s;%s;%s;%s;%s;%s;%s" % (postbox, ext,
|
||||
street, city,
|
||||
state, zip,
|
||||
country))
|
||||
|
||||
phone = address.get_phone()
|
||||
if phone:
|
||||
self.writeln("TEL:%s" % phone)
|
||||
|
||||
url_list = person.get_url_list()
|
||||
for url in url_list:
|
||||
href = url.get_path()
|
||||
if href:
|
||||
self.writeln("URL:%s" % href)
|
||||
|
||||
self.writeln("END:VCARD");
|
||||
self.writeln("");
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
def exportData(database, filename, option_box=None, callback=None):
|
||||
cw = CardWriter(database, 0, filename, option_box, callback)
|
||||
return cw.export_data(filename)
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# Register with the plugin system
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
_description = _('vCard is used in many addressbook and pim applications.')
|
||||
_config = (_('vCard export options'), CardWriterOptionBox)
|
||||
|
||||
pmgr = PluginManager.get_instance()
|
||||
plugin = ExportPlugin(name = _('_vCard'),
|
||||
description = _description,
|
||||
export_function = exportData,
|
||||
extension = "vcf",
|
||||
config = _config )
|
||||
pmgr.register_plugin(plugin)
|
||||
28
src/plugins/export/Makefile.am
Normal file
28
src/plugins/export/Makefile.am
Normal file
@@ -0,0 +1,28 @@
|
||||
# This is the src/plugins/export level Makefile for Gramps
|
||||
# We could use GNU make's ':=' syntax for nice wildcard use,
|
||||
# but that is not necessarily portable.
|
||||
# If not using GNU make, then list all .py files individually
|
||||
|
||||
pkgdatadir = $(datadir)/@PACKAGE@/plugins/export
|
||||
|
||||
pkgdata_PYTHON = \
|
||||
ExportCd.py \
|
||||
ExportCsv.py \
|
||||
ExportFtree.py \
|
||||
ExportGedcom.py \
|
||||
ExportGeneWeb.py \
|
||||
ExportPkg.py \
|
||||
ExportVCalendar.py \
|
||||
ExportVCard.py
|
||||
|
||||
pkgpyexecdir = @pkgpyexecdir@/plugins/export
|
||||
pkgpythondir = @pkgpythondir@/plugins/export
|
||||
|
||||
# Clean up all the byte-compiled files
|
||||
MOSTLYCLEANFILES = *pyc *pyo
|
||||
|
||||
GRAMPS_PY_MODPATH = "../../"
|
||||
|
||||
pycheck:
|
||||
(export PYTHONPATH=$(GRAMPS_PY_MODPATH); \
|
||||
pychecker $(pkgdata_PYTHON));
|
||||
Reference in New Issue
Block a user