Merge branch 'gramps51'

This commit is contained in:
Nick Hall 2022-02-06 19:07:14 +00:00
commit a5ac4ac43c
77 changed files with 963 additions and 362 deletions

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -251,7 +251,7 @@ PLACES
<!ELEMENT places (placeobj)*> <!ELEMENT places (placeobj)*>
<!ELEMENT placeobj (ptitle?, pname+, code?, coord?, placeref*, location*, <!ELEMENT placeobj (ptitle?, code?, pname+, coord?, placeref*, location*,
objref*, url*, noteref*, citationref*, tagref*)> objref*, url*, noteref*, citationref*, tagref*)>
<!ATTLIST placeobj <!ATTLIST placeobj
id CDATA #IMPLIED id CDATA #IMPLIED

View File

@ -453,10 +453,10 @@
<ref name="primary-object"/> <ref name="primary-object"/>
<attribute name="type"><text/></attribute> <attribute name="type"><text/></attribute>
<optional><element name="ptitle"><text/></element></optional> <optional><element name="ptitle"><text/></element></optional>
<optional><element name="code"><text/></element></optional>
<oneOrMore><element name="pname"> <oneOrMore><element name="pname">
<ref name="placename-content"/> <ref name="placename-content"/>
</element></oneOrMore> </element></oneOrMore>
<optional><element name="code"><text/></element></optional>
<optional><element name="coord"> <optional><element name="coord">
<attribute name="long"><text/></attribute> <attribute name="long"><text/></attribute>
<attribute name="lat"><text/></attribute> <attribute name="lat"><text/></attribute>

16
debian/changelog vendored
View File

@ -1,3 +1,19 @@
gramps (5.1.4-1) unstable; urgency=medium
* New release
* Add new copyrights
* Update watch file
* Patch probably alive test to fix FTBFS
-- Ross Gammon <rossgammon@debian.org> Sun, 15 Aug 2021 18:31:56 +0200
gramps (5.1.3-1) focal; urgency=medium
* New release
* Update debian/copyright for Alex Roitman
-- Ross Gammon <rosco2@ubuntu.com> Sun, 16 Aug 2020 20:23:34 +0200
gramps (5.1.2-1) unstable; urgency=medium gramps (5.1.2-1) unstable; urgency=medium
* New release * New release

2
debian/copyright vendored
View File

@ -92,6 +92,8 @@ Copyright: 2000-2007, Alex Roitman
2018, Robin van der Vliet 2018, Robin van der Vliet
2018, Theo van Rijn 2018, Theo van Rijn
2019, Matthias Kemmer 2019, Matthias Kemmer
2020, Jan Sparreboom
2021, Mirko Leonhaeuser
License: GPL-2+ License: GPL-2+
Files: debian/* Files: debian/*

View File

@ -0,0 +1,22 @@
Description: Fix probably alive test
The probably alive funtion was fixed just prior to the Gramps 5.1.4
release. It appears the relevant unit test was not updated to match.
The relevant commit:
https://github.com/gramps-project/gramps/commit/a685b96f700dcfc6b953413cb3adc8be61d87438
Author: Ross Gammon <rossgammon@debian.org>
Forwarded: no
Applied-Upstream: no
Last-Update: 2021-08-09
---
This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
--- a/gramps/gen/filters/rules/test/person_rules_test.py
+++ b/gramps/gen/filters/rules/test/person_rules_test.py
@@ -347,7 +347,7 @@
"""
rule = ProbablyAlive(['1900'])
res = self.filter_with_rule(rule)
- self.assertEqual(len(res), 766)
+ self.assertEqual(len(res), 733)
def test_RegExpName(self):
"""

1
debian/patches/series vendored Normal file
View File

@ -0,0 +1 @@
fix-probably_alive_test.patch

8
debian/watch vendored
View File

@ -1,8 +1,6 @@
version=3 version=4
opts=\ opts=\
dversionmangle=s/(\~|\+)(debian|dfsg|ds|deb)(\.\d+)?$//,\ filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/gramps-project-$1\.tar\.gz/,\
filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/$1\.tar\.gz/,\
repacksuffix=~dfsg \ repacksuffix=~dfsg \
https://github.com/gramps-project/gramps/tags \ https://github.com/gramps-project/gramps/tags \
.*/archive/v?([\d\.]+).tar.gz .*/v?(\d\S+)\.tar\.gz

View File

@ -226,7 +226,7 @@ GTK_GETTEXT_DOMAIN = 'gtk30'
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
COPYRIGHT_MSG = "© 2001-2006 Donald N. Allingham\n" \ COPYRIGHT_MSG = "© 2001-2006 Donald N. Allingham\n" \
"© 2007-2020 The Gramps Developers" "© 2007-2022 The Gramps Developers"
COMMENTS = _("Gramps\n (Genealogical Research and Analysis " COMMENTS = _("Gramps\n (Genealogical Research and Analysis "
"Management Programming System)\n" "Management Programming System)\n"
"is a personal genealogy program.") "is a personal genealogy program.")

View File

@ -83,35 +83,37 @@ class DateParserNL(DateParser):
month_to_int["xbris"] = 12 month_to_int["xbris"] = 12
modifier_to_int = { modifier_to_int = {
'voor' : Date.MOD_BEFORE, 'voor' : Date.MOD_BEFORE,
'na' : Date.MOD_AFTER, 'na' : Date.MOD_AFTER,
'tegen' : Date.MOD_ABOUT, 'ca.' : Date.MOD_ABOUT,
'om' : Date.MOD_ABOUT, 'circa' : Date.MOD_ABOUT,
'rond' : Date.MOD_ABOUT, 'om' : Date.MOD_ABOUT,
'circa' : Date.MOD_ABOUT, 'omstreeks' : Date.MOD_ABOUT,
'ca.' : Date.MOD_ABOUT, 'ongeveer' : Date.MOD_ABOUT,
'rond' : Date.MOD_ABOUT,
'tegen' : Date.MOD_ABOUT,
} }
calendar_to_int = { calendar_to_int = {
'gregoriaans' : Date.CAL_GREGORIAN, 'gregoriaans' : Date.CAL_GREGORIAN,
'greg.' : Date.CAL_GREGORIAN, 'greg.' : Date.CAL_GREGORIAN,
'juliaans' : Date.CAL_JULIAN, 'juliaans' : Date.CAL_JULIAN,
'jul.' : Date.CAL_JULIAN, 'jul.' : Date.CAL_JULIAN,
'hebreeuws' : Date.CAL_HEBREW, 'hebreeuws' : Date.CAL_HEBREW,
'hebr.' : Date.CAL_HEBREW, 'hebr.' : Date.CAL_HEBREW,
'islamitisch' : Date.CAL_ISLAMIC, 'islamitisch' : Date.CAL_ISLAMIC,
'isl.' : Date.CAL_ISLAMIC, 'isl.' : Date.CAL_ISLAMIC,
'franse republiek': Date.CAL_FRENCH, 'frans republiekeins' : Date.CAL_FRENCH,
'fran.' : Date.CAL_FRENCH, 'fran.' : Date.CAL_FRENCH,
'persisch' : Date.CAL_PERSIAN, 'persisch' : Date.CAL_PERSIAN,
'zweeds' : Date.CAL_SWEDISH, 'zweeds' : Date.CAL_SWEDISH,
'z' : Date.CAL_SWEDISH, 'z' : Date.CAL_SWEDISH,
} }
quality_to_int = { quality_to_int = {
'geschat' : Date.QUAL_ESTIMATED, 'geschat' : Date.QUAL_ESTIMATED,
'gesch.' : Date.QUAL_ESTIMATED, 'gesch.' : Date.QUAL_ESTIMATED,
'berekend' : Date.QUAL_CALCULATED, 'berekend' : Date.QUAL_CALCULATED,
'ber.' : Date.QUAL_CALCULATED, 'ber.' : Date.QUAL_CALCULATED,
} }
@ -147,17 +149,17 @@ class DateDisplayNL(DateDisplay):
calendar = ( calendar = (
"", "juliaans", "hebreeuws", "", "juliaans", "hebreeuws",
"franse republiek", "persisch", "islamitisch", "frans republikeins", "persisch", "islamitisch",
"zweeds" ) "zweeds" )
_mod_str = ("", "voor ", "na ", "rond ", "", "", "") _mod_str = ("", "voor ", "na ", "omstreeks ", "", "", "")
_qual_str = ("", "geschat ", "berekend ") _qual_str = ("", "geschat ", "berekend ")
_bce_str = "%s v. Chr." _bce_str = "%s v. Chr."
formats = ( formats = (
"JJJJ-MM-DD (ISO)", "Numerisch DD/MM/JJ", "Maand Dag, Jaar", "JJJJ-MM-DD (ISO)", "Numeriek DD/MM/JJJJ", "Maand Dag, Jaar",
"Mnd. Dag Jaar", "Dag Maand Jaar", "Dag Mnd. Jaar" "Mnd. Dag Jaar", "Dag Maand Jaar", "Dag Mnd. Jaar"
) )
# this definition must agree with its "_display_gregorian" method # this definition must agree with its "_display_gregorian" method

View File

@ -52,7 +52,6 @@ methods should be changed to generate exceptions. Possibly by globally changing
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
import logging import logging
import os
import inspect import inspect
from abc import ABCMeta from abc import ABCMeta
from types import FunctionType from types import FunctionType
@ -160,10 +159,12 @@ def wrapper(method):
""" """
class_name = args[0].__class__.__name__ class_name = args[0].__class__.__name__
func_name = method.__name__ func_name = method.__name__
caller_frame = inspect.stack()[1] frame = inspect.currentframe()
c_frame = frame.f_back
c_code = c_frame.f_code
LOG.debug('calling %s.%s()... from file %s, line %s in %s', LOG.debug('calling %s.%s()... from file %s, line %s in %s',
class_name, func_name, os.path.split(caller_frame[1])[1], class_name, func_name, c_code.co_filename, c_frame.f_lineno,
caller_frame[2], caller_frame[3]) c_code.co_name)
return method(*args, **keywargs) return method(*args, **keywargs)
return wrapped return wrapped

View File

@ -78,15 +78,13 @@ class DbTxn(defaultdict):
elapsed_time = time.time() - self.start_time elapsed_time = time.time() - self.start_time
if __debug__: if __debug__:
caller_frame = inspect.stack()[1] frame = inspect.currentframe()
c_frame = frame.f_back
c_code = c_frame.f_code
_LOG.debug(" **** DbTxn %s exited. Called from file %s, " _LOG.debug(" **** DbTxn %s exited. Called from file %s, "
"line %s, in %s **** %.2f seconds" % "line %s, in %s **** %.2f seconds",
((hex(id(self)),)+ hex(id(self)), c_code.co_filename, c_frame.f_lineno,
(os.path.split(caller_frame[1])[1],)+ c_code.co_name, elapsed_time)
tuple(caller_frame[i] for i in range(2, 4))+
(elapsed_time,)
)
)
return False return False

View File

@ -42,6 +42,8 @@ from ..const import PLUGINS_DIR, USER_PLUGINS
from ..constfunc import win, get_env_var from ..constfunc import win, get_env_var
from ..config import config from ..config import config
from .dbconst import DBLOGNAME, DBLOCKFN, DBBACKEND from .dbconst import DBLOGNAME, DBLOCKFN, DBBACKEND
from ..const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -70,12 +72,14 @@ def make_database(plugin_id):
database = getattr(mod, pdata.databaseclass) database = getattr(mod, pdata.databaseclass)
db = database() db = database()
import inspect import inspect
caller_frame = inspect.stack()[1] frame = inspect.currentframe()
c_frame = frame.f_back
c_code = c_frame.f_code
_LOG.debug("Database class instance created Class:%s instance:%s. " _LOG.debug("Database class instance created Class:%s instance:%s. "
"Called from File %s, line %s, in %s" "Called from File %s, line %s, in %s",
% ((db.__class__.__name__, hex(id(db))) db.__class__.__name__, hex(id(db)), c_code.co_filename,
+ (os.path.split(caller_frame[1])[1],) c_frame.f_lineno, c_code.co_name)
+ tuple(caller_frame[i] for i in range(2, 4))))
return db return db
else: else:
raise Exception("can't load database backend: '%s'" % plugin_id) raise Exception("can't load database backend: '%s'" % plugin_id)
@ -209,8 +213,8 @@ def write_lock_file(name):
if win(): if win():
user = get_env_var('USERNAME') user = get_env_var('USERNAME')
host = get_env_var('USERDOMAIN') host = get_env_var('USERDOMAIN')
if host is None: if not user:
host = "" user = _("Unknown")
else: else:
host = os.uname()[1] host = os.uname()[1]
# An ugly workaround for os.getlogin() issue with Konsole # An ugly workaround for os.getlogin() issue with Konsole

View File

@ -29,7 +29,6 @@ Provide the database state class
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
import sys import sys
import os
import logging import logging
import inspect import inspect
@ -88,10 +87,12 @@ class DbState(Callback):
""" """
class_name = self.__class__.__name__ class_name = self.__class__.__name__
func_name = "is_open" func_name = "is_open"
caller_frame = inspect.stack()[1] frame = inspect.currentframe()
c_frame = frame.f_back
c_code = c_frame.f_code
_LOG.debug('calling %s.%s()... from file %s, line %s in %s', _LOG.debug('calling %s.%s()... from file %s, line %s in %s',
class_name, func_name, os.path.split(caller_frame[1])[1], class_name, func_name, c_code.co_filename, c_frame.f_lineno,
caller_frame[2], caller_frame[3]) c_code.co_name)
return (self.db is not None) and self.db.is_open() return (self.db is not None) and self.db.is_open()
def change_database(self, database): def change_database(self, database):

View File

@ -999,6 +999,8 @@ class NameDisplay:
1. if group name is defined, use that 1. if group name is defined, use that
2. if group name is defined for the primary surname, use that 2. if group name is defined for the primary surname, use that
3. use primary surname itself otherwise 3. use primary surname itself otherwise
4. if no primary surname, do we have a ma/patronymic surname ?
in this case, group name will be the ma/patronymic name.
:param pn: raw unserialized data of name :param pn: raw unserialized data of name
:type pn: tuple :type pn: tuple
@ -1007,8 +1009,25 @@ class NameDisplay:
""" """
if pn[_GROUP]: if pn[_GROUP]:
return pn[_GROUP] return pn[_GROUP]
return db.get_name_group_mapping(_raw_primary_surname_only( name = pn[_GROUP]
pn[_SURNAME_LIST])) if not name:
# if we have no primary surname, perhaps we have a
# patronymic/matronynic name ?
srnme = pn[_ORIGINPATRO]
surname = []
for _surname in srnme:
if (_surname[_TYPE_IN_LIST][0] == _ORIGINPATRO
or _surname[_TYPE_IN_LIST][0] == _ORIGINMATRO):
# Yes, we have one.
surname = [_surname]
# name1 is the ma/patronymic name.
name1 = _raw_patro_surname_only(surname)
if name1 and len(srnme) == 1:
name = db.get_name_group_mapping(name1)
if not name:
name = db.get_name_group_mapping(_raw_primary_surname_only(
pn[_SURNAME_LIST]))
return name
def _make_fn(self, format_str, d, args): def _make_fn(self, format_str, d, args):
""" """

View File

@ -51,6 +51,7 @@ editor_rule_list = [
MediaPrivate, MediaPrivate,
MatchesFilter, MatchesFilter,
MatchesSourceConfidence, MatchesSourceConfidence,
HasMedia,
HasAttribute, HasAttribute,
ChangedSince, ChangedSince,
HasTag, HasTag,

View File

@ -52,7 +52,7 @@ class MatchesEventFilter(MatchesEventFilterBase):
name = _('Persons with events matching the <event filter>') name = _('Persons with events matching the <event filter>')
description = _("Matches persons who have events that match a certain" description = _("Matches persons who have events that match a certain"
" event filter") " event filter")
category = _('General filters') category = _('Event filters')
# we want to have this filter show event filters # we want to have this filter show event filters
namespace = 'Event' namespace = 'Event'

View File

@ -98,9 +98,10 @@ class BaseTest(unittest.TestCase):
filter_.set_invert(invert) filter_.set_invert(invert)
stime = perf_counter() stime = perf_counter()
results = filter_.apply(self.db) results = filter_.apply(self.db)
if __debug__: # if __debug__:
rulename = inspect.stack()[1][3] # frame = inspect.currentframe()
print("%s: %.2f\n" % (rulename, perf_counter() - stime)) # rulename = frame.f_back.f_code.co_name
# print("%s: %.2f\n" % (rulename, perf_counter() - stime))
return set(results) return set(results)
def test_Complex_1(self): def test_Complex_1(self):
@ -346,7 +347,7 @@ class BaseTest(unittest.TestCase):
""" """
rule = ProbablyAlive(['1900']) rule = ProbablyAlive(['1900'])
res = self.filter_with_rule(rule) res = self.filter_with_rule(rule)
self.assertEqual(len(res), 766) self.assertEqual(len(res), 733)
def test_RegExpName(self): def test_RegExpName(self):
""" """

View File

@ -77,14 +77,14 @@ class Span:
self.precision = 2 self.precision = 2
self.negative = False self.negative = False
if self.valid: if self.valid:
if self.date1.calendar != Date.CAL_GREGORIAN:
self.date1 = self.date1.to_calendar("gregorian")
if self.date2.calendar != Date.CAL_GREGORIAN:
self.date2 = self.date2.to_calendar("gregorian")
if self.date1.sortval < self.date2.sortval: if self.date1.sortval < self.date2.sortval:
self.date1 = date2 self.date1 = date2
self.date2 = date1 self.date2 = date1
self.negative = True self.negative = True
if self.date1.calendar != Date.CAL_GREGORIAN:
self.date1 = self.date1.to_calendar("gregorian")
if self.date2.calendar != Date.CAL_GREGORIAN:
self.date2 = self.date2.to_calendar("gregorian")
if self.date1.get_modifier() == Date.MOD_NONE: if self.date1.get_modifier() == Date.MOD_NONE:
if self.date2.get_modifier() == Date.MOD_NONE: if self.date2.get_modifier() == Date.MOD_NONE:
val = self.date1.sortval - self.date2.sortval val = self.date1.sortval - self.date2.sortval

View File

@ -38,7 +38,7 @@ from ...datehandler import get_date_formats, set_format
from ...datehandler import parser as _dp from ...datehandler import parser as _dp
from ...datehandler import displayer as _dd from ...datehandler import displayer as _dd
from ...datehandler._datedisplay import DateDisplayEn from ...datehandler._datedisplay import DateDisplayEn
from ...lib.date import Date, DateError, Today, calendar_has_fixed_newyear from ...lib.date import Date, DateError, Today, calendar_has_fixed_newyear, Span
date_tests = {} date_tests = {}
@ -432,6 +432,36 @@ class ArithmeticDateTest(BaseDateTest):
self.assertEqual(val1, val2, self.assertEqual(val1, val2,
"'%s' should be '%s' but was '%s'" % (exp1, val2, val1)) "'%s' should be '%s' but was '%s'" % (exp1, val2, val1))
#-------------------------------------------------------------------------
#
# SpanTest
#
#-------------------------------------------------------------------------
class SpanTest(BaseDateTest):
"""
Test spans.
"""
tests = [((2000, 1, 31), (2000, 1, 1), 30),
((1799, 11, 19), (8, 2, 18, Date.CAL_FRENCH), 10),
((8, 2, 18, Date.CAL_FRENCH), (1799, 11, 4), 5),
((8, 2, 18, Date.CAL_FRENCH), (3, 2, 9, Date.CAL_FRENCH), 1836)]
def test_evaluate(self):
for value1, value2, duration in self.tests:
date1 = self._get_date(value1)
date2 = self._get_date(value2)
span1 = Span(date1, date2)
self.assertEqual(int(span1), duration)
span2 = Span(date2, date1)
self.assertEqual(int(span2), -duration)
def _get_date(self, value):
date = Date()
if len(value) == 4:
date.set_calendar(value[3])
date.set_yr_mon_day(value[0], value[1], value[2])
return date
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# SwedishDateTest # SwedishDateTest

View File

@ -31,8 +31,8 @@ Provide merge capabilities for persons.
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from ..db import DbTxn from ..db import DbTxn
from ..const import GRAMPS_LOCALE as glocale from ..const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
from ..errors import MergeError from ..errors import MergeError
_ = glocale.translation.sgettext
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -49,11 +49,12 @@ class MergePersonQuery:
self.titanic = titanic self.titanic = titanic
if self.check_for_spouse(self.phoenix, self.titanic): if self.check_for_spouse(self.phoenix, self.titanic):
raise MergeError(_("Spouses cannot be merged. To merge these " raise MergeError(_("Spouses cannot be merged. To merge these "
"people, you must first break the relationship between them.")) "people, you must first break the relationship"
" between them."))
if self.check_for_child(self.phoenix, self.titanic): if self.check_for_child(self.phoenix, self.titanic):
raise MergeError(_("A parent and child cannot be merged. To merge " raise MergeError(_("A parent and child cannot be merged. To merge "
"these people, you must first break the relationship between " "these people, you must first break the relatio"
"them.")) "nship between them."))
def check_for_spouse(self, person1, person2): def check_for_spouse(self, person1, person2):
"""Return if person1 and person2 are spouses of eachother.""" """Return if person1 and person2 are spouses of eachother."""
@ -80,12 +81,12 @@ class MergePersonQuery:
main_family.merge(family) main_family.merge(family)
for childref in family.get_child_ref_list(): for childref in family.get_child_ref_list():
child = self.database.get_person_from_handle( child = self.database.get_person_from_handle(
childref.get_reference_handle()) childref.get_reference_handle())
if main_family_handle in child.parent_family_list: if main_family_handle in child.parent_family_list:
child.remove_handle_references('Family', [family_handle]) child.remove_handle_references('Family', [family_handle])
else: else:
child.replace_handle_reference('Family', family_handle, child.replace_handle_reference('Family', family_handle,
main_family_handle) main_family_handle)
self.database.commit_person(child, trans) self.database.commit_person(child, trans)
if self.phoenix: if self.phoenix:
self.phoenix.remove_family_handle(family_handle) self.phoenix.remove_family_handle(family_handle)
@ -143,7 +144,8 @@ class MergePersonQuery:
for family_handle in self.phoenix.get_parent_family_handle_list(): for family_handle in self.phoenix.get_parent_family_handle_list():
family = self.database.get_family_from_handle(family_handle) family = self.database.get_family_from_handle(family_handle)
if family.has_handle_reference('Person', old_handle): if family.has_handle_reference('Person', old_handle):
family.replace_handle_reference('Person', old_handle,new_handle) family.replace_handle_reference('Person', old_handle,
new_handle)
self.database.commit_family(family, trans) self.database.commit_family(family, trans)
family_merge_guard = False family_merge_guard = False
@ -182,7 +184,10 @@ class MergePersonQuery:
self.database.commit_family(family, trans) self.database.commit_family(family, trans)
parent_list.append(parents) parent_list.append(parents)
if self.database.get_default_handle() == old_handle: hp_hdl = self.database.get_default_handle()
self.database.set_default_person_handle(None) if (hp_hdl in (self.phoenix.get_handle(), self.titanic.get_handle())
and hp_hdl != self.phoenix.get_handle()):
self.database.set_default_person_handle(self.phoenix.get_handle())
self.database.remove_person(old_handle, trans) self.database.remove_person(old_handle, trans)
return family_merge_ok return family_merge_ok

View File

@ -113,6 +113,10 @@ else:
_GS_CMD = where_is("gs") _GS_CMD = where_is("gs")
def esc(id_txt):
return id_txt.replace('"', '\\"')
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# #
# GVOptions # GVOptions
@ -575,7 +579,7 @@ class GVDocBase(BaseDoc, GVDoc):
text += ' URL="%s"' % url text += ' URL="%s"' % url
text += " ]" text += " ]"
self.write(' "%s" %s;\n' % (node_id, text)) self.write(' "%s" %s;\n' % (esc(node_id), text))
def add_link(self, id1, id2, style="", head="", tail="", comment=""): def add_link(self, id1, id2, style="", head="", tail="", comment=""):
""" """
@ -583,7 +587,7 @@ class GVDocBase(BaseDoc, GVDoc):
Implements GVDocBase.add_link(). Implements GVDocBase.add_link().
""" """
self.write(' "%s" -> "%s"' % (id1, id2)) self.write(' "%s" -> "%s"' % (esc(id1), esc(id2)))
if style or head or tail: if style or head or tail:
self.write(' [') self.write(' [')
@ -635,7 +639,7 @@ class GVDocBase(BaseDoc, GVDoc):
Implements GVDocBase.add_samerank(). Implements GVDocBase.add_samerank().
""" """
self.write(' {rank=same "%s" "%s"}\n' % (id1, id2)) self.write(' {rank=same "%s" "%s"}\n' % (esc(id1), esc(id2)))
def rewrite_label(self, id, label): def rewrite_label(self, id, label):
""" """
@ -643,7 +647,7 @@ class GVDocBase(BaseDoc, GVDoc):
Implements GVDocBase.rewrite_label(). Implements GVDocBase.rewrite_label().
""" """
self.write(' "%s" [label = "%s"]\n' % (id, label)) self.write(' "%s" [label = "%s"]\n' % (esc(id), label))
def start_subgraph(self, graph_id): def start_subgraph(self, graph_id):
""" Implement GVDocBase.start_subgraph() """ """ Implement GVDocBase.start_subgraph() """

View File

@ -142,6 +142,8 @@ class ProbablyAlive:
# person died more than MAX after current year # person died more than MAX after current year
if death_date.is_valid(): if death_date.is_valid():
birth_date = death_date.copy_offset_ymd(year=-self.MAX_AGE_PROB_ALIVE) birth_date = death_date.copy_offset_ymd(year=-self.MAX_AGE_PROB_ALIVE)
else:
birth_date = death_date
explain = _("death date") explain = _("death date")
if not death_date and birth_date: if not death_date and birth_date:

View File

@ -324,12 +324,16 @@ class Callback:
return return
# Check signal exists # Check signal exists
frame = inspect.currentframe()
c_frame = frame.f_back
c_code = c_frame.f_code
frame_info = (c_code.co_filename, c_frame.f_lineno, c_code.co_name)
if signal_name not in self.__signal_map: if signal_name not in self.__signal_map:
self._warn("Attempt to emit to unknown signal: %s\n" self._warn("Attempt to emit to unknown signal: %s\n"
" from: file: %s\n" " from: file: %s\n"
" line: %d\n" " line: %d\n"
" func: %s\n" " func: %s\n"
% ((str(signal_name), ) + inspect.stack()[1][1:4])) % ((str(signal_name), ) + frame_info))
return return
# check that the signal is not already being emitted. This prevents # check that the signal is not already being emitted. This prevents
@ -340,7 +344,7 @@ class Callback:
" from: file: %s\n" " from: file: %s\n"
" line: %d\n" " line: %d\n"
" func: %s\n" " func: %s\n"
% ((str(signal_name), ) + inspect.stack()[1][1:4])) % ((str(signal_name), ) + frame_info))
return return
try: try:
@ -358,7 +362,7 @@ class Callback:
" from: file: %s\n" " from: file: %s\n"
" line: %d\n" " line: %d\n"
" func: %s\n" " func: %s\n"
% ((str(signal_name), ) + inspect.stack()[1][1:4])) % ((str(signal_name), ) + frame_info))
return return
# type check arguments # type check arguments
@ -369,7 +373,7 @@ class Callback:
" from: file: %s\n" " from: file: %s\n"
" line: %d\n" " line: %d\n"
" func: %s\n" " func: %s\n"
% ((str(signal_name), ) + inspect.stack()[1][1:4])) % ((str(signal_name), ) + frame_info))
return return
if len(args) > 0: if len(args) > 0:
@ -379,7 +383,7 @@ class Callback:
" from: file: %s\n" " from: file: %s\n"
" line: %d\n" " line: %d\n"
" func: %s\n" " func: %s\n"
% ((str(signal_name), ) + inspect.stack()[1][1:4])) % ((str(signal_name), ) + frame_info))
return return
if arg_types is not None: if arg_types is not None:
@ -391,7 +395,7 @@ class Callback:
" line: %d\n" " line: %d\n"
" func: %s\n" " func: %s\n"
" arg passed was: %s, type of arg passed %s, type should be: %s\n" " arg passed was: %s, type of arg passed %s, type should be: %s\n"
% ((str(signal_name), ) + inspect.stack()[1][1:4] +\ % ((str(signal_name), ) + frame_info +\
(args[i], repr(type(args[i])), repr(arg_types[i])))) (args[i], repr(type(args[i])), repr(arg_types[i]))))
return return
if signal_name in self.__callback_map: if signal_name in self.__callback_map:

View File

@ -49,7 +49,7 @@ class CSVTab(TabbedDoc):
else: else:
self.filename = filename self.filename = filename
self.f = open(self.filename, "w", self.f = open(self.filename, "w", newline='',
encoding='utf_8_sig' if win() else 'utf_8') encoding='utf_8_sig' if win() else 'utf_8')
self.writer = csv.writer(self.f) self.writer = csv.writer(self.f)

View File

@ -526,6 +526,8 @@ class GrampsLocale:
# with locale instead of gettext. Win32 doesn't support bindtextdomain. # with locale instead of gettext. Win32 doesn't support bindtextdomain.
if self.localedir: if self.localedir:
if not sys.platform == 'win32': if not sys.platform == 'win32':
# bug12278, _build_popup_ui() under linux and macOS
locale.textdomain(self.localedomain)
locale.bindtextdomain(self.localedomain, self.localedir) locale.bindtextdomain(self.localedomain, self.localedir)
else: else:
self._win_bindtextdomain(self.localedomain.encode('utf-8'), self._win_bindtextdomain(self.localedomain.encode('utf-8'),

View File

@ -127,15 +127,32 @@ if win():
elif not os.path.isdir(HOME_DIR): elif not os.path.isdir(HOME_DIR):
os.makedirs(HOME_DIR) os.makedirs(HOME_DIR)
sys.stdout = sys.stderr = open(logfile, "w", encoding='utf-8') sys.stdout = sys.stderr = open(logfile, "w", encoding='utf-8')
stderrh = logging.StreamHandler(sys.stderr) # macOS sets stderr to /dev/null when running without a terminal,
stderrh.setFormatter(form) # e.g. if Gramps.app is lauched by double-clicking on it in
stderrh.setLevel(logging.DEBUG) # finder. Write to a file instead.
if mac() and not sys.stdin.isatty():
from tempfile import gettempdir
# Setup the base level logger, this one gets log_file_name = 'gramps-' + str(os.getpid()) + '.log'
# everything. log_file_path = os.path.join(gettempdir(), log_file_name)
l = logging.getLogger() log_file_handler = logging.FileHandler(log_file_path, mode='a',
l.setLevel(logging.WARNING) encoding='utf-8')
l.addHandler(stderrh) log_file_handler.setFormatter(form)
log_file_handler.setLevel(logging.DEBUG)
logger = logging.getLogger()
logger.setLevel(logging.WARNING)
logger.addHandler(log_file_handler)
else:
stderrh = logging.StreamHandler(sys.stderr)
stderrh.setFormatter(form)
stderrh.setLevel(logging.DEBUG)
# Setup the base level logger, this one gets
# everything.
l = logging.getLogger()
l.setLevel(logging.WARNING)
l.addHandler(stderrh)
def exc_hook(err_type, value, t_b): def exc_hook(err_type, value, t_b):

View File

@ -471,27 +471,36 @@ class ClipCitation(ClipHandleWrapper):
def refresh(self): def refresh(self):
if self._handle: if self._handle:
citation = clipdb.get_citation_from_handle(self._handle) try:
if citation: citation = clipdb.get_citation_from_handle(self._handle)
self._title = citation.get_gramps_id() if citation:
notelist = list(map(clipdb.get_note_from_handle, self._title = citation.get_gramps_id()
citation.get_note_list())) notelist = list(map(clipdb.get_note_from_handle,
srctxtlist = [note for note in notelist citation.get_note_list()))
if note.get_type() == NoteType.SOURCE_TEXT] srctxtlist = [note for note in notelist
page = citation.get_page() if note.get_type() == NoteType.SOURCE_TEXT]
if not page: page = citation.get_page()
page = _('NA', 'not available') if not page:
text = "" page = _('NA', 'not available')
if srctxtlist: text = ""
text = " ".join(srctxtlist[0].get().split()) if srctxtlist:
#String must be unicode for truncation to work for non text = " ".join(srctxtlist[0].get().split())
#ascii characters #String must be unicode for truncation to work for non
text = str(text) #ascii characters
if len(text) > 60: text = str(text)
text = text[:60] + "..." if len(text) > 60:
self._value = _("Volume/Page: %(pag)s -- %(sourcetext)s") % { text = text[:60] + "..."
'pag' : page, self._value = _("Volume/Page: %(pag)s -- %(sourcetext)s"
'sourcetext' : text} ) % { 'pag' : page,
'sourcetext' : text}
except:
# We are in the Source tree view. The shortcuts only
# work for citations.
print("We cannot copy the source from this view."
" Use drag and drop.")
self._title = self._value = ''
self._pickle = self._type = self._objclass = None
self._handle = self._dbid = self._dbname = None
class ClipRepoRef(ClipObjWrapper): class ClipRepoRef(ClipObjWrapper):
@ -1281,6 +1290,14 @@ class ClipboardListView:
model.insert_before(node, data) model.insert_before(node, data)
else: else:
model.insert_after(node, data) model.insert_after(node, data)
elif isinstance(data[1], ClipCitation):
if data[3]:
# we have a real citation
model.append(data)
#else:
# We are in a Source treeview and trying
# to copy a source with a shortcut.
# Use drag and drop to do that.
else: else:
model.append(data) model.append(data)

View File

@ -469,7 +469,7 @@ class GrampsImportFileDialog(ManagedWindow):
return True return True
else: else:
try: try:
f = open(filename,'w') f = open(filename, 'w')
f.close() f.close()
os.remove(filename) os.remove(filename)
except IOError: except IOError:
@ -485,7 +485,6 @@ class GrampsImportFileDialog(ManagedWindow):
self.import_info = None self.import_info = None
self._begin_progress() self._begin_progress()
self.uistate.set_sensitive(False) self.uistate.set_sensitive(False)
self.uistate.viewmanager.enable_menu(False)
try: try:
#an importer can return an object with info, object.info_text() #an importer can return an object with info, object.info_text()
@ -506,7 +505,6 @@ class GrampsImportFileDialog(ManagedWindow):
except Exception: except Exception:
_LOG.error("Failed to import database.", exc_info=True) _LOG.error("Failed to import database.", exc_info=True)
self.uistate.set_sensitive(True) self.uistate.set_sensitive(True)
self.uistate.viewmanager.enable_menu(True)
self._end_progress() self._end_progress()
def build_menu_names(self, obj): # this is meaningless since it's modal def build_menu_names(self, obj): # this is meaningless since it's modal

View File

@ -1013,7 +1013,7 @@ class DbManager(CLIDbManager, ManagedWindow):
""" """
Handle the reception of drag data Handle the reception of drag data
""" """
drag_value = selection.get_data().decode() drag_value = selection.get_data().decode().strip(' \r\n\x00')
fname = None fname = None
type = None type = None
title = None title = None

View File

@ -538,7 +538,10 @@ class DisplayState(Callback):
history.push(handle) history.push(handle)
def set_sensitive(self, state): def set_sensitive(self, state):
self.window.set_sensitive(state) tbar = self.uimanager.get_widget('ToolBar')
tbar.set_sensitive(state)
self.viewmanager.hpane.set_sensitive(state)
self.uimanager.enable_all_actions(state)
def db_changed(self, db): def db_changed(self, db):
db.connect('long-op-start', self.progress_monitor.add_op) db.connect('long-op-start', self.progress_monitor.add_op)

View File

@ -366,6 +366,7 @@ class EditName(EditSecondary):
5/ local set, not global set --> set (change local) 5/ local set, not global set --> set (change local)
6/ local set, global set --> set (set to global if possible) 6/ local set, global set --> set (set to global if possible)
""" """
ngm = False # name group mapping setting
closeit = True closeit = True
surname = self.obj.get_primary_surname().get_surname() surname = self.obj.get_primary_surname().get_surname()
group_as= self.obj.get_group_as() group_as= self.obj.get_group_as()
@ -388,7 +389,7 @@ class EditName(EditSecondary):
val = q.run() val = q.run()
if val: if val:
#delete the grouping link on database #delete the grouping link on database
self.db.set_name_group_mapping(surname, None) ngm = None # delay setting until dialog closes
self.obj.set_group_as("") self.obj.set_group_as("")
else : else :
closeit = False closeit = False
@ -421,9 +422,9 @@ class EditName(EditSecondary):
val = q.run() val = q.run()
if val: if val:
if group_as == surname : if group_as == surname :
self.db.set_name_group_mapping(surname, None) ngm = None # delay setting until dialog closes
else: else:
self.db.set_name_group_mapping(surname, group_as) ngm = group_as # delay setting until dialog closes
self.obj.set_group_as("") self.obj.set_group_as("")
else: else:
if self.global_group_set : if self.global_group_set :
@ -455,10 +456,15 @@ class EditName(EditSecondary):
pass pass
if closeit: if closeit:
db = self.db # close cleanup loses self.db, so save for later
if self.callback: if self.callback:
self.callback(self.obj) self.callback(self.obj)
self.callback = None self.callback = None
self.close() self.close()
# bug 12328 to avoid gui interaction during view rebuild, delay
# the rebuild until closeing this dialog
if ngm is not False:
db.set_name_group_mapping(surname, ngm)
def _cleanup_on_exit(self): def _cleanup_on_exit(self):
""" """

View File

@ -186,13 +186,40 @@ class EditPlace(EditPrimary):
self.db.readonly) self.db.readonly)
def set_latlongitude(self, value): def set_latlongitude(self, value):
"""
This method is useful for directly copying the coordinates
of openstreetmap, googlemaps, and perhaps other if they
provide coordinates like it is define in conv_lat_lon
(see gramps/gen/utils/place.py)
To copy the coordinates:
- openstreetmap:
1 - choose the place where you want to save the coordinates.
2 - right click on this place
3 - select "show address"
4 - On the left side of the map, copy the coordinates of
"Result from internal"
5 - In the latlon field of the edit place window of gramps,
type <CTRL> V
- googlemap:
1 - choose the place where you want to save the coordinates.
2 - right click on this place
3 - select the coordinates at the top of the popup window.
They are automaticaly copied.
4 - In the latlon field of the edit place window of gramps,
type <CTRL> V
"""
try: try:
parts = value.index(', ') # Bug 12349, 12374
parts = value.split(', ')
if len(parts) == 2: if len(parts) == 2:
longitude = parts[0].strip().replace(',', '.') latitude = parts[0].strip().replace(',', '.')
latitude = parts[1].strip().replace(',', '.') longitude = parts[1].strip().replace(',', '.')
else: else:
longitude, latitude = value.split(',') latitude, longitude = value.split(',')
self.longitude.set_text(longitude) self.longitude.set_text(longitude)
self.latitude.set_text(latitude) self.latitude.set_text(latitude)

View File

@ -181,12 +181,13 @@ class EditPlaceRef(EditReference):
def set_latlongitude(self, value): def set_latlongitude(self, value):
try: try:
parts = value.index(', ') # Bug 12349, 12374
parts = value.split(', ')
if len(parts) == 2: if len(parts) == 2:
longitude = parts[0].strip().replace(',', '.') latitude = parts[0].strip().replace(',', '.')
latitude = parts[1].strip().replace(',', '.') longitude = parts[1].strip().replace(',', '.')
else: else:
longitude, latitude = value.split(',') latitude, longitude = value.split(',')
self.longitude.set_text(longitude) self.longitude.set_text(longitude)
self.latitude.set_text(latitude) self.latitude.set_text(latitude)

View File

@ -1,11 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 --> <!-- Generated with glade 3.22.2 -->
<interface> <interface>
<requires lib="gtk+" version="3.10"/> <requires lib="gtk+" version="3.10"/>
<requires lib="grampswidgets" version="0.0"/>
<object class="GtkDialog" id="editplace"> <object class="GtkDialog" id="editplace">
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="type_hint">dialog</property> <property name="type_hint">dialog</property>
<child type="titlebar">
<placeholder/>
</child>
<child internal-child="vbox"> <child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox19"> <object class="GtkBox" id="dialog-vbox19">
<property name="visible">True</property> <property name="visible">True</property>
@ -101,7 +103,7 @@
<child> <child>
<object class="GtkLabel" id="comment1"> <object class="GtkLabel" id="comment1">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="label" translatable="yes">Either use the two fields below to enter coordinates (latitude and longitude),</property> <property name="label" translatable="yes">Either use the two fields below to enter coordinates (latitude and longitude),</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>

View File

@ -325,7 +325,6 @@ class BaseSelector(ManagedWindow):
self.sortorder = Gtk.SortType.ASCENDING self.sortorder = Gtk.SortType.ASCENDING
else: else:
self.sortorder = Gtk.SortType.DESCENDING self.sortorder = Gtk.SortType.DESCENDING
self.model.reverse_order()
self.build_tree() self.build_tree()
return True return True

View File

@ -496,6 +496,16 @@ class UIManager():
""" """
return group.act_group.lookup_action(actionname) return group.act_group.lookup_action(actionname)
def enable_all_actions(self, state):
for group in self.action_groups:
if group.act_group:
for item in group.actionlist:
action = group.act_group.lookup_action(item[ACTION_NAME])
if action:
# We check in case the group has not been inserted into
# UIManager yet
action.set_enabled(group.sensitive if state else False)
def dump_all_accels(self): def dump_all_accels(self):
''' A function used diagnostically to see what accels are present. ''' A function used diagnostically to see what accels are present.
This will only dump the current accel set, if other non-open windows This will only dump the current accel set, if other non-open windows

View File

@ -450,7 +450,7 @@ def open_file_with_default_application(path, uistate):
GLib.timeout_add_seconds(1, poll_external, (proc, errstrings, uistate)) GLib.timeout_add_seconds(1, poll_external, (proc, errstrings, uistate))
return return
def process_pending_events(max_count=10): def process_pending_events(max_count=20):
""" """
Process pending events, but don't get into an infinite loop. Process pending events, but don't get into an infinite loop.
""" """

View File

@ -277,13 +277,13 @@ class ViewManager(CLIManager):
Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.MOD1_MASK) Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.MOD1_MASK)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.window.add(vbox) self.window.add(vbox)
hpane = Gtk.Paned() self.hpane = Gtk.Paned()
self.ebox = Gtk.EventBox() self.ebox = Gtk.EventBox()
self.navigator = Navigator(self) self.navigator = Navigator(self)
self.ebox.add(self.navigator.get_top()) self.ebox.add(self.navigator.get_top())
hpane.pack1(self.ebox, False, False) self.hpane.pack1(self.ebox, False, False)
hpane.show() self.hpane.show()
self.notebook = Gtk.Notebook() self.notebook = Gtk.Notebook()
self.notebook.set_scrollable(True) self.notebook.set_scrollable(True)
@ -292,13 +292,14 @@ class ViewManager(CLIManager):
self.__init_lists() self.__init_lists()
self.__build_ui_manager() self.__build_ui_manager()
hpane.add2(self.notebook) self.hpane.add2(self.notebook)
toolbar = self.uimanager.get_widget('ToolBar') toolbar = self.uimanager.get_widget('ToolBar')
toolbar.show_all()
self.statusbar = Statusbar() self.statusbar = Statusbar()
self.statusbar.show() self.statusbar.show()
vbox.pack_end(self.statusbar, False, True, 0) vbox.pack_end(self.statusbar, False, True, 0)
vbox.pack_start(toolbar, False, True, 0) vbox.pack_start(toolbar, False, True, 0)
vbox.pack_end(hpane, True, True, 0) vbox.pack_end(self.hpane, True, True, 0)
vbox.show() vbox.show()
self.uistate = DisplayState(self.window, self.statusbar, self.uistate = DisplayState(self.window, self.statusbar,
@ -839,6 +840,7 @@ class ViewManager(CLIManager):
hbox.add(Gtk.Label(label=pdata.name)) hbox.add(Gtk.Label(label=pdata.name))
hbox.show_all() hbox.show_all()
page_num = self.notebook.append_page(page.get_display(), hbox) page_num = self.notebook.append_page(page.get_display(), hbox)
self.active_page.post_create()
if not self.file_loaded: if not self.file_loaded:
self.uimanager.set_actions_visible(self.actiongroup, False) self.uimanager.set_actions_visible(self.actiongroup, False)
self.uimanager.set_actions_visible(self.readonlygroup, False) self.uimanager.set_actions_visible(self.readonlygroup, False)
@ -887,12 +889,17 @@ class ViewManager(CLIManager):
while Gtk.events_pending(): while Gtk.events_pending():
Gtk.main_iteration() Gtk.main_iteration()
self.uimanager.update_menu() # bug 12048 this avoids crash if part of toolbar in view is not shown
# because of a small screen when changing views. Part of the Gtk code
# was deleting a toolbar object too soon; and another part of Gtk still
# had a reference.
def page_changer(self):
self.uimanager.update_menu()
self.active_page.change_page()
return False
while Gtk.events_pending(): GLib.idle_add(page_changer, self,
Gtk.main_iteration() priority=GLib.PRIORITY_DEFAULT_IDLE - 10)
self.active_page.change_page()
def __delete_pages(self): def __delete_pages(self):
""" """
@ -997,7 +1004,8 @@ class ViewManager(CLIManager):
The method called after load of a new database. The method called after load of a new database.
Inherit CLI method to add GUI part Inherit CLI method to add GUI part
""" """
self._post_load_newdb_nongui(filename, title) if self.dbstate.db.is_open():
self._post_load_newdb_nongui(filename, title)
self._post_load_newdb_gui(filename, filetype, title) self._post_load_newdb_gui(filename, filetype, title)
def _post_load_newdb_gui(self, filename, filetype, title=None): def _post_load_newdb_gui(self, filename, filetype, title=None):
@ -1065,51 +1073,6 @@ class ViewManager(CLIManager):
config.set('paths.recent-file', '') config.set('paths.recent-file', '')
config.save() config.save()
def enable_menu(self, enable):
""" Enable/disable the menues. Used by the dbloader for import to
prevent other operations during import. Needed because simpler methods
don't work under Gnome with application menus at top of screen (instead
of Gramps window).
Note: enable must be set to False on first call.
"""
if not enable:
self.action_st = (
self.uimanager.get_actions_sensitive(self.actiongroup),
self.uimanager.get_actions_sensitive(self.readonlygroup),
self.uimanager.get_actions_sensitive(self.undoactions),
self.uimanager.get_actions_sensitive(self.redoactions),
self.uimanager.get_actions_sensitive(self.fileactions),
self.uimanager.get_actions_sensitive(self.toolactions),
self.uimanager.get_actions_sensitive(self.reportactions),
self.uimanager.get_actions_sensitive(
self.recent_manager.action_group))
self.uimanager.set_actions_sensitive(self.actiongroup, enable)
self.uimanager.set_actions_sensitive(self.readonlygroup, enable)
self.uimanager.set_actions_sensitive(self.undoactions, enable)
self.uimanager.set_actions_sensitive(self.redoactions, enable)
self.uimanager.set_actions_sensitive(self.fileactions, enable)
self.uimanager.set_actions_sensitive(self.toolactions, enable)
self.uimanager.set_actions_sensitive(self.reportactions, enable)
self.uimanager.set_actions_sensitive(
self.recent_manager.action_group, enable)
else:
self.uimanager.set_actions_sensitive(
self.actiongroup, self.action_st[0])
self.uimanager.set_actions_sensitive(
self.readonlygroup, self.action_st[1])
self.uimanager.set_actions_sensitive(
self.undoactions, self.action_st[2])
self.uimanager.set_actions_sensitive(
self.redoactions, self.action_st[3])
self.uimanager.set_actions_sensitive(
self.fileactions, self.action_st[4])
self.uimanager.set_actions_sensitive(
self.toolactions, self.action_st[5])
self.uimanager.set_actions_sensitive(
self.reportactions, self.action_st[6])
self.uimanager.set_actions_sensitive(
self.recent_manager.action_group, self.action_st[7])
def __change_undo_label(self, label, update_menu=True): def __change_undo_label(self, label, update_menu=True):
""" """
Change the UNDO label Change the UNDO label

View File

@ -138,6 +138,7 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
self.sidebar = None self.sidebar = None
self.bottombar = None self.bottombar = None
self.widget = None self.widget = None
self.vpane = None
DbGUIElement.__init__(self, dbstate.db) DbGUIElement.__init__(self, dbstate.db)
@ -154,18 +155,20 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
self.ident + "_bottombar", self.ident + "_bottombar",
defaults[1]) defaults[1])
hpane = Gtk.Paned() hpane = Gtk.Paned()
vpane = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL) self.vpane = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL)
hpane.pack1(vpane, resize=True, shrink=False) hpane.pack1(self.vpane, resize=True, shrink=False)
hpane.pack2(self.sidebar, resize=False, shrink=False) hpane.pack2(self.sidebar, resize=False, shrink=False)
hpane.show() hpane.show()
vpane.show() self.vpane.show()
self.widget = self.build_widget() self.widget = self.build_widget()
self.widget.show_all() self.widget.show_all()
self.widget.set_name('view') self.widget.set_name('view')
vpane.pack1(self.widget, resize=True, shrink=False) self.vpane.pack1(self.widget, resize=True, shrink=False)
vpane.pack2(self.bottombar, resize=False, shrink=True) self.vpane.pack2(self.bottombar, resize=False, shrink=False)
self._setup_slider_config(vpane, 'vpane.slider-position') self.vpane.show()
self._config.register('vpane.slider-position', -1)
self.vpane.set_position(self._config.get('vpane.slider-position'))
self.sidebar_toggled(self.sidebar.get_property('visible')) self.sidebar_toggled(self.sidebar.get_property('visible'))
self.hpane_sig = hpane.connect("draw", self.set_page_slider) self.hpane_sig = hpane.connect("draw", self.set_page_slider)
@ -343,6 +346,11 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
self.bottombar.set_inactive() self.bottombar.set_inactive()
self.active = False self.active = False
def post_create(self):
if self.vpane:
self._setup_slider_config(self.vpane, 'vpane.slider-position')
self.vpane = None
@abstractmethod @abstractmethod
def build_tree(self): def build_tree(self):
""" """

View File

@ -373,10 +373,6 @@ class GrampletBar(Gtk.Notebook):
""" """
Add a tab to the notebook for the given gramplet. Add a tab to the notebook for the given gramplet.
""" """
width = -1 # Allow tab width to adjust (smaller) to sidebar
height = min(int(self.uistate.screen_height() * 0.20), 400)
gramplet.set_size_request(width, height)
label = self.__create_tab_label(gramplet) label = self.__create_tab_label(gramplet)
page_num = self.append_page(gramplet, label) page_num = self.append_page(gramplet, label)
return page_num return page_num

View File

@ -1240,6 +1240,12 @@ class GrampletPane(Gtk.ScrolledWindow):
else: else:
cnt = 0 cnt = 0
for item in base_opts["data"]: for item in base_opts["data"]:
# If we have a "%" in a string,
# escape it by writing "%%"
# to avoid InterpolationSyntaxError
# in python configparser module.
if isinstance(item, str):
item = item.replace("%", "%%")
fp.write("data[%d]=%s\n" % (cnt, item)) fp.write("data[%d]=%s\n" % (cnt, item))
cnt += 1 cnt += 1
else: else:

View File

@ -225,6 +225,16 @@ class DBAPI(DbGeneric):
if self.transaction == None: if self.transaction == None:
self.dbapi.rollback() self.dbapi.rollback()
def _collation(self, locale):
"""
Get the adjusted collation if there is one, falling back on
the locale.collation.
"""
collation = self.dbapi.check_collation(locale)
if collation == None:
return locale.get_collation()
return collation
def transaction_begin(self, transaction): def transaction_begin(self, transaction):
""" """
Transactions are handled automatically by the db layer. Transactions are handled automatically by the db layer.
@ -365,12 +375,9 @@ class DBAPI(DbGeneric):
:type locale: A GrampsLocale object. :type locale: A GrampsLocale object.
""" """
if sort_handles: if sort_handles:
if locale != glocale:
self.dbapi.check_collation(locale)
self.dbapi.execute('SELECT handle FROM person ' self.dbapi.execute('SELECT handle FROM person '
'ORDER BY surname ' 'ORDER BY surname '
'COLLATE "%s"' % locale.get_collation()) 'COLLATE "%s"' % self._collation(locale))
else: else:
self.dbapi.execute("SELECT handle FROM person") self.dbapi.execute("SELECT handle FROM person")
rows = self.dbapi.fetchall() rows = self.dbapi.fetchall()
@ -387,9 +394,6 @@ class DBAPI(DbGeneric):
:type locale: A GrampsLocale object. :type locale: A GrampsLocale object.
""" """
if sort_handles: if sort_handles:
if locale != glocale:
self.dbapi.check_collation(locale)
sql = ('SELECT family.handle ' + sql = ('SELECT family.handle ' +
'FROM family ' + 'FROM family ' +
'LEFT JOIN person AS father ' + 'LEFT JOIN person AS father ' +
@ -404,7 +408,7 @@ class DBAPI(DbGeneric):
'THEN mother.given_name ' + 'THEN mother.given_name ' +
'ELSE father.given_name ' + 'ELSE father.given_name ' +
'END) ' + 'END) ' +
'COLLATE "%s"' % locale.get_collation()) 'COLLATE "%s"' % self._collation(locale))
self.dbapi.execute(sql) self.dbapi.execute(sql)
else: else:
self.dbapi.execute("SELECT handle FROM family") self.dbapi.execute("SELECT handle FROM family")
@ -431,12 +435,9 @@ class DBAPI(DbGeneric):
:type locale: A GrampsLocale object. :type locale: A GrampsLocale object.
""" """
if sort_handles: if sort_handles:
if locale != glocale:
self.dbapi.check_collation(locale)
self.dbapi.execute('SELECT handle FROM citation ' self.dbapi.execute('SELECT handle FROM citation '
'ORDER BY page ' 'ORDER BY page '
'COLLATE "%s"' % locale.get_collation()) 'COLLATE "%s"' % self._collation(locale))
else: else:
self.dbapi.execute("SELECT handle FROM citation") self.dbapi.execute("SELECT handle FROM citation")
rows = self.dbapi.fetchall() rows = self.dbapi.fetchall()
@ -453,12 +454,9 @@ class DBAPI(DbGeneric):
:type locale: A GrampsLocale object. :type locale: A GrampsLocale object.
""" """
if sort_handles: if sort_handles:
if locale != glocale:
self.dbapi.check_collation(locale)
self.dbapi.execute('SELECT handle FROM source ' self.dbapi.execute('SELECT handle FROM source '
'ORDER BY title ' 'ORDER BY title '
'COLLATE "%s"' % locale.get_collation()) 'COLLATE "%s"' % self._collation(locale))
else: else:
self.dbapi.execute("SELECT handle from source") self.dbapi.execute("SELECT handle from source")
rows = self.dbapi.fetchall() rows = self.dbapi.fetchall()
@ -475,12 +473,9 @@ class DBAPI(DbGeneric):
:type locale: A GrampsLocale object. :type locale: A GrampsLocale object.
""" """
if sort_handles: if sort_handles:
if locale != glocale:
self.dbapi.check_collation(locale)
self.dbapi.execute('SELECT handle FROM place ' self.dbapi.execute('SELECT handle FROM place '
'ORDER BY title ' 'ORDER BY title '
'COLLATE "%s"' % locale.get_collation()) 'COLLATE "%s"' % self._collation(locale))
else: else:
self.dbapi.execute("SELECT handle FROM place") self.dbapi.execute("SELECT handle FROM place")
rows = self.dbapi.fetchall() rows = self.dbapi.fetchall()
@ -506,12 +501,9 @@ class DBAPI(DbGeneric):
:type locale: A GrampsLocale object. :type locale: A GrampsLocale object.
""" """
if sort_handles: if sort_handles:
if locale != glocale:
self.dbapi.check_collation(locale)
self.dbapi.execute('SELECT handle FROM media ' self.dbapi.execute('SELECT handle FROM media '
'ORDER BY desc ' 'ORDER BY desc '
'COLLATE "%s"' % locale.get_collation()) 'COLLATE "%s"' % self._collation(locale))
else: else:
self.dbapi.execute("SELECT handle FROM media") self.dbapi.execute("SELECT handle FROM media")
rows = self.dbapi.fetchall() rows = self.dbapi.fetchall()
@ -537,12 +529,9 @@ class DBAPI(DbGeneric):
:type locale: A GrampsLocale object. :type locale: A GrampsLocale object.
""" """
if sort_handles: if sort_handles:
if locale != glocale:
self.dbapi.check_collation(locale)
self.dbapi.execute('SELECT handle FROM tag ' self.dbapi.execute('SELECT handle FROM tag '
'ORDER BY name ' 'ORDER BY name '
'COLLATE "%s"' % locale.get_collation()) 'COLLATE "%s"' % self._collation(locale))
else: else:
self.dbapi.execute("SELECT handle FROM tag") self.dbapi.execute("SELECT handle FROM tag")
rows = self.dbapi.fetchall() rows = self.dbapi.fetchall()
@ -589,12 +578,13 @@ class DBAPI(DbGeneric):
"WHERE name = ?", [grouping, name]) "WHERE name = ?", [grouping, name])
elif row and grouping is None: elif row and grouping is None:
self.dbapi.execute("DELETE FROM name_group WHERE name = ?", [name]) self.dbapi.execute("DELETE FROM name_group WHERE name = ?", [name])
grouping = ''
else: else:
self.dbapi.execute( self.dbapi.execute(
"INSERT INTO name_group (name, grouping) VALUES (?, ?)", "INSERT INTO name_group (name, grouping) VALUES (?, ?)",
[name, grouping]) [name, grouping])
self._txn_commit() self._txn_commit()
if grouping is None:
grouping = ''
self.emit('person-groupname-rebuild', (name, grouping)) self.emit('person-groupname-rebuild', (name, grouping))
def _commit_base(self, obj, obj_key, trans, change_time): def _commit_base(self, obj, obj_key, trans, change_time):

View File

@ -117,6 +117,8 @@ class Connection:
collation = locale.get_collation().translate(self.__tmap) collation = locale.get_collation().translate(self.__tmap)
if collation not in self.__collations: if collation not in self.__collations:
self.__connection.create_collation(collation, locale.strcoll) self.__connection.create_collation(collation, locale.strcoll)
self.__collations.append(collation)
return collation
def execute(self, *args, **kwargs): def execute(self, *args, **kwargs):
""" """

View File

@ -31,7 +31,7 @@ SVG document generator.
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from io import StringIO from io import StringIO
from xml.sax.saxutils import escape
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# Gramps modules # Gramps modules
@ -147,7 +147,7 @@ class SvgDrawDoc(BaseDoc, DrawDoc):
linex = xpos + (width - self.string_width(font, line)) / 2 linex = xpos + (width - self.string_width(font, line)) / 2
self.buffer.write( self.buffer.write(
'<tspan x="%4.2f" dy="%d">' % (linex, size) + '<tspan x="%4.2f" dy="%d">' % (linex, size) +
line + escape(line) +
'</tspan>' '</tspan>'
) )
self.buffer.write('</text>\n') self.buffer.write('</text>\n')
@ -273,7 +273,7 @@ class SvgDrawDoc(BaseDoc, DrawDoc):
self.buffer.write(' font-family:serif;') self.buffer.write(' font-family:serif;')
self.buffer.write( self.buffer.write(
'">' + '">' +
line + escape(line) +
'</text>\n' '</text>\n'
) )
@ -307,7 +307,7 @@ class SvgDrawDoc(BaseDoc, DrawDoc):
self.buffer.write('font-family:serif;') self.buffer.write('font-family:serif;')
self.buffer.write( self.buffer.write(
'">' + '">' +
text + escape(text) +
'</text>\n' '</text>\n'
) )

View File

@ -267,7 +267,8 @@ class Calendar(Report):
day_col * cell_width + cell_width/2, day_col * cell_width + cell_width/2,
header + week_row * cell_height) header + week_row * cell_height)
list_ = self.calendar.get(month, {}).get(thisday.day, []) list_ = self.calendar.get(month, {}).get(thisday.day, [])
list_.sort() # to get CAL-Holiday on bottom # sort the list to get CAL-Holiday on bottom
list_.sort(key=lambda x: (x[0], x[1]))
position = spacing position = spacing
for (format, p, m_list) in list_: for (format, p, m_list) in list_:
for line in reversed(p.split("\n")): for line in reversed(p.split("\n")):

View File

@ -202,7 +202,7 @@ class CalendarWriter:
date = event.get_date_object() date = event.get_date_object()
place_handle = event.get_place_handle() place_handle = event.get_place_handle()
date_string = self.format_date(date, 1) date_string = self.format_date(date, 1)
if date_string is not "": if date_string != "":
# self.writeln("") # self.writeln("")
self.writeln("BEGIN:VEVENT") self.writeln("BEGIN:VEVENT")
time_s = time.gmtime(event.change) time_s = time.gmtime(event.change)

View File

@ -125,13 +125,17 @@ class Backlinks(Gramplet):
edit_object(self.dbstate, self.uistate, objclass, handle) edit_object(self.dbstate, self.uistate, objclass, handle)
def db_changed(self):
for item in ['person', 'family', 'source', 'citation', 'event',
'media', 'place', 'repository', 'note']:
self.connect(self.dbstate.db, '%s-delete' % item, self.update)
self.connect(self.dbstate.db, '%s-add' % item, self.update)
self.connect(self.dbstate.db, '%s-update' % item, self.update)
class PersonBacklinks(Backlinks): class PersonBacklinks(Backlinks):
""" """
Displays the back references for a person. Displays the back references for a person.
""" """
def db_changed(self):
self.connect(self.dbstate.db, 'person-update', self.update)
def active_changed(self, handle): def active_changed(self, handle):
self.update() self.update()
@ -152,7 +156,7 @@ class EventBacklinks(Backlinks):
Displays the back references for an event. Displays the back references for an event.
""" """
def db_changed(self): def db_changed(self):
self.connect(self.dbstate.db, 'event-update', self.update) super().db_changed()
self.connect_signal('Event', self.update) self.connect_signal('Event', self.update)
def update_has_data(self): def update_has_data(self):
@ -172,7 +176,7 @@ class FamilyBacklinks(Backlinks):
Displays the back references for a family. Displays the back references for a family.
""" """
def db_changed(self): def db_changed(self):
self.connect(self.dbstate.db, 'family-update', self.update) super().db_changed()
self.connect_signal('Family', self.update) self.connect_signal('Family', self.update)
def update_has_data(self): def update_has_data(self):
@ -192,7 +196,7 @@ class PlaceBacklinks(Backlinks):
Displays the back references for a place. Displays the back references for a place.
""" """
def db_changed(self): def db_changed(self):
self.connect(self.dbstate.db, 'place-update', self.update) super().db_changed()
self.connect_signal('Place', self.update) self.connect_signal('Place', self.update)
def update_has_data(self): def update_has_data(self):
@ -212,7 +216,7 @@ class SourceBacklinks(Backlinks):
Displays the back references for a source,. Displays the back references for a source,.
""" """
def db_changed(self): def db_changed(self):
self.connect(self.dbstate.db, 'source-update', self.update) super().db_changed()
self.connect_signal('Source', self.update) self.connect_signal('Source', self.update)
def update_has_data(self): def update_has_data(self):
@ -232,7 +236,7 @@ class CitationBacklinks(Backlinks):
Displays the back references for a Citation,. Displays the back references for a Citation,.
""" """
def db_changed(self): def db_changed(self):
self.connect(self.dbstate.db, 'citation-update', self.update) super().db_changed()
self.connect_signal('Citation', self.update) self.connect_signal('Citation', self.update)
def update_has_data(self): def update_has_data(self):
@ -252,7 +256,7 @@ class RepositoryBacklinks(Backlinks):
Displays the back references for a repository. Displays the back references for a repository.
""" """
def db_changed(self): def db_changed(self):
self.connect(self.dbstate.db, 'repository-update', self.update) super().db_changed()
self.connect_signal('Repository', self.update) self.connect_signal('Repository', self.update)
def update_has_data(self): def update_has_data(self):
@ -272,7 +276,7 @@ class MediaBacklinks(Backlinks):
Displays the back references for a media object. Displays the back references for a media object.
""" """
def db_changed(self): def db_changed(self):
self.connect(self.dbstate.db, 'media-update', self.update) super().db_changed()
self.connect_signal('Media', self.update) self.connect_signal('Media', self.update)
def update_has_data(self): def update_has_data(self):
@ -292,7 +296,7 @@ class NoteBacklinks(Backlinks):
Displays the back references for a note. Displays the back references for a note.
""" """
def db_changed(self): def db_changed(self):
self.connect(self.dbstate.db, 'note-update', self.update) super().db_changed()
self.connect_signal('Note', self.update) self.connect_signal('Note', self.update)
def update_has_data(self): def update_has_data(self):

View File

@ -300,6 +300,8 @@ class DateRange:
""" """
start = None start = None
stop = None stop = None
if date.is_empty():
return (None, None)
if date.modifier == Date.MOD_NONE: if date.modifier == Date.MOD_NONE:
start = date.sortval start = date.sortval
stop = date.sortval stop = date.sortval

View File

@ -206,8 +206,10 @@ class PlaceBaseView(ListView):
""" """
if action: if action:
action.set_state(value) action.set_state(value)
self.mapservice = mapkey = value.get_string() self.mapservice = value.get_string()
config.set('interface.mapservice', mapkey) else:
self.mapservice = value
config.set('interface.mapservice', self.mapservice)
config.save() config.save()
_ui = self.__create_maps_menu_actions() _ui = self.__create_maps_menu_actions()
self.uimanager.add_ui_from_string(_ui) self.uimanager.add_ui_from_string(_ui)

View File

@ -292,9 +292,6 @@ class GeoGraphyView(OsmGps, NavigationView):
if self.active: if self.active:
self.bookmarks.redraw() self.bookmarks.redraw()
self.build_tree() self.build_tree()
if self.osm:
self.osm.grab_focus()
self.set_crosshair(config.get("geography.show_cross"))
def can_configure(self): def can_configure(self):
""" """

View File

@ -191,14 +191,11 @@ class OsmGps:
self.osm = DummyMapNoGpsPoint() self.osm = DummyMapNoGpsPoint()
else: else:
if http_proxy: if http_proxy:
self.osm = osmgpsmap.Map(tile_cache=tiles_path, self.osm = osmgpsmap.Map(proxy_uri=http_proxy)
proxy_uri=http_proxy,
map_source=constants.MAP_TYPE[
map_type])
else: else:
self.osm = osmgpsmap.Map(tile_cache=tiles_path, self.osm = osmgpsmap.Map()
map_source=constants.MAP_TYPE[ self.osm.set_property("tile_cache", tiles_path)
map_type]) self.osm.set_property("map_source", constants.MAP_TYPE[map_type])
self.osm.props.tile_cache = osmgpsmap.MAP_CACHE_AUTO self.osm.props.tile_cache = osmgpsmap.MAP_CACHE_AUTO
current_map = osmgpsmap.MapOsd(show_dpad=False, show_zoom=True) current_map = osmgpsmap.MapOsd(show_dpad=False, show_zoom=True)
self.end_selection = None self.end_selection = None

View File

@ -5,6 +5,7 @@
# Copyright (C) 2003-2005 Donald N. Allingham # Copyright (C) 2003-2005 Donald N. Allingham
# Copyright (C) 2008 Brian G. Matherly # Copyright (C) 2008 Brian G. Matherly
# Copyright (C) 2018 Robin van der Vliet # Copyright (C) 2018 Robin van der Vliet
# Copyright (C) 2020 Jan Sparreboom
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -35,7 +36,7 @@ import gramps.gen.relationship
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# # Levels
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -69,9 +70,207 @@ _child_level = [ "", "",
_nibling_level = [ "", "", _nibling_level = [ "", "",
"achter", "achterachter", "achterachterachter" ] "achter", "achterachter", "achterachterachter" ]
_parents_level = ["",
"ouders",
"grootouders",
"overgrootouders",
"betovergrootouders",
"overgrootouders 5e graad",
"overgrootouders 6e graad",
"overgrootouders 7e graad",
"overgrootouders 8e graad",
"overgrootouders 9e graad",
"overgrootouders 10e graad",
"overgrootouders 11e graad",
"overgrootouders 12e graad",
"overgrootouders 13e graad",
"overgrootouders 14e graad",
"overgrootouders 15e graad",
"overgrootouders 16e graad",
"overgrootouders 17e graad",
"overgrootouders 18e graad",
"overgrootouders 19e graad",
"overgrootouders 20e graad",
"overgrootouders 21e graad",
"overgrootouders 22e graad",
"overgrootouders 23e graad",
"overgrootouders 24e graad",
"overgrootouders 25e graad",
"overgrootouders 26e graad",
"overgrootouders 27e graad",
"overgrootouders 28e graad",
"overgrootouders 29e graad",
"overgrootouders 30e graad",
"overgrootouders 31e graad",
"overgrootouders 32e graad",
"overgrootouders 33e graad",
"overgrootouders 34e graad",
"overgrootouders 35e graad",
"overgrootouders 36e graad",
"overgrootouders 37e graad",
"overgrootouders 38e graad",
"overgrootouders 39e graad",
"overgrootouders 40e graad",
"overgrootouders 41e graad",
"overgrootouders 42e graad",
"overgrootouders 43e graad",
"overgrootouders 44e graad",
"overgrootouders 45e graad",
"overgrootouders 46e graad",
"overgrootouders 47e graad",
"overgrootouders 48e graad",
"overgrootouders 49e graad",
"overgrootouders 50e graad", ]
_siblings_level = ["",
"broers en zussen",
"ooms en tantes",
"oudooms en -tantes",
"overoudooms en -tantes",
"overoudooms en -tantes 5e graad",
"overoudooms en -tantes 6e graad",
"overoudooms en -tantes 7e graad",
"overoudooms en -tantes 8e graad",
"overoudooms en -tantes 9e graad",
"overoudooms en -tantes 10e graad",
"overoudooms en -tantes 11e graad",
"overoudooms en -tantes 12e graad",
"overoudooms en -tantes 13e graad",
"overoudooms en -tantes 14e graad",
"overoudooms en -tantes 15e graad",
"overoudooms en -tantes 16e graad",
"overoudooms en -tantes 17e graad",
"overoudooms en -tantes 18e graad",
"overoudooms en -tantes 19e graad",
"overoudooms en -tantes 20e graad",
"overoudooms en -tantes 21e graad",
"overoudooms en -tantes 22e graad",
"overoudooms en -tantes 23e graad",
"overoudooms en -tantes 24e graad",
"overoudooms en -tantes 25e graad",
"overoudooms en -tantes 26e graad",
"overoudooms en -tantes 27e graad",
"overoudooms en -tantes 28e graad",
"overoudooms en -tantes 29e graad",
"overoudooms en -tantes 30e graad",
"overoudooms en -tantes 41e graad",
"overoudooms en -tantes 42e graad",
"overoudooms en -tantes 43e graad",
"overoudooms en -tantes 44e graad",
"overoudooms en -tantes 45e graad",
"overoudooms en -tantes 46e graad",
"overoudooms en -tantes 47e graad",
"overoudooms en -tantes 48e graad",
"overoudooms en -tantes 49e graad",
"overoudooms en -tantes 50e graad", ]
_children_level = ["",
"kinderen",
"kleinkinderen",
"achterkleinkinderen",
"betachterkleinkinderen",
"kleinkinderen 5e graad",
"kleinkinderen 6e graad",
"kleinkinderen 7e graad",
"kleinkinderen 8e graad",
"kleinkinderen 9e graad",
"kleinkinderen 10e graad",
"kleinkinderen 11e graad",
"kleinkinderen 12e graad",
"kleinkinderen 13e graad",
"kleinkinderen 14e graad",
"kleinkinderen 15e graad",
"kleinkinderen 16e graad",
"kleinkinderen 17e graad",
"kleinkinderen 18e graad",
"kleinkinderen 19e graad",
"kleinkinderen 20e graad",
"kleinkinderen 21e graad",
"kleinkinderen 22e graad",
"kleinkinderen 23e graad",
"kleinkinderen 24e graad",
"kleinkinderen 25e graad",
"kleinkinderen 26e graad",
"kleinkinderen 27e graad",
"kleinkinderen 28e graad",
"kleinkinderen 29e graad",
"kleinkinderen 30e graad",
"kleinkinderen 31e graad",
"kleinkinderen 32e graad",
"kleinkinderen 33e graad",
"kleinkinderen 34e graad",
"kleinkinderen 35e graad",
"kleinkinderen 36e graad",
"kleinkinderen 37e graad",
"kleinkinderen 38e graad",
"kleinkinderen 39e graad",
"kleinkinderen 40e graad",
"kleinkinderen 41e graad",
"kleinkinderen 42e graad",
"kleinkinderen 43e graad",
"kleinkinderen 44e graad",
"kleinkinderen 45e graad",
"kleinkinderen 46e graad",
"kleinkinderen 47e graad",
"kleinkinderen 48e graad",
"kleinkinderen 49e graad",
"kleinkinderen 50e graad", ]
_nephews_nieces_level = ["",
"broers en zussen",
"neven en nichten",
"achterneven en -nichten",
"achterneven en -nichten 4e graad",
"achterneven en -nichten 5e graad",
"achterneven en -nichten 6e graad",
"achterneven en -nichten 7e graad",
"achterneven en -nichten 8e graad",
"achterneven en -nichten 9e graad",
"achterneven en -nichten 10e graad",
"achterneven en -nichten 11e graad",
"achterneven en -nichten 12e graad",
"achterneven en -nichten 13e graad",
"achterneven en -nichten 14e graad",
"achterneven en -nichten 15e graad",
"achterneven en -nichten 16e graad",
"achterneven en -nichten 17e graad",
"achterneven en -nichten 18e graad",
"achterneven en -nichten 19e graad",
"achterneven en -nichten 20e graad",
"achterneven en -nichten 21e graad",
"achterneven en -nichten 22e graad",
"achterneven en -nichten 23e graad",
"achterneven en -nichten 24e graad",
"achterneven en -nichten 25e graad",
"achterneven en -nichten 26e graad",
"achterneven en -nichten 27e graad",
"achterneven en -nichten 28e graad",
"achterneven en -nichten 29e graad",
"achterneven en -nichten 30e graad",
"achterneven en -nichten 31e graad",
"achterneven en -nichten 32e graad",
"achterneven en -nichten 33e graad",
"achterneven en -nichten 34e graad",
"achterneven en -nichten 35e graad",
"achterneven en -nichten 36e graad",
"achterneven en -nichten 37e graad",
"achterneven en -nichten 38e graad",
"achterneven en -nichten 39e graad",
"achterneven en -nichten 40e graad",
"achterneven en -nichten 41e graad",
"achterneven en -nichten 42e graad",
"achterneven en -nichten 43e graad",
"achterneven en -nichten 44e graad",
"achterneven en -nichten 45e graad",
"achterneven en -nichten 46e graad",
"achterneven en -nichten 47e graad",
"achterneven en -nichten 48e graad",
"achterneven en -nichten 49e graad",
"achterneven en -nichten 50e graad", ]
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# # Relationship calculator Dutch version
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -273,6 +472,104 @@ class RelationshipCalculator(gramps.gen.relationship.RelationshipCalculator):
else: else:
return "%s%snicht (kozijn)" % (inlaw, step) \ return "%s%snicht (kozijn)" % (inlaw, step) \
+ " " + _ordinal_level[removed] + " graad" + " " + _ordinal_level[removed] + " graad"
# NIEUW
def get_plural_relationship_string(self, Ga, Gb,
reltocommon_a='', reltocommon_b='',
only_birth=True,
in_law_a=False, in_law_b=False):
"""
Provide a string that describes the relationsip between a person, and
a group of people with the same relationship. E.g. "grandparents" or
"children".
Ga and Gb can be used to mathematically calculate the relationship.
.. seealso::
http://en.wikipedia.org/wiki/Cousin#Mathematical_definitions
:param Ga: The number of generations between the main person and the
common ancestor.
:type Ga: int
:param Gb: The number of generations between the group of people and the
common ancestor
:type Gb: int
:param reltocommon_a: relation path to common ancestor or common
Family for person a.
Note that length = Ga
:type reltocommon_a: str
:param reltocommon_b: relation path to common ancestor or common
Family for person b.
Note that length = Gb
:type reltocommon_b: str
:param only_birth: True if relation between a and b is by birth only
False otherwise
:type only_birth: bool
:param in_law_a: True if path to common ancestors is via the partner
of person a
:type in_law_a: bool
:param in_law_b: True if path to common ancestors is via the partner
of person b
:type in_law_b: bool
:returns: A string describing the relationship between the person and
the group.
:rtype: str
"""
rel_str = "verre familie"
if Ga == 0:
# These are descendants
if Gb < len(_children_level):
rel_str = _children_level[Gb]
else:
rel_str = "verre afstammelingen"
elif Gb == 0:
# These are parents/grand parents
if Ga < len(_parents_level):
rel_str = _parents_level[Ga]
else:
rel_str = "verre voorouders"
elif Gb == 1:
# These are siblings/aunts/uncles
if Ga < len(_siblings_level):
rel_str = _siblings_level[Ga]
else:
rel_str = "verre ooms/tantes"
elif Ga == 1:
# These are nieces/nephews
if Gb < len(_nephews_nieces_level):
rel_str = _nephews_nieces_level[Gb]
else:
rel_str = "verre neven/nichten"
elif Ga > 1 and Ga == Gb:
# These are cousins in the same generation
if Ga <= len(_ordinal_level):
rel_str = "%s neven" % _ordinal_level[Ga-1]
else:
rel_str = "verre neven"
elif Ga > 1 and Ga > Gb:
# These are cousins in different generations with the second person
# being in a higher generation from the common ancestor than the
# first person.
if Gb <= len(_LEVEL_NAME) and (Ga-Gb) < len(_removed_level):
rel_str = "%s neven%s (omhoog)" % (_ordinal_level[Gb-1],
_removed_level[Ga-Gb])
else:
rel_str = "verre neven"
elif Gb > 1 and Gb > Ga:
# These are cousins in different generations with the second person
# being in a lower generation from the common ancestor than the
# first person.
if Ga <= len(_LEVEL_NAME) and (Gb-Ga) < len(_removed_level):
rel_str = "%s neven%s (omlaag)" % (_ordinal_level[Ga-1],
_removed_level[Gb-Ga])
else:
rel_str = "verre neven"
if in_law_b is True:
rel_str = "echtgenoten van %s" % rel_str
return rel_str
def get_single_relationship_string(self, Ga, Gb, gender_a, gender_b, def get_single_relationship_string(self, Ga, Gb, gender_a, gender_b,
reltocommon_a, reltocommon_b, reltocommon_a, reltocommon_b,
@ -424,3 +721,6 @@ if __name__ == "__main__":
from gramps.gen.relationship import test from gramps.gen.relationship import test
RC = RelationshipCalculator() RC = RelationshipCalculator()
test(RC, True) test(RC, True)

View File

@ -132,7 +132,7 @@ class DbTestClassBase(object):
self._log_sig("note-delete", args) self._log_sig("note-delete", args)
def _log_sig(self, sig, args): def _log_sig(self, sig, args):
print("('%s', %s)," % (sig, args)) # print("('%s', %s)," % (sig, args))
self.sigs.append((sig, args[0])) self.sigs.append((sig, args[0]))
def _cm_pers_add(self, *args): def _cm_pers_add(self, *args):

View File

@ -271,6 +271,7 @@ class BirthdayReport(Report):
for person_handle in people: for person_handle in people:
step() step()
person = self.database.get_person_from_handle(person_handle) person = self.database.get_person_from_handle(person_handle)
short_name = self.get_name(person)
birth_ref = person.get_birth_ref() birth_ref = person.get_birth_ref()
birth_date = None birth_date = None
if birth_ref: if birth_ref:

View File

@ -441,7 +441,8 @@ class TagReport(Report):
for place_handle in place_list: for place_handle in place_list:
place = self.database.get_place_from_handle(place_handle) place = self.database.get_place_from_handle(place_handle)
place_title = _pd.display(self.database, place, self.place_format) place_title = _pd.display(self.database, place, None,
self.place_format)
self.doc.start_row() self.doc.start_row()

View File

@ -247,6 +247,14 @@ class GeoClose(GeoGraphyView):
self.add_item = None self.add_item = None
self.newmenu = None self.newmenu = None
self.config_meeting_slider = None self.config_meeting_slider = None
self.dbstate.connect('database-changed', self.reset_change_db)
def reset_change_db(self, dummy_dbase):
"""
Used to reset the family reference
"""
self.refperson = None
def get_title(self): def get_title(self):
""" """

View File

@ -244,6 +244,13 @@ class GeoFamClose(GeoGraphyView):
self.cal = config.get('preferences.calendar-format-report') self.cal = config.get('preferences.calendar-format-report')
self.no_show_places_in_status_bar = False self.no_show_places_in_status_bar = False
self.config_meeting_slider = None self.config_meeting_slider = None
self.dbstate.connect('database-changed', self.reset_change_db)
def reset_change_db(self, dummy_dbase):
"""
Used to reset the family reference
"""
self.reffamily = None
def get_title(self): def get_title(self):
""" """

View File

@ -370,8 +370,9 @@ class GeoFamily(GeoGraphyView):
_("Family places for %s") % self.family_label(family)) _("Family places for %s") % self.family_label(family))
person = None person = None
if family: if family:
person = dbstate.db.get_person_from_handle( handle = family.get_father_handle()
family.get_father_handle()) if handle:
person = dbstate.db.get_person_from_handle(handle)
else: else:
return return
family_id = family.gramps_id family_id = family.gramps_id

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@ -7,7 +7,7 @@
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>Gramps</string> <string>Gramps</string>
<key>CFBundleGetInfoString</key> <key>CFBundleGetInfoString</key>
<string>Gramps-5.1.3-1, (C) 1997-2020 The Gramps Team http://www.gramps-project.org</string> <string>Gramps-5.1.5-1, (C) 1997-2022 The Gramps Team http://www.gramps-project.org</string>
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>gramps.icns</string> <string>gramps.icns</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
@ -17,15 +17,15 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>Gramps-5.1.3-1</string> <string>Gramps-5.1.5-1</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>Gramps-5.1.3-1</string> <string>Gramps-5.1.5-1</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>Copyright 1997 - 2020 The Gramps Team, GNU General Public License.</string> <string>Copyright 1997 - 2022 The Gramps Team, GNU General Public License.</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>10.9</string> <string>10.12</string>
<key>GtkOSXLaunchScriptFile</key> <key>GtkOSXLaunchScriptFile</key>
<string>gramps_launcher.py</string> <string>gramps_launcher.py</string>
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>

View File

@ -12,8 +12,9 @@
</meta> </meta>
<plist>${project}/Info.plist</plist> <plist>${project}/Info.plist</plist>
<entitlements>${project}/release.entitlements.plist</entitlements>
<!-- Build gramps-launcher with: <!-- Build gramps-launcher with:
gcc -L$PREFIX/lib `python-config -\-cflags -\-ldflags` \ gcc -L$PREFIX/lib `python-config -\-cflags -\-ldflags -\-embed` \
-o $PREFIX/bin/gramps-launcher \ -o $PREFIX/bin/gramps-launcher \
path/to/gtk-mac-bundler/examples/python-launcher.c path/to/gtk-mac-bundler/examples/python-launcher.c
with the obvious substitution. with the obvious substitution.
@ -41,19 +42,15 @@
</binary> </binary>
<binary recurse="True"> <binary recurse="True">
${prefix}/lib/python3.6/*.so ${prefix}/lib/python3.9/*.so
</binary> </binary>
<binary> <binary>
${prefix}/lib/librsvg-2.2.dylib ${prefix}/lib/librsvg-2.2.dylib
</binary> </binary>
<!--binary>
${prefix}/lib/libwebkit-1.0.2.dylib
</binary-->
<binary> <binary>
${prefix}/lib/libgtkmacintegration-gtk3.2.dylib ${prefix}/lib/libgtkmacintegration-gtk3.4.dylib
</binary> </binary>
<binary> <binary>
@ -65,7 +62,7 @@
</binary> </binary>
<binary> <binary>
${prefix}/lib/enchant ${prefix}/lib/enchant-2
</binary> </binary>
<binary> <binary>
@ -77,7 +74,7 @@
</binary> </binary>
<binary> <binary>
${prefix}/lib/libhunspell-1.6.0.dylib ${prefix}/lib/libhunspell-1.7.0.dylib
</binary> </binary>
<binary> <binary>
@ -96,6 +93,14 @@
${prefix}/lib/libgexiv2.dylib ${prefix}/lib/libgexiv2.dylib
</binary> </binary>
<binary>
${prefix}/lib/libgeocode-glib.dylib
</binary>
<binary>
${prefix}/lib/gio/modules/libgiognutls.so
</binary>
<gir> <gir>
${prefix}/share/gir-1.0/*.gir ${prefix}/share/gir-1.0/*.gir
</gir> </gir>
@ -137,6 +142,10 @@
${project}/gramps_launcher.py ${project}/gramps_launcher.py
</data> </data>
<data>
${prefix}/etc/fonts
</data>
<data> <data>
${prefix}/share/glib-2.0/schemas ${prefix}/share/glib-2.0/schemas
</data> </data>
@ -144,19 +153,19 @@
<!-- We have to pull in the python modules, which are mixed python <!-- We have to pull in the python modules, which are mixed python
and loadable modules. --> and loadable modules. -->
<data recurse="True"> <data recurse="True">
${prefix}/lib/python3.6/*.py ${prefix}/lib/python3.9/*.py
</data> </data>
<data> <data>
${prefix}/lib/python3.6/config-3.6m-darwin/ ${prefix}/lib/python3.9/config-3.9-darwin/
</data> </data>
<data> <data>
${prefix}/lib/python3.6/site-packages/gramps/gen/utils/resource-path ${prefix}/lib/python3.9/site-packages/gramps/gen/utils/resource-path
</data> </data>
<data> <data>
${prefix}/include/python3.6m/pyconfig.h ${prefix}/include/python3.9/pyconfig.h
</data> </data>
@ -173,7 +182,7 @@
</data> </data>
<data recurse="True"> <data recurse="True">
${prefix}/lib/python3.6/site-packages/gramps/*.glade ${prefix}/lib/python3.9/site-packages/gramps/*.glade
</data> </data>
<data> <data>
@ -205,6 +214,7 @@
<data> <data>
${prefix}/share/icons ${prefix}/share/icons
</data> </data>
<!-- Copy icons. Note that the .icns file is an Apple format which <!-- Copy icons. Note that the .icns file is an Apple format which
contains up to 4 sizes of icon. You can use contains up to 4 sizes of icon. You can use
/Developer/Applications/Utilities/Icon Composer.app to import /Developer/Applications/Utilities/Icon Composer.app to import

View File

@ -9,22 +9,12 @@
href="http://pywebkitgtk.googlecode.com/files/"/> href="http://pywebkitgtk.googlecode.com/files/"/>
<repository type="tarball" name="ftp.gnome.org" <repository type="tarball" name="ftp.gnome.org"
href="http://ftp.gnome.org/pub/GNOME/sources/"/> href="http://ftp.gnome.org/pub/GNOME/sources/"/>
<repository type="tarball" name="pyxdg"
href="http://www.gnome.org/~fpeters/pyxdg/"/>
<repository type="tarball" name="xdg-utils"
href="http://portland.freedesktop.org/download/"/>
<repository type="svn" name="gramps-addons"
href="https://svn.code.sf.net/p/gramps-addons/code/"/>
<repository type="tarball" name="oracle" <repository type="tarball" name="oracle"
href="http://download.oracle.com/"/> href="http://download.oracle.com/"/>
<repository type="tarball" name="pymodules" <repository type="tarball" name="pymodules"
href="https://pypi.python.org/packages/"/> href="https://pypi.python.org/packages/"/>
<repository type="tarball" name="stowers"
href="http://www.johnstowers.co.nz/files/"/>
<repository type="git" name="github" href="git://github.com/"/> <repository type="git" name="github" href="git://github.com/"/>
<repository type="tarball" name="github-tarball" href="https://github.com/"/> <repository type="tarball" name="github-tarball" href="https://github.com/"/>
<repository type="tarball" name="graphviz"
href="https://graphviz.gitlab.io/pub/graphviz/stable/SOURCES/"/>
<repository type="tarball" name="exiv2.org" <repository type="tarball" name="exiv2.org"
href="http://www.exiv2.org/releases/"/> href="http://www.exiv2.org/releases/"/>
<repository type="tarball" name="pythonware" <repository type="tarball" name="pythonware"
@ -52,8 +42,8 @@ gtk-mac-bundler gtk-osx-build/projects/gramps/gramps.bundle
--> -->
<include href="https://gitlab.gnome.org/GNOME/gtk-osx/raw/master/modulesets-stable/gtk-osx.modules"/> <!--include href="https://gitlab.gnome.org/GNOME/gtk-osx/raw/master/modulesets-stable/gtk-osx.modules"/-->
<!--include href="/Users/john/Development/GTK-OSX/gtk-osx-build/modulesets-stable/gtk-osx.modules"/--> <include href="/Users/john/Development/GTK-OSX/gtk-osx-build/modulesets-stable/gtk-osx.modules"/>
<distutils id="gramps-git" supports-non-srcdir-builds="no"> <distutils id="gramps-git" supports-non-srcdir-builds="no">
<branch module="gramps-project/gramps.git" repo="github" <branch module="gramps-project/gramps.git" repo="github"
@ -65,9 +55,9 @@ gtk-mac-bundler gtk-osx-build/projects/gramps/gramps.bundle
</distutils> </distutils>
<distutils id="gramps" supports-non-srcdir-builds="no"> <distutils id="gramps" supports-non-srcdir-builds="no">
<branch module="gramps-project/gramps/archive/v5.1.3.tar.gz" <branch module="gramps-project/gramps/archive/v5.1.5.tar.gz"
repo="github-tarball" version="5.1.3" repo="github-tarball" version="5.1.5"
checkoutdir="gramps-gramps-5.1.3"/> checkoutdir="gramps-gramps-5.1.5"/>
<dependencies> <dependencies>
<dep package="meta-gramps-modules"/> <dep package="meta-gramps-modules"/>
</dependencies> </dependencies>
@ -81,35 +71,10 @@ gtk-mac-bundler gtk-osx-build/projects/gramps/gramps.bundle
</dependencies> </dependencies>
</distutils> </distutils>
<autotools id="pyWebKitGtk" > <meson id="json-glib" mesonargs="-Dgtk_doc=disabled -Dman=false -Dtests=false">
<branch module="pywebkitgtk-1.1.7.tar.bz2" version="1.1.7" <branch module="json-glib/1.6/json-glib-1.6.6.tar.xz"
repo="pywebkitgtk"/> version="1.6.6" repo="ftp.gnome.org"
<dependencies> hash="sha256:96ec98be7a91f6dde33636720e3da2ff6ecbb90e76ccaa49497f31a6855a490e"/>
<dep package="WebKit"/>
<dep package="sqlite"/>
</dependencies>
</autotools>
<distutils id="pyenchant">
<branch repo="pymodules" module="73/73/49f95fe636ab3deed0ef1e3b9087902413bcdf74ec00298c3059e660cfbb/pyenchant-1.6.8.tar.gz"
version="1.6.1"/>
</distutils>
<distutils id="pyxdg">
<branch repo="pyxdg" module="pyxdg-0.17.tar.gz" version="0.17"
hash="sha256:fbc87711922b2dd6ceb23ee041f1f96da9b7dbb6971df03a3081b439def069ce"
md5sum="a086de99cc536095684d87f15594e4db" size="37372"/>
</distutils>
<autotools id="xdg-utils">
<branch module="xdg-utils-1.0.2.tgz" version="1.0.2" repo="xdg-utils"/>
</autotools>
<meson id="json-glib">
<branch module="json-glib/1.4/json-glib-1.4.4.tar.xz"
version="1.4.4" repo="ftp.gnome.org"
hash="sha256:720c5f4379513dc11fd97dc75336eb0c0d3338c53128044d9fabec4374f4bc47"/>
<dependencies> <dependencies>
<dep package="gobject-introspection"/> <dep package="gobject-introspection"/>
</dependencies> </dependencies>
@ -128,46 +93,34 @@ gtk-mac-bundler gtk-osx-build/projects/gramps/gramps.bundle
<autotools id="osmgpsmap" skip-autogen="never" <autotools id="osmgpsmap" skip-autogen="never"
autogenargs="--disable-gtk-doc-html" autogenargs="--disable-gtk-doc-html"
supports-non-srcdir-builds="no"> supports-non-srcdir-builds="no">
<branch module="nzjrs/osm-gps-map" revision="1.1.0" repo="github"/> <branch module="nzjrs/osm-gps-map" revision="1.2.0" repo="github"/>
<dependencies> <dependencies>
<dep package="libsoup"/> <dep package="libsoup"/>
</dependencies> <dep package="gtk+-3.0"/>
<after>
<dep package="meta-gtk-osx-gtk3"/>
<dep package="meta-gtk-osx-gtk3.14"/>
</after>
</autotools>
<autotools id="graphviz" autogen-sh="configure"
autogenargs="--disable-sharp --disable-guile --disable-java --disable-lua --disable-ocaml --disable-perl --disable-php --disable-r --disable-ruby --disable-tcl --with-pangocairo">
<branch module="graphviz.tar.gz" version="2.40.1"
repo="graphviz" checkoutdir="graphviz-2.40.1"/>
<dependencies>
<dep package="pango"/>
<dep package="meta-gtk-osx-freetype"/>
<dep package="librsvg"/>
</dependencies> </dependencies>
</autotools> </autotools>
<cmake id="exiv2" cmakeargs="-DEXIV2_ENABLE_PNG=ON"> <cmake id="exiv2" cmakeargs="-DEXIV2_ENABLE_PNG=ON">
<branch module="exiv2-0.27.0a-Source.tar.gz" repo="exiv2.org" <branch module="exiv2-0.27.4-Source.tar.gz" repo="exiv2.org"
checkoutdir="exiv2-0.27.0-Source" version="0.27.0"/> checkoutdir="exiv2-0.27.4-Source" version="0.27.4"
hash="sha256:84366dba7c162af9a7603bcd6c16f40fe0e9af294ba2fd2f66ffffb9fbec904e"/>
</cmake> </cmake>
<meson id="gexiv2" mesonargs="-Dvapi=false"> <meson id="gexiv2" mesonargs="-Dvapi=false">
<branch module="gexiv2/0.12/gexiv2-0.12.0.tar.xz" <branch module="gexiv2/0.14/gexiv2-0.14.0.tar.xz"
repo="ftp.gnome.org" version="0.12.0" repo="ftp.gnome.org" version="0.14.0"
hash="sha256:58f539b0386f36300b76f3afea3a508de4914b27e78f58ee4d142486a42f926a"> hash="sha256:e58279a6ff20b6f64fa499615da5e9b57cf65ba7850b72fafdf17221a9d6d69e">
</branch> </branch>
<dependencies> <dependencies>
<dep package="exiv2"/> <dep package="exiv2"/>
<dep package="pygobject3"/>
</dependencies> </dependencies>
</meson> </meson>
https://files.pythonhosted.org/packages/
<distutils id="pil"> <distutils id="pillow">
<branch module="93/73/66854f63b1941aad9af18a1de59f9cf95ad1a87c801540222e332f6688d7/Pillow-4.1.1.tar.gz" version="4.1.1" <branch module="21/23/af6bac2a601be6670064a817273d4190b79df6f74d8012926a39bc7aa77f/Pillow-8.2.0.tar.gz" version="8.2.0"
repo="pymodules" repo="pymodules"
hash="md5:f2565954955c8d10f3b4f1f72f852bf7"> hash="sha256:a787ab10d7bb5494e5f76536ac460741788f1fbce851068d73a87ca7c35fc3e1">
</branch> </branch>
<dependencies> <dependencies>
<!--dep package="setuptools"/--> <!--dep package="setuptools"/-->
@ -175,18 +128,74 @@ gtk-mac-bundler gtk-osx-build/projects/gramps/gramps.bundle
</distutils> </distutils>
<distutils id='pyicu'> <distutils id='pyicu'>
<branch version='2.5' repo='pymodules' <branch version='2.7.2' repo='pymodules'
module='5a/99/c48c816095208bf3f4936ff67e571621fbddef461303a35a076f234e31f6/PyICU-2.5.tar.gz'/> module='17/0f/9d6b7eb01650960239a5d4dc21cd6e7a96921807c043d287bae4b2f440e1/PyICU-2.7.2.tar.gz'
hash="sha256:1382869b22d91cc99274f9b525fa7d9199b44d9007ff0036a09747839a01e9dc"/>
<dependencies> <dependencies>
<dep package='icu'/> <dep package='icu'/>
</dependencies> </dependencies>
</distutils>
<!--Note the leading ; in autogen-template. It's there on purpose in case the user has set nice_build so that the nice prepended to the command doesn't eat the cd. -->
<autotools id="berkeleydb" autogen-sh="configure"
supports-non-srcdir-builds="no" makeargs="-C build_unix"
autogen-template="cd .;cd build_unix; ../dist/%(autogen-sh)s --prefix %(prefix)s %(autogenargs)s"
makeinstallargs="-C build_unix install">
<branch module="berkeley-db/db-4.8.30.NC.tar.gz" version="4.8.30"
repo="oracle"
hash="sha256:12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef" >
<patch file="berkeleydb-4.8-atomic.patch" strip='1'/>
</branch>
</autotools>
<!-- For out-of-source-tree builds (i.e., builddir is defined either
in .jhbuildrc-custom or passed as an option on the
command-line, the normal berkeleydb module will build in its
srcdir/build_unix directory. If you want to build it in the
build directory with most of the other modules, use this module
instead. -->
<autotools id="berkeleydb-nonsrctree" autogen-sh="configure"
autogen-template="%(srcdir)s/dist/%(autogen-sh)s --prefix %(prefix)s %(autogenargs)s" >
<branch module="berkeley-db/db-4.8.30.NC.tar.gz" version="4.8.30"
repo="oracle"
hash="sha256:12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef">
<patch file="berkeleydb-4.8-atomic.patch" strip='1'/>
</branch>
</autotools>
<distutils id="pybsddb">
<branch repo="pymodules" version="6.2.9"
module="f0/24/92034482656945fc6ceb10551222b43a0ff8d0c87e15839120487820067e/bsddb3-6.2.9.tar.gz"
hash="sha256:70d05ec8dc568f42e70fc919a442e0daadc2a905a1cfb7ca77f549d49d6e7801" />
<dependencies>
<dep package="python3"/>
</dependencies>
<after>
<dep package="berkeleydb"/>
<dep package="berkeleydb-nonsrctree"/>
</after>
</distutils>
<distutils id='pyfontconfig'>
<branch repo='pymodules' version="0.5.1"
module="e6/01/a28b0160f82ca5e946e315251c797f07c74e5c5a53f2a9e706eebc680191/Python-fontconfig-0.5.1.tar.gz"
hash="sha256:b7cfe366242f83b8cd7175b7d4dd95d19f42d619c58a51914f72b1e741739994">
<patch file="pyfontconfig-curexc.patch" strip="1"/>
</branch>
<dependencies>
<dep package="python3"/>
<dep package="fontconfig"/>
</dependencies>
</distutils> </distutils>
<metamodule id="meta-gramps-modules"> <metamodule id="meta-gramps-modules">
<dependencies> <dependencies>
<dep package="python3"/> <dep package="python3"/>
<dep package="meta-gtk-osx-gtk3"/> <dep package="meta-gtk-osx-gtk3"/>
<dep package="meta-gtk-osx-gtk3-core-themes"/>
<dep package="goocanvas2"/> <dep package="goocanvas2"/>
<dep package="librsvg"/> <dep package="librsvg"/>
<dep package="shared-mime-info"/> <dep package="shared-mime-info"/>
@ -202,7 +211,7 @@ gtk-mac-bundler gtk-osx-build/projects/gramps/gramps.bundle
<dep package="pygobject3"/> <dep package="pygobject3"/>
<dep package='pyicu'/> <dep package='pyicu'/>
<dep package='pybsddb'/> <dep package='pybsddb'/>
<dep package="pil"/> <dep package="pillow"/>
</dependencies> </dependencies>
</metamodule> </metamodule>

View File

@ -24,6 +24,7 @@ environ['GTK_PATH'] = bundle_res
environ['PANGO_RC_FILE'] = join(bundle_etc, 'pango', 'pangorc') environ['PANGO_RC_FILE'] = join(bundle_etc, 'pango', 'pangorc')
environ['PANGO_SYSCONFDIR'] = bundle_etc environ['PANGO_SYSCONFDIR'] = bundle_etc
environ['PANGO_LIBDIR'] = bundle_lib environ['PANGO_LIBDIR'] = bundle_lib
environ['GIO_MODULE_DIR'] = join(bundle_lib, 'gio', 'modules')
environ['GDK_PIXBUF_MODULE_FILE'] = join(bundle_lib, 'gdk-pixbuf-2.0', environ['GDK_PIXBUF_MODULE_FILE'] = join(bundle_lib, 'gdk-pixbuf-2.0',
'2.10.0', 'loaders.cache') '2.10.0', 'loaders.cache')
environ['GI_TYPELIB_PATH'] = join(bundle_lib, 'girepository-1.0') environ['GI_TYPELIB_PATH'] = join(bundle_lib, 'girepository-1.0')
@ -40,6 +41,8 @@ environ['USERPROFILE'] = environ['HOME']
environ['APPDATA'] = join(environ['HOME'], 'Library', 'Application Support') environ['APPDATA'] = join(environ['HOME'], 'Library', 'Application Support')
environ['PATH'] = join(bundle_contents, 'MacOS') + ':' + environ['PATH'] environ['PATH'] = join(bundle_contents, 'MacOS') + ':' + environ['PATH']
if __name__ == '__main__':
__file__ = 'gramps_launcher.py'
import gramps.grampsapp as app import gramps.grampsapp as app
app.main() app.main()

View File

@ -0,0 +1,40 @@
--- a/dist/configure 2010-04-12 13:25:23.000000000 -0700
+++ b/dist/configure 2021-04-11 11:27:32.000000000 -0700
@@ -19158,7 +19158,7 @@
# x86_64/gcc: FreeBSD, NetBSD, BSD/OS, Linux
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-
+#include <stdlib.h>
int
main ()
{
@@ -20197,7 +20197,7 @@
if test "$db_cv_atomic" = no; then
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-
+#include <stdlib.h>
int
main ()
{
--- a/dbinc/atomic.h 2013-03-12 14:07:22.000000000 -0400
+++ b/dbinc/atomic.h 2013-03-12 14:06:35.000000000 -0400
@@ -144,7 +144,7 @@
#define atomic_inc(env, p) __atomic_inc(p)
#define atomic_dec(env, p) __atomic_dec(p)
#define atomic_compare_exchange(env, p, o, n) \
- __atomic_compare_exchange((p), (o), (n))
+ __atomic_compare_exchange_db((p), (o), (n))
static inline int __atomic_inc(db_atomic_t *p)
{
int temp;
@@ -176,7 +176,7 @@
* http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
* which configure could be changed to use.
*/
-static inline int __atomic_compare_exchange(
+static inline int __atomic_compare_exchange_db(
db_atomic_t *p, atomic_value_t oldval, atomic_value_t newval)
{
atomic_value_t was;

View File

@ -0,0 +1,56 @@
--- a/fontconfig.c 2011-11-02 07:59:41.000000000 -0700
+++ b/fontconfig.c 2021-08-09 18:07:50.000000000 -0700
@@ -4525,12 +4525,12 @@
Py_INCREF(local_type);
Py_INCREF(local_value);
Py_INCREF(local_tb);
- tmp_type = tstate->exc_type;
- tmp_value = tstate->exc_value;
- tmp_tb = tstate->exc_traceback;
- tstate->exc_type = local_type;
- tstate->exc_value = local_value;
- tstate->exc_traceback = local_tb;
+ tmp_type = tstate->curexc_type;
+ tmp_value = tstate->curexc_value;
+ tmp_tb = tstate->curexc_traceback;
+ tstate->curexc_type = local_type;
+ tstate->curexc_value = local_value;
+ tstate->curexc_traceback = local_tb;
/* Make sure tstate is in a consistent state when we XDECREF
these objects (XDECREF may run arbitrary code). */
Py_XDECREF(tmp_type);
@@ -4735,9 +4735,9 @@
static CYTHON_INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb) {
PyThreadState *tstate = PyThreadState_GET();
- *type = tstate->exc_type;
- *value = tstate->exc_value;
- *tb = tstate->exc_traceback;
+ *type = tstate->curexc_type;
+ *value = tstate->curexc_value;
+ *tb = tstate->curexc_traceback;
Py_XINCREF(*type);
Py_XINCREF(*value);
Py_XINCREF(*tb);
@@ -4746,12 +4746,12 @@
static void __Pyx_ExceptionReset(PyObject *type, PyObject *value, PyObject *tb) {
PyObject *tmp_type, *tmp_value, *tmp_tb;
PyThreadState *tstate = PyThreadState_GET();
- tmp_type = tstate->exc_type;
- tmp_value = tstate->exc_value;
- tmp_tb = tstate->exc_traceback;
- tstate->exc_type = type;
- tstate->exc_value = value;
- tstate->exc_traceback = tb;
+ tmp_type = tstate->curexc_type;
+ tmp_value = tstate->curexc_value;
+ tmp_tb = tstate->curexc_traceback;
+ tstate->curexc_type = type;
+ tstate->curexc_value = value;
+ tstate->curexc_traceback = tb;
Py_XDECREF(tmp_type);
Py_XDECREF(tmp_value);
Py_XDECREF(tmp_tb);
Diff finished. Mon Aug 9 18:09:16 2021

View File

@ -353,8 +353,8 @@ data_files_core.append(('share/gramps/css/swanky-purse/images', SWANKY_IMG))
PNG_FILES = glob.glob(os.path.join('data', '*.png')) PNG_FILES = glob.glob(os.path.join('data', '*.png'))
SVG_FILES = glob.glob(os.path.join('data', '*.svg')) SVG_FILES = glob.glob(os.path.join('data', '*.svg'))
data_files_core.append(('share/icons/gnome/48x48/mimetypes', PNG_FILES)) data_files_core.append(('share/icons/hicolor/48x48/mimetypes', PNG_FILES))
data_files_core.append(('share/icons/gnome/scalable/mimetypes', SVG_FILES)) data_files_core.append(('share/icons/hicolor/scalable/mimetypes', SVG_FILES))
DTD_FILES = glob.glob(os.path.join('data', '*.dtd')) DTD_FILES = glob.glob(os.path.join('data', '*.dtd'))
RNG_FILES = glob.glob(os.path.join('data', '*.rng')) RNG_FILES = glob.glob(os.path.join('data', '*.rng'))
@ -381,11 +381,15 @@ APP_16 = os.path.join(THEME, '16x16', 'apps', 'gramps.png')
APP_22 = os.path.join(THEME, '22x22', 'apps', 'gramps.png') APP_22 = os.path.join(THEME, '22x22', 'apps', 'gramps.png')
APP_24 = os.path.join(THEME, '24x24', 'apps', 'gramps.png') APP_24 = os.path.join(THEME, '24x24', 'apps', 'gramps.png')
APP_48 = os.path.join(THEME, '48x48', 'apps', 'gramps.png') APP_48 = os.path.join(THEME, '48x48', 'apps', 'gramps.png')
APP_128 = os.path.join(THEME, '128x128', 'apps', 'gramps.png')
APP_256 = os.path.join(THEME, '256x256', 'apps', 'gramps.png')
APP_SC = os.path.join(THEME, 'scalable', 'apps', 'gramps.svg') APP_SC = os.path.join(THEME, 'scalable', 'apps', 'gramps.svg')
data_files_gui.append(('share/icons/hicolor/16x16/apps', [APP_16])) data_files_gui.append(('share/icons/hicolor/16x16/apps', [APP_16]))
data_files_gui.append(('share/icons/hicolor/22x22/apps', [APP_22])) data_files_gui.append(('share/icons/hicolor/22x22/apps', [APP_22]))
data_files_gui.append(('share/icons/hicolor/24x24/apps', [APP_24])) data_files_gui.append(('share/icons/hicolor/24x24/apps', [APP_24]))
data_files_gui.append(('share/icons/hicolor/48x48/apps', [APP_48])) data_files_gui.append(('share/icons/hicolor/48x48/apps', [APP_48]))
data_files_gui.append(('share/icons/hicolor/128x128/apps', [APP_128]))
data_files_gui.append(('share/icons/hicolor/256x256/apps', [APP_256]))
data_files_gui.append(('share/icons/hicolor/scalable/apps', [APP_SC])) data_files_gui.append(('share/icons/hicolor/scalable/apps', [APP_SC]))
data_files = data_files_core + data_files_gui data_files = data_files_core + data_files_gui