move database code into new package

svn: r5598
This commit is contained in:
Richard Taylor
2005-12-21 11:27:05 +00:00
parent 9c64f37c87
commit deaaf16717
28 changed files with 380 additions and 98 deletions

View File

@@ -0,0 +1,251 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2005 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
import const
ADOPT_NONE = 0
ADOPT_EVENT = 1
ADOPT_FTW = 2
ADOPT_LEGACY = 3
ADOPT_PEDI = 4
ADOPT_STD = 5
CONC_OK = 0
CONC_BROKEN = 1
ALT_NAME_NONE = 0
ALT_NAME_STD = 1
ALT_NAME_ALIAS = 2
ALT_NAME_AKA = 3
ALT_NAME_EVENT_AKA = 4
ALT_NAME_UALIAS = 5
CALENDAR_NO = 0
CALENDAR_YES = 1
OBJE_NO = 0
OBJE_YES = 1
PREFIX_NO = 0
PREFIX_YES = 1
RESIDENCE_ADDR = 0
RESIDENCE_PLAC = 1
SOURCE_REFS_NO = 0
SOURCE_REFS_YES = 1
#-------------------------------------------------------------------------
#
# XML parser
#
#-------------------------------------------------------------------------
from xml.parsers.expat import ParserCreate
class GedcomDescription:
def __init__(self,name):
self.name = name
self.dest = ""
self.adopt = ADOPT_STD
self.conc = CONC_OK
self.altname = ALT_NAME_STD
self.cal = CALENDAR_YES
self.obje = OBJE_YES
self.resi = RESIDENCE_ADDR
self.source_refs = SOURCE_REFS_YES
self.gramps2tag_map = {}
self.tag2gramps_map = {}
self.prefix = PREFIX_YES
self.endl = "\n"
def set_dest(self,val):
self.dest = val
def get_dest(self):
return self.dest
def set_endl(self,val):
self.endl = val.replace('\\r','\r').replace('\\n','\n')
def get_endl(self):
return self.endl
def set_adopt(self,val):
self.adopt = val
def get_adopt(self):
return self.adopt
def set_prefix(self,val):
self.prefix=val
def get_prefix(self):
return self.prefix
def set_conc(self,val):
self.conc = val
def get_conc(self):
return self.conc
def set_alt_name(self,val):
self.altname = val
def get_alt_name(self):
return self.altname
def set_alt_calendar(self,val):
self.cal = val
def get_alt_calendar(self):
return self.cal
def set_obje(self,val):
self.obje = val
def get_obje(self):
return self.obje
def set_resi(self,val):
self.resi = val
def get_resi(self):
return self.resi
def set_source_refs(self,val):
self.source_refs = val
def get_source_refs(self):
return self.source_refs
def add_tag_value(self,tag,value):
self.gramps2tag_map[value] = tag
self.tag2gramps_map[tag] = value
def gramps2tag(self,key):
if self.gramps2tag_map.has_key(key):
return self.gramps2tag_map[key]
return ""
def tag2gramps(self,key):
if self.tag2gramps_map.has_key(key):
return self.tag2gramps_map[key]
return key
class GedcomInfoDB:
def __init__(self):
self.map = {}
self.standard = GedcomDescription("GEDCOM 5.5 standard")
self.standard.set_dest("GEDCOM 5.5")
try:
filepath = "%s/gedcom.xml" % const.dataDir
f = open(filepath.encode('iso8859-1'),"r")
except:
return
parser = GedInfoParser(self)
parser.parse(f)
f.close()
def add_description(self,name,obj):
self.map[name] = obj
def get_description(self,name):
if self.map.has_key(name):
return self.map[name]
return self.standard
def get_from_source_tag(self,name):
for k in self.map.keys():
val = self.map[k]
if val.get_dest() == name:
return val
return self.standard
def get_name_list(self):
mylist = self.map.keys()
mylist.sort()
return ["GEDCOM 5.5 standard"] + mylist
#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
class GedInfoParser:
def __init__(self,parent):
self.parent = parent
self.current = None
def parse(self,file):
p = ParserCreate()
p.StartElementHandler = self.startElement
p.ParseFile(file)
def startElement(self,tag,attrs):
if tag == "target":
name = attrs['name']
self.current = GedcomDescription(name)
self.parent.add_description(name,self.current)
elif tag == "dest":
self.current.set_dest(attrs['val'])
elif tag == "endl":
self.current.set_endl(attrs['val'])
elif tag == "adopt":
val = attrs['val']
if val == 'none':
self.current.set_adopt(ADOPT_NONE)
elif val == 'event':
self.current.set_adopt(ADOPT_EVENT)
elif val == 'ftw':
self.current.set_adopt(ADOPT_FTW)
elif val == 'legacy':
self.current.set_adopt(ADOPT_LEGACY)
elif val == 'pedigree':
self.current.set_adopt(ADOPT_PEDI)
elif tag == "conc":
if attrs['val'] == 'broken':
self.current.set_conc(CONC_BROKEN)
elif tag == "alternate_names":
val = attrs['val']
if val == 'none':
self.current.set_alt_name(ALT_NAME_NONE)
elif val == 'event_aka':
self.current.set_alt_name(ALT_NAME_EVENT_AKA)
elif val == 'alias':
self.current.set_alt_name(ALT_NAME_ALIAS)
elif val == 'aka':
self.current.set_alt_name(ALT_NAME_AKA)
elif val == '_alias':
self.current.set_alt_name(ALT_NAME_UALIAS)
elif tag == "calendars":
if attrs['val'] == 'no':
self.current.set_alt_calendar(CALENDAR_NO)
elif tag == "event":
self.current.add_tag_value(attrs['tag'],attrs['value'])
elif tag == "object_support":
if attrs['val'] == 'no':
self.current.set_obje(OBJE_NO)
elif tag == "prefix":
if attrs['val'] == 'no':
self.current.set_obje(PREFIX_NO)
elif tag == "residence":
if attrs['val'] == 'place':
self.current.set_resi(RESIDENCE_PLAC)
elif tag == "source_refs":
if attrs['val'] == 'no':
self.current.set_source_refs(SOURCE_REFS_NO)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,758 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2005 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
Introduction
============
Gramps is devided into two parts. The database code, that does not
require any particular GUI libraries, and the gtk-based UI code
that requires gtk and gnome libraries. The gtk-based code can use
the gobject signal support to manage callback signals but the database
code can not.
The module provides a subset of the signal mechanisms that are available
from the gobject framework. It enables the database code to use signals
to communicate events to any callback methods in either the database code
or the UI code.
"""
import sys
import os
import types
import traceback
import inspect
log = sys.stderr.write
#-------------------------------------------------------------------------
#
# Callback signal support for non-gtk parts of Gramps
#
#-------------------------------------------------------------------------
class GrampsDBCallback(object):
"""
Callback and signal support for non-gtk parts of gramps.
Declaring signals
=================
Classes that want to emit signals need to inherit from the
GrampsDBCallback class and ensure that its __init__ method
is called. They then need to declare the signals that they
can emit and the types of each callbacks arguments. For
example::
class TestSignals(GrampsDBCallback):
__signals__ = {
'test-signal' : (int,),
'test-noarg' : None
}
def __init__(self):
GrampsDBCallback.__init__(self)
The type signature is a tuple of types or classes. The type
checking code uses the isinstance method to check that the
argument passed to the emit call is an instance of the type
in the signature declaration.
If the signal does not have an argument use None as the
signature.
The signals will be inherited by any subclasses. Duplicate
signal names in subclasses are not alowed.
Emitting signals
================
Signals are emitted using the emit method. e.g.::
def emit_signal(self):
self.emit('test-signal',(1,))
The parameters are passed as a tuple so a single parameter
must be passed as a 1 element tuple.
Connecting callbacks to signals
===============================
Attaching a callback to the signals is similar to the gtk
connect methods. e.g.::
# connect to a function.
def fn(i):
print 'got signal value = ', i
t = TestSignals()
t.connect('test-signal', fn)
# connect to a bound method
class C(object):
def cb_func(self, i):
print 'got class signal = ', 1
r = R()
t.connect('test-signal', r.cb_func)
Disconnecting callbacks
=======================
If you want to disconnect a callback from a signals you must remember the
key returned from the connect call. This key can be passed to the disconnect
method to remove the callback from the signals callback list.
e.g.::
t = TestSignals()
# connect to a bound method
class C(object):
def cb_func(self, i):
print 'got class signal = ', 1
r = R()
key = t.connect('test-signal', r.cb_func)
...
t.disconnect(key)
Stopping and starting signals
=============================
Signals can be blocked on a per instance bassis or they can be blocked
for all instances of the GrampsDBCallback class. disable_signals() can
be used to block the signals for a single instance and disable_all_signals()
can be used to block signals for the class:
e.g.::
class TestSignals(GrampsDBCallback):
__signals__ = {
'test-signal' : (int,),
'test-noarg' : None
}
def __init__(self):
GrampsDBCallback.__init__(self)
def emit_signal(self):
self.emit('test-signal',(1,))
t = TestSignals()
# block signals from instance t
t.disable_signals()
...
# unblock
t.enable_signals()
# block all signals
GrampsDBCallback.disable_all_signals()
...
# unblock all signals
GrampsDBCallback.enable_all_signals()
Any signals emited whilst signals are blocked will be lost.
Debugging signal callbacks
==========================
To help with debugging the signals and callbacks you can turn on
lots of logging information. To switch on logging for a single
instance call self.enable_logging(), to switch it off again call
self.disable_logging(). To switch on logging for all instance
you can toggle GrampsDBCallback.__LOG_ALL to True.
"""
# If this True no signals will be emitted from any instance of
# any class derived from this class. This should be toggled using
# the class methods, dissable_all_signals() and enable_all_signals().
__BLOCK_ALL_SIGNALS = False
# If this is True logging will be turned on for all instances
# whether or not instance based logging is enabled.
try:
__LOG_ALL = int(os.environ.get('GRAMPS_SIGNAL',"0")) == 1
except:
__LOG_ALL = False
def __init__(self):
self.__enable_logging = False # controls whether lots of debug
# information will be produced.
self.__block_instance_signals = False # controls the blocking of
# signals from this instance
self.__callback_map = {} # dictionary containing all the connected
# callback functions. The keys are the
# signal names and the values are tuples
# of the form (key,bound_method), where
# the key is unique within the instance
# and the bound_method is the callback
# that will be called when the signal is
# emitted
self.__signal_map = {} # dictionary contains all the signals that
# this instance can emit. The keys are the
# signal names and the values are tuples
# containing the list of types of the arguments
# that the callback methods must accept.
self._current_key = 0 # counter to give a unique key to each callback.
self._current_signals = [] # list of all the signals that are currently
# being emitted by this instance. This is
# used to prevent recursive emittion of the
# same signal.
# To speed up the signal type checking the signals declared by
# each of the classes in the inheritance tree of this instance
# are consolidated into a single dictionary.
# The signals can't change so we only need to do this once.
def trav(cls):
"""A traversal function to walk through all the classes in
the inheritance tree. The return is a list of all the
__signals__ dictionaries."""
if cls.__dict__.has_key('__signals__'):
signal_list = [cls.__signals__]
else:
signal_list = []
for base_cls in cls.__bases__:
base_list = trav(base_cls)
if len(base_list) > 0:
signal_list = signal_list + base_list
return signal_list
# Build a signal dict from the list of signal dicts
for s in trav(self.__class__):
for (k,v) in s.items():
if self.__signal_map.has_key(k):
# signal name clash
sys.err.write("Warning: signal name clash: %s\n" % str(k))
self.__signal_map[k] = v
# self.__signal_map now contains the connonical list
# of signals that this instance can emit.
self._log("registed signals: \n %s\n" %
"\n ".join([ "%s: %s" % (k,v) for (k,v)
in self.__signal_map.items() ]))
def connect(self, signal_name, callback):
"""
Connect a callable to a signal_name. The callable will be called
with the signal is emitted. The callable must accept the argument
types declared in the signals signature.
returns a unique key that can be passed to disconnect().
"""
# Check that signal exists.
if signal_name not in self.__signal_map.keys():
self._log("Warning: attempt to connect to unknown signal: %s\n" % str(signal_name))
return
# Add callable to callback_map
if signal_name not in self.__callback_map.keys():
self.__callback_map[signal_name] = []
self._current_key += 1
self._log("Connecting callback to signal: "
"%s with key: %s\n"
% (signal_name,str(self._current_key)))
self.__callback_map[signal_name].append((self._current_key,callback))
return self._current_key
def disconnect(self,key):
"""
Disconnect a callback.
"""
# Find the key in the callback map.
for signal_name in self.__callback_map.keys():
for cb in self.__callback_map[signal_name]:
(skey,fn) = cb
if skey == key:
# delete the callback from the map.
self._log("Disconnecting callback from signal"
": %s with key: %s\n" % (signal_name,
str(key)))
self.__callback_map[signal_name].remove(cb)
def emit(self, signal_name, args=tuple()):
"""
Emit the signal called signal_name. The args must be a tuple of
arguments that match the types declared for the signals signature.
"""
# Check that signals are not blocked
if GrampsDBCallback.__BLOCK_ALL_SIGNALS or \
self.__block_instance_signals:
return
# Check signal exists
if signal_name not in self.__signal_map.keys():
self._warn("Attempt to emit to unknown signal: %s\n"
" from: file: %s\n"
" line: %d\n"
" func: %s\n"
% ((str(signal_name),) + inspect.stack()[1][1:4]))
return
# check that the signal is not already being emitted. This prevents
# against recursive signal emmissions.
if signal_name in self._current_signals:
self._warn("Signal recursion blocked. "
"Signals was : %s\n"
" from: file: %s\n"
" line: %d\n"
" func: %s\n"
% ((str(signal_name),) + inspect.stack()[1][1:4]))
return
try:
self._current_signals.append(signal_name)
# check that args is a tuple. This is a common programming error.
if not (isinstance(args,tuple) or args == None):
self._warn("Signal emitted with argument that is not a tuple.\n"
" emit() takes two arguments, the signal name and a \n"
" tuple that contains the arguments that are to be \n"
" passed to the callbacks. If you are passing a signal \n"
" argument it must be done as a single element tuple \n"
" e.g. emit('my-signal',(1,)) \n"
" signal was: %s\n"
" from: file: %s\n"
" line: %d\n"
" func: %s\n"
% ((str(signal_name),) + inspect.stack()[1][1:4]))
return
# type check arguments
arg_types = self.__signal_map[signal_name]
if arg_types == None and len(args) > 0:
self._warn("Signal emitted with "
"wrong number of args: %s\n"
" from: file: %s\n"
" line: %d\n"
" func: %s\n"
% ((str(signal_name),) + inspect.stack()[1][1:4]))
return
if len(args) > 0:
if len(args) != len(arg_types):
self._warn("Signal emitted with "
"wrong number of args: %s\n"
" from: file: %s\n"
" line: %d\n"
" func: %s\n"
% ((str(signal_name),) + inspect.stack()[1][1:4]))
return
if arg_types != None:
for i in range(0,len(arg_types)):
if not isinstance(args[i],arg_types[i]):
self._warn("Signal emitted with "
"wrong arg types: %s\n"
" from: file: %s\n"
" line: %d\n"
" func: %s\n"
" arg passed was: %s, type of arg passed %s, type should be: %s\n"
% ((str(signal_name),) + inspect.stack()[1][1:4] +\
(args[i],repr(type(args[i])),repr(arg_types[i]))))
return
if signal_name in self.__callback_map.keys():
self._log("emmitting signal: %s\n" % (signal_name,))
# Don't bother if there are no callbacks.
for (key,fn) in self.__callback_map[signal_name]:
self._log("Calling callback with key: %s\n" % (key,))
try:
if type(fn) == tuple: # call class method
cb[0](fn[1],*args)
elif type(fn) == types.FunctionType or \
type(fn) == types.MethodType: # call func
fn(*args)
else:
self._warn("Badly formed entry in callback map.\n")
except:
self._warn("Exception occured in callback function.\n"
"%s" % ("".join(traceback.format_exception(*sys.exc_info())),))
finally:
self._current_signals.remove(signal_name)
#
# instance signals control methods
#
def disable_signals(self):
self.__block_instance_signals = True
def enable_signals(self):
self.__block_instance_signals = False
# logging methods
def disable_logging(self):
self.__enable_logging = False
def enable_logging(self):
self.__enable_logging = True
def _log(self,msg):
if GrampsDBCallback.__LOG_ALL or self.__enable_logging:
log("%s: %s" % (self.__class__.__name__, str(msg)))
def _warn(self,msg):
log("Warning: %s: %s" % (self.__class__.__name__, str(msg)))
#
# Class methods
#
def __disable_all_signals(cls):
GrampsDBCallback.__BLOCK_ALL_SIGNALS = True
disable_all_signals = classmethod(__disable_all_signals)
def __enable_all_signals(cls):
GrampsDBCallback.__BLOCK_ALL_SIGNALS = False
enable_all_signals = classmethod(__enable_all_signals)
#-------------------------------------------------------------------------
#
# Testing code below this point
#
#-------------------------------------------------------------------------
if __name__ == "__main__":
import unittest
class TestGrampsDBCallback(unittest.TestCase):
def test_simple(self):
class TestSignals(GrampsDBCallback):
__signals__ = {
'test-signal' : (int,)
}
rl = []
def fn(i,r=rl):
rl.append(i)
t = TestSignals()
t.connect('test-signal',fn)
t.emit('test-signal',(1,))
assert len(rl) == 1, "No signal emitted"
assert rl[0] == 1, "Wrong argument recieved"
def test_exception_catch(self):
class TestSignals(GrampsDBCallback):
__signals__ = {
'test-signal' : (int,)
}
rl = []
def fn(i,r=rl):
rl.append(i)
def borked(i):
rubish.append(i)
t = TestSignals()
def null(s):
pass
global log
_log = log
log = null
t.connect('test-signal',borked)
t.connect('test-signal',fn)
t.emit('test-signal',(1,))
log = _log
assert len(rl) == 1, "No signal emitted"
assert rl[0] == 1, "Wrong argument recieved"
def test_disconnect(self):
class TestSignals(GrampsDBCallback):
__signals__ = {
'test-signal' : (int,)
}
rl = []
def fn(i,r=rl):
rl.append(i)
t = TestSignals()
key = t.connect('test-signal',fn)
t.emit('test-signal',(1,))
assert len(rl) == 1, "No signal emitted"
assert rl[0] == 1, "Wrong argument recieved"
t.disconnect(key)
t.emit('test-signal',(1,))
assert len(rl) == 1, "Callback not disconnected"
assert rl[0] == 1, "Callback not disconnected"
def test_noargs(self):
class TestSignals(GrampsDBCallback):
__signals__ = {
'test-noargs' : None
}
rl = []
def fn(r=rl):
rl.append(1)
t = TestSignals()
t.connect('test-noargs',fn)
t.emit('test-noargs')
assert len(rl) == 1, "No signal emitted"
assert rl[0] == 1, "Wrong argument recieved"
def test_no_callback(self):
class TestSignals(GrampsDBCallback):
__signals__ = {
'test-noargs' : None
}
t = TestSignals()
t.emit('test-noargs')
def test_subclassing(self):
class TestSignals(GrampsDBCallback):
__signals__ = {
'test-signal' : (int,)
}
class TestSignalsSubclass(TestSignals):
__signals__ = {
'test-sub-signal' : (int,),
}
rl = []
def fn(i,r=rl):
rl.append(i)
t = TestSignalsSubclass()
t.connect('test-signal',fn)
t.emit('test-signal',(1,))
assert len(rl) == 1, "No signal emitted"
assert rl[0] == 1, "Wrong argument recieved"
t.connect('test-sub-signal',fn)
t.emit('test-sub-signal',(1,))
assert len(rl) == 2, "No subclass signal emitted"
assert rl[1] == 1, "Wrong argument recieved in subclass"
def test_signal_block(self):
class TestSignals(GrampsDBCallback):
__signals__ = {
'test-signal' : (int,)
}
rl = []
def fn(i,r=rl):
rl.append(i)
t = TestSignals()
t.connect('test-signal',fn)
t.emit('test-signal',(1,))
assert len(rl) == 1, "No signal emitted"
assert rl[0] == 1, "Wrong argument recieved"
GrampsDBCallback.disable_all_signals()
t.emit('test-signal',(1,))
assert len(rl) == 1, "Signal emitted while class blocked"
GrampsDBCallback.enable_all_signals()
t.emit('test-signal',(1,))
assert len(rl) == 2, "Signals not class unblocked"
t.disable_signals()
t.emit('test-signal',(1,))
assert len(rl) == 2, "Signal emitted while instance blocked"
t.enable_signals()
t.emit('test-signal',(1,))
assert len(rl) == 3, "Signals not instance unblocked"
def test_type_checking(self):
class TestSignals(GrampsDBCallback):
__signals__ = {
'test-int' : (int,),
'test-list': (list,),
'test-object': (object,),
'test-str': (str,),
'test-float': (float,),
'test-dict': (dict,),
'test-lots': (int,str,list,object,float)
}
rl = []
def fn(i,r=rl):
rl.append(i)
t = TestSignals()
t.connect('test-int',fn), t.emit('test-int',(1,))
assert type(rl[0]) == int, "not int"
t.connect('test-list',fn), t.emit('test-list',([1,2],))
assert type(rl[1]) == list, "not list"
t.connect('test-object',fn), t.emit('test-object',(t,))
assert isinstance(rl[2],object), "not object"
t.connect('test-float',fn), t.emit('test-float',(2.3,))
assert type(rl[3]) == float, "not float"
t.connect('test-dict',fn), t.emit('test-dict',({1:2},))
assert type(rl[4]) == dict, "not dict"
rl = []
def fn2(i,s,l,o,f,r=rl):
rl.append(i)
t.connect('test-lots',fn2), t.emit('test-lots',(1,'a',[1,2],t,1.2))
assert type(rl[0]) == int, "not lots"
# This should fail because the type of arg1 is wrong
res=[]
def fn(s,r=res):
res.append(s)
t._warn = fn
t.connect('test-lots',fn2), t.emit('test-lots',('a','a',[1,2],t,1.2))
assert res[0][0:6] == "Signal", "Type error not detected"
def test_recursion_block(self):
class TestSignals(GrampsDBCallback):
__signals__ = {
'test-recursion' : (GrampsDBCallback,)
}
def fn(cb):
cb.emit('test-recursion',(t,))
res=[]
def fn2(s,r=res):
res.append(s)
t = TestSignals()
t._warn = fn2
t.connect('test-recursion',fn)
try:
t.emit('test-recursion',(t,))
except RuntimeError:
assert False, "signal recursion not blocked1."
assert res[0][0:6] == "Signal", "signal recursion not blocked"
def test_multisignal_recursion_block(self):
class TestSignals(GrampsDBCallback):
__signals__ = {
'test-top' : (GrampsDBCallback,),
'test-middle' : (GrampsDBCallback,),
'test-bottom' : (GrampsDBCallback,)
}
def top(cb):
cb.emit('test-middle',(t,))
def middle(cb):
cb.emit('test-bottom',(t,))
def bottom(cb):
cb.emit('test-top',(t,))
res=[]
def fn2(s,r=res):
res.append(s)
t = TestSignals()
t._warn = fn2
t.connect('test-top',top)
t.connect('test-middle',middle)
t.connect('test-bottom',bottom)
try:
t.emit('test-top',(t,))
except RuntimeError:
assert False, "multisignal recursion not blocked1."
assert res[0][0:6] == "Signal", "multisignal recursion not blocked"
unittest.main()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2004-2005 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""Exceptions generated by the GrampsDb package."""
class GrampsDbException(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)

View File

@@ -0,0 +1,123 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2004-2005 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
This module contains factory methods for accessing the different
GrampsDb backends. These methods should be used obtain the correct class
for a database backend.
The app_* constants in const.py can be used to indicate which backend is
required e.g.:
# To get the class for the grdb backend
db_class = GrampsDb.gramps_db_factory(db_type = const.app_gramps)
# To get a XML writer
GrampsDb.gramps_db_writer_factory(db_type = const.app_gramps_xml)
# To get a Gedcom reader
GrampsDb.gramps_db_reader_factory(db_type = const.app_gedcom)
"""
import const
from _GrampsDbExceptions import GrampsDbException
def gramps_db_factory(db_type):
"""Factory class for obtaining a Gramps database backend.
@param db_type: the type of backend required.
@type db_type: one of the app_* constants in const.py
Raises GrampsDbException if the db_type is not recognised.
"""
if db_type == const.app_gramps:
from _GrampsBSDDB import GrampsBSDDB
cls = GrampsBSDDB
elif db_type == const.app_gramps_xml:
from _GrampsXMLDB import GrampsXMLDB
cls = GrampsXMLDB
elif db_type == const.app_gedcom:
from _GrampsGEDDB import GrampsGEDDB
cls = GrampsGEDDB
else:
raise GrampsDbException("Attempt to create unknown "
"database backend class: "
"db_type = %s" % (str(db_type),))
return cls
def gramps_db_writer_factory(db_type):
"""Factory class for obtaining a Gramps database writers.
@param db_type: the type of backend required.
@type db_type: one of the app_* constants in const.py
Raises GrampsDbException if the db_type is not recognised.
"""
if db_type == const.app_gramps:
import _WriteGrdb as WriteGrdb
md = WriteGrdb.exportData
elif db_type == const.app_gramps_xml:
import _WriteXML as WriteXML
md = WriteXML.exportData
elif db_type == const.app_gedcom:
import _WriteGedcom as WriteGedcom
md = WriteGedcom.exportData
else:
raise GrampsDbException("Attempt to create a database "
"writer for unknown format: "
"db_type = %s" % (str(db_type),))
return md
def gramps_db_reader_factory(db_type):
"""Factory class for obtaining a Gramps database writers.
@param db_type: the type of backend required.
@type db_type: one of the app_* constants in const.py
Raises GrampsDbException if the db_type is not recognised.
"""
if db_type == const.app_gramps:
import _ReadGrdb as ReadGrdb
md = ReadGrdb.importData
elif db_type == const.app_gramps_xml:
import _ReadXML as ReadXML
md = ReadXML.importData
elif db_type == const.app_gedcom:
import _ReadGedcom as ReadGedcom
md = ReadGedcom.importData
else:
raise GrampsDbException("Attempt to create a database "
"reader for unknown format: "
"db_type = %s" % (str(db_type),))
return md

View File

@@ -0,0 +1,60 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2004 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
Provides the GRAMPS DB interface for supporting in-memory editing
of GEDCOM files.
"""
from RelLib import *
from _GrampsInMemDB import *
import _ReadGedcom as ReadGedcom
import _WriteGedcom as WriteGedcom
#-------------------------------------------------------------------------
#
# GrampsGEDDB
#
#-------------------------------------------------------------------------
class GrampsGEDDB(GrampsInMemDB):
"""GRAMPS database object. This object is a base class for other
objects."""
def __init__(self):
"""creates a new GrampsDB"""
GrampsInMemDB.__init__(self)
def load(self,name,callback, mode="w"):
GrampsInMemDB.load(self,name,callback,mode)
ReadGedcom.importData(self,name,use_trans=False)
self.bookmarks = self.metadata.get('bookmarks')
if self.bookmarks == None:
self.bookmarks = []
return 1
def close(self):
if not self.readonly and len(self.undodb) > 0:
writer = WriteGedcom.GedcomWriter(self,self.get_default_person())
writer.export_data(self.filename)

View File

@@ -0,0 +1,327 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2005 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
Provides the common infrastructure for database formats that
must hold all of their data in memory.
"""
from bsddb import dbshelve, db
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
from RelLib import *
from _GrampsDbBase import *
import sets
class GrampsInMemCursor(GrampsCursor):
"""
Cursor class for in-memory database classes. Since the in-memory
classes use python dictionaries, the python iter class is used
to provide the cursor function.
"""
def __init__(self,src_map):
self.src_map = src_map
self.current = iter(src_map)
def first(self):
self.current = iter(self.src_map)
return self.next()
def next(self):
try:
index = self.current.next()
return (index,self.src_map[index])
except StopIteration:
return None
def close(self):
pass
#-------------------------------------------------------------------------
#
# GrampsInMemDB
#
#-------------------------------------------------------------------------
class GrampsInMemDB(GrampsDbBase):
"""GRAMPS database object. This object is a base class for other
objects."""
def __init__(self):
"""creates a new GrampsDB"""
GrampsDbBase.__init__(self)
self.person_map = {}
self.name_group = {}
self.family_map = {}
self.place_map = {}
self.source_map = {}
self.repository_map = {}
self.media_map = {}
self.event_map = {}
self.metadata = {}
self.filename = ""
self.id_trans = {}
self.pid_trans = {}
self.fid_trans = {}
self.eid_trans = {}
self.sid_trans = {}
self.rid_trans = {}
self.oid_trans = {}
self.eventnames = {}
self.repository_types = {}
self.undodb = []
def load(self,name,callback,mode="w"):
self.undolog = "%s.log" % name
self.undodb = db.DB()
self.undodb.open(self.undolog, db.DB_RECNO, db.DB_CREATE)
self.filename = name
self.readonly = mode == "r"
def get_person_cursor(self):
return GrampsInMemCursor(self.person_map)
def get_family_cursor(self):
return GrampsInMemCursor(self.family_map)
def get_event_cursor(self):
return GrampsInMemCursor(self.event_map)
def get_place_cursor(self):
return GrampsInMemCursor(self.place_map)
def get_source_cursor(self):
return GrampsInMemCursor(self.source_map)
def get_repository_cursor(self):
return GrampsInMemCursor(self.repository_map)
def get_media_cursor(self):
return GrampsInMemCursor(self.media_map)
def get_event_cursor(self):
return GrampsInMemCursor(self.event_map)
def close(self):
if not self.readonly:
self.undodb.close()
try:
os.remove(self.undolog)
except:
pass
def abort_changes(self):
pass
def set_name_group_mapping(self,name,group):
if group == None and self.name_group.has_key(name):
del self.name_group[name]
else:
self.name_group[name] = group
def get_surname_list(self):
a = {}
for person_id in iter(self.person_map):
p = self.get_person_from_handle(person_id)
a[p.get_primary_name().get_group_as()] = 1
vals = a.keys()
vals.sort()
return vals
def get_person_event_type_list(self):
names = self.eventnames.keys()
a = {}
for name in names:
a[unicode(name)] = 1
vals = a.keys()
vals.sort()
return vals
def get_repository_type_list(self):
repos_types = self.repository_types.keys()
a = {}
for repos_type in repos_types:
a[unicode(repos_type)] = 1
vals = a.keys()
vals.sort()
return vals
#FIXME: WHICH one to keep?
def _del_person(self,handle):
#def remove_person(self,handle,transaction):
if self.readonly or not handle or str(handle) not in self.person_map:
return
person = self.get_person_from_handle(handle)
self.genderStats.uncount_person (person)
if transaction != None:
old_data = self.person_map.get(handle)
transaction.add(PERSON_KEY,handle,old_data)
self.emit('person-delete',([handle],))
del self.id_trans[person.get_gramps_id()]
del self.person_map[handle]
def _del_source(self,handle):
del self.sid_trans[source.get_gramps_id()]
del self.source_map[str(handle)]
def _del_repository(self,handle):
del self.rid_trans[repository.get_gramps_id()]
del self.repository_map[str(handle)]
def _del_place(self,handle):
del self.pid_trans[place.get_gramps_id()]
del self.place_map[str(handle)]
def _del_media(self,handle):
del self.oid_trans[obj.get_gramps_id()]
del self.media_map[str(handle)]
def _del_family(self,handle):
del self.fid_trans[family.get_gramps_id()]
del self.family_map[str(handle)]
def _del_event(self,handle):
del self.eid_trans[event.get_gramps_id()]
del self.event_map[str(handle)]
def commit_person(self,person,transaction,change_time=None):
if self.readonly or not person.get_handle():
return
gid = person.get_gramps_id()
self.id_trans[gid] = person.get_handle()
GrampsDbBase.commit_person(self,person,transaction,change_time)
def commit_place(self,place,transaction,change_time=None):
if self.readonly or not place.get_handle():
return
gid = place.get_gramps_id()
self.pid_trans[gid] = place.get_handle()
GrampsDbBase.commit_place(self,place,transaction,change_time)
def commit_family(self,family,transaction,change_time=None):
if self.readonly or not family.get_handle():
return
gid = family.get_gramps_id()
self.fid_trans[gid] = family.get_handle()
GrampsDbBase.commit_family(self,family,transaction,change_time)
def commit_event(self,event,transaction,change_time=None):
if self.readonly or not event.get_handle():
return
gid = event.get_gramps_id()
self.eid_trans[gid] = event.get_handle()
GrampsDbBase.commit_event(self,event,transaction,change_time)
def commit_media_object(self,obj,transaction,change_time=None):
if self.readonly or not obj.get_handle():
return
gid = obj.get_gramps_id()
self.oid_trans[gid] = obj.get_handle()
GrampsDbBase.commit_media_object(self,obj,transaction,change_time)
def commit_source(self,source,transaction,change_time=None):
if self.readonly or not source.get_handle():
return
gid = source.get_gramps_id()
self.sid_trans[gid] = source.get_handle()
GrampsDbBase.commit_source(self,source,transaction,change_time)
def commit_repository(self,repository,transaction,change_time=None):
if self.readonly or not repository.get_handle():
return
gid = repository.get_gramps_id()
self.rid_trans[gid] = repository.get_handle()
GrampsDbBase.commit_repository(self,repository,transaction,change_time)
def get_person_from_gramps_id(self,val):
handle = self.id_trans.get(str(val))
if handle:
data = self.person_map[handle]
if data:
person = Person()
person.unserialize(data)
return person
return None
def get_family_from_gramps_id(self,val):
handle = self.fid_trans.get(str(val))
if handle:
data = self.family_map[handle]
if data:
family = Family()
family.unserialize(data)
return family
return None
def get_event_from_gramps_id(self,val):
handle = self.eid_trans.get(str(val))
if handle:
data = self.event_map[handle]
if data:
event = Event()
event.unserialize(data)
return event
return None
def get_place_from_gramps_id(self,val):
handle = self.pid_trans.get(str(val))
if handle:
data = self.place_map[handle]
if data:
place = Place()
place.unserialize(data)
return place
return None
def get_source_from_gramps_id(self,val):
handle = self.sid_trans.get(str(val))
if handle:
data = self.source_map[handle]
if data:
source = Source()
source.unserialize(data)
return source
return None
def get_repository_from_gramps_id(self,val):
handle = self.rid_trans.get(str(val))
if handle:
data = self.repository_map[handle]
if data:
repository = Repository()
repository.unserialize(data)
return repository
return None
def get_object_from_gramps_id(self,val):
handle = self.oid_trans.get(str(val))
if handle:
data = self.media_map[handle]
if data:
obj = MediaObject()
obj.unserialize(data)
return obj
return None

View File

@@ -0,0 +1,61 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2004 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
Provides the GRAMPS DB interface for supporting in-memory editing
of GRAMPS XML format.
"""
from RelLib import *
from _GrampsInMemDB import *
import _ReadXML as ReadXML
import _WriteXML as WriteXML
#-------------------------------------------------------------------------
#
# GrampsXMLDB
#
#-------------------------------------------------------------------------
class GrampsXMLDB(GrampsInMemDB):
"""GRAMPS database object. This object is a base class for other
objects."""
def __init__(self):
"""creates a new GrampsDB"""
GrampsInMemDB.__init__(self)
def load(self,name,callback,mode="w"):
GrampsInMemDB.load(self,name,callback,mode)
self.id_trans = {}
ReadXML.importData(self,name,callback,use_trans=False)
self.bookmarks = self.metadata.get('bookmarks')
if self.bookmarks == None:
self.bookmarks = []
return 1
def close(self):
if not self.readonly and len(self.undodb) > 0:
WriteXML.quick_write(self,self.filename)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,193 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2005 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
# Written by Alex Roitman,
# largely based on ReadXML by Don Allingham
#-------------------------------------------------------------------------
#
# Standard Python Modules
#
#-------------------------------------------------------------------------
import os
from gettext import gettext as _
import sets
#-------------------------------------------------------------------------
#
# Gramps Modules
#
#-------------------------------------------------------------------------
from _GrampsBSDDB import GrampsBSDDB
from QuestionDialog import ErrorDialog
import Errors
#-------------------------------------------------------------------------
#
# Importing data into the currently open database.
#
#-------------------------------------------------------------------------
def importData(database, filename, callback=None,cl=0,use_trans=True):
filename = os.path.normpath(filename)
other_database = GrampsBSDDB()
try:
other_database.load(filename,callback)
except:
if cl:
print "Error: %s could not be opened. Exiting." % filename
else:
ErrorDialog(_("%s could not be opened") % filename)
return
if not other_database.version_supported():
if cl:
print "Error: %s could not be opened.\n%s Exiting." \
% (filename,
_("The database version is not supported "
"by this version of GRAMPS.\n"\
"Please upgrade to the corresponding version "
"or use XML for porting data between different "
"database versions."))
else:
ErrorDialog(_("%s could not be opened") % filename,
_("The Database version is not supported "
"by this version of GRAMPS."))
return
# Check for duplicate handles. At the moment we simply exit here,
# before modifying any data. In the future we will need to handle
# this better.
handles = sets.Set(database.person_map.keys())
other_handles = sets.Set(other_database.person_map.keys())
if handles.intersection(other_handles):
raise Errors.HandleError('Personal handles in two databases overlap.')
handles = sets.Set(database.family_map.keys())
other_handles = sets.Set(other_database.family_map.keys())
if handles.intersection(other_handles):
raise Errors.HandleError('Family handles in two databases overlap.')
handles = sets.Set(database.place_map.keys())
other_handles = sets.Set(other_database.place_map.keys())
if handles.intersection(other_handles):
raise Errors.HandleError('Place handles in two databases overlap.')
handles = sets.Set(database.source_map.keys())
other_handles = sets.Set(other_database.source_map.keys())
if handles.intersection(other_handles):
raise Errors.HandleError('Source handles in two databases overlap.')
handles = sets.Set(database.media_map.keys())
other_handles = sets.Set(other_database.media_map.keys())
if handles.intersection(other_handles):
raise Errors.HandleError('Media handles in two databases overlap.')
handles = sets.Set(database.event_map.keys())
other_handles = sets.Set(other_database.event_map.keys())
if handles.intersection(other_handles):
raise Errors.HandleError('Event handles in two databases overlap.')
# Proceed with preparing for import
if use_trans:
trans = database.transaction_begin()
trans.set_batch(True)
else:
trans = None
database.disable_signals()
# copy all data from new_database to database,
# rename gramps IDs of first-class objects when conflicts are found
# People table
for person_handle in other_database.person_map.keys():
person = other_database.get_person_from_handle(person_handle)
# Then we check gramps_id for conflicts and change it if needed
gramps_id = str(person.get_gramps_id())
if database.id_trans.has_key(gramps_id):
gramps_id = database.find_next_person_gramps_id()
person.set_gramps_id(gramps_id)
database.add_person(person,trans)
# Family table
for family_handle in other_database.family_map.keys():
family = other_database.get_family_from_handle(family_handle)
# Then we check gramps_id for conflicts and change it if needed
gramps_id = str(family.get_gramps_id())
if database.fid_trans.has_key(gramps_id):
gramps_id = database.find_next_family_gramps_id()
family.set_gramps_id(gramps_id)
database.add_family(family,trans)
# Place table
for place_handle in other_database.place_map.keys():
place = other_database.get_place_from_handle(place_handle)
# Then we check gramps_id for conflicts and change it if needed
gramps_id = str(place.get_gramps_id())
if database.pid_trans.has_key(gramps_id):
gramps_id = database.find_next_place_gramps_id()
place.set_gramps_id(gramps_id)
database.add_place(place,trans)
# Source table
for source_handle in other_database.source_map.keys():
source = other_database.get_source_from_handle(source_handle)
# Then we check gramps_id for conflicts and change it if needed
gramps_id = str(source.get_gramps_id())
if database.sid_trans.has_key(gramps_id):
gramps_id = database.find_next_source_gramps_id()
source.set_gramps_id(gramps_id)
database.add_source(source,trans)
# Media table
for media_handle in other_database.media_map.keys():
media = other_database.get_object_from_handle(media_handle)
# Then we check gramps_id for conflicts and change it if needed
gramps_id = str(media.get_gramps_id())
if database.oid_trans.has_key(gramps_id):
gramps_id = database.find_next_object_gramps_id()
media.set_gramps_id(gramps_id)
database.add_object(media,trans)
# Event table
for event_handle in other_database.event_map.keys():
event = other_database.get_event_from_handle(event_handle)
# Then we check gramps_id for conflicts and change it if needed
gramps_id = str(event.get_gramps_id())
if database.eid_trans.has_key(gramps_id):
gramps_id = database.find_next_event_gramps_id()
event.set_gramps_id(gramps_id)
database.add_event(event,trans)
# close the other database and clean things up
other_database.close()
database.transaction_commit(trans,_("Import database"))
database.enable_signals()
database.request_rebuild()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2005 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
# Written by Alex Roitman
#-------------------------------------------------------------------------
#
# Standard Python Modules
#
#-------------------------------------------------------------------------
import os
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# Gramps Modules
#
#-------------------------------------------------------------------------
from _GrampsBSDDB import GrampsBSDDB
from QuestionDialog import ErrorDialog
#-------------------------------------------------------------------------
#
# Importing data into the currently open database.
#
#-------------------------------------------------------------------------
def exportData(database, filename, person=None, callback=None, cl=False):
filename = os.path.normpath(filename)
new_database = GrampsBSDDB()
try:
new_database.load(filename,callback)
except:
if cl:
print "Error: %s could not be opened. Exiting." % filename
else:
ErrorDialog(_("%s could not be opened") % filename)
return
# copy all data from new_database to database,
for handle in database.person_map.keys():
new_database.person_map.put(handle,
database.person_map.get(handle))
for handle in database.family_map.keys():
new_database.family_map.put(handle,
database.family_map.get(handle))
for handle in database.place_map.keys():
new_database.place_map.put(handle,
database.place_map.get(handle))
for handle in database.source_map.keys():
new_database.source_map.put(handle,
database.source_map.get(handle))
for handle in database.media_map.keys():
new_database.media_map.put(handle,
database.media_map.get(handle))
for handle in database.event_map.keys():
new_database.event_map.put(handle,
database.event_map.get(handle))
for handle in database.metadata.keys():
new_database.metadata.put(handle,
database.metadata.get(handle))
new_database.close()

View File

@@ -0,0 +1,914 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2005 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
Contains the interface to allow a database to get written using
GRAMPS' XML file format.
"""
#-------------------------------------------------------------------------
#
# load standard python libraries
#
#-------------------------------------------------------------------------
import time
import shutil
import os
import codecs
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# load gtk libraries
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# load GRAMPS libraries
#
#-------------------------------------------------------------------------
import const
import RelLib
import Date
from QuestionDialog import ErrorDialog
#-------------------------------------------------------------------------
#
# Attempt to load the GZIP library. Some version of python do not seem
# to be compiled with this available.
#
#-------------------------------------------------------------------------
try:
import gzip
_gzip_ok = 1
except:
_gzip_ok = 0
_xml_version = "1.0.0"
#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
def exportData(database, filename, person, callback=None):
ret = 0
if os.path.isfile(filename):
try:
shutil.copyfile(filename, filename + ".bak")
shutil.copystat(filename, filename + ".bak")
except:
pass
compress = _gzip_ok == 1
try:
g = XmlWriter(database,callback,0,compress)
ret = g.write(filename)
except:
import DisplayTrace
DisplayTrace.DisplayTrace()
ErrorDialog(_("Failure writing %s") % filename,
_("An attempt is being made to recover the original file"))
shutil.copyfile(filename + ".bak", filename)
try:
shutil.copystat(filename + ".bak", filename)
except:
pass
return ret
#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
def quick_write(database, filename,callback=None):
g = XmlWriter(database,callback,0,1)
g.write(filename)
#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
class XmlWriter:
"""
Writes a database to the XML file.
"""
def __init__(self,db,callback,strip_photos,compress=1):
"""
Initializes, but does not write, an XML file.
db - database to write
callback - function to provide progress indication
strip_photos - remove full paths off of media object paths
compress - attempt to compress the database
"""
self.compress = compress
self.db = db
self.callback = callback
self.strip_photos = strip_photos
def write(self,filename):
"""
Write the database to the specified file.
"""
base = os.path.dirname(filename)
if os.path.isdir(base):
if not os.access(base,os.W_OK) or not os.access(base,os.R_OK):
ErrorDialog(_('Failure writing %s') % filename,
_("The database cannot be saved because you do not "
"have permission to write to the directory. "
"Please make sure you have write access to the "
"directory and try again."))
return 0
if os.path.exists(filename):
if not os.access(filename,os.W_OK):
ErrorDialog(_('Failure writing %s') % filename,
_("The database cannot be saved because you do not "
"have permission to write to the file. "
"Please make sure you have write access to the "
"file and try again."))
return 0
self.fileroot = os.path.dirname(filename)
try:
if self.compress:
try:
g = gzip.open(filename,"wb")
except:
g = open(filename,"w")
else:
g = open(filename,"w")
except IOError,msg:
ErrorDialog(_('Failure writing %s') % filename,msg)
return 0
self.g = codecs.getwriter("utf8")(g)
self.write_xml_data()
g.close()
return 1
def write_handle(self,handle):
"""
Write the database to the specified file handle.
"""
if self.compress:
try:
g = gzip.GzipFile(mode="wb",fileobj=handle)
except:
g = handle
else:
g = handle
self.g = codecs.getwriter("utf8")(g)
self.write_xml_data()
g.close()
return 1
def write_xml_data(self):
date = time.localtime(time.time())
owner = self.db.get_researcher()
person_len = self.db.get_number_of_people()
family_len = len(self.db.get_family_handles())
source_len = len(self.db.get_source_handles())
place_len = len(self.db.get_place_handles())
objList = self.db.get_media_object_handles()
total = person_len + family_len + place_len + source_len
self.g.write('<?xml version="1.0" encoding="UTF-8"?>\n')
self.g.write('<!DOCTYPE database '
'PUBLIC "-//GRAMPS//DTD GRAMPS XML %s//EN"\n'
'"http://gramps-project.org/xml/%s/grampsxml.dtd">\n'
% (_xml_version,_xml_version))
self.g.write('<database xmlns="http://gramps-project.org/xml/%s/">\n'
% _xml_version)
self.g.write(" <header>\n")
self.g.write(' <created date="%04d-%02d-%02d\"' %
(date[0],date[1],date[2]) )
self.g.write(" version=\"" + const.version + "\"")
self.g.write("/>\n")
self.g.write(" <researcher>\n")
self.write_line("resname",owner.get_name(),3)
self.write_line("resaddr",owner.get_address(),3)
self.write_line("rescity",owner.get_city(),3)
self.write_line("resstate",owner.get_state(),3)
self.write_line("rescountry",owner.get_country(),3)
self.write_line("respostal",owner.get_postal_code(),3)
self.write_line("resphone",owner.get_phone(),3)
self.write_line("resemail",owner.get_email(),3)
self.g.write(" </researcher>\n")
self.g.write(" </header>\n")
count = 0
delta = max(int(total/50),1)
if person_len > 0:
self.g.write(" <people")
person = self.db.get_default_person()
if person:
self.g.write(' default="%s" home="%s"' %
(person.get_gramps_id (),
"_"+person.get_handle()))
self.g.write(">\n")
keys = self.db.get_person_handles(sort_handles=False)
sorted_keys = []
for key in keys:
person = self.db.get_person_from_handle (key)
value = (person.get_gramps_id (), person)
sorted_keys.append (value)
sorted_keys.sort ()
for (gramps_id, person) in sorted_keys:
if self.callback and count % delta == 0:
self.callback(float(count)/float(total))
count += 1
self.write_id("person",person,2)
if person.get_gender() == RelLib.Person.MALE:
self.write_line("gender","M",3)
elif person.get_gender() == RelLib.Person.FEMALE:
self.write_line("gender","F",3)
else:
self.write_line("gender","U",3)
self.dump_name(person.get_primary_name(),False,3)
for name in person.get_alternate_names():
self.dump_name(name,True,3)
self.write_line("nick",person.get_nick_name(),3)
birth = self.db.get_event_from_handle(person.get_birth_handle())
death = self.db.get_event_from_handle(person.get_death_handle())
self.dump_my_event("Birth",birth,3)
self.dump_my_event("Death",death,3)
for event_handle in person.get_event_list():
event = self.db.get_event_from_handle(event_handle)
self.dump_event(event,3)
self.dump_ordinance("baptism",person.get_lds_baptism(),3)
self.dump_ordinance("endowment",person.get_lds_endowment(),3)
self.dump_ordinance("sealed_to_parents",person.get_lds_sealing(),3)
self.write_media_list(person.get_media_list())
if len(person.get_address_list()) > 0:
for address in person.get_address_list():
self.g.write(' <address%s>\n' % conf_priv(address))
self.write_date(address.get_date_object(),4)
self.write_line("street",address.get_street(),4)
self.write_line("city",address.get_city(),4)
self.write_line("state",address.get_state(),4)
self.write_line("country",address.get_country(),4)
self.write_line("postal",address.get_postal_code(),4)
self.write_line("phone",address.get_phone(),4)
if address.get_note() != "":
self.write_note("note",address.get_note_object(),4)
for s in address.get_source_references():
self.dump_source_ref(s,4)
self.g.write(' </address>\n')
self.write_attribute_list(person.get_attribute_list())
self.write_url_list(person.get_url_list())
for alt in person.get_parent_family_handle_list():
if alt[1] != RelLib.Person.CHILD_BIRTH:
mrel=' mrel="%s"' % const.child_rel_notrans[alt[1]]
else:
mrel=''
if alt[2] != RelLib.Person.CHILD_BIRTH:
frel=' frel="%s"' % const.child_rel_notrans[alt[2]]
else:
frel=''
self.g.write(" <childof hlink=\"%s\"%s%s/>\n" % \
("_"+alt[0], mrel, frel))
for family_handle in person.get_family_handle_list():
self.write_ref("parentin",family_handle,3)
self.write_note("note",person.get_note_object(),3)
for s in person.get_source_references():
self.dump_source_ref(s,4)
self.g.write(" </person>\n")
self.g.write(" </people>\n")
if family_len > 0:
self.g.write(" <families>\n")
keys = self.db.get_family_handles()
sorted_keys = []
for key in keys:
family = self.db.get_family_from_handle(key)
value = (family.get_gramps_id (), family)
sorted_keys.append (value)
sorted_keys.sort ()
for (gramps_id, family) in sorted_keys:
if self.callback and count % delta == 0:
self.callback(float(count)/float(total))
count = count + 1
self.write_family_handle(family,2)
fhandle = family.get_father_handle()
mhandle = family.get_mother_handle()
if fhandle:
self.write_ref("father",fhandle,3)
if mhandle:
self.write_ref("mother",mhandle,3)
for event_handle in family.get_event_list():
event = self.db.get_event_from_handle(event_handle)
self.dump_event(event,3)
self.dump_ordinance("sealed_to_spouse",family.get_lds_sealing(),3)
self.write_media_list(family.get_media_list())
if len(family.get_child_handle_list()) > 0:
for person_handle in family.get_child_handle_list():
self.write_ref("child",person_handle,3)
self.write_attribute_list(family.get_attribute_list())
self.write_note("note",family.get_note_object(),3)
for s in family.get_source_references():
self.dump_source_ref(s,3)
self.g.write(" </family>\n")
self.g.write(" </families>\n")
if source_len > 0:
self.g.write(" <sources>\n")
keys = self.db.get_source_handles ()
keys.sort ()
for key in keys:
source = self.db.get_source_from_handle(key)
if self.callback and count % delta == 0:
self.callback(float(count)/float(total))
count = count + 1
self.g.write(" <source id=\"%s\" handle=\"%s\" change=\"%d\">\n" %
(source.get_gramps_id(), "_"+source.get_handle(),
source.get_change_time()))
self.write_force_line("stitle",source.get_title(),3)
self.write_line("sauthor",source.get_author(),3)
self.write_line("spubinfo",source.get_publication_info(),3)
self.write_line("sabbrev",source.get_abbreviation(),3)
if source.get_note() != "":
self.write_note("note",source.get_note_object(),3)
self.write_media_list(source.get_media_list())
self.write_data_map(source.get_data_map())
self.g.write(" </source>\n")
self.g.write(" </sources>\n")
if place_len > 0:
self.g.write(" <places>\n")
keys = self.db.get_place_handles()
keys.sort ()
for key in keys:
try:
place = self.db.get_place_from_handle(key)
if self.callback and count % delta == 0:
self.callback(float(count)/float(total))
self.write_place_obj(place)
except:
print "Could not find place %s" % key
count = count + 1
self.g.write(" </places>\n")
if len(objList) > 0:
self.g.write(" <objects>\n")
keys = self.db.get_media_object_handles()
sorted_keys = []
for key in keys:
obj = self.db.get_object_from_handle (key)
value = (obj.get_gramps_id (), obj)
sorted_keys.append (value)
sorted_keys.sort ()
for (gramps_id, obj) in sorted_keys:
self.write_object(obj)
self.g.write(" </objects>\n")
if len(self.db.get_bookmarks()) > 0:
self.g.write(" <bookmarks>\n")
for person_handle in self.db.get_bookmarks():
self.g.write(' <bookmark hlink="%s"/>\n' % ("_"+person_handle))
self.g.write(" </bookmarks>\n")
if len(self.db.name_group) > 0:
self.g.write(' <groups>\n')
for key in self.db.name_group.keys():
self.g.write(' <group_map name="%s" group="%s"/>\n' %
(key,self.db.name_group[key]))
self.g.write(' </groups>\n')
self.g.write("</database>\n")
def fix(self,line):
l = line.strip()
l = l.replace('&','&amp;')
l = l.replace('>','&gt;')
l = l.replace('<','&lt;')
return l.replace('"','&quot;')
def write_note(self,val,noteobj,indent=0):
if not noteobj:
return
text = noteobj.get()
if not text:
return
if indent != 0:
self.g.write(" " * indent)
format = noteobj.get_format()
if format:
self.g.write('<%s format="%d">' % (val,format))
else:
self.g.write('<%s>' % val)
self.g.write(self.fix(text.rstrip()))
self.g.write("</%s>\n" % val)
def write_text(self,val,text,indent=0):
if not text:
return
if indent != 0:
self.g.write(" " * indent)
self.g.write('<%s>' % val)
self.g.write(self.fix(text.rstrip()))
self.g.write("</%s>\n" % val)
def dump_event(self,event,index=1):
if event:
self.dump_my_event(event.get_name(),event,index)
def write_witness(self,witness_list,index):
if not witness_list:
return
for w in witness_list:
sp = " "*index
com = self.fix(w.get_comment())
if w.get_type() == RelLib.Event.ID:
self.g.write('%s<witness hlink="%s">\n' % (sp,"_"+w.get_value()))
if com:
self.g.write(' %s<comment>%s</comment>\n' % (sp,com))
self.g.write('%s</witness>\n' % sp)
else:
nm = self.fix(w.get_value())
self.g.write('%s<witness name="%s">\n' % (sp,nm))
if com:
self.g.write(' %s<comment>%s</comment>\n' % (sp,com))
self.g.write('%s</witness>\n' % sp)
def dump_my_event(self,name,event,index=1):
if not event or event.is_empty():
return
sp = " " * index
name = const.save_event(name)
self.g.write('%s<event type="%s"%s>\n' % (sp,self.fix(name),conf_priv(event)))
self.write_date(event.get_date_object(),index+1)
self.write_witness(event.get_witness_list(),index+1)
self.write_ref("place",event.get_place_handle(),index+1)
self.write_line("cause",event.get_cause(),index+1)
self.write_line("description",event.get_description(),index+1)
if event.get_note():
self.write_note("note",event.get_note_object(),index+1)
for s in event.get_source_references():
self.dump_source_ref(s,index+1)
self.write_media_list(event.get_media_list(),index+1)
self.g.write("%s</event>\n" % sp)
def dump_ordinance(self,name,ord,index=1):
if not ord:
return
sp = " " * index
sp2 = " " * (index+1)
self.g.write('%s<lds_ord type="%s">\n' % (sp,self.fix(name)))
dateobj = ord.get_date_object()
if dateobj and not dateobj.is_empty():
self.write_date(dateobj,index+1)
if ord.get_temple():
self.g.write('%s<temple val="%s"/>\n' % (sp2,self.fix(ord.get_temple())))
self.write_ref("place",ord.get_place_handle(),index+1)
if ord.get_status() != 0:
self.g.write('%s<status val="%d"/>\n' % (sp2,ord.get_status()))
if ord.get_family_handle():
self.g.write('%s<sealed_to hlink="%s"/>\n' %
(sp2,"_"+self.fix(ord.get_family_handle())))
if ord.get_note() != "":
self.write_note("note",ord.get_note_object(),index+1)
for s in ord.get_source_references():
self.dump_source_ref(s,index+1)
self.g.write('%s</lds_ord>\n' % sp)
def dump_source_ref(self,source_ref,index=1):
source = self.db.get_source_from_handle(source_ref.get_base_handle())
if source:
p = source_ref.get_page()
c = source_ref.get_note()
t = source_ref.get_text()
d = source_ref.get_date_object()
q = source_ref.get_confidence_level()
self.g.write(" " * index)
if p == "" and c == "" and t == "" and d.is_empty() and q == 2:
self.g.write('<sourceref hlink="%s"/>\n' % ("_"+source.get_handle()))
else:
if q == 2:
self.g.write('<sourceref hlink="%s">\n' % ("_"+source.get_handle()))
else:
self.g.write('<sourceref hlink="%s" conf="%d">\n' % ("_"+source.get_handle(),q))
self.write_line("spage",p,index+1)
self.write_text("scomments",c,index+1)
self.write_text("stext",t,index+1)
self.write_date(d,index+1)
self.g.write("%s</sourceref>\n" % (" " * index))
def write_ref(self,label,gid,index=1):
if gid:
self.g.write('%s<%s hlink="%s"/>\n' % (" "*index,label,"_"+gid))
def write_id(self,label,person,index=1):
if person:
self.g.write('%s<%s id="%s" handle="%s" change="%d"' %
(" "*index,label,person.get_gramps_id(),"_"+person.get_handle(),
person.get_change_time()))
comp = person.get_complete_flag()
if comp:
self.g.write(' complete="1"')
self.g.write('>\n')
def write_family_handle(self,family,index=1):
if family:
rel = family.get_relationship()
comp = family.get_complete_flag()
sp = " " * index
self.g.write('%s<family id="%s" handle="%s" change="%d"' %
(sp,family.get_gramps_id(),"_"+family.get_handle(),family.get_change_time()))
if comp:
self.g.write(' complete="1"')
if rel != "":
self.g.write(' type="%s">\n' % const.save_frel(rel))
else:
self.g.write('>\n')
def write_last(self,name,indent=1):
p = name.get_surname_prefix()
n = name.get_surname()
g = name.get_group_as()
self.g.write('%s<last' % (' '*indent))
if p:
self.g.write(' prefix="%s"' % p)
if g:
self.g.write(' group="%s"' % g)
self.g.write('>%s</last>\n' % self.fix(n))
def write_line(self,label,value,indent=1):
if value:
self.g.write('%s<%s>%s</%s>\n' % (' '*indent,label,self.fix(value),label))
def get_iso_date(self,date):
if date[2] == 0:
y = "????"
else:
y = "%04d" % date[2]
if date[1] == 0:
if date[0] == 0:
m = ""
else:
m = "-??"
else:
m = "-%02d" % (date[1])
if date[0] == 0:
d = ''
else:
d = "-%02d" % date[0]
ret = "%s%s%s" % (y,m,d)
# If the result does not contain anything beyond dashes
# and question marks then it's as good as empty
if ret.replace('-','').replace('?','') == '':
ret = ''
return ret
def write_date(self,date,indent=1):
sp = ' '*indent
cal= date.get_calendar()
if cal != Date.CAL_GREGORIAN:
calstr = ' cformat="%s"' % Date.Date.calendar_names[cal]
else:
calstr = ''
qual = date.get_quality()
if qual == Date.QUAL_ESTIMATED:
qual_str = ' quality="estimated"'
elif qual == Date.QUAL_CALCULATED:
qual_str = ' quality="calculated"'
else:
qual_str = ""
mode = date.get_modifier()
if date.is_compound():
d1 = self.get_iso_date(date.get_start_date())
d2 = self.get_iso_date(date.get_stop_date())
if d1 != "" or d2 != "":
self.g.write('%s<daterange start="%s" stop="%s"%s%s/>\n'
% (sp,d1,d2,qual_str,calstr))
elif mode != Date.MOD_TEXTONLY:
date_str = self.get_iso_date(date.get_start_date())
if date_str == "":
return
if mode == Date.MOD_BEFORE:
mode_str = ' type="before"'
elif mode == Date.MOD_AFTER:
mode_str = ' type="after"'
elif mode == Date.MOD_ABOUT:
mode_str = ' type="about"'
else:
mode_str = ""
self.g.write('%s<dateval val="%s"%s%s%s/>\n'
% (sp,date_str,mode_str,qual_str,calstr))
else:
self.g.write('%s<datestr val="%s"/>\n'
%(sp,self.fix(date.get_text())))
def write_force_line(self,label,value,indent=1):
if value != None:
self.g.write('%s<%s>%s</%s>\n' % (' '*indent,label,self.fix(value),label))
def dump_name(self,name,alternative=False,index=1):
sp = " "*index
name_type = name.get_type()
self.g.write('%s<name' % sp)
if alternative:
self.g.write(' alt="1"')
if name_type:
self.g.write(' type="%s"' % name_type)
if name.get_privacy() != 0:
self.g.write(' priv="%d"' % name.get_privacy())
if name.get_sort_as() != 0:
self.g.write(' sort="%d"' % name.get_sort_as())
if name.get_display_as() != 0:
self.g.write(' display="%d"' % name.get_display_as())
self.g.write('>\n')
self.write_line("first",name.get_first_name(),index+1)
self.write_last(name,index+1)
self.write_line("suffix",name.get_suffix(),index+1)
self.write_line("patronymic",name.get_patronymic(),index+1)
self.write_line("title",name.get_title(),index+1)
if name.date:
self.write_date(name.date,4)
if name.get_note() != "":
self.write_note("note",name.get_note_object(),index+1)
for s in name.get_source_references():
self.dump_source_ref(s,index+1)
self.g.write('%s</name>\n' % sp)
def append_value(self,orig,val):
if orig:
return "%s, %s" % (orig,val)
else:
return val
def build_place_title(self,loc):
"Builds a title from a location"
city = self.fix(loc.get_city())
parish = self.fix(loc.get_parish())
state = self.fix(loc.get_state())
country = self.fix(loc.get_country())
county = self.fix(loc.get_county())
value = ""
if city:
value = city
if parish:
value = self.append_value(value,parish)
if county:
value = self.append_value(value,county)
if state:
value = self.append_value(value,state)
if country:
value = self.append_value(value,country)
return value
def dump_location(self,loc):
"Writes the location information to the output file"
city = self.fix(loc.get_city())
parish = self.fix(loc.get_parish())
state = self.fix(loc.get_state())
country = self.fix(loc.get_country())
county = self.fix(loc.get_county())
zip_code = self.fix(loc.get_postal_code())
phone = self.fix(loc.get_phone())
self.g.write(' <location')
if city:
self.g.write(' city="%s"' % city)
if parish:
self.g.write(' parish="%s"' % parish)
if county:
self.g.write(' county="%s"' % county)
if state:
self.g.write(' state="%s"' % state)
if country:
self.g.write(' country="%s"' % country)
if zip_code:
self.g.write(' postal="%s"' % zip_code)
if phone:
self.g.write(' phone="%s"' % phone)
self.g.write('/>\n')
def write_attribute_list(self, list, indent=3):
sp = ' ' * indent
for attr in list:
self.g.write('%s<attribute%s type="%s" value="%s"' % \
(sp,conf_priv(attr),const.save_attr(attr.get_type()),
self.fix(attr.get_value())))
slist = attr.get_source_references()
note = attr.get_note()
if note == "" and len(slist) == 0:
self.g.write('/>\n')
else:
self.g.write('>\n')
for s in attr.get_source_references():
self.dump_source_ref(s,indent+1)
self.write_note("note",attr.get_note_object(),4)
self.g.write('%s</attribute>\n' % sp)
def write_media_list(self,list,indent=3):
sp = ' '*indent
for photo in list:
mobj_id = photo.get_reference_handle()
self.g.write('%s<objref hlink="%s"' % (sp,"_"+mobj_id))
if photo.get_privacy():
self.g.write(' priv="1"')
proplist = photo.get_attribute_list()
refslist = photo.get_source_references()
if len(proplist) == 0 and len(refslist) == 0 \
and photo.get_note() == "":
self.g.write("/>\n")
else:
self.g.write(">\n")
self.write_attribute_list(proplist,indent+1)
for ref in refslist:
self.dump_source_ref(ref,indent+1)
self.write_note("note",photo.get_note_object(),indent+1)
self.g.write('%s</objref>\n' % sp)
def write_data_map(self,datamap,indent=3):
if len(datamap) == 0:
return
sp = ' '*indent
for key in datamap.keys():
self.g.write('%s<data_item key="%s" value="%s"/>' %
(sp,key,datamap[key]))
def write_url_list(self,list):
for url in list:
self.g.write(' <url priv="%d" href="%s"' % \
(url.get_privacy(),self.fix(url.get_path())))
if url.get_description() != "":
self.g.write(' description="%s"' % self.fix(url.get_description()))
self.g.write('/>\n')
def write_place_obj(self,place):
title = self.fix(place.get_title())
longitude = self.fix(place.get_longitude())
lat = self.fix(place.get_latitude())
handle = place.get_gramps_id()
main_loc = place.get_main_location()
llen = len(place.get_alternate_locations()) + len(place.get_url_list()) + \
len(place.get_media_list()) + len(place.get_source_references())
ml_empty = main_loc.is_empty()
note = place.get_note()
if title == "":
title = self.fix(self.build_place_title(place.get_main_location()))
self.g.write(' <placeobj id="%s" handle="%s" change="%d" title="%s"' %
(handle,"_"+place.get_handle(),place.get_change_time(),title))
if longitude or lat or not ml_empty or llen > 0 or note:
self.g.write('>\n')
else:
self.g.write('/>\n')
return
if longitude or lat:
self.g.write(' <coord long="%s" lat="%s"/>\n' % (longitude,lat))
self.dump_location(main_loc)
for loc in place.get_alternate_locations():
self.dump_location(loc)
self.write_media_list(place.get_media_list())
self.write_url_list(place.get_url_list())
if note != "":
self.write_note("note",place.get_note_object(),3)
for s in place.get_source_references():
self.dump_source_ref(s,3)
self.g.write(" </placeobj>\n")
def write_object(self,obj):
handle = obj.get_gramps_id()
mime_type = obj.get_mime_type()
path = obj.get_path()
if self.strip_photos:
path = os.path.basename(path)
self.g.write(' <object id="%s" handle="%s" change="%d" src="%s" mime="%s"' %
(handle,"_"+obj.get_handle(),obj.get_change_time(),path,mime_type))
self.g.write(' description="%s"' % self.fix(obj.get_description()))
alist = obj.get_attribute_list()
note = obj.get_note()
dval = obj.get_date_object()
slist = obj.get_source_references()
if len(alist) == 0 and len(slist) == 0 and note == "" \
and not dval.is_empty():
self.g.write('/>\n')
else:
self.g.write('>\n')
self.write_attribute_list(alist)
if note != "":
self.write_note("note",obj.get_note_object(),3)
if not dval.is_empty():
self.write_date(dval,3)
for s in slist:
self.dump_source_ref(s,3)
self.g.write(" </object>\n")
#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
def sortById(first,second):
fid = first.get_gramps_id()
sid = second.get_gramps_id()
if fid < sid:
return -1
else:
return fid != sid
#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
def conf_priv(obj):
if obj.get_privacy() != 0:
return ' priv="%d"' % obj.get_privacy()
else:
return ''
#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
_title = _('GRAMPS _XML database')
_description = _('The GRAMPS XML database is a format used by older '
'versions of GRAMPS. It is read-write compatible with '
'the present GRAMPS database format.')
_config = None
_filename = 'gramps'
from PluginMgr import register_export
register_export(exportData,_title,_description,_config,_filename)

View File

@@ -0,0 +1,56 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2004-2005 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
"""
This package implements the GrampsDb database. It provides a number
of different backends for different storage mechanisms.
A number of importers and exporters are provided to convert between
the different backend formats.
To obtain a class that implements the backend required you should use the
gramps_db_factory method, likewise for writers use the gramps_db_writer_factory
method and for readers use the gramps_db_reader_factory method. For information
on using these factories see the _GrampsDbFactories.py file comments.
The package also contains GrampsDBCallback which provides signal/slot type
functionality to allow objects to hook into signals that are generated from
the database objects. Read the comments in _GrampsDBCallback.py for more
information.
"""
from _GrampsDbBase import DbState
from _GrampsDbFactories import \
gramps_db_factory, \
gramps_db_writer_factory, \
gramps_db_reader_factory
from _ReadGedcom import GedcomParser
from _WriteGedcom import GedcomWriter
from _WriteXML import XmlWriter
from _GrampsDbExceptions import GrampsDbException
from _GrampsDBCallback import GrampsDBCallback