Merge remote-tracking branch 'upstream/master' into bug9475
This commit is contained in:
commit
0cfc375a27
@ -26,3 +26,4 @@ from .filter import FilterProxyDb
|
||||
from .living import LivingProxyDb
|
||||
from .private import PrivateProxyDb
|
||||
from .referencedbyselection import ReferencedBySelectionProxyDb
|
||||
from .cache import CacheProxyDb
|
||||
|
180
gramps/gen/proxy/cache.py
Normal file
180
gramps/gen/proxy/cache.py
Normal file
@ -0,0 +1,180 @@
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (c) 2016 Gramps Development Team
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""
|
||||
Proxy class for the Gramps databases. Caches lookups from handles.
|
||||
"""
|
||||
|
||||
class CacheProxyDb:
|
||||
"""
|
||||
A Proxy for a database with cached lookups on handles.
|
||||
|
||||
Does not invalid caches. Should be used only in read-only
|
||||
places, and not where caches are altered.
|
||||
"""
|
||||
def __init__(self, database):
|
||||
"""
|
||||
CacheProxy will cache items based on their handle.
|
||||
|
||||
Assumes all handles (regardless of type) are unique.
|
||||
Database is called self.db for consistency with other
|
||||
proxies.
|
||||
"""
|
||||
self.db = database
|
||||
self.clear_cache()
|
||||
|
||||
def __getattr__(self, attr):
|
||||
"""
|
||||
If an attribute isn't found here, use the self.db
|
||||
version.
|
||||
"""
|
||||
return getattr(self.db, attr)
|
||||
|
||||
def clear_cache(self, handle=None):
|
||||
"""
|
||||
Clears all caches if handle is None, or
|
||||
specific entry.
|
||||
"""
|
||||
from gramps.gui.views.treemodels.lru import LRU
|
||||
if handle:
|
||||
del self.cache_handle[handle]
|
||||
else:
|
||||
self.cache_handle = LRU(100000)
|
||||
|
||||
def get_person_from_handle(self, handle):
|
||||
"""
|
||||
Gets item from cache if it exists. Converts
|
||||
handles to string, for uniformity.
|
||||
"""
|
||||
if isinstance(handle, bytes):
|
||||
handle = str(handle, "utf-8")
|
||||
if handle not in self.cache_handle:
|
||||
self.cache_handle[handle] = self.db.get_person_from_handle(handle)
|
||||
return self.cache_handle[handle]
|
||||
|
||||
def get_event_from_handle(self, handle):
|
||||
"""
|
||||
Gets item from cache if it exists. Converts
|
||||
handles to string, for uniformity.
|
||||
"""
|
||||
if isinstance(handle, bytes):
|
||||
handle = str(handle, "utf-8")
|
||||
if handle not in self.cache_handle:
|
||||
self.cache_handle[handle] = self.db.get_event_from_handle(handle)
|
||||
return self.cache_handle[handle]
|
||||
|
||||
def get_family_from_handle(self, handle):
|
||||
"""
|
||||
Gets item from cache if it exists. Converts
|
||||
handles to string, for uniformity.
|
||||
"""
|
||||
if isinstance(handle, bytes):
|
||||
handle = str(handle, "utf-8")
|
||||
if handle not in self.cache_handle:
|
||||
self.cache_handle[handle] = self.db.get_family_from_handle(handle)
|
||||
return self.cache_handle[handle]
|
||||
|
||||
def get_repository_from_handle(self, handle):
|
||||
"""
|
||||
Gets item from cache if it exists. Converts
|
||||
handles to string, for uniformity.
|
||||
"""
|
||||
if isinstance(handle, bytes):
|
||||
handle = str(handle, "utf-8")
|
||||
if handle not in self.cache_handle:
|
||||
self.cache_handle[handle] = self.db.get_repository_from_handle(handle)
|
||||
return self.cache_handle[handle]
|
||||
|
||||
def get_place_from_handle(self, handle):
|
||||
"""
|
||||
Gets item from cache if it exists. Converts
|
||||
handles to string, for uniformity.
|
||||
"""
|
||||
if isinstance(handle, bytes):
|
||||
handle = str(handle, "utf-8")
|
||||
if handle not in self.cache_handle:
|
||||
self.cache_handle[handle] = self.db.get_place_from_handle(handle)
|
||||
return self.cache_handle[handle]
|
||||
|
||||
def get_place_from_handle(self, handle):
|
||||
"""
|
||||
Gets item from cache if it exists. Converts
|
||||
handles to string, for uniformity.
|
||||
"""
|
||||
if isinstance(handle, bytes):
|
||||
handle = str(handle, "utf-8")
|
||||
if handle not in self.cache_handle:
|
||||
self.cache_handle[handle] = self.db.get_place_from_handle(handle)
|
||||
return self.cache_handle[handle]
|
||||
|
||||
def get_citation_from_handle(self, handle):
|
||||
"""
|
||||
Gets item from cache if it exists. Converts
|
||||
handles to string, for uniformity.
|
||||
"""
|
||||
if isinstance(handle, bytes):
|
||||
handle = str(handle, "utf-8")
|
||||
if handle not in self.cache_handle:
|
||||
self.cache_handle[handle] = self.db.get_citation_from_handle(handle)
|
||||
return self.cache_handle[handle]
|
||||
|
||||
def get_source_from_handle(self, handle):
|
||||
"""
|
||||
Gets item from cache if it exists. Converts
|
||||
handles to string, for uniformity.
|
||||
"""
|
||||
if isinstance(handle, bytes):
|
||||
handle = str(handle, "utf-8")
|
||||
if handle not in self.cache_handle:
|
||||
self.cache_handle[handle] = self.db.get_source_from_handle(handle)
|
||||
return self.cache_handle[handle]
|
||||
|
||||
def get_note_from_handle(self, handle):
|
||||
"""
|
||||
Gets item from cache if it exists. Converts
|
||||
handles to string, for uniformity.
|
||||
"""
|
||||
if isinstance(handle, bytes):
|
||||
handle = str(handle, "utf-8")
|
||||
if handle not in self.cache_handle:
|
||||
self.cache_handle[handle] = self.db.get_note_from_handle(handle)
|
||||
return self.cache_handle[handle]
|
||||
|
||||
def get_media_from_handle(self, handle):
|
||||
"""
|
||||
Gets item from cache if it exists. Converts
|
||||
handles to string, for uniformity.
|
||||
"""
|
||||
if isinstance(handle, bytes):
|
||||
handle = str(handle, "utf-8")
|
||||
if handle not in self.cache_handle:
|
||||
self.cache_handle[handle] = self.db.get_media_from_handle(handle)
|
||||
return self.cache_handle[handle]
|
||||
|
||||
def get_tag_from_handle(self, handle):
|
||||
"""
|
||||
Gets item from cache if it exists. Converts
|
||||
handles to string, for uniformity.
|
||||
"""
|
||||
if isinstance(handle, bytes):
|
||||
handle = str(handle, "utf-8")
|
||||
if handle not in self.cache_handle:
|
||||
self.cache_handle[handle] = self.db.get_tag_from_handle(handle)
|
||||
return self.cache_handle[handle]
|
@ -249,7 +249,8 @@ class Callback:
|
||||
for (k, v) in s.items():
|
||||
if k in self.__signal_map:
|
||||
# signal name clash
|
||||
sys.stderr.write("Warning: signal name clash: %s\n" % str(k))
|
||||
sys.stderr.write("Warning: signal name clash: %s\n"
|
||||
% str(k))
|
||||
self.__signal_map[k] = v
|
||||
# Set to None to prevent a memory leak in this recursive function
|
||||
trav = None
|
||||
@ -258,8 +259,8 @@ class Callback:
|
||||
# of signals that this instance can emit.
|
||||
|
||||
self._log("registered signals: \n %s\n" %
|
||||
"\n ".join([ "%s: %s" % (k, v) for (k, v)
|
||||
in list(self.__signal_map.items()) ]))
|
||||
"\n ".join(["%s: %s" % (k, v) for (k, v)
|
||||
in list(self.__signal_map.items())]))
|
||||
|
||||
|
||||
def connect(self, signal_name, callback):
|
||||
@ -273,7 +274,7 @@ class Callback:
|
||||
# Check that signal exists.
|
||||
if signal_name not in self.__signal_map:
|
||||
self._log("Warning: attempt to connect to unknown signal: %s\n"
|
||||
% str(signal_name))
|
||||
% str(signal_name))
|
||||
return
|
||||
|
||||
# Add callable to callback_map
|
||||
|
@ -72,17 +72,17 @@ NOTECLASS = 'Note'
|
||||
TAGCLASS = 'Tag'
|
||||
|
||||
CLASS2KEY = {
|
||||
PERSONCLASS: PERSONKEY,
|
||||
FAMILYCLASS: FAMILYKEY,
|
||||
EVENTCLASS: EVENTKEY,
|
||||
PLACECLASS: PLACEKEY,
|
||||
MEDIACLASS: MEDIAKEY,
|
||||
SOURCECLASS: SOURCEKEY,
|
||||
CITATIONCLASS: CITATIONKEY,
|
||||
REPOCLASS: REPOKEY,
|
||||
NOTECLASS: NOTEKEY,
|
||||
TAGCLASS: TAGKEY
|
||||
}
|
||||
PERSONCLASS: PERSONKEY,
|
||||
FAMILYCLASS: FAMILYKEY,
|
||||
EVENTCLASS: EVENTKEY,
|
||||
PLACECLASS: PLACEKEY,
|
||||
MEDIACLASS: MEDIAKEY,
|
||||
SOURCECLASS: SOURCEKEY,
|
||||
CITATIONCLASS: CITATIONKEY,
|
||||
REPOCLASS: REPOKEY,
|
||||
NOTECLASS: NOTEKEY,
|
||||
TAGCLASS: TAGKEY
|
||||
}
|
||||
|
||||
def _return(*args):
|
||||
"""
|
||||
@ -115,17 +115,17 @@ class CallbackManager:
|
||||
#no handles to track
|
||||
self.database = database
|
||||
self.__handles = {
|
||||
PERSONKEY: [],
|
||||
FAMILYKEY: [],
|
||||
EVENTKEY: [],
|
||||
PLACEKEY: [],
|
||||
MEDIAKEY: [],
|
||||
SOURCEKEY: [],
|
||||
CITATIONKEY: [],
|
||||
REPOKEY: [],
|
||||
NOTEKEY: [],
|
||||
TAGKEY: [],
|
||||
}
|
||||
PERSONKEY: [],
|
||||
FAMILYKEY: [],
|
||||
EVENTKEY: [],
|
||||
PLACEKEY: [],
|
||||
MEDIAKEY: [],
|
||||
SOURCEKEY: [],
|
||||
CITATIONKEY: [],
|
||||
REPOKEY: [],
|
||||
NOTEKEY: [],
|
||||
TAGKEY: [],
|
||||
}
|
||||
#no custom callbacks to do
|
||||
self.custom_signal_keys = []
|
||||
#set up callbacks to do nothing
|
||||
@ -180,7 +180,7 @@ class CallbackManager:
|
||||
handles = ahandledict.get(key)
|
||||
if handles:
|
||||
self.__handles[key] = list(
|
||||
set(self.__handles[key]).union(handles))
|
||||
set(self.__handles[key]).union(handles))
|
||||
|
||||
def unregister_handles(self, ahandledict):
|
||||
"""
|
||||
@ -199,17 +199,17 @@ class CallbackManager:
|
||||
Unregister all handles that are registered
|
||||
"""
|
||||
self.__handles = {
|
||||
PERSONKEY: [],
|
||||
FAMILYKEY: [],
|
||||
EVENTKEY: [],
|
||||
PLACEKEY: [],
|
||||
MEDIAKEY: [],
|
||||
SOURCEKEY: [],
|
||||
CITATIONKEY: [],
|
||||
REPOKEY: [],
|
||||
NOTEKEY: [],
|
||||
TAGKEY: [],
|
||||
}
|
||||
PERSONKEY: [],
|
||||
FAMILYKEY: [],
|
||||
EVENTKEY: [],
|
||||
PLACEKEY: [],
|
||||
MEDIAKEY: [],
|
||||
SOURCEKEY: [],
|
||||
CITATIONKEY: [],
|
||||
REPOKEY: [],
|
||||
NOTEKEY: [],
|
||||
TAGKEY: [],
|
||||
}
|
||||
|
||||
def register_callbacks(self, callbackdict):
|
||||
"""
|
||||
@ -253,15 +253,12 @@ class CallbackManager:
|
||||
signal = key + method
|
||||
self.__do_unconnect(signal)
|
||||
self.__callbacks[signal][1] = self.database.connect(
|
||||
signal,
|
||||
self.__callbackcreator(signal))
|
||||
signal, self.__callbackcreator(signal))
|
||||
for method in METHODS_NONE:
|
||||
signal = key + method
|
||||
self.__do_unconnect(signal)
|
||||
self.__callbacks[signal][1] = self.database.connect(
|
||||
signal,
|
||||
self.__callbackcreator(signal,
|
||||
noarg=True))
|
||||
signal, self.__callbackcreator(signal, noarg=True))
|
||||
|
||||
def __do_callback(self, signal, *arg):
|
||||
"""
|
||||
@ -304,7 +301,8 @@ class CallbackManager:
|
||||
managed automatically.
|
||||
"""
|
||||
if self.database:
|
||||
self.custom_signal_keys.append(self.database.connect(name, callback))
|
||||
self.custom_signal_keys.append(self.database.connect(name,
|
||||
callback))
|
||||
|
||||
def __callbackcreator(self, signal, noarg=False):
|
||||
"""
|
||||
@ -338,17 +336,17 @@ def directhandledict(baseobj):
|
||||
Build a handledict from baseobj with all directly referenced objects
|
||||
"""
|
||||
handles = {
|
||||
PERSONKEY: [],
|
||||
FAMILYKEY: [],
|
||||
EVENTKEY: [],
|
||||
PLACEKEY: [],
|
||||
MEDIAKEY: [],
|
||||
SOURCEKEY: [],
|
||||
CITATIONKEY: [],
|
||||
REPOKEY: [],
|
||||
NOTEKEY: [],
|
||||
TAGKEY: [],
|
||||
}
|
||||
PERSONKEY: [],
|
||||
FAMILYKEY: [],
|
||||
EVENTKEY: [],
|
||||
PLACEKEY: [],
|
||||
MEDIAKEY: [],
|
||||
SOURCEKEY: [],
|
||||
CITATIONKEY: [],
|
||||
REPOKEY: [],
|
||||
NOTEKEY: [],
|
||||
TAGKEY: [],
|
||||
}
|
||||
for classn, handle in baseobj.get_referenced_handles():
|
||||
handles[CLASS2KEY[classn]].append(handle)
|
||||
return handles
|
||||
@ -359,17 +357,17 @@ def handledict(baseobj):
|
||||
referenced base obj that are present
|
||||
"""
|
||||
handles = {
|
||||
PERSONKEY: [],
|
||||
FAMILYKEY: [],
|
||||
EVENTKEY: [],
|
||||
PLACEKEY: [],
|
||||
MEDIAKEY: [],
|
||||
SOURCEKEY: [],
|
||||
CITATIONKEY: [],
|
||||
REPOKEY: [],
|
||||
NOTEKEY: [],
|
||||
TAGKEY: [],
|
||||
}
|
||||
PERSONKEY: [],
|
||||
FAMILYKEY: [],
|
||||
EVENTKEY: [],
|
||||
PLACEKEY: [],
|
||||
MEDIAKEY: [],
|
||||
SOURCEKEY: [],
|
||||
CITATIONKEY: [],
|
||||
REPOKEY: [],
|
||||
NOTEKEY: [],
|
||||
TAGKEY: [],
|
||||
}
|
||||
for classn, handle in baseobj.get_referenced_handles_recursively():
|
||||
handles[CLASS2KEY[classn]].append(handle)
|
||||
return handles
|
||||
|
@ -48,14 +48,14 @@ import math
|
||||
degrees = "1"
|
||||
North = _("%(north_latitude)s N") % {'north_latitude' : degrees}
|
||||
South = _("%(south_latitude)s S") % {'south_latitude' : degrees}
|
||||
East = _("%(east_longitude)s E") % {'east_longitude' : degrees}
|
||||
West = _("%(west_longitude)s W") % {'west_longitude' : degrees}
|
||||
East = _("%(east_longitude)s E") % {'east_longitude' : degrees}
|
||||
West = _("%(west_longitude)s W") % {'west_longitude' : degrees}
|
||||
|
||||
# extract letters we really need
|
||||
North = North.replace("1"," ").strip()
|
||||
South = South.replace("1"," ").strip()
|
||||
East = East.replace("1"," ").strip()
|
||||
West = West.replace("1"," ").strip()
|
||||
North = North.replace("1", " ").strip()
|
||||
South = South.replace("1", " ").strip()
|
||||
East = East.replace("1", " ").strip()
|
||||
West = West.replace("1", " ").strip()
|
||||
|
||||
# build dictionary with translation en to local language
|
||||
translate_en_loc = {}
|
||||
@ -79,7 +79,7 @@ if 'N' == South or 'S' == North or 'E' == West or 'W' == East:
|
||||
#
|
||||
#------------------
|
||||
|
||||
def __convert_structure_to_float(sign, degs, mins=0, secs=0.0) :
|
||||
def __convert_structure_to_float(sign, degs, mins=0, secs=0.0):
|
||||
"""helper function which converts a structure to a nice
|
||||
representation
|
||||
"""
|
||||
@ -94,29 +94,29 @@ def __convert_using_float_repr(stringValue):
|
||||
""" helper function that tries to convert the string using the float
|
||||
representation
|
||||
"""
|
||||
try :
|
||||
try:
|
||||
v = float(stringValue)
|
||||
return v
|
||||
except ValueError :
|
||||
return None;
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
def __convert_using_colon_repr(stringValue):
|
||||
""" helper function that tries to convert the string using the colon
|
||||
representation
|
||||
"""
|
||||
if stringValue.find(r':') == -1 :
|
||||
if stringValue.find(r':') == -1:
|
||||
return None
|
||||
|
||||
l = stringValue.split(':')
|
||||
if len(l) < 2 or len(l) > 3:
|
||||
return None
|
||||
l[0]=l[0].strip()
|
||||
l[0] = l[0].strip()
|
||||
# if no characters before ':' nothing useful is input!
|
||||
if len(l[0]) == 0:
|
||||
return None
|
||||
if l[0][0] in ['+', '-']:
|
||||
sign = l[0][0]
|
||||
l[0]=l[0][1:].strip()
|
||||
l[0] = l[0][1:].strip()
|
||||
# regard a second sign as an error
|
||||
if l[0][0] in ['+', '-']:
|
||||
return None
|
||||
@ -134,7 +134,7 @@ def __convert_using_colon_repr(stringValue):
|
||||
return None
|
||||
except:
|
||||
return None
|
||||
secs=0.
|
||||
secs = 0.
|
||||
if len(l) == 3:
|
||||
try:
|
||||
secs = float(l[2])
|
||||
@ -153,16 +153,16 @@ def __convert_using_classic_repr(stringValue, typedeg):
|
||||
return None # not a valid lat or lon
|
||||
|
||||
#exchange some characters
|
||||
stringValue = stringValue.replace('°',r'_')
|
||||
stringValue = stringValue.replace('°', r'_')
|
||||
#allow to input ° as #, UTF-8 code c2b00a
|
||||
stringValue = stringValue.replace('º',r'_')
|
||||
#allow to input º as #, UTF-8 code c2ba0a
|
||||
stringValue = stringValue.replace(r'#',r'_')
|
||||
stringValue = stringValue.replace('º', r'_')
|
||||
#allow to input º as #, UTF-8 code c2b a0a
|
||||
stringValue = stringValue.replace(r'#', r'_')
|
||||
#allow to input " as ''
|
||||
stringValue = stringValue.replace(r"''",r'"')
|
||||
stringValue = stringValue.replace(r"''", r'"')
|
||||
#allow some special unicode symbols
|
||||
stringValue = stringValue.replace('\u2033',r'"')
|
||||
stringValue = stringValue.replace('\u2032',r"'")
|
||||
stringValue = stringValue.replace('\u2033', r'"')
|
||||
stringValue = stringValue.replace('\u2032', r"'")
|
||||
#ignore spaces, a regex with \s* would be better here...
|
||||
stringValue = stringValue.replace(r' ', r'')
|
||||
stringValue = stringValue.replace(r'\t', r'')
|
||||
@ -193,9 +193,9 @@ def __convert_using_classic_repr(stringValue, typedeg):
|
||||
l2[0] = l4[0]
|
||||
# Convert the decimal part of minutes to seconds
|
||||
try:
|
||||
lsecs=float('0.' + l4[1]) * 60.0
|
||||
# Set the seconds followed by direction letter N/S/W/E
|
||||
l2[1] = str(lsecs) + '"' + l2[1]
|
||||
lsecs = float('0.' + l4[1]) * 60.0
|
||||
# Set the seconds followed by direction letter N/S/W/E
|
||||
l2[1] = str(lsecs) + '"' + l2[1]
|
||||
except:
|
||||
return None
|
||||
|
||||
@ -269,13 +269,13 @@ def __convert_using_modgedcom_repr(val, typedeg):
|
||||
stringValue = '-' + val[:pos]
|
||||
else:
|
||||
return None
|
||||
try :
|
||||
try:
|
||||
v = float(stringValue)
|
||||
return v
|
||||
except ValueError :
|
||||
return None;
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
def __convert_float_val(val, typedeg = "lat"):
|
||||
def __convert_float_val(val, typedeg="lat"):
|
||||
# function converting input to float, recognizing decimal input, or
|
||||
# degree notation input. Only english input
|
||||
# There is no check on maximum/minimum of degree
|
||||
@ -287,7 +287,7 @@ def __convert_float_val(val, typedeg = "lat"):
|
||||
#this is no problem, as a number like 100,000.20 cannot appear in
|
||||
#lat/lon
|
||||
#change XX,YY into XX.YY
|
||||
if val.find(r'.') == -1 :
|
||||
if val.find(r'.') == -1:
|
||||
val = val.replace(',', '.')
|
||||
|
||||
# format: XX.YYYY
|
||||
@ -297,17 +297,17 @@ def __convert_float_val(val, typedeg = "lat"):
|
||||
|
||||
# format: XX:YY:ZZ
|
||||
v = __convert_using_colon_repr(val)
|
||||
if v is not None :
|
||||
if v is not None:
|
||||
return v
|
||||
|
||||
# format: XX° YY' ZZ" [NSWE]
|
||||
v = __convert_using_classic_repr(val, typedeg)
|
||||
if v is not None :
|
||||
if v is not None:
|
||||
return v
|
||||
|
||||
# format XX.YYYY[NSWE]
|
||||
v = __convert_using_modgedcom_repr(val, typedeg)
|
||||
if v is not None :
|
||||
if v is not None:
|
||||
return v
|
||||
|
||||
# no format succeeded
|
||||
@ -365,12 +365,12 @@ def conv_lat_lon(latitude, longitude, format="D.D4"):
|
||||
# we start the function changing latitude/longitude in english
|
||||
if latitude.find('N') == -1 and latitude.find('S') == -1:
|
||||
# entry is not in english, convert to english
|
||||
latitude = latitude.replace(translate_en_loc['N'],'N')
|
||||
latitude = latitude.replace(translate_en_loc['S'],'S')
|
||||
latitude = latitude.replace(translate_en_loc['N'], 'N')
|
||||
latitude = latitude.replace(translate_en_loc['S'], 'S')
|
||||
if longitude.find('E') == -1 and longitude.find('W') == -1:
|
||||
# entry is not in english, convert to english
|
||||
longitude = longitude.replace(translate_en_loc['W'],'W')
|
||||
longitude = longitude.replace(translate_en_loc['E'],'E')
|
||||
longitude = longitude.replace(translate_en_loc['W'], 'W')
|
||||
longitude = longitude.replace(translate_en_loc['E'], 'E')
|
||||
|
||||
# take away leading spaces
|
||||
latitude = latitude.lstrip()
|
||||
@ -383,7 +383,7 @@ def conv_lat_lon(latitude, longitude, format="D.D4"):
|
||||
longitude = longitude[1:] + longitude[0]
|
||||
|
||||
# convert to float
|
||||
lat_float = __convert_float_val(latitude, 'lat')
|
||||
lat_float = __convert_float_val(latitude, 'lat')
|
||||
lon_float = __convert_float_val(longitude, 'lon')
|
||||
|
||||
# give output (localized if needed)
|
||||
@ -403,19 +403,19 @@ def conv_lat_lon(latitude, longitude, format="D.D4"):
|
||||
# correct possible roundoff error
|
||||
str_lon = "%.4f" % (lon_float)
|
||||
if str_lon == "180.0000":
|
||||
str_lon ="-180.0000"
|
||||
return ("%.4f" % lat_float , str_lon)
|
||||
str_lon = "-180.0000"
|
||||
return ("%.4f" % lat_float, str_lon)
|
||||
|
||||
if format == "D.D8" or format == "RT90":
|
||||
# correct possible roundoff error
|
||||
str_lon = "%.8f" % (lon_float)
|
||||
if str_lon == "180.00000000":
|
||||
str_lon ="-180.00000000"
|
||||
str_lon = "-180.00000000"
|
||||
if format == "RT90":
|
||||
tx = __conv_WGS84_SWED_RT90(lat_float, lon_float)
|
||||
return ("%i" % tx[0], "%i" % tx[1])
|
||||
else:
|
||||
return ("%.8f" % lat_float , str_lon)
|
||||
return ("%.8f" % lat_float, str_lon)
|
||||
|
||||
if format == "GEDCOM":
|
||||
# The 5.5.1 spec is inconsistent. Length is supposedly 5 to 8 chars,
|
||||
@ -426,20 +426,21 @@ def conv_lat_lon(latitude, longitude, format="D.D4"):
|
||||
if lon_float >= 0:
|
||||
str_lon = "%.6f" % (lon_float)
|
||||
if str_lon == "180.000000":
|
||||
str_lon ="W180.000000"
|
||||
str_lon = "W180.000000"
|
||||
else:
|
||||
str_lon = "E" + str_lon
|
||||
else:
|
||||
str_lon = "W" + "%.6f" % (-lon_float)
|
||||
str_lon = str_lon[:-5] + str_lon[-5:].rstrip("0")
|
||||
str_lat = ("%s%.6f" % (("N", lat_float) if lat_float >= 0 else ("S", -lat_float)))
|
||||
str_lat = ("%s%.6f" % (("N", lat_float) if lat_float >= 0
|
||||
else ("S", -lat_float)))
|
||||
str_lat = str_lat[:-5] + str_lat[-5:].rstrip("0")
|
||||
return (str_lat, str_lon)
|
||||
|
||||
deg_lat = int(lat_float)
|
||||
deg_lon = int(lon_float)
|
||||
min_lat = int(60. * (lat_float - float(deg_lat) ))
|
||||
min_lon = int(60. * (lon_float - float(deg_lon) ))
|
||||
min_lat = int(60. * (lat_float - float(deg_lat)))
|
||||
min_lon = int(60. * (lon_float - float(deg_lon)))
|
||||
sec_lat = 3600. * (lat_float - float(deg_lat) - float(min_lat) / 60.)
|
||||
sec_lon = 3600. * (lon_float - float(deg_lon) - float(min_lon) / 60.)
|
||||
|
||||
@ -463,14 +464,14 @@ def conv_lat_lon(latitude, longitude, format="D.D4"):
|
||||
dir_lat = translate_en_loc['N']
|
||||
else:
|
||||
dir_lat = translate_en_loc['S']
|
||||
sign_lat= "-"
|
||||
sign_lon= "+"
|
||||
sign_lat = "-"
|
||||
sign_lon = "+"
|
||||
dir_lon = ""
|
||||
if lon_float >= 0.:
|
||||
dir_lon = translate_en_loc['E']
|
||||
else:
|
||||
dir_lon = translate_en_loc['W']
|
||||
sign_lon= "-"
|
||||
sign_lon = "-"
|
||||
|
||||
if format == "DEG":
|
||||
str_lat = ("%d°%02d'%05.2f\"" % (deg_lat, min_lat, sec_lat)) + dir_lat
|
||||
@ -497,10 +498,10 @@ def conv_lat_lon(latitude, longitude, format="D.D4"):
|
||||
return (str_lat, str_lon)
|
||||
|
||||
if format == "DEG-:":
|
||||
if sign_lat=="+":
|
||||
if sign_lat == "+":
|
||||
sign_lat = ""
|
||||
sign_lon_h = sign_lon
|
||||
if sign_lon=="+":
|
||||
if sign_lon == "+":
|
||||
sign_lon_h = ""
|
||||
str_lat = sign_lat + ("%d:%02d:%05.2f" % (deg_lat, min_lat, sec_lat))
|
||||
str_lon = sign_lon_h + ("%d:%02d:%05.2f" % (deg_lon, min_lon, sec_lon))
|
||||
@ -598,7 +599,7 @@ def __conv_WGS84_SWED_RT90(lat, lon):
|
||||
L0 = math.radians(15.8062845294) # 15 deg 48 min 22.624306 sec
|
||||
k0 = 1.00000561024
|
||||
a = 6378137.0 # meter
|
||||
at = a/(1.0+n)*(1.0+ 1.0/4.0* pow(n,2)+1.0/64.0*pow(n,4))
|
||||
at = a/(1.0+n)*(1.0+ 1.0/4.0* pow(n, 2)+1.0/64.0*pow(n, 4))
|
||||
FN = -667.711 # m
|
||||
FE = 1500064.274 # m
|
||||
|
||||
@ -606,20 +607,21 @@ def __conv_WGS84_SWED_RT90(lat, lon):
|
||||
lat_rad = math.radians(lat)
|
||||
lon_rad = math.radians(lon)
|
||||
A = e2
|
||||
B = 1.0/6.0*(5.0*pow(e2,2) - pow(e2,3))
|
||||
C = 1.0/120.0*(104.0*pow(e2,3) - 45.0*pow(e2,4))
|
||||
D = 1.0/1260.0*(1237.0*pow(e2,4))
|
||||
B = 1.0/6.0*(5.0*pow(e2, 2) - pow(e2, 3))
|
||||
C = 1.0/120.0*(104.0*pow(e2, 3) - 45.0*pow(e2, 4))
|
||||
D = 1.0/1260.0*(1237.0*pow(e2, 4))
|
||||
DL = lon_rad - L0
|
||||
E = A + B*pow(math.sin(lat_rad),2) + \
|
||||
C*pow(math.sin(lat_rad),4) + \
|
||||
D*pow(math.sin(lat_rad),6)
|
||||
E = A + B*pow(math.sin(lat_rad), 2) + \
|
||||
C*pow(math.sin(lat_rad), 4) + \
|
||||
D*pow(math.sin(lat_rad), 6)
|
||||
psi = lat_rad - math.sin(lat_rad)*math.cos(lat_rad)*E
|
||||
xi = math.atan2(math.tan(psi),math.cos(DL))
|
||||
xi = math.atan2(math.tan(psi), math.cos(DL))
|
||||
eta = atanh(math.cos(psi)*math.sin(DL))
|
||||
B1 = 1.0/2.0*n - 2.0/3.0*pow(n,2) + 5.0/16.0*pow(n,3) + 41.0/180.0*pow(n,4)
|
||||
B2 = 13.0/48.0*pow(n,2) - 3.0/5.0*pow(n,3) + 557.0/1440.0*pow(n,4)
|
||||
B3 = 61.0/240.0*pow(n,3) - 103.0/140.0*pow(n,4)
|
||||
B4 = 49561.0/161280.0*pow(n,4)
|
||||
B1 = 1.0/2.0*n - 2.0/3.0*pow(n, 2) + 5.0/16.0*pow(n, 3) + \
|
||||
41.0/180.0*pow(n, 4)
|
||||
B2 = 13.0/48.0*pow(n, 2) - 3.0/5.0*pow(n, 3) + 557.0/1440.0*pow(n, 4)
|
||||
B3 = 61.0/240.0*pow(n, 3) - 103.0/140.0*pow(n, 4)
|
||||
B4 = 49561.0/161280.0*pow(n, 4)
|
||||
X = xi + B1*math.sin(2.0*xi)*math.cosh(2.0*eta) + \
|
||||
B2*math.sin(4.0*xi)*math.cosh(4.0*eta) + \
|
||||
B3*math.sin(6.0*xi)*math.cosh(6.0*eta) + \
|
||||
@ -644,16 +646,17 @@ def __conv_SWED_RT90_WGS84(X, Y):
|
||||
L0 = math.radians(15.8062845294) # 15 deg 48 min 22.624306 sec
|
||||
k0 = 1.00000561024
|
||||
a = 6378137.0 # meter
|
||||
at = a/(1.0+n)*(1.0+ 1.0/4.0* pow(n,2)+1.0/64.0*pow(n,4))
|
||||
at = a/(1.0+n)*(1.0+ 1.0/4.0* pow(n, 2)+1.0/64.0*pow(n, 4))
|
||||
FN = -667.711 # m
|
||||
FE = 1500064.274 # m
|
||||
|
||||
xi = (X - FN)/(k0*at)
|
||||
eta = (Y - FE)/(k0*at)
|
||||
D1 = 1.0/2.0*n - 2.0/3.0*pow(n,2) + 37.0/96.0*pow(n,3) - 1.0/360.0*pow(n,4)
|
||||
D2 = 1.0/48.0*pow(n,2) + 1.0/15.0*pow(n,3) - 437.0/1440.0*pow(n,4)
|
||||
D3 = 17.0/480.0*pow(n,3) - 37.0/840.0*pow(n,4)
|
||||
D4 = 4397.0/161280.0*pow(n,4)
|
||||
D1 = 1.0/2.0*n - 2.0/3.0*pow(n, 2) + 37.0/96.0*pow(n, 3) - \
|
||||
1.0/360.0*pow(n, 4)
|
||||
D2 = 1.0/48.0*pow(n, 2) + 1.0/15.0*pow(n, 3) - 437.0/1440.0*pow(n, 4)
|
||||
D3 = 17.0/480.0*pow(n, 3) - 37.0/840.0*pow(n, 4)
|
||||
D4 = 4397.0/161280.0*pow(n, 4)
|
||||
xip = xi - D1*math.sin(2.0*xi)*math.cosh(2.0*eta) - \
|
||||
D2*math.sin(4.0*xi)*math.cosh(4.0*eta) - \
|
||||
D3*math.sin(6.0*xi)*math.cosh(6.0*eta) - \
|
||||
@ -663,15 +666,15 @@ def __conv_SWED_RT90_WGS84(X, Y):
|
||||
D3*math.cos(6.0*xi)*math.sinh(6.0*eta) - \
|
||||
D4*math.cos(8.0*xi)*math.sinh(8.0*eta)
|
||||
psi = math.asin(math.sin(xip)/math.cosh(etap))
|
||||
DL = math.atan2(math.sinh(etap),math.cos(xip))
|
||||
DL = math.atan2(math.sinh(etap), math.cos(xip))
|
||||
LON = L0 + DL
|
||||
A = e2 + pow(e2,2) + pow(e2,3) + pow(e2,4)
|
||||
B = -1.0/6.0*(7.0*pow(e2,2) + 17*pow(e2,3) + 30*pow(e2,4))
|
||||
C = 1.0/120.0*(224.0*pow(e2,3) + 889.0*pow(e2,4))
|
||||
D = 1.0/1260.0*(4279.0*pow(e2,4))
|
||||
E = A + B*pow(math.sin(psi),2) + \
|
||||
C*pow(math.sin(psi),4) + \
|
||||
D*pow(math.sin(psi),6)
|
||||
A = e2 + pow(e2, 2) + pow(e2, 3) + pow(e2, 4)
|
||||
B = -1.0/6.0*(7.0*pow(e2, 2) + 17*pow(e2, 3) + 30*pow(e2, 4))
|
||||
C = 1.0/120.0*(224.0*pow(e2, 3) + 889.0*pow(e2, 4))
|
||||
D = 1.0/1260.0*(4279.0*pow(e2, 4))
|
||||
E = A + B*pow(math.sin(psi), 2) + \
|
||||
C*pow(math.sin(psi), 4) + \
|
||||
D*pow(math.sin(psi), 6)
|
||||
LAT = psi + math.sin(psi)*math.cos(psi)*E
|
||||
LAT = math.degrees(LAT)
|
||||
LON = math.degrees(LON)
|
||||
@ -686,7 +689,7 @@ def __conv_SWED_RT90_WGS84(X, Y):
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
if __name__ == '__main__':
|
||||
def test_formats_success(lat1,lon1, text=''):
|
||||
def test_formats_success(lat1, lon1, text=''):
|
||||
format0 = "D.D4"
|
||||
format1 = "D.D8"
|
||||
format2 = "DEG"
|
||||
@ -697,29 +700,29 @@ if __name__ == '__main__':
|
||||
format7 = "RT90"
|
||||
format8 = "GEDCOM"
|
||||
print("Testing conv_lat_lon function, "+text+':')
|
||||
res1, res2 = conv_lat_lon(lat1,lon1,format0)
|
||||
print(lat1,lon1,"in format",format0, "is ",res1,res2)
|
||||
res1, res2 = conv_lat_lon(lat1,lon1,format1)
|
||||
print(lat1,lon1,"in format",format1, "is ",res1,res2)
|
||||
res1, res2 = conv_lat_lon(lat1,lon1,format2)
|
||||
print(lat1,lon1,"in format",format2, "is ",res1,res2)
|
||||
res1, res2 = conv_lat_lon(lat1,lon1,format3)
|
||||
print(lat1,lon1,"in format",format3, "is ",res1,res2)
|
||||
res = conv_lat_lon(lat1,lon1,format4)
|
||||
print(lat1,lon1,"in format",format4, "is ",res)
|
||||
res = conv_lat_lon(lat1,lon1,format5)
|
||||
print(lat1,lon1,"in format",format5, "is",res)
|
||||
res = conv_lat_lon(lat1,lon1,format6)
|
||||
print(lat1,lon1,"in format",format6, "is",res)
|
||||
res1, res2 = conv_lat_lon(lat1,lon1,format7)
|
||||
print(lat1,lon1,"in format",format7, "is",res1,res2,"\n")
|
||||
res1, res2 = conv_lat_lon(lat1,lon1,format8)
|
||||
print(lat1,lon1,"in format",format8, "is",res1,res2,"\n")
|
||||
res1, res2 = conv_lat_lon(lat1, lon1, format0)
|
||||
print(lat1, lon1, "in format", format0, "is ", res1, res2)
|
||||
res1, res2 = conv_lat_lon(lat1, lon1, format1)
|
||||
print(lat1, lon1, "in format", format1, "is ", res1, res2)
|
||||
res1, res2 = conv_lat_lon(lat1, lon1, format2)
|
||||
print(lat1, lon1, "in format", format2, "is ", res1, res2)
|
||||
res1, res2 = conv_lat_lon(lat1, lon1, format3)
|
||||
print(lat1, lon1, "in format", format3, "is ", res1, res2)
|
||||
res = conv_lat_lon(lat1, lon1, format4)
|
||||
print(lat1, lon1, "in format", format4, "is ", res)
|
||||
res = conv_lat_lon(lat1, lon1, format5)
|
||||
print(lat1, lon1, "in format", format5, "is", res)
|
||||
res = conv_lat_lon(lat1, lon1, format6)
|
||||
print(lat1, lon1, "in format", format6, "is", res)
|
||||
res1, res2 = conv_lat_lon(lat1, lon1, format7)
|
||||
print(lat1, lon1, "in format", format7, "is", res1, res2, "\n")
|
||||
res1, res2 = conv_lat_lon(lat1, lon1, format8)
|
||||
print(lat1, lon1, "in format", format8, "is", res1, res2, "\n")
|
||||
|
||||
def test_formats_fail(lat1,lon1,text=''):
|
||||
def test_formats_fail(lat1, lon1, text=''):
|
||||
print("This test should make conv_lat_lon function fail, "+text+":")
|
||||
res1, res2 = conv_lat_lon(lat1,lon1)
|
||||
print(lat1,lon1," fails to convert, result=", res1,res2,"\n")
|
||||
res1, res2 = conv_lat_lon(lat1, lon1)
|
||||
print(lat1, lon1, " fails to convert, result=", res1, res2, "\n")
|
||||
|
||||
def test_RT90_conversion():
|
||||
"""
|
||||
@ -728,128 +731,130 @@ if __name__ == '__main__':
|
||||
la = 59.0 + 40.0/60. + 9.09/3600.0
|
||||
lo = 12.0 + 58.0/60.0 + 57.74/3600.0
|
||||
x, y = __conv_WGS84_SWED_RT90(la, lo)
|
||||
lanew, lonew = __conv_SWED_RT90_WGS84(x,y)
|
||||
lanew, lonew = __conv_SWED_RT90_WGS84(x, y)
|
||||
assert math.fabs(lanew - la) < 1e-6, math.fabs(lanew - la)
|
||||
assert math.fabs(lonew - lo) < 1e-6, math.fabs(lonew - lo)
|
||||
|
||||
lat, lon = '50.849888888888', '2.885897222222'
|
||||
test_formats_success(lat,lon)
|
||||
test_formats_success(lat, lon)
|
||||
lat, lon = ' 50°50\'59.60"N', ' 2°53\'9.23"E'
|
||||
test_formats_success(lat,lon)
|
||||
test_formats_success(lat, lon)
|
||||
lat, lon = ' 50 : 50 : 59.60 ', ' -2:53 : 9.23 '
|
||||
test_formats_success(lat,lon)
|
||||
test_formats_success(lat, lon)
|
||||
lat, lon = ' dummy', ' 2#53 \' 9.23 " E '
|
||||
test_formats_fail(lat,lon)
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = ' 50:50: 59.60', ' d u m my'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = ' 50°59.60"N', ' 2°53\'E'
|
||||
test_formats_success(lat,lon)
|
||||
lat, lon = ' 11° 11\' 11" N, 11° 11\' 11" O', ' '
|
||||
test_formats_fail(lat,lon)
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = ' 50°59.60"N', ' 2°53\'E'
|
||||
test_formats_success(lat, lon)
|
||||
lat, lon = ' 11° 11\' 11" N, 11° 11\' 11" O', ' '
|
||||
test_formats_fail(lat, lon)
|
||||
# very small negative
|
||||
lat, lon = '-0.00006', '-0.00006'
|
||||
test_formats_success(lat,lon)
|
||||
lat, lon = '-0.00006', '-0.00006'
|
||||
test_formats_success(lat, lon)
|
||||
# missing direction N/S
|
||||
lat, lon = ' 50°59.60"', ' 2°53\'E'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = ' 50°59.60"', ' 2°53\'E'
|
||||
test_formats_fail(lat, lon)
|
||||
# wrong direction on latitude
|
||||
lat, lon = ' 50°59.60"E', ' 2°53\'N'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = ' 50°59.60"E', ' 2°53\'N'
|
||||
test_formats_fail(lat, lon)
|
||||
# same as above
|
||||
lat, lon = ' 50°59.99"E', ' 2°59\'59.99"N'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = ' 50°59.99"E', ' 2°59\'59.99"N'
|
||||
test_formats_fail(lat, lon)
|
||||
# test precision
|
||||
lat, lon = ' 50°59.99"S', ' 2°59\'59.99"E'
|
||||
test_formats_success(lat,lon)
|
||||
lat, lon = ' 50°59.99"S', ' 2°59\'59.99"E'
|
||||
test_formats_success(lat, lon)
|
||||
lat, lon = 'N50.849888888888', 'E2.885897222222'
|
||||
test_formats_success(lat,lon)
|
||||
test_formats_success(lat, lon)
|
||||
# to large value of lat
|
||||
lat, lon = '90.849888888888', '2.885897222222'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = '90.849888888888', '2.885897222222'
|
||||
test_formats_fail(lat, lon)
|
||||
# extreme values allowed
|
||||
lat, lon = '90', '-180'
|
||||
test_formats_success(lat,lon)
|
||||
lat, lon = '90', '-180'
|
||||
test_formats_success(lat, lon)
|
||||
# extreme values allowed
|
||||
lat, lon = '90° 00\' 00.00" S ', '179° 59\'59.99"W'
|
||||
test_formats_success(lat,lon)
|
||||
lat, lon = '90° 00\' 00.00" S ', '179° 59\'59.99"W'
|
||||
test_formats_success(lat, lon)
|
||||
# extreme value not allowed
|
||||
lat, lon = '90° 00\' 00.00" N', '180° 00\'00.00" E'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = '90° 00\' 00.00" N', '180° 00\'00.00" E'
|
||||
test_formats_fail(lat, lon)
|
||||
# extreme values allowed
|
||||
lat, lon = '90: 00: 00.00 ', '-179: 59:59.99'
|
||||
test_formats_success(lat,lon)
|
||||
lat, lon = '90: 00: 00.00 ', '-179: 59:59.99'
|
||||
test_formats_success(lat, lon)
|
||||
# extreme value not allowed
|
||||
lat, lon = '90° 00\' 00.00" N', '180:00:00.00'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = '90° 00\' 00.00" N', '180:00:00.00'
|
||||
test_formats_fail(lat, lon)
|
||||
# extreme values not allowed
|
||||
lat, lon = '90', '180'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = ' 89°59\'60"N', ' 2°53\'W'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = ' 89°60\'00"N', ' 2°53\'W'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = ' 89.1°40\'00"N', ' 2°53\'W'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = ' 89°40\'00"N', ' 2°53.1\'W'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = '0', '0'
|
||||
test_formats_success(lat,lon,
|
||||
"Special 0 value, crossing 0-meridian and equator")
|
||||
lat, lon = '90', '180'
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = ' 89°59\'60"N', ' 2°53\'W'
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = ' 89°60\'00"N', ' 2°53\'W'
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = ' 89.1°40\'00"N', ' 2°53\'W'
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = ' 89°40\'00"N', ' 2°53.1\'W'
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = '0', '0'
|
||||
test_formats_success(lat, lon,
|
||||
"Special 0 value, crossing 0-meridian and equator")
|
||||
# small values close to equator
|
||||
lat, lon = ' 1°1"N', ' 1°1\'E'
|
||||
test_formats_success(lat,lon)
|
||||
lat, lon = ' 1°1"N', ' 1°1\'E'
|
||||
test_formats_success(lat, lon)
|
||||
# roundoff
|
||||
lat, lon = ' 1°59.999"N', ' 1°59.999"E'
|
||||
test_formats_success(lat,lon,'Examples of round off and how it behaves')
|
||||
lat, lon = ' 1°59\'59.9999"N', ' 1°59\'59.9999"E'
|
||||
test_formats_success(lat,lon,'Examples of round off and how it behaves')
|
||||
lat, lon = '89°59\'59.9999"S', '179°59\'59.9999"W'
|
||||
test_formats_success(lat,lon,'Examples of round off and how it behaves')
|
||||
lat, lon = '89°59\'59.9999"N', '179°59\'59.9999"E'
|
||||
test_formats_success(lat,lon,'Examples of round off and how it behaves')
|
||||
lat, lon = ' 1°59.999"N', ' 1°59.999"E'
|
||||
test_formats_success(lat, lon, 'Examples of round off and how it behaves')
|
||||
lat, lon = ' 1°59\'59.9999"N', ' 1°59\'59.9999"E'
|
||||
test_formats_success(lat, lon, 'Examples of round off and how it behaves')
|
||||
lat, lon = '89°59\'59.9999"S', '179°59\'59.9999"W'
|
||||
test_formats_success(lat, lon, 'Examples of round off and how it behaves')
|
||||
lat, lon = '89°59\'59.9999"N', '179°59\'59.9999"E'
|
||||
test_formats_success(lat, lon, 'Examples of round off and how it behaves')
|
||||
#insane number of decimals:
|
||||
lat, lon = '89°59\'59.99999999"N', '179°59\'59.99999999"E'
|
||||
test_formats_success(lat,lon,'Examples of round off and how it begaves')
|
||||
lat, lon = '89°59\'59.99999999"N', '179°59\'59.99999999"E'
|
||||
test_formats_success(lat, lon, 'Examples of round off and how it begaves')
|
||||
#recognise '' as seconds "
|
||||
lat, lon = '89°59\'59.99\'\' N', '179°59\'59.99\'\'E'
|
||||
test_formats_success(lat,lon, "input \" as ''")
|
||||
lat, lon = '89°59\'59.99\'\' N', '179°59\'59.99\'\'E'
|
||||
test_formats_success(lat, lon, "input \" as ''")
|
||||
#test localisation of , and . as delimiter
|
||||
lat, lon = '50.849888888888', '2,885897222222'
|
||||
test_formats_success(lat,lon, 'localisation of . and , ')
|
||||
lat, lon = '89°59\'59.9999"S', '179°59\'59,9999"W'
|
||||
test_formats_success(lat,lon, 'localisation of . and , ')
|
||||
lat, lon = '89°59\'1.599,999"S', '179°59\'59,9999"W'
|
||||
test_formats_fail(lat,lon, 'localisation of . and , ')
|
||||
test_formats_success(lat, lon, 'localisation of . and , ')
|
||||
lat, lon = '89°59\'59.9999"S', '179°59\'59,9999"W'
|
||||
test_formats_success(lat, lon, 'localisation of . and , ')
|
||||
lat, lon = '89°59\'1.599,999"S', '179°59\'59,9999"W'
|
||||
test_formats_fail(lat, lon, 'localisation of . and , ')
|
||||
#rest
|
||||
lat, lon = '81.2', '-182.3'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = '-91.2', '-1'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = '++50:10:1', '2:1:2'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = '-50:10:1', '-+2:1:2'
|
||||
test_formats_success(lat,lon)
|
||||
lat, lon = '-50::1', '-2:1:2'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = '- 50 : 2 : 1 ', '-2:1:2'
|
||||
test_formats_success(lat,lon)
|
||||
lat, lon = '+ 50:2 : 1', '-2:1:2'
|
||||
test_formats_success(lat,lon)
|
||||
lat, lon = '+50:', '-2:1:2'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = '+50:1', '-2:1:2'
|
||||
test_formats_success(lat,lon)
|
||||
lat, lon = '+50: 0 : 1 : 1', '-2:1:2'
|
||||
test_formats_fail(lat,lon)
|
||||
lat, lon = '81.2', '-182.3'
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = '-91.2', '-1'
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = '++50:10:1', '2:1:2'
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = '-50:10:1', '-+2:1:2'
|
||||
test_formats_success(lat, lon)
|
||||
lat, lon = '-50::1', '-2:1:2'
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = '- 50 : 2 : 1 ', '-2:1:2'
|
||||
test_formats_success(lat, lon)
|
||||
lat, lon = '+ 50:2 : 1', '-2:1:2'
|
||||
test_formats_success(lat, lon)
|
||||
lat, lon = '+50:', '-2:1:2'
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = '+50:1', '-2:1:2'
|
||||
test_formats_success(lat, lon)
|
||||
lat, lon = '+50: 0 : 1 : 1', '-2:1:2'
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = '+61° 43\' 60.00"', '+17° 7\' 60.00"'
|
||||
test_formats_fail(lat,lon)
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = '+61° 44\' 00.00"N', '+17° 8\' 00.00"E'
|
||||
test_formats_success(lat,lon)
|
||||
lat, lon = ': 0 : 1 : 1', ':1:2'
|
||||
test_formats_fail(lat,lon)
|
||||
test_formats_success(lat, lon)
|
||||
lat, lon = ': 0 : 1 : 1', ':1:2'
|
||||
test_formats_fail(lat, lon)
|
||||
lat, lon = 'N 50º52\'21.92"', 'E 124º52\'21.92"'
|
||||
test_formats_success(lat,lon, 'New format with N/E first and another º - character')
|
||||
test_formats_success(lat, lon,
|
||||
'New format with N/E first and another º - character')
|
||||
lat, lon = 'S 50º52\'21.92"', 'W 124º52\'21.92"'
|
||||
test_formats_success(lat,lon, 'New format with S/W first and another º - character')
|
||||
test_formats_success(lat, lon,
|
||||
'New format with S/W first and another º - character')
|
||||
|
||||
test_RT90_conversion()
|
||||
|
@ -48,7 +48,7 @@ gender = {
|
||||
Person.UNKNOWN : _("gender|unknown"),
|
||||
}
|
||||
|
||||
def format_gender( type):
|
||||
def format_gender(type):
|
||||
return gender.get(type[0], _("Invalid"))
|
||||
|
||||
conf_strings = {
|
||||
@ -63,16 +63,16 @@ conf_strings = {
|
||||
|
||||
family_rel_descriptions = {
|
||||
FamilyRelType.MARRIED : _("A legal or common-law relationship "
|
||||
"between a husband and wife"),
|
||||
"between a husband and wife"),
|
||||
FamilyRelType.UNMARRIED : _("No legal or common-law relationship "
|
||||
"between man and woman"),
|
||||
"between man and woman"),
|
||||
FamilyRelType.CIVIL_UNION : _("An established relationship between "
|
||||
"members of the same sex"),
|
||||
"members of the same sex"),
|
||||
FamilyRelType.UNKNOWN : _("Unknown relationship between a man "
|
||||
"and woman"),
|
||||
"and woman"),
|
||||
FamilyRelType.CUSTOM : _("An unspecified relationship between "
|
||||
"a man and woman"),
|
||||
"a man and woman"),
|
||||
}
|
||||
|
||||
data_recover_msg = _('The data can only be recovered by Undo operation '
|
||||
'or by quitting with abandoning changes.')
|
||||
'or by quitting with abandoning changes.')
|
||||
|
@ -43,7 +43,6 @@ from gi.repository import GObject
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GdkPixbuf
|
||||
from gi.repository import Pango
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@ -63,111 +62,6 @@ from .undoableentry import UndoableEntry
|
||||
#
|
||||
#============================================================================
|
||||
|
||||
class FadeOut(GObject.GObject):
|
||||
"""
|
||||
I am a helper class to draw the fading effect of the background
|
||||
Call my methods :meth:`start` and :meth:`stop` to control the fading.
|
||||
"""
|
||||
__gsignals__ = {
|
||||
'done': (GObject.SignalFlags.RUN_FIRST,
|
||||
None,
|
||||
()),
|
||||
'color-changed': (GObject.SignalFlags.RUN_FIRST,
|
||||
None,
|
||||
(Gdk.Color, )),
|
||||
}
|
||||
|
||||
# How long time it'll take before we start (in ms)
|
||||
COMPLAIN_DELAY = 500
|
||||
|
||||
MERGE_COLORS_DELAY = 100
|
||||
|
||||
def __init__(self, widget, err_color = "#ffd5d5"):
|
||||
GObject.GObject.__init__(self)
|
||||
self.ERROR_COLOR = err_color
|
||||
self._widget = widget
|
||||
self._start_color = None
|
||||
self._background_timeout_id = -1
|
||||
self._countdown_timeout_id = -1
|
||||
self._done = False
|
||||
|
||||
def _merge_colors(self, src_color, dst_color, steps=10):
|
||||
"""
|
||||
Change the background of widget from src_color to dst_color
|
||||
in the number of steps specified
|
||||
"""
|
||||
##_LOG.debug('_merge_colors: %s -> %s' % (src_color, dst_color))
|
||||
|
||||
rs, gs, bs = src_color.red, src_color.green, src_color.blue
|
||||
rd, gd, bd = dst_color.red, dst_color.green, dst_color.blue
|
||||
rinc = (rd - rs) / float(steps)
|
||||
ginc = (gd - gs) / float(steps)
|
||||
binc = (bd - bs) / float(steps)
|
||||
for dummy in range(steps):
|
||||
rs += rinc
|
||||
gs += ginc
|
||||
bs += binc
|
||||
col = Gdk.color_parse("#%02X%02X%02X" % (int(rs) >> 8,
|
||||
int(gs) >> 8,
|
||||
int(bs) >> 8))
|
||||
self.emit('color-changed', col)
|
||||
yield True
|
||||
|
||||
self.emit('done')
|
||||
self._background_timeout_id = -1
|
||||
self._done = True
|
||||
yield False
|
||||
|
||||
def _start_merging(self):
|
||||
# If we changed during the delay
|
||||
if self._background_timeout_id != -1:
|
||||
##_LOG.debug('_start_merging: Already running')
|
||||
return
|
||||
|
||||
##_LOG.debug('_start_merging: Starting')
|
||||
generator = self._merge_colors(self._start_color,
|
||||
Gdk.color_parse(self.ERROR_COLOR))
|
||||
self._background_timeout_id = (
|
||||
GLib.timeout_add(FadeOut.MERGE_COLORS_DELAY, generator.__next__))
|
||||
self._countdown_timeout_id = -1
|
||||
|
||||
def start(self, color):
|
||||
"""
|
||||
Schedules a start of the countdown.
|
||||
|
||||
:param color: initial background color
|
||||
:returns: True if we could start, False if was already in progress
|
||||
"""
|
||||
if self._background_timeout_id != -1:
|
||||
##_LOG.debug('start: Background change already running')
|
||||
return False
|
||||
if self._countdown_timeout_id != -1:
|
||||
##_LOG.debug('start: Countdown already running')
|
||||
return False
|
||||
if self._done:
|
||||
##_LOG.debug('start: Not running, already set')
|
||||
return False
|
||||
|
||||
self._start_color = color
|
||||
##_LOG.debug('start: Scheduling')
|
||||
self._countdown_timeout_id = GLib.timeout_add(
|
||||
FadeOut.COMPLAIN_DELAY, self._start_merging)
|
||||
|
||||
return True
|
||||
|
||||
def stop(self):
|
||||
"""Stops the fadeout and restores the background color"""
|
||||
##_LOG.debug('Stopping')
|
||||
if self._background_timeout_id != -1:
|
||||
GLib.source_remove(self._background_timeout_id)
|
||||
self._background_timeout_id = -1
|
||||
if self._countdown_timeout_id != -1:
|
||||
GLib.source_remove(self._countdown_timeout_id)
|
||||
self._countdown_timeout_id = -1
|
||||
|
||||
self._widget.update_background(self._start_color, unset=True)
|
||||
self._done = False
|
||||
|
||||
(DIRECTION_LEFT, DIRECTION_RIGHT) = (1, -1)
|
||||
|
||||
(INPUT_ASCII_LETTER,
|
||||
@ -1013,52 +907,6 @@ class MaskedEntry(UndoableEntry):
|
||||
def set_stock(self, icon_name):
|
||||
self.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon_name)
|
||||
|
||||
def update_background(self, color, unset=False):
|
||||
maxvalcol = 65535.
|
||||
if color:
|
||||
red = int(color.red/ maxvalcol*255)
|
||||
green = int(color.green/ maxvalcol*255)
|
||||
blue = int(color.blue/ maxvalcol*255)
|
||||
rgba = Gdk.RGBA()
|
||||
Gdk.RGBA.parse(rgba, 'rgb(%f,%f,%f)'%(red, green, blue))
|
||||
self.override_background_color(Gtk.StateFlags.NORMAL |
|
||||
Gtk.StateFlags.ACTIVE | Gtk.StateFlags.SELECTED |
|
||||
Gtk.StateFlags.FOCUSED, rgba)
|
||||
#GTK 3: workaround, background not changing in themes, use symbolic
|
||||
self.override_symbolic_color('bg_color', rgba)
|
||||
self.override_symbolic_color('base_color', rgba)
|
||||
self.override_symbolic_color('theme_bg_color', rgba)
|
||||
self.override_symbolic_color('theme_base_color', rgba)
|
||||
##self.get_window().set_background_rgba(rgba)
|
||||
pango_context = self.get_layout().get_context()
|
||||
font_description = pango_context.get_font_description()
|
||||
if unset:
|
||||
font_description.set_weight(Pango.Weight.NORMAL)
|
||||
else:
|
||||
font_description.set_weight(Pango.Weight.BOLD)
|
||||
self.override_font(font_description)
|
||||
else:
|
||||
self.override_background_color(Gtk.StateFlags.NORMAL |
|
||||
Gtk.StateFlags.ACTIVE | Gtk.StateFlags.SELECTED |
|
||||
Gtk.StateFlags.FOCUSED, None)
|
||||
# Setting the following to None causes an error (bug #6353).
|
||||
#self.override_symbolic_color('bg_color', None)
|
||||
#self.override_symbolic_color('base_color', None)
|
||||
#self.override_symbolic_color('theme_bg_color', None)
|
||||
#self.override_symbolic_color('theme_base_color', None)
|
||||
pango_context = self.get_layout().get_context()
|
||||
font_description = pango_context.get_font_description()
|
||||
font_description.set_weight(Pango.Weight.NORMAL)
|
||||
self.override_font(font_description)
|
||||
|
||||
def get_background(self):
|
||||
backcol = self.get_style_context().get_background_color(Gtk.StateType.NORMAL)
|
||||
bcol= Gdk.Color.parse('#fff')[1]
|
||||
bcol.red = int(backcol.red * 65535)
|
||||
bcol.green = int(backcol.green * 65535)
|
||||
bcol.blue = int(backcol.blue * 65535)
|
||||
return bcol
|
||||
|
||||
# Gtk.EntryCompletion convenience function
|
||||
|
||||
def prefill(self, itemdata, sort=False):
|
||||
@ -1091,6 +939,7 @@ class MaskedEntry(UndoableEntry):
|
||||
VALIDATION_ICON_WIDTH = 16
|
||||
MANDATORY_ICON = 'dialog-information'
|
||||
ERROR_ICON = 'process-stop'
|
||||
FADE_TIME = 2500
|
||||
|
||||
class ValidatableMaskedEntry(MaskedEntry):
|
||||
"""
|
||||
@ -1132,7 +981,7 @@ class ValidatableMaskedEntry(MaskedEntry):
|
||||
#allowed_data_types = (basestring, datetime.date, datetime.time,
|
||||
#datetime.datetime, object) + number
|
||||
|
||||
def __init__(self, data_type=None, err_color = "#ffd5d5", error_icon=ERROR_ICON):
|
||||
def __init__(self, data_type=None, err_color="pink", error_icon=ERROR_ICON):
|
||||
self.data_type = None
|
||||
self.mandatory = False
|
||||
self.error_icon = error_icon
|
||||
@ -1142,8 +991,19 @@ class ValidatableMaskedEntry(MaskedEntry):
|
||||
|
||||
self._valid = True
|
||||
self._def_error_msg = None
|
||||
self._fade = FadeOut(self, err_color)
|
||||
self._fade.connect('color-changed', self._on_fadeout__color_changed)
|
||||
|
||||
self.__fade_tag = None
|
||||
provider = Gtk.CssProvider()
|
||||
css = '.fade {\n'
|
||||
css += ' background: {};\n'.format(err_color)
|
||||
css += ' transition: background {:d}ms linear;\n'.format(FADE_TIME)
|
||||
css += '}'
|
||||
css += '.bg {\n'
|
||||
css += ' background: {};\n'.format(err_color)
|
||||
css += '}'
|
||||
provider.load_from_data(css.encode('utf8'))
|
||||
context = self.get_style_context()
|
||||
context.add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
||||
|
||||
# FIXME put data type support back
|
||||
#self.set_property('data-type', data_type)
|
||||
@ -1265,10 +1125,18 @@ class ValidatableMaskedEntry(MaskedEntry):
|
||||
reset the background color
|
||||
"""
|
||||
##_LOG.debug('Setting state for %s to VALID' % self.model_attribute)
|
||||
if self.is_valid():
|
||||
return
|
||||
|
||||
self._set_valid_state(True)
|
||||
|
||||
self._fade.stop()
|
||||
self.set_pixbuf(None)
|
||||
if self.__fade_tag is not None:
|
||||
GLib.source_remove(self.__fade_tag)
|
||||
self.__fade_tag = None
|
||||
self.set_stock(None)
|
||||
context = self.get_style_context()
|
||||
context.remove_class('fade')
|
||||
context.remove_class('bg')
|
||||
|
||||
def set_invalid(self, text=None, fade=True):
|
||||
"""
|
||||
@ -1278,6 +1146,8 @@ class ValidatableMaskedEntry(MaskedEntry):
|
||||
:param fade: if we should fade the background
|
||||
"""
|
||||
##_LOG.debug('Setting state for %s to INVALID' % self.model_attribute)
|
||||
if not self.is_valid():
|
||||
return
|
||||
|
||||
self._set_valid_state(False)
|
||||
|
||||
@ -1306,29 +1176,13 @@ class ValidatableMaskedEntry(MaskedEntry):
|
||||
|
||||
self.set_tooltip(text)
|
||||
|
||||
if not fade:
|
||||
if self.error_icon:
|
||||
self.set_stock(self.error_icon)
|
||||
self.update_background(Gdk.color_parse(self._fade.ERROR_COLOR))
|
||||
return
|
||||
|
||||
# When the fading animation is finished, set the error icon
|
||||
# We don't need to check if the state is valid, since stop()
|
||||
# (which removes this timeout) is called as soon as the user
|
||||
# types valid data.
|
||||
def done(fadeout, c):
|
||||
if self.error_icon:
|
||||
self.set_stock(self.error_icon)
|
||||
self.queue_draw()
|
||||
fadeout.disconnect(c.signal_id)
|
||||
|
||||
class SignalContainer:
|
||||
pass
|
||||
c = SignalContainer()
|
||||
c.signal_id = self._fade.connect('done', done, c)
|
||||
|
||||
if self._fade.start(self.get_background()):
|
||||
self.set_pixbuf(None)
|
||||
context = self.get_style_context()
|
||||
if fade:
|
||||
self.__fade_tag = GLib.timeout_add(FADE_TIME, self.__fade_finished)
|
||||
context.add_class('fade')
|
||||
else:
|
||||
self.set_stock(self.error_icon)
|
||||
context.add_class('bg')
|
||||
|
||||
def set_blank(self):
|
||||
"""
|
||||
@ -1340,9 +1194,7 @@ class ValidatableMaskedEntry(MaskedEntry):
|
||||
|
||||
if self.mandatory:
|
||||
self.set_stock(MANDATORY_ICON)
|
||||
self.queue_draw()
|
||||
self.set_tooltip(_('This field is mandatory'))
|
||||
self._fade.stop()
|
||||
valid = False
|
||||
else:
|
||||
valid = True
|
||||
@ -1377,10 +1229,11 @@ class ValidatableMaskedEntry(MaskedEntry):
|
||||
self.emit('validation-changed', state)
|
||||
self._valid = state
|
||||
|
||||
# Callbacks
|
||||
|
||||
def _on_fadeout__color_changed(self, fadeout, color):
|
||||
self.update_background(color)
|
||||
def __fade_finished(self):
|
||||
"""Set error icon after fade has finished."""
|
||||
self.__fade_tag = None
|
||||
self.set_stock(self.error_icon)
|
||||
return False
|
||||
|
||||
|
||||
def main(args):
|
||||
|
@ -47,6 +47,7 @@ from gramps.gen.plug.docgen import (FontStyle, ParagraphStyle, GraphicsStyle,
|
||||
FONT_SANS_SERIF, PARA_ALIGN_CENTER)
|
||||
from gramps.plugins.lib.libtreebase import *
|
||||
from gramps.plugins.lib.librecurse import AscendPerson
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
PT2CM = ReportUtils.pt2cm
|
||||
#cm2pt = ReportUtils.cm2pt
|
||||
@ -550,6 +551,7 @@ class AncestorTree(Report):
|
||||
self._locale = self.set_locale(lang)
|
||||
stdoptions.run_private_data_option(self, options.menu)
|
||||
stdoptions.run_living_people_option(self, options.menu, self._locale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
stdoptions.run_name_format_option(self, options.menu)
|
||||
self._nd = self._name_display
|
||||
|
||||
|
@ -43,6 +43,7 @@ from gramps.gen.plug.report import utils as ReportUtils
|
||||
from gramps.gen.plug.docgen import (FontStyle, ParagraphStyle, GraphicsStyle,
|
||||
FONT_SANS_SERIF, PARA_ALIGN_CENTER)
|
||||
from gramps.plugins.lib.libtreebase import *
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
PT2CM = ReportUtils.pt2cm
|
||||
|
||||
@ -1286,6 +1287,7 @@ class DescendTree(Report):
|
||||
self._locale = self.set_locale(lang)
|
||||
stdoptions.run_private_data_option(self, options.menu)
|
||||
stdoptions.run_living_people_option(self, options.menu, self._locale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
stdoptions.run_name_format_option(self, options.menu)
|
||||
self._nd = self._name_display
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
""" fanchart report """
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# python modules
|
||||
@ -56,6 +58,7 @@ from gramps.gen.plug.report import stdoptions
|
||||
from gramps.gen.config import config
|
||||
from gramps.gen.utils.db import get_birth_or_fallback, get_death_or_fallback
|
||||
from gramps.gen.lib import EventType
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -67,25 +70,22 @@ HALF_CIRCLE = 1
|
||||
QUAR_CIRCLE = 2
|
||||
|
||||
BACKGROUND_WHITE = 0
|
||||
BACKGROUND_GEN = 1
|
||||
BACKGROUND_GEN = 1
|
||||
|
||||
RADIAL_UPRIGHT = 0
|
||||
RADIAL_UPRIGHT = 0
|
||||
RADIAL_ROUNDABOUT = 1
|
||||
|
||||
# minor offset just usefull for generation 11,
|
||||
# to not a bit offset between the text and the polygon
|
||||
# this can be considered as a bad hack
|
||||
WEDGE_TEXT_BARRE_OFFSET = 0.0016
|
||||
pt2cm = utils.pt2cm
|
||||
|
||||
cal = config.get('preferences.calendar-format-report')
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# private functions
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
def draw_wedge(doc, style, centerx, centery, radius, start_angle,
|
||||
def draw_wedge(doc, style, centerx, centery, radius, start_angle,
|
||||
end_angle, do_rendering, short_radius=0):
|
||||
"""
|
||||
Draw a wedge shape.
|
||||
@ -93,7 +93,7 @@ def draw_wedge(doc, style, centerx, centery, radius, start_angle,
|
||||
while end_angle < start_angle:
|
||||
end_angle += 360
|
||||
|
||||
p = []
|
||||
path = []
|
||||
|
||||
degreestoradians = pi / 180.0
|
||||
radiansdelta = degreestoradians / 2
|
||||
@ -105,40 +105,40 @@ def draw_wedge(doc, style, centerx, centery, radius, start_angle,
|
||||
|
||||
if short_radius == 0:
|
||||
if (end_angle - start_angle) != 360:
|
||||
p.append((centerx, centery))
|
||||
path.append((centerx, centery))
|
||||
else:
|
||||
origx = (centerx + cos(angle) * short_radius)
|
||||
origy = (centery + sin(angle) * short_radius)
|
||||
p.append((origx, origy))
|
||||
path.append((origx, origy))
|
||||
|
||||
while angle < eangle:
|
||||
x = centerx + cos(angle) * radius
|
||||
y = centery + sin(angle) * radius
|
||||
p.append((x, y))
|
||||
_x_ = centerx + cos(angle) * radius
|
||||
_y_ = centery + sin(angle) * radius
|
||||
path.append((_x_, _y_))
|
||||
angle = angle + radiansdelta
|
||||
x = centerx + cos(eangle) * radius
|
||||
y = centery + sin(eangle) * radius
|
||||
p.append((x, y))
|
||||
_x_ = centerx + cos(eangle) * radius
|
||||
_y_ = centery + sin(eangle) * radius
|
||||
path.append((_x_, _y_))
|
||||
|
||||
if short_radius:
|
||||
x = centerx + cos(eangle) * short_radius
|
||||
y = centery + sin(eangle) * short_radius
|
||||
p.append((x, y))
|
||||
_x_ = centerx + cos(eangle) * short_radius
|
||||
_y_ = centery + sin(eangle) * short_radius
|
||||
path.append((_x_, _y_))
|
||||
|
||||
angle = eangle
|
||||
while angle >= sangle:
|
||||
x = centerx + cos(angle) * short_radius
|
||||
y = centery + sin(angle) * short_radius
|
||||
p.append((x, y))
|
||||
_x_ = centerx + cos(angle) * short_radius
|
||||
_y_ = centery + sin(angle) * short_radius
|
||||
path.append((_x_, _y_))
|
||||
angle -= radiansdelta
|
||||
if do_rendering:
|
||||
doc.draw_path(style, p)
|
||||
doc.draw_path(style, path)
|
||||
|
||||
delta = (eangle - sangle) / 2.0
|
||||
rad = short_radius + (radius - short_radius) / 2.0
|
||||
|
||||
return ( (centerx + cos(sangle + delta + WEDGE_TEXT_BARRE_OFFSET) * rad),
|
||||
(centery + sin(sangle + delta + WEDGE_TEXT_BARRE_OFFSET) * rad))
|
||||
return ((centerx + cos(sangle + delta + WEDGE_TEXT_BARRE_OFFSET) * rad),
|
||||
(centery + sin(sangle + delta + WEDGE_TEXT_BARRE_OFFSET) * rad))
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -180,21 +180,22 @@ class FanChart(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
stdoptions.run_living_people_option(self, menu, rlocale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
|
||||
self.max_generations = menu.get_option_by_name('maxgen').get_value()
|
||||
self.circle = menu.get_option_by_name('circle').get_value()
|
||||
self.background = menu.get_option_by_name('background').get_value()
|
||||
self.radial = menu.get_option_by_name('radial').get_value()
|
||||
pid = menu.get_option_by_name('pid').get_value()
|
||||
self.draw_empty = menu.get_option_by_name('draw_empty').get_value()
|
||||
self.same_style = menu.get_option_by_name('same_style').get_value()
|
||||
self.circle = menu.get_option_by_name('circle').get_value()
|
||||
self.background = menu.get_option_by_name('background').get_value()
|
||||
self.radial = menu.get_option_by_name('radial').get_value()
|
||||
pid = menu.get_option_by_name('pid').get_value()
|
||||
self.draw_empty = menu.get_option_by_name('draw_empty').get_value()
|
||||
self.same_style = menu.get_option_by_name('same_style').get_value()
|
||||
self.center_person = self.database.get_person_from_gramps_id(pid)
|
||||
if self.center_person is None:
|
||||
raise ReportError(_("Person %s is not in the Database") % pid )
|
||||
raise ReportError(_("Person %s is not in the Database") % pid)
|
||||
|
||||
self.graphic_style = []
|
||||
self.text_style = []
|
||||
for i in range (0, self.max_generations):
|
||||
for i in range(0, self.max_generations):
|
||||
self.graphic_style.append('FC-Graphic' + '%02d' % i)
|
||||
self.text_style.append('FC-Text' + '%02d' % i)
|
||||
|
||||
@ -204,7 +205,7 @@ class FanChart(Report):
|
||||
self.map = [None] * 2**self.max_generations
|
||||
self.text = {}
|
||||
|
||||
def apply_filter(self,person_handle,index):
|
||||
def apply_filter(self, person_handle, index):
|
||||
"""traverse the ancestors recursively until either the end
|
||||
of a line is found, or until we reach the maximum number of
|
||||
generations that we want to deal with"""
|
||||
@ -218,151 +219,160 @@ class FanChart(Report):
|
||||
family_handle = person.get_main_parents_family_handle()
|
||||
if family_handle:
|
||||
family = self.database.get_family_from_handle(family_handle)
|
||||
self.apply_filter(family.get_father_handle(),index*2)
|
||||
self.apply_filter(family.get_mother_handle(),(index*2)+1)
|
||||
self.apply_filter(family.get_father_handle(), index*2)
|
||||
self.apply_filter(family.get_mother_handle(), (index*2)+1)
|
||||
|
||||
def write_report(self):
|
||||
self.doc.start_page()
|
||||
|
||||
self.apply_filter(self.center_person.get_handle(),1)
|
||||
n = self.center_person.get_primary_name().get_regular_name()
|
||||
self.apply_filter(self.center_person.get_handle(), 1)
|
||||
p_rn = self.center_person.get_primary_name().get_regular_name()
|
||||
|
||||
if self.circle == FULL_CIRCLE:
|
||||
max_angle = 360.0
|
||||
start_angle = 90
|
||||
max_circular = 5
|
||||
x = self.doc.get_usable_width() / 2.0
|
||||
y = self.doc.get_usable_height() / 2.0
|
||||
min_xy = min (x, y)
|
||||
_x_ = self.doc.get_usable_width() / 2.0
|
||||
_y_ = self.doc.get_usable_height() / 2.0
|
||||
min_xy = min(_x_, _y_)
|
||||
|
||||
elif self.circle == HALF_CIRCLE:
|
||||
max_angle = 180.0
|
||||
start_angle = 180
|
||||
max_circular = 3
|
||||
x = (self.doc.get_usable_width()/2.0)
|
||||
y = self.doc.get_usable_height()
|
||||
min_xy = min (x, y)
|
||||
_x_ = (self.doc.get_usable_width()/2.0)
|
||||
_y_ = self.doc.get_usable_height()
|
||||
min_xy = min(_x_, _y_)
|
||||
|
||||
else: # quarter circle
|
||||
max_angle = 90.0
|
||||
start_angle = 270
|
||||
max_circular = 2
|
||||
x = 0
|
||||
y = self.doc.get_usable_height()
|
||||
min_xy = min (self.doc.get_usable_width(), y)
|
||||
_x_ = 0
|
||||
_y_ = self.doc.get_usable_height()
|
||||
min_xy = min(self.doc.get_usable_width(), _y_)
|
||||
|
||||
# choose one line or two lines translation according to the width
|
||||
title = self._("%(generations)d Generation Fan Chart "
|
||||
"for %(person)s" ) % {
|
||||
'generations' : self.max_generations,
|
||||
'person' : n }
|
||||
"for %(person)s") % {
|
||||
'generations' : self.max_generations,
|
||||
'person' : p_rn}
|
||||
title_nb_lines = 1
|
||||
style_sheet = self.doc.get_style_sheet()
|
||||
if style_sheet:
|
||||
paragraph_style = style_sheet.get_paragraph_style('FC-Title')
|
||||
if paragraph_style:
|
||||
font = paragraph_style.get_font()
|
||||
if font:
|
||||
title_width = pt2cm(self.doc.string_width(font, title))
|
||||
if title_width > self.doc.get_usable_width():
|
||||
title = self._("%(generations)d Generation Fan Chart "
|
||||
"for\n%(person)s" ) % {
|
||||
'generations' : self.max_generations,
|
||||
'person' : n }
|
||||
title_nb_lines = 2
|
||||
p_style = style_sheet.get_paragraph_style('FC-Title')
|
||||
if p_style:
|
||||
font = p_style.get_font()
|
||||
if font:
|
||||
title_width = utils.pt2cm(self.doc.string_width(font,
|
||||
title))
|
||||
if title_width > self.doc.get_usable_width():
|
||||
title = self._(
|
||||
"%(generations)d Generation Fan Chart "
|
||||
"for\n%(person)s") % {
|
||||
'generations' : self.max_generations,
|
||||
'person' : p_rn}
|
||||
title_nb_lines = 2
|
||||
|
||||
if self.circle == FULL_CIRCLE or self.circle == QUAR_CIRCLE:
|
||||
# adjust only if full circle or 1/4 circle in landscape mode
|
||||
if self.doc.get_usable_height() <= self.doc.get_usable_width():
|
||||
# Should be in Landscape now
|
||||
style_sheet = self.doc.get_style_sheet()
|
||||
paragraph_style = style_sheet.get_paragraph_style('FC-Title')
|
||||
if paragraph_style:
|
||||
font = paragraph_style.get_font()
|
||||
p_style = style_sheet.get_paragraph_style('FC-Title')
|
||||
if p_style:
|
||||
font = p_style.get_font()
|
||||
if font:
|
||||
fontsize = pt2cm(font.get_size())
|
||||
# y is vertical distance to center of circle, move center down 1 fontsize
|
||||
y += fontsize*title_nb_lines
|
||||
# min_XY is the diameter of the circle, subtract two fontsize
|
||||
fontsize = utils.pt2cm(font.get_size())
|
||||
# _y_ is vertical distance to center of circle,
|
||||
# move center down 1 fontsize
|
||||
_y_ += fontsize*title_nb_lines
|
||||
# min_XY is the diameter of the circle,
|
||||
# subtract two fontsize
|
||||
# so we dont draw outside bottom of the paper
|
||||
min_xy = min(min_xy, y - 2*fontsize*title_nb_lines)
|
||||
min_xy = min(min_xy, _y_ - 2*fontsize*title_nb_lines)
|
||||
if self.max_generations > max_circular:
|
||||
block_size = min_xy / (self.max_generations * 2 - max_circular)
|
||||
else:
|
||||
block_size = min_xy / self.max_generations
|
||||
|
||||
# adaptation of the fonts (title and others)
|
||||
optimized_style_sheet = self.get_optimized_style_sheet(title,
|
||||
max_circular, block_size, self.same_style,
|
||||
not self.same_style,
|
||||
# if same_style, use default generated colors
|
||||
self.background == BACKGROUND_WHITE)
|
||||
optimized_style_sheet = self.get_optimized_style_sheet(
|
||||
title, max_circular, block_size, self.same_style,
|
||||
not self.same_style,
|
||||
# if same_style, use default generated colors
|
||||
self.background == BACKGROUND_WHITE)
|
||||
|
||||
if optimized_style_sheet:
|
||||
self.doc.set_style_sheet(optimized_style_sheet)
|
||||
self.doc.set_style_sheet(optimized_style_sheet)
|
||||
|
||||
# title
|
||||
mark = IndexMark(title, INDEX_TYPE_TOC, 1)
|
||||
self.doc.center_text ('FC-Graphic-title', title,
|
||||
self.doc.get_usable_width() / 2, 0, mark)
|
||||
#wheel
|
||||
for generation in range (0, min (max_circular, self.max_generations)):
|
||||
self.draw_circular (x, y, start_angle, max_angle, block_size, generation)
|
||||
for generation in range (max_circular, self.max_generations):
|
||||
self.draw_radial (x, y, start_angle, max_angle, block_size, generation)
|
||||
self.doc.center_text('FC-Graphic-title', title,
|
||||
self.doc.get_usable_width() / 2, 0, mark)
|
||||
# wheel
|
||||
for generation in range(0, min(max_circular, self.max_generations)):
|
||||
self.draw_circular(_x_, _y_,
|
||||
start_angle, max_angle, block_size, generation)
|
||||
for generation in range(max_circular, self.max_generations):
|
||||
self.draw_radial(_x_, _y_,
|
||||
start_angle, max_angle, block_size, generation)
|
||||
self.doc.end_page()
|
||||
|
||||
def get_info(self,person_handle,generation):
|
||||
def get_info(self, person_handle, generation):
|
||||
""" get info about a person """
|
||||
person = self.database.get_person_from_handle(person_handle)
|
||||
pn = person.get_primary_name()
|
||||
p_pn = person.get_primary_name()
|
||||
self.calendar = config.get('preferences.calendar-format-report')
|
||||
|
||||
birth = get_birth_or_fallback(self.database, person)
|
||||
b = ""
|
||||
bth = ""
|
||||
if birth:
|
||||
b = str(birth.get_date_object().to_calendar(self.calendar).get_year())
|
||||
if b == 0:
|
||||
b = ""
|
||||
bth = birth.get_date_object()
|
||||
bth = str(bth.to_calendar(self.calendar).get_year())
|
||||
if bth == 0:
|
||||
bth = ""
|
||||
elif birth.get_type() != EventType.BIRTH:
|
||||
b += '*'
|
||||
bth += '*'
|
||||
|
||||
death = get_death_or_fallback(self.database, person)
|
||||
d = ""
|
||||
dth = ""
|
||||
if death:
|
||||
d = str(death.get_date_object().to_calendar(self.calendar).get_year())
|
||||
if d == 0:
|
||||
d = ""
|
||||
dth = death.get_date_object()
|
||||
dth = str(dth.to_calendar(self.calendar).get_year())
|
||||
if dth == 0:
|
||||
dth = ""
|
||||
elif death.get_type() != EventType.DEATH:
|
||||
d += '*'
|
||||
if b and d:
|
||||
val = "%s - %s" % (str(b),str(d))
|
||||
elif b:
|
||||
val = "* %s" % (str(b))
|
||||
elif d:
|
||||
val = "+ %s" % (str(d))
|
||||
dth += '*'
|
||||
if bth and dth:
|
||||
val = "%s - %s" % (str(bth), str(dth))
|
||||
elif bth:
|
||||
val = "* %s" % (str(bth))
|
||||
elif dth:
|
||||
val = "+ %s" % (str(dth))
|
||||
else:
|
||||
val = ""
|
||||
|
||||
if generation > 7:
|
||||
if (pn.get_first_name() != "") and (pn.get_surname() != ""):
|
||||
name = pn.get_first_name() + " " + pn.get_surname()
|
||||
if (p_pn.get_first_name() != "") and (p_pn.get_surname() != ""):
|
||||
name = p_pn.get_first_name() + " " + p_pn.get_surname()
|
||||
else:
|
||||
name = pn.get_first_name() + pn.get_surname()
|
||||
name = p_pn.get_first_name() + p_pn.get_surname()
|
||||
if (name != "") and (val != ""):
|
||||
string = name + ", " + val
|
||||
else:
|
||||
string = name + val
|
||||
return [ string ]
|
||||
return [string]
|
||||
elif generation == 7:
|
||||
if (pn.get_first_name() != "") and (pn.get_surname() != ""):
|
||||
name = pn.get_first_name() + " " + pn.get_surname()
|
||||
if (p_pn.get_first_name() != "") and (p_pn.get_surname() != ""):
|
||||
name = p_pn.get_first_name() + " " + p_pn.get_surname()
|
||||
else:
|
||||
name = pn.get_first_name() + pn.get_surname()
|
||||
name = p_pn.get_first_name() + p_pn.get_surname()
|
||||
|
||||
if self.circle == FULL_CIRCLE:
|
||||
return [ name, val ]
|
||||
return [name, val]
|
||||
elif self.circle == HALF_CIRCLE:
|
||||
return [ name, val ]
|
||||
return [name, val]
|
||||
else:
|
||||
if (name != "") and (val != ""):
|
||||
string = name + ", " + val
|
||||
@ -371,20 +381,21 @@ class FanChart(Report):
|
||||
return [string]
|
||||
elif generation == 6:
|
||||
if self.circle == FULL_CIRCLE:
|
||||
return [ pn.get_first_name(), pn.get_surname(), val ]
|
||||
return [p_pn.get_first_name(), p_pn.get_surname(), val]
|
||||
elif self.circle == HALF_CIRCLE:
|
||||
return [ pn.get_first_name(), pn.get_surname(), val ]
|
||||
return [p_pn.get_first_name(), p_pn.get_surname(), val]
|
||||
else:
|
||||
if (pn.get_first_name() != "") and (pn.get_surname() != ""):
|
||||
name = pn.get_first_name() + " " + pn.get_surname()
|
||||
if (p_pn.get_first_name() != "") and (p_pn.get_surname() != ""):
|
||||
name = p_pn.get_first_name() + " " + p_pn.get_surname()
|
||||
else:
|
||||
name = pn.get_first_name() + pn.get_surname()
|
||||
return [ name, val ]
|
||||
name = p_pn.get_first_name() + p_pn.get_surname()
|
||||
return [name, val]
|
||||
else:
|
||||
return [ pn.get_first_name(), pn.get_surname(), val ]
|
||||
return [p_pn.get_first_name(), p_pn.get_surname(), val]
|
||||
|
||||
def get_max_width_for_circles(self, rad1, rad2, max_centering_proportion):
|
||||
"""
|
||||
r"""
|
||||
(the "r" in the above line is to keep pylint happy)
|
||||
__
|
||||
/__\ <- compute the line width which is drawable between 2 circles.
|
||||
/ _ \ max_centering_proportion : 0, touching the circle1, 1,
|
||||
@ -400,13 +411,14 @@ class FanChart(Report):
|
||||
return sin(acos(rmid/rad2)) * rad2 * 2
|
||||
|
||||
def get_max_width_for_circles_line(self, rad1, rad2, line, nb_lines,
|
||||
centering = False):
|
||||
"""
|
||||
centering=False):
|
||||
r"""
|
||||
(the "r" in the above line is to keep pylint happy)
|
||||
__
|
||||
/__\ <- compute the line width which is drawable between 2 circles.
|
||||
/ _ \ instead of a max_centering_proportion, you get a line/nb_lines position.
|
||||
| |_| | (we suppose that lines have the same heights)
|
||||
| | for example, if you've 2 lines to draw,
|
||||
/ _ \ instead of a max_centering_proportion, you get a
|
||||
| |_| | line/nb_lines position. (we suppose that lines have the
|
||||
| | same heights.) for example, if you've 2 lines to draw,
|
||||
\ / line 2 max width is at the 2/3 between the 2 circles
|
||||
\__/
|
||||
"""
|
||||
@ -417,7 +429,7 @@ class FanChart(Report):
|
||||
line/float(nb_lines+1))
|
||||
|
||||
def get_optimized_font_size_for_text(self, rad1, rad2, text, font,
|
||||
centering = False):
|
||||
centering=False):
|
||||
"""
|
||||
a text can be several lines
|
||||
find the font size equals or lower than font.get_size() which fit
|
||||
@ -429,7 +441,8 @@ class FanChart(Report):
|
||||
i = 1
|
||||
nb_lines = len(text)
|
||||
for line in text:
|
||||
font_size = self.get_optimized_font_size(line, font,
|
||||
font_size = self.get_optimized_font_size(
|
||||
line, font,
|
||||
self.get_max_width_for_circles_line(rad1, rad2, i, nb_lines,
|
||||
centering))
|
||||
i += 1
|
||||
@ -443,10 +456,10 @@ class FanChart(Report):
|
||||
or smaller than font which make line fit into max_width
|
||||
"""
|
||||
test_font = FontStyle(font)
|
||||
w = pt2cm(self.doc.string_width(test_font, line))
|
||||
while w > max_width and test_font.get_size() > 1:
|
||||
width = utils.pt2cm(self.doc.string_width(test_font, line))
|
||||
while width > max_width and test_font.get_size() > 1:
|
||||
test_font.set_size(test_font.get_size() -1)
|
||||
w = pt2cm(self.doc.string_width(test_font, line))
|
||||
width = utils.pt2cm(self.doc.string_width(test_font, line))
|
||||
return test_font.get_size()
|
||||
|
||||
def get_optimized_style_sheet(self, title, max_circular, block_size,
|
||||
@ -457,66 +470,69 @@ class FanChart(Report):
|
||||
returns an optimized (modified) style sheet which make fanchart
|
||||
look nicer
|
||||
"""
|
||||
redefined_style_sheet = self.doc.get_style_sheet()
|
||||
if not redefined_style_sheet:
|
||||
new_style_sheet = self.doc.get_style_sheet()
|
||||
if not new_style_sheet:
|
||||
return self.doc.get_style_sheet()
|
||||
|
||||
# update title font size
|
||||
pstyle_name = 'FC-Title'
|
||||
paragraph_style = redefined_style_sheet.get_paragraph_style(pstyle_name)
|
||||
if paragraph_style:
|
||||
title_font = paragraph_style.get_font()
|
||||
p_style = new_style_sheet.get_paragraph_style(pstyle_name)
|
||||
if p_style:
|
||||
title_font = p_style.get_font()
|
||||
if title_font:
|
||||
title_width = pt2cm(self.doc.string_multiline_width(title_font,
|
||||
title))
|
||||
title_width = utils.pt2cm(
|
||||
self.doc.string_multiline_width(title_font, title))
|
||||
while (title_width > self.doc.get_usable_width() and
|
||||
title_font.get_size() > 1):
|
||||
title_font.set_size(title_font.get_size()-1)
|
||||
title_width = pt2cm(self.doc.string_multiline_width(
|
||||
title_font, title))
|
||||
redefined_style_sheet.add_paragraph_style(pstyle_name,
|
||||
paragraph_style)
|
||||
title_width = utils.pt2cm(
|
||||
self.doc.string_multiline_width(title_font, title))
|
||||
new_style_sheet.add_paragraph_style(pstyle_name, p_style)
|
||||
|
||||
# biggest font allowed is the one of the fist generation, after,
|
||||
# always lower than the previous one
|
||||
paragraph_style = redefined_style_sheet.get_paragraph_style(self.text_style[0])
|
||||
p_style = new_style_sheet.get_paragraph_style(self.text_style[0])
|
||||
font = None
|
||||
if paragraph_style:
|
||||
font = paragraph_style.get_font()
|
||||
if p_style:
|
||||
font = p_style.get_font()
|
||||
if font:
|
||||
previous_generation_font_size = font.get_size()
|
||||
|
||||
for generation in range (0, self.max_generations):
|
||||
for generation in range(0, self.max_generations):
|
||||
gstyle_name = self.graphic_style[generation]
|
||||
pstyle_name = self.text_style [generation]
|
||||
g = redefined_style_sheet.get_draw_style(gstyle_name)
|
||||
pstyle_name = self.text_style[generation]
|
||||
g_style = new_style_sheet.get_draw_style(gstyle_name)
|
||||
|
||||
# paragraph_style is a copy of 'FC-Text' - use different style
|
||||
# p_style is a copy of 'FC-Text' - use different style
|
||||
# to be able to auto change some fonts for some generations
|
||||
if map_style_from_single:
|
||||
paragraph_style = redefined_style_sheet.get_paragraph_style('FC-Text')
|
||||
p_style = new_style_sheet.get_paragraph_style('FC-Text')
|
||||
else:
|
||||
paragraph_style = redefined_style_sheet.get_paragraph_style(pstyle_name)
|
||||
p_style = new_style_sheet.get_paragraph_style(pstyle_name)
|
||||
|
||||
if g and paragraph_style:
|
||||
# set graphic colors to paragraph colors, while it's fonctionnaly
|
||||
if g_style and p_style:
|
||||
# set graphic colors to paragraph colors,
|
||||
# while it's functionnaly
|
||||
# the same for fanchart or make backgrounds white
|
||||
if make_background_white:
|
||||
g.set_fill_color((255,255,255))
|
||||
redefined_style_sheet.add_draw_style(gstyle_name, g)
|
||||
g_style.set_fill_color((255, 255, 255))
|
||||
new_style_sheet.add_draw_style(gstyle_name, g_style)
|
||||
elif map_paragraphs_colors_to_graphics:
|
||||
pstyle = redefined_style_sheet.get_paragraph_style(pstyle_name)
|
||||
pstyle = new_style_sheet.get_paragraph_style(
|
||||
pstyle_name)
|
||||
if pstyle:
|
||||
g.set_fill_color(pstyle.get_background_color())
|
||||
redefined_style_sheet.add_draw_style(gstyle_name, g)
|
||||
g_style.set_fill_color(
|
||||
pstyle.get_background_color())
|
||||
new_style_sheet.add_draw_style(gstyle_name,
|
||||
g_style)
|
||||
|
||||
# adapt font size if too big
|
||||
segments = 2**generation
|
||||
if generation < min (max_circular, self.max_generations):
|
||||
if generation < min(max_circular, self.max_generations):
|
||||
# adpatation for circular fonts
|
||||
rad1, rad2 = self.get_circular_radius(block_size,
|
||||
generation, self.circle)
|
||||
font = paragraph_style.get_font()
|
||||
rad1, rad2 = self.get_circular_radius(
|
||||
block_size, generation, self.circle)
|
||||
font = p_style.get_font()
|
||||
if font:
|
||||
min_font_size = font.get_size()
|
||||
# find the smallest font required
|
||||
@ -524,55 +540,57 @@ class FanChart(Report):
|
||||
if self.map[index]:
|
||||
font_size = \
|
||||
self.get_optimized_font_size_for_text(
|
||||
rad1, rad2, self.text[index],
|
||||
paragraph_style.get_font(),
|
||||
(self.circle == FULL_CIRCLE and
|
||||
generation == 0)
|
||||
)
|
||||
rad1, rad2, self.text[index],
|
||||
p_style.get_font(),
|
||||
(self.circle == FULL_CIRCLE and
|
||||
generation == 0)
|
||||
)
|
||||
if font_size < min_font_size:
|
||||
min_font_size = font_size
|
||||
font.set_size(min(previous_generation_font_size,
|
||||
min_font_size))
|
||||
min_font_size))
|
||||
else:
|
||||
# adaptation for radial fonts
|
||||
|
||||
# find the largest string for the generation
|
||||
longest_line = ""
|
||||
longest_line = ""
|
||||
longest_width = 0
|
||||
for index in range(segments - 1, 2*segments - 1):
|
||||
if self.map[index]:
|
||||
for line in self.text[index]:
|
||||
width = pt2cm(self.doc.string_multiline_width(
|
||||
paragraph_style.get_font(), line))
|
||||
width = utils.pt2cm(
|
||||
self.doc.string_multiline_width(
|
||||
p_style.get_font(), line))
|
||||
if width > longest_width:
|
||||
longest_line = line
|
||||
longest_line = line
|
||||
longest_width = width
|
||||
|
||||
# determine maximum width allowed for this generation
|
||||
rad1, rad2 = self.get_radial_radius(block_size,
|
||||
generation, self.circle)
|
||||
rad1, rad2 = self.get_radial_radius(
|
||||
block_size, generation, self.circle)
|
||||
max_width = rad2 - rad1
|
||||
|
||||
# reduce the font so that longest_width fit into max_width
|
||||
font = paragraph_style.get_font()
|
||||
# reduce the font so that longest_width
|
||||
# fit into max_width
|
||||
font = p_style.get_font()
|
||||
if font:
|
||||
font.set_size(min(previous_generation_font_size,
|
||||
self.get_optimized_font_size(longest_line,
|
||||
paragraph_style.get_font(),
|
||||
max_width))
|
||||
)
|
||||
self.get_optimized_font_size(
|
||||
longest_line,
|
||||
p_style.get_font(),
|
||||
max_width)))
|
||||
|
||||
# redefine the style
|
||||
redefined_style_sheet.add_paragraph_style(pstyle_name,
|
||||
paragraph_style)
|
||||
font = paragraph_style.get_font()
|
||||
new_style_sheet.add_paragraph_style(pstyle_name, p_style)
|
||||
font = p_style.get_font()
|
||||
if font:
|
||||
previous_generation_font_size = font.get_size()
|
||||
|
||||
# finished
|
||||
return redefined_style_sheet
|
||||
return new_style_sheet
|
||||
|
||||
def draw_circular(self, x, y, start_angle, max_angle, size, generation):
|
||||
def draw_circular(self, _x_, _y_,
|
||||
start_angle, max_angle, size, generation):
|
||||
segments = 2**generation
|
||||
delta = max_angle / segments
|
||||
end_angle = start_angle
|
||||
@ -583,19 +601,20 @@ class FanChart(Report):
|
||||
for index in range(segments - 1, 2*segments - 1):
|
||||
start_angle = end_angle
|
||||
end_angle = start_angle + delta
|
||||
(xc,yc) = draw_wedge(self.doc, graphic_style, x, y, rad2,
|
||||
start_angle, end_angle,
|
||||
self.map[index] or self.draw_empty, rad1)
|
||||
(_xc, _yc) = draw_wedge(self.doc, graphic_style, _x_, _y_, rad2,
|
||||
start_angle, end_angle,
|
||||
self.map[index] or self.draw_empty, rad1)
|
||||
if self.map[index]:
|
||||
if (generation == 0) and self.circle == FULL_CIRCLE:
|
||||
yc = y
|
||||
_yc = _y_
|
||||
person = self.database.get_person_from_handle(self.map[index])
|
||||
mark = utils.get_person_mark(self.database, person)
|
||||
self.doc.rotate_text(graphic_style, self.text[index],
|
||||
xc, yc, text_angle, mark)
|
||||
_xc, _yc, text_angle, mark)
|
||||
text_angle += delta
|
||||
|
||||
def get_radial_radius(self, size, generation, circle):
|
||||
""" determine the radius """
|
||||
if circle == FULL_CIRCLE:
|
||||
rad1 = size * ((generation * 2) - 5)
|
||||
rad2 = size * ((generation * 2) - 3)
|
||||
@ -608,9 +627,11 @@ class FanChart(Report):
|
||||
return rad1, rad2
|
||||
|
||||
def get_circular_radius(self, size, generation, circle):
|
||||
""" determine the radius """
|
||||
return size * generation, size * (generation + 1)
|
||||
|
||||
def draw_radial(self, x, y, start_angle, max_angle, size, generation):
|
||||
def draw_radial(self, _x_, _y_,
|
||||
start_angle, max_angle, size, generation):
|
||||
segments = 2**generation
|
||||
delta = max_angle / segments
|
||||
end_angle = start_angle
|
||||
@ -621,19 +642,21 @@ class FanChart(Report):
|
||||
for index in range(segments - 1, 2*segments - 1):
|
||||
start_angle = end_angle
|
||||
end_angle = start_angle + delta
|
||||
(xc,yc) = draw_wedge(self.doc, graphic_style, x, y, rad2,
|
||||
start_angle, end_angle,
|
||||
self.map[index] or self.draw_empty, rad1)
|
||||
(_xc, _yc) = draw_wedge(self.doc, graphic_style, _x_, _y_, rad2,
|
||||
start_angle, end_angle,
|
||||
self.map[index] or self.draw_empty, rad1)
|
||||
text_angle += delta
|
||||
if self.map[index]:
|
||||
person = self.database.get_person_from_handle(self.map[index])
|
||||
mark = utils.get_person_mark(self.database, person)
|
||||
if self.radial == RADIAL_UPRIGHT and (start_angle >= 90) and (start_angle < 270):
|
||||
if (self.radial == RADIAL_UPRIGHT
|
||||
and (start_angle >= 90)
|
||||
and (start_angle < 270)):
|
||||
self.doc.rotate_text(graphic_style, self.text[index],
|
||||
xc, yc, text_angle + 180, mark)
|
||||
_xc, _yc, text_angle + 180, mark)
|
||||
else:
|
||||
self.doc.rotate_text(graphic_style, self.text[index],
|
||||
xc, yc, text_angle, mark)
|
||||
_xc, _yc, text_angle, mark)
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -641,9 +664,10 @@ class FanChart(Report):
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
class FanChartOptions(MenuReportOptions):
|
||||
""" options for fanchart report """
|
||||
|
||||
def __init__(self, name, dbase):
|
||||
self.MAX_GENERATIONS = 11
|
||||
self.max_generations = 11
|
||||
|
||||
MenuReportOptions.__init__(self, name, dbase)
|
||||
|
||||
@ -661,7 +685,7 @@ class FanChartOptions(MenuReportOptions):
|
||||
|
||||
stdoptions.add_living_people_option(menu, category_name)
|
||||
|
||||
max_gen = NumberOption(_("Generations"), 5, 1, self.MAX_GENERATIONS)
|
||||
max_gen = NumberOption(_("Generations"), 5, 1, self.max_generations)
|
||||
max_gen.set_help(_("The number of generations "
|
||||
"to include in the report"))
|
||||
menu.add_option(category_name, "maxgen", max_gen)
|
||||
@ -670,8 +694,8 @@ class FanChartOptions(MenuReportOptions):
|
||||
circle.add_item(FULL_CIRCLE, _('full circle'))
|
||||
circle.add_item(HALF_CIRCLE, _('half circle'))
|
||||
circle.add_item(QUAR_CIRCLE, _('quarter circle'))
|
||||
circle.set_help( _("The form of the graph: full circle, half circle,"
|
||||
" or quarter circle."))
|
||||
circle.set_help(_("The form of the graph: full circle, half circle,"
|
||||
" or quarter circle."))
|
||||
menu.add_option(category_name, "circle", circle)
|
||||
|
||||
background = EnumeratedListOption(_('Background color'), BACKGROUND_GEN)
|
||||
@ -681,8 +705,8 @@ class FanChartOptions(MenuReportOptions):
|
||||
" dependent"))
|
||||
menu.add_option(category_name, "background", background)
|
||||
|
||||
radial = EnumeratedListOption( _('Orientation of radial texts'),
|
||||
RADIAL_UPRIGHT )
|
||||
radial = EnumeratedListOption(_('Orientation of radial texts'),
|
||||
RADIAL_UPRIGHT)
|
||||
radial.add_item(RADIAL_UPRIGHT, _('upright'))
|
||||
radial.add_item(RADIAL_ROUNDABOUT, _('roundabout'))
|
||||
radial.set_help(_("Print radial texts upright or roundabout"))
|
||||
@ -700,59 +724,60 @@ class FanChartOptions(MenuReportOptions):
|
||||
|
||||
stdoptions.add_localization_option(menu, category_name)
|
||||
|
||||
def make_default_style(self,default_style):
|
||||
def make_default_style(self, default_style):
|
||||
"""Make the default output style for the Fan Chart report."""
|
||||
BACKGROUND_COLORS = [
|
||||
(255, 63, 0),
|
||||
(255,175, 15),
|
||||
(255,223, 87),
|
||||
(255,255,111),
|
||||
(159,255,159),
|
||||
(111,215,255),
|
||||
( 79,151,255),
|
||||
(231, 23,255),
|
||||
(231, 23,221),
|
||||
(210,170,124),
|
||||
(189,153,112)
|
||||
background_colors = [(255, 63, 0),
|
||||
(255, 175, 15),
|
||||
(255, 223, 87),
|
||||
(255, 255, 111),
|
||||
(159, 255, 159),
|
||||
(111, 215, 255),
|
||||
(79, 151, 255),
|
||||
(231, 23, 255),
|
||||
(231, 23, 221),
|
||||
(210, 170, 124),
|
||||
(189, 153, 112)
|
||||
]
|
||||
|
||||
#Paragraph Styles
|
||||
f = FontStyle()
|
||||
f.set_size(18)
|
||||
f.set_bold(1)
|
||||
f.set_type_face(FONT_SANS_SERIF)
|
||||
p = ParagraphStyle()
|
||||
p.set_font(f)
|
||||
p.set_alignment(PARA_ALIGN_CENTER)
|
||||
p.set_description(_('The style used for the title.'))
|
||||
default_style.add_paragraph_style("FC-Title",p)
|
||||
f_style = FontStyle()
|
||||
f_style.set_size(18)
|
||||
f_style.set_bold(1)
|
||||
f_style.set_type_face(FONT_SANS_SERIF)
|
||||
p_style = ParagraphStyle()
|
||||
p_style.set_font(f_style)
|
||||
p_style.set_alignment(PARA_ALIGN_CENTER)
|
||||
p_style.set_description(_('The style used for the title.'))
|
||||
default_style.add_paragraph_style("FC-Title", p_style)
|
||||
|
||||
f = FontStyle()
|
||||
f.set_size(9)
|
||||
f.set_type_face(FONT_SANS_SERIF)
|
||||
p = ParagraphStyle()
|
||||
p.set_font(f)
|
||||
p.set_alignment(PARA_ALIGN_CENTER)
|
||||
p.set_description(_('The basic style used for the default text display.'))
|
||||
default_style.add_paragraph_style("FC-Text", p)
|
||||
f_style = FontStyle()
|
||||
f_style.set_size(9)
|
||||
f_style.set_type_face(FONT_SANS_SERIF)
|
||||
p_style = ParagraphStyle()
|
||||
p_style.set_font(f_style)
|
||||
p_style.set_alignment(PARA_ALIGN_CENTER)
|
||||
p_style.set_description(
|
||||
_('The basic style used for the default text display.'))
|
||||
default_style.add_paragraph_style("FC-Text", p_style)
|
||||
|
||||
for i in range (0, self.MAX_GENERATIONS):
|
||||
f = FontStyle()
|
||||
f.set_size(9)
|
||||
f.set_type_face(FONT_SANS_SERIF)
|
||||
p = ParagraphStyle()
|
||||
p.set_font(f)
|
||||
p.set_alignment(PARA_ALIGN_CENTER)
|
||||
p.set_description(_('The style used for the text display of generation "%d"') % i)
|
||||
default_style.add_paragraph_style("FC-Text" + "%02d" % i, p)
|
||||
for i in range(0, self.max_generations):
|
||||
f_style = FontStyle()
|
||||
f_style.set_size(9)
|
||||
f_style.set_type_face(FONT_SANS_SERIF)
|
||||
p_style = ParagraphStyle()
|
||||
p_style.set_font(f_style)
|
||||
p_style.set_alignment(PARA_ALIGN_CENTER)
|
||||
p_style.set_description(
|
||||
_('The style used for the text display of generation "%d"') % i)
|
||||
default_style.add_paragraph_style("FC-Text" + "%02d" % i, p_style)
|
||||
|
||||
# GraphicsStyles
|
||||
g = GraphicsStyle()
|
||||
g.set_paragraph_style('FC-Title')
|
||||
default_style.add_draw_style('FC-Graphic-title', g)
|
||||
g_style = GraphicsStyle()
|
||||
g_style.set_paragraph_style('FC-Title')
|
||||
default_style.add_draw_style('FC-Graphic-title', g_style)
|
||||
|
||||
for i in range (0, self.MAX_GENERATIONS):
|
||||
g = GraphicsStyle()
|
||||
g.set_paragraph_style('FC-Text' + '%02d' % i)
|
||||
g.set_fill_color(BACKGROUND_COLORS[i])
|
||||
default_style.add_draw_style('FC-Graphic' + '%02d' % i, g)
|
||||
for i in range(0, self.max_generations):
|
||||
g_style = GraphicsStyle()
|
||||
g_style.set_paragraph_style('FC-Text' + '%02d' % i)
|
||||
g_style.set_fill_color(background_colors[i])
|
||||
default_style.add_draw_style('FC-Graphic' + '%02d' % i, g_style)
|
||||
|
@ -59,6 +59,7 @@ from gramps.gen.plug.report import MenuReportOptions
|
||||
from gramps.gen.plug.report import stdoptions
|
||||
from gramps.gen.datehandler import parser
|
||||
from gramps.gen.display.place import displayer as place_displayer
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -745,6 +746,7 @@ class StatisticsChart(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
living_opt = stdoptions.run_living_people_option(self, menu, rlocale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
|
||||
get_option_by_name = menu.get_option_by_name
|
||||
get_value = lambda name: get_option_by_name(name).get_value()
|
||||
|
@ -45,6 +45,7 @@ from gramps.gen.plug.docgen import (FontStyle, ParagraphStyle, GraphicsStyle,
|
||||
from gramps.gen.sort import Sort
|
||||
from gramps.gen.config import config
|
||||
from gramps.gen.utils.db import get_birth_or_fallback, get_death_or_fallback
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -104,6 +105,7 @@ class TimeLine(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
living_opt = stdoptions.run_living_people_option(self, menu, rlocale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
|
||||
self.filter = menu.get_option_by_name('filter').get_filter()
|
||||
self.fil_name = "(%s)" % self.filter.get_name(rlocale)
|
||||
|
@ -61,6 +61,7 @@ from gramps.gen.plug.menu import (NumberOption, ColorOption, BooleanOption,
|
||||
SurnameColorOption)
|
||||
from gramps.gen.utils.db import get_birth_or_fallback, get_death_or_fallback
|
||||
from gramps.gen.utils.location import get_main_location
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -319,6 +320,7 @@ class FamilyLinesReport(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
stdoptions.run_living_people_option(self, menu, self._locale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
self._db = self.database
|
||||
|
||||
# initialize several convenient variables
|
||||
|
@ -48,6 +48,7 @@ from gramps.gen.plug.report import MenuReportOptions
|
||||
from gramps.gen.plug.report import stdoptions
|
||||
from gramps.gen.datehandler import get_date
|
||||
from gramps.gen.utils.db import get_birth_or_fallback, get_death_or_fallback
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -86,6 +87,7 @@ class HourGlassReport(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
stdoptions.run_living_people_option(self, menu, locale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
self.__db = self.database
|
||||
|
||||
self.__used_people = []
|
||||
|
@ -60,6 +60,7 @@ from gramps.gen.utils.thumbnails import get_thumbnail_path
|
||||
from gramps.gen.relationship import get_relationship_calculator
|
||||
from gramps.gen.utils.db import get_birth_or_fallback, get_death_or_fallback
|
||||
from gramps.gen.display.place import displayer as place_displayer
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -130,6 +131,7 @@ class RelGraphReport(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
stdoptions.run_living_people_option(self, menu, self._locale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
self._db = self.database
|
||||
|
||||
self.includeid = get_value('incid')
|
||||
|
@ -48,6 +48,7 @@ from gramps.gen.plug.report import utils as ReportUtils
|
||||
from gramps.gen.plug.report import MenuReportOptions
|
||||
from gramps.gen.plug.report import stdoptions
|
||||
from gramps.plugins.lib.libnarrate import Narrator
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -110,6 +111,8 @@ class AncestorReport(Report):
|
||||
|
||||
stdoptions.run_name_format_option(self, menu)
|
||||
|
||||
self.database = CacheProxyDb(self.database)
|
||||
|
||||
self.__narrator = Narrator(self.database, use_fulldate=True,
|
||||
nlocale=rlocale)
|
||||
|
||||
|
@ -55,6 +55,7 @@ from gramps.gen.sort import Sort
|
||||
from gramps.gen.utils.db import (get_birth_or_fallback, get_death_or_fallback,
|
||||
get_marriage_or_fallback,
|
||||
get_divorce_or_fallback)
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -341,6 +342,7 @@ class DescendantReport(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
stdoptions.run_living_people_option(self, menu, self._locale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
|
||||
self.max_generations = menu.get_option_by_name('gen').get_value()
|
||||
pid = menu.get_option_by_name('pid').get_value()
|
||||
|
@ -59,6 +59,7 @@ from gramps.gen.plug.report import MenuReportOptions
|
||||
from gramps.gen.plug.report import stdoptions
|
||||
from gramps.plugins.lib.libnarrate import Narrator
|
||||
from gramps.gen.display.place import displayer as place_displayer
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -124,6 +125,7 @@ class DetAncestorReport(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
stdoptions.run_living_people_option(self, menu, self._locale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
self._db = self.database
|
||||
|
||||
self.max_generations = get_value('gen')
|
||||
|
@ -59,6 +59,7 @@ from gramps.gen.plug.report import MenuReportOptions
|
||||
from gramps.gen.plug.report import stdoptions
|
||||
from gramps.plugins.lib.libnarrate import Narrator
|
||||
from gramps.gen.display.place import displayer as place_displayer
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -136,6 +137,7 @@ class DetDescendantReport(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
stdoptions.run_living_people_option(self, menu, self._locale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
self.db = self.database
|
||||
|
||||
self.max_generations = get_value('gen')
|
||||
|
@ -46,6 +46,7 @@ from gramps.gen.plug.report import utils as ReportUtils
|
||||
from gramps.gen.plug.report import MenuReportOptions
|
||||
from gramps.gen.plug.report import stdoptions
|
||||
from gramps.gen.datehandler import get_date
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -80,6 +81,7 @@ class EndOfLineReport(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
stdoptions.run_living_people_option(self, menu, rlocale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
|
||||
pid = menu.get_option_by_name('pid').get_value()
|
||||
self.center_person = self.database.get_person_from_gramps_id(pid)
|
||||
|
@ -49,6 +49,7 @@ from gramps.gen.plug.docgen import (IndexMark, FontStyle, ParagraphStyle,
|
||||
FONT_SANS_SERIF, FONT_SERIF,
|
||||
INDEX_TYPE_TOC, PARA_ALIGN_CENTER)
|
||||
from gramps.gen.display.place import displayer as place_displayer
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -89,6 +90,7 @@ class FamilyGroup(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
stdoptions.run_living_people_option(self, menu, self._locale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
self.db = self.database
|
||||
|
||||
self.filter = menu.get_option_by_name('filter').get_filter()
|
||||
|
@ -57,6 +57,7 @@ from gramps.gen.plug.report import endnotes as Endnotes
|
||||
from gramps.gen.plug.report import stdoptions
|
||||
from gramps.gen.utils.file import media_path_full
|
||||
from gramps.gen.utils.lds import TEMPLES
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -123,6 +124,7 @@ class IndivCompleteReport(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
stdoptions.run_living_people_option(self, menu, self._locale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
self._db = self.database
|
||||
|
||||
self.use_pagebreak = menu.get_option_by_name('pageben').get_value()
|
||||
|
@ -48,6 +48,7 @@ from gramps.gen.plug.report import utils as ReportUtils
|
||||
from gramps.gen.plug.report import MenuReportOptions
|
||||
from gramps.gen.plug.report import stdoptions
|
||||
from gramps.gen.utils.db import get_birth_or_fallback, get_death_or_fallback
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -88,6 +89,7 @@ class KinshipReport(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
stdoptions.run_living_people_option(self, menu, rlocale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
self.__db = self.database
|
||||
|
||||
self.max_descend = menu.get_option_by_name('maxdescend').get_value()
|
||||
|
@ -50,7 +50,7 @@ from gramps.gen.utils.location import get_location_list
|
||||
from gramps.gen.display.place import displayer as place_displayer
|
||||
from gramps.gen.lib import PlaceType
|
||||
from gramps.gen.errors import ReportError
|
||||
from gramps.gen.proxy import LivingProxyDb
|
||||
from gramps.gen.proxy import LivingProxyDb, CacheProxyDb
|
||||
|
||||
class PlaceReport(Report):
|
||||
"""
|
||||
@ -87,6 +87,7 @@ class PlaceReport(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, menu)
|
||||
living_opt = stdoptions.run_living_people_option(self, menu, rlocale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
|
||||
self._lv = menu.get_option_by_name('living_people').get_value()
|
||||
for (value, description) in living_opt.get_items(xml_items=True):
|
||||
|
@ -49,7 +49,7 @@ from gramps.gen.plug.report import MenuReportOptions
|
||||
from gramps.gen.plug.report import stdoptions
|
||||
from gramps.gen.lib import Span
|
||||
from gramps.gen.errors import ReportError
|
||||
from gramps.gen.proxy import LivingProxyDb
|
||||
from gramps.gen.proxy import LivingProxyDb, CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -100,6 +100,8 @@ class RecordsReport(Report):
|
||||
|
||||
self._nf = stdoptions.run_name_format_option(self, menu)
|
||||
|
||||
self.database = CacheProxyDb(self.database)
|
||||
|
||||
def write_report(self):
|
||||
"""
|
||||
Build the actual report.
|
||||
|
@ -49,6 +49,7 @@ from gramps.gen.plug.docgen import (IndexMark, FontStyle, ParagraphStyle,
|
||||
PARA_ALIGN_CENTER)
|
||||
from gramps.gen.utils.file import media_path_full
|
||||
from gramps.gen.datehandler import get_date
|
||||
from gramps.gen.proxy import CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -79,6 +80,7 @@ class SummaryReport(Report):
|
||||
|
||||
stdoptions.run_private_data_option(self, options.menu)
|
||||
stdoptions.run_living_people_option(self, options.menu, rlocale)
|
||||
self.database = CacheProxyDb(self.database)
|
||||
self.__db = self.database
|
||||
|
||||
def write_report(self):
|
||||
|
@ -52,7 +52,7 @@ from gramps.gen.errors import ReportError
|
||||
from gramps.gen.datehandler import get_date
|
||||
from gramps.gen.utils.db import get_participant_from_event
|
||||
from gramps.gen.display.place import displayer as place_displayer
|
||||
from gramps.gen.proxy import LivingProxyDb
|
||||
from gramps.gen.proxy import LivingProxyDb, CacheProxyDb
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
@ -104,6 +104,8 @@ class TagReport(Report):
|
||||
|
||||
stdoptions.run_name_format_option(self, menu)
|
||||
|
||||
self.database = CacheProxyDb(self.database)
|
||||
|
||||
def write_report(self):
|
||||
self.doc.start_paragraph("TR-Title")
|
||||
# feature request 2356: avoid genitive form
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user