#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
"""
Base type for all gramps types.
"""
#------------------------------------------------------------------------
#
# Python modules
#
#------------------------------------------------------------------------
from __future__ import unicode_literals
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
from ..const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from ..constfunc import STRTYPE, cuni
_UNKNOWN = _('Unknown')
#-------------------------------------------------------------------------
#
# GrampsTypeMeta class
#
#-------------------------------------------------------------------------
GrampsTypeC = GrampsTypeMeta(str('GrampsTypeC'), (object, ), {})
#-------------------------------------------------------------------------
#
# GrampsType class
#
#-------------------------------------------------------------------------
## python 3: class GrampsType(object, metaclass=GrampsTypeMeta):
[docs]class GrampsType(GrampsTypeC):
"""Base class for all Gramps object types.
:cvar _DATAMAP:
(list) 3-tuple like (index, localized_string, english_string).
:cvar _BLACKLIST:
List of indices to ignore (obsolete/retired entries).
(gramps policy is never to delete type values, or reuse the name (TOKEN)
of any specific type value)
:cvar POS_<x>: (int)
Position of <x> attribute in the serialized format of
an instance.
.. warning:: The POS_<x> class variables reflect the serialized object,
they have to be updated in case the data structure or the
:meth:`serialize` method changes!
:cvar _CUSTOM: (int) a custom type object
:cvar _DEFAULT: (int) the default type, used on creation
:attribute value: (int) Returns or sets integer value
:attribute string: (str) Returns or sets string value
"""
(POS_VALUE, POS_STRING) = list(range(2))
_CUSTOM = 0
_DEFAULT = 0
_DATAMAP = []
_BLACKLIST = None
_MENU = None
__slots__ = ('__value', '__string')
def __getstate__(self):
return {'__value': self.__value, '__string': self.__string}
def __setstate__(self, dict_):
self.__value = dict_['__value']
if self.__value == self._CUSTOM:
self.__string = dict_['__string']
else:
self.__string = ''
def __init__(self, value=None):
"""
Create a new type, initialize the value from one of several possible
states.
"""
self.set(value)
def __set_tuple(self, value):
"Set the value/string properties from a tuple."
val, strg = self._DEFAULT, ''
if value:
val = value[0]
if len(value) > 1 and val == self._CUSTOM:
strg = value[1]
self.__value = val
self.__string = strg
def __set_int(self, value):
"Set the value/string properties from an integer."
self.__value = value
self.__string = ''
def __set_instance(self, value):
"Set the value/string properties from another grampstype."
self.__value = value.value
if self.__value == self._CUSTOM:
self.__string = value.string
else:
self.__string = ''
def __set_str(self, value):
"Set the value/string properties from a string."
self.__value = self._S2IMAP.get(value, self._CUSTOM)
if self.__value == self._CUSTOM:
self.__string = value
else:
self.__string = ''
[docs] def set(self, value):
"Set the value/string properties from the passed in value."
if isinstance(value, tuple):
self.__set_tuple(value)
elif isinstance(value, int):
self.__set_int(value)
elif isinstance(value, self.__class__):
self.__set_instance(value)
elif isinstance(value, STRTYPE):
self.__set_str(value)
else:
self.__value = self._DEFAULT
self.__string = ''
[docs] def set_from_xml_str(self, value):
"""
This method sets the type instance based on the untranslated string
(obtained e.g. from XML).
"""
if value in self._E2IMAP:
self.__value = self._E2IMAP[value]
self.__string = ''
if self.__value == self._CUSTOM:
#if the custom event is actually 'Custom' then we should save it
# with that string value. That is, 'Custom' is in _E2IMAP
self.__string = value
else:
self.__value = self._CUSTOM
self.__string = value
[docs] def xml_str(self):
"""
Return the untranslated string (e.g. suitable for XML) corresponding
to the type.
"""
if self.__value == self._CUSTOM:
return self.__string
elif self.__value in self._I2EMAP:
return self._I2EMAP[self.__value]
else:
return _UNKNOWN
[docs] def serialize(self):
"""Convert the object to a serialized tuple of data. """
return (self.__value, self.__string)
[docs] def to_struct(self):
"""
Convert the data held in this object to a structure (eg,
struct) that represents all the data elements.
This method is used to recursively convert the object into a
self-documenting form that can easily be used for various
purposes, including diffs and queries.
These structures may be primitive Python types (string,
integer, boolean, etc.) or complex Python types (lists,
tuples, or dicts). If the return type is a dict, then the keys
of the dict match the fieldname of the object. If the return
struct (or value of a dict key) is a list, then it is a list
of structs. Otherwise, the struct is just the value of the
attribute.
:returns: Returns a struct containing the data of the object.
:rtype: dict
"""
return {"_class": self.__class__.__name__,
"value": self.__value,
"string": cuni(self)}
@classmethod
[docs] def from_struct(cls, struct):
"""
Given a struct data representation, return a serialized object.
:returns: Returns a serialized object
"""
default = cls()
if struct.get("value", cls._CUSTOM) == cls._CUSTOM:
return (struct.get("value", default.value), struct.get("string", ""))
else:
return (struct.get("value", default.value), '')
[docs] def unserialize(self, data):
"""Convert a serialized tuple of data to an object."""
self.__value, self.__string = data
if self.__value != self._CUSTOM:
self.__string = ''
return self
def __str__(self):
if self.__value == self._CUSTOM:
return self.__string
else:
return self._I2SMAP.get(self.__value, _UNKNOWN)
def __int__(self):
return self.__value
[docs] def get_map(self):
return self._I2SMAP
[docs] def get_standard_names(self):
"""Return the list of localized names for all standard types."""
return [s for (i, s) in list(self._I2SMAP.items())
if (i != self._CUSTOM) and s.strip()]
[docs] def get_standard_xml(self):
"""Return the list of XML (english) names for all standard types."""
return [s for (i, s) in list(self._I2EMAP.items())
if (i != self._CUSTOM) and s.strip()]
[docs] def is_custom(self):
return self.__value == self._CUSTOM
[docs] def is_default(self):
return self.__value == self._DEFAULT
[docs] def get_custom(self):
return self._CUSTOM
def __eq__(self, value):
if isinstance(value, int):
return self.__value == value
elif isinstance(value, STRTYPE):
if self.__value == self._CUSTOM:
return self.__string == value
else:
return self._I2SMAP.get(self.__value) == value
elif isinstance(value, tuple):
if self.__value == self._CUSTOM:
return (self.__value, self.__string) == value
else:
return self.__value == value[0]
else:
if value.value == self._CUSTOM:
return self.__string == value.string
else:
return self.__value == value.value
def __ne__(self, value):
return not self.__eq__(value)
## Python 3 does not have __cmp__
## def __cmp__(self, value):
## print ('cmp', type(value), STRTYPE)
## if isinstance(value, int):
## return cmp(self.__value, value)
## elif isinstance(value, STRTYPE):
## print('ok!')
## if self.__value == self._CUSTOM:
## return cmp(self.__string, value)
## else:
## print (self._I2SMAP.get(self.__value), value, cmp(self._I2SMAP.get(self.__value), value))
## return cmp(self._I2SMAP.get(self.__value), value)
## elif isinstance(value, tuple):
## if self.__value == self._CUSTOM:
## return cmp((self.__value, self.__string), value)
## else:
## return cmp(self.__value, value[0])
## else:
## if value.value == self._CUSTOM:
## return cmp(self.__string, value.string)
## else:
## return cmp(self.__value, value.value)
value = property(__int__, __set_int, None, "Returns or sets integer value")
string = property(__str__, __set_str, None, "Returns or sets string value")