diff --git a/data/gnome-mime-application-x-gedcom.png b/data/application-x-gedcom.png
similarity index 100%
rename from data/gnome-mime-application-x-gedcom.png
rename to data/application-x-gedcom.png
diff --git a/data/gnome-mime-application-x-gedcom.svg b/data/application-x-gedcom.svg
similarity index 100%
rename from data/gnome-mime-application-x-gedcom.svg
rename to data/application-x-gedcom.svg
diff --git a/data/gnome-mime-application-x-geneweb.png b/data/application-x-geneweb.png
similarity index 100%
rename from data/gnome-mime-application-x-geneweb.png
rename to data/application-x-geneweb.png
diff --git a/data/gnome-mime-application-x-geneweb.svg b/data/application-x-geneweb.svg
similarity index 100%
rename from data/gnome-mime-application-x-geneweb.svg
rename to data/application-x-geneweb.svg
diff --git a/data/gnome-mime-application-x-gramps-package.png b/data/application-x-gramps-package.png
similarity index 100%
rename from data/gnome-mime-application-x-gramps-package.png
rename to data/application-x-gramps-package.png
diff --git a/data/gnome-mime-application-x-gramps-package.svg b/data/application-x-gramps-package.svg
similarity index 100%
rename from data/gnome-mime-application-x-gramps-package.svg
rename to data/application-x-gramps-package.svg
diff --git a/data/gnome-mime-application-x-gramps-xml.png b/data/application-x-gramps-xml.png
similarity index 100%
rename from data/gnome-mime-application-x-gramps-xml.png
rename to data/application-x-gramps-xml.png
diff --git a/data/gnome-mime-application-x-gramps-xml.svg b/data/application-x-gramps-xml.svg
similarity index 100%
rename from data/gnome-mime-application-x-gramps-xml.svg
rename to data/application-x-gramps-xml.svg
diff --git a/data/gnome-mime-application-x-gramps.png b/data/application-x-gramps.png
similarity index 100%
rename from data/gnome-mime-application-x-gramps.png
rename to data/application-x-gramps.png
diff --git a/data/gnome-mime-application-x-gramps.svg b/data/application-x-gramps.svg
similarity index 100%
rename from data/gnome-mime-application-x-gramps.svg
rename to data/application-x-gramps.svg
diff --git a/data/grampsxml.dtd b/data/grampsxml.dtd
index 160d4add5..6bd622d3e 100644
--- a/data/grampsxml.dtd
+++ b/data/grampsxml.dtd
@@ -251,7 +251,7 @@ PLACES
-
+
-
diff --git a/debian/changelog b/debian/changelog
index 4de28caf7..951372468 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -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 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 Sun, 16 Aug 2020 20:23:34 +0200
+
gramps (5.1.2-1) unstable; urgency=medium
* New release
diff --git a/debian/copyright b/debian/copyright
index e2d1f1cc3..10ff8b324 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -92,6 +92,8 @@ Copyright: 2000-2007, Alex Roitman
2018, Robin van der Vliet
2018, Theo van Rijn
2019, Matthias Kemmer
+ 2020, Jan Sparreboom
+ 2021, Mirko Leonhaeuser
License: GPL-2+
Files: debian/*
diff --git a/debian/patches/fix-probably_alive_test.patch b/debian/patches/fix-probably_alive_test.patch
new file mode 100644
index 000000000..9c3dc5405
--- /dev/null
+++ b/debian/patches/fix-probably_alive_test.patch
@@ -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
+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):
+ """
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 000000000..1ee1833c6
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1 @@
+fix-probably_alive_test.patch
diff --git a/debian/watch b/debian/watch
index 37a5375ec..95985b298 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,8 +1,6 @@
-version=3
-
+version=4
opts=\
-dversionmangle=s/(\~|\+)(debian|dfsg|ds|deb)(\.\d+)?$//,\
-filenamemangle=s/.+\/v?(\d\S*)\.tar\.gz/$1\.tar\.gz/,\
+filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/gramps-project-$1\.tar\.gz/,\
repacksuffix=~dfsg \
https://github.com/gramps-project/gramps/tags \
-.*/archive/v?([\d\.]+).tar.gz
+.*/v?(\d\S+)\.tar\.gz
diff --git a/gramps/gen/const.py b/gramps/gen/const.py
index bd8fb728d..9eaa4244b 100644
--- a/gramps/gen/const.py
+++ b/gramps/gen/const.py
@@ -226,7 +226,7 @@ GTK_GETTEXT_DOMAIN = 'gtk30'
#
#-------------------------------------------------------------------------
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 "
"Management Programming System)\n"
"is a personal genealogy program.")
diff --git a/gramps/gen/datehandler/_date_nl.py b/gramps/gen/datehandler/_date_nl.py
index add9a14cc..83c4fbde1 100644
--- a/gramps/gen/datehandler/_date_nl.py
+++ b/gramps/gen/datehandler/_date_nl.py
@@ -83,35 +83,37 @@ class DateParserNL(DateParser):
month_to_int["xbris"] = 12
modifier_to_int = {
- 'voor' : Date.MOD_BEFORE,
- 'na' : Date.MOD_AFTER,
- 'tegen' : Date.MOD_ABOUT,
- 'om' : Date.MOD_ABOUT,
- 'rond' : Date.MOD_ABOUT,
- 'circa' : Date.MOD_ABOUT,
- 'ca.' : Date.MOD_ABOUT,
+ 'voor' : Date.MOD_BEFORE,
+ 'na' : Date.MOD_AFTER,
+ 'ca.' : Date.MOD_ABOUT,
+ 'circa' : Date.MOD_ABOUT,
+ 'om' : Date.MOD_ABOUT,
+ 'omstreeks' : Date.MOD_ABOUT,
+ 'ongeveer' : Date.MOD_ABOUT,
+ 'rond' : Date.MOD_ABOUT,
+ 'tegen' : Date.MOD_ABOUT,
}
calendar_to_int = {
- 'gregoriaans' : Date.CAL_GREGORIAN,
- 'greg.' : Date.CAL_GREGORIAN,
- 'juliaans' : Date.CAL_JULIAN,
- 'jul.' : Date.CAL_JULIAN,
- 'hebreeuws' : Date.CAL_HEBREW,
- 'hebr.' : Date.CAL_HEBREW,
- 'islamitisch' : Date.CAL_ISLAMIC,
- 'isl.' : Date.CAL_ISLAMIC,
- 'franse republiek': Date.CAL_FRENCH,
- 'fran.' : Date.CAL_FRENCH,
- 'persisch' : Date.CAL_PERSIAN,
- 'zweeds' : Date.CAL_SWEDISH,
- 'z' : Date.CAL_SWEDISH,
+ 'gregoriaans' : Date.CAL_GREGORIAN,
+ 'greg.' : Date.CAL_GREGORIAN,
+ 'juliaans' : Date.CAL_JULIAN,
+ 'jul.' : Date.CAL_JULIAN,
+ 'hebreeuws' : Date.CAL_HEBREW,
+ 'hebr.' : Date.CAL_HEBREW,
+ 'islamitisch' : Date.CAL_ISLAMIC,
+ 'isl.' : Date.CAL_ISLAMIC,
+ 'frans republiekeins' : Date.CAL_FRENCH,
+ 'fran.' : Date.CAL_FRENCH,
+ 'persisch' : Date.CAL_PERSIAN,
+ 'zweeds' : Date.CAL_SWEDISH,
+ 'z' : Date.CAL_SWEDISH,
}
quality_to_int = {
- 'geschat' : Date.QUAL_ESTIMATED,
+ 'geschat' : Date.QUAL_ESTIMATED,
'gesch.' : Date.QUAL_ESTIMATED,
- 'berekend' : Date.QUAL_CALCULATED,
+ 'berekend' : Date.QUAL_CALCULATED,
'ber.' : Date.QUAL_CALCULATED,
}
@@ -147,17 +149,17 @@ class DateDisplayNL(DateDisplay):
calendar = (
"", "juliaans", "hebreeuws",
- "franse republiek", "persisch", "islamitisch",
+ "frans republikeins", "persisch", "islamitisch",
"zweeds" )
- _mod_str = ("", "voor ", "na ", "rond ", "", "", "")
+ _mod_str = ("", "voor ", "na ", "omstreeks ", "", "", "")
_qual_str = ("", "geschat ", "berekend ")
_bce_str = "%s v. Chr."
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"
)
# this definition must agree with its "_display_gregorian" method
diff --git a/gramps/gen/db/dummydb.py b/gramps/gen/db/dummydb.py
index 2efec5f93..79b702c58 100644
--- a/gramps/gen/db/dummydb.py
+++ b/gramps/gen/db/dummydb.py
@@ -52,7 +52,6 @@ methods should be changed to generate exceptions. Possibly by globally changing
#
#-------------------------------------------------------------------------
import logging
-import os
import inspect
from abc import ABCMeta
from types import FunctionType
@@ -160,10 +159,12 @@ def wrapper(method):
"""
class_name = args[0].__class__.__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',
- class_name, func_name, os.path.split(caller_frame[1])[1],
- caller_frame[2], caller_frame[3])
+ class_name, func_name, c_code.co_filename, c_frame.f_lineno,
+ c_code.co_name)
return method(*args, **keywargs)
return wrapped
diff --git a/gramps/gen/db/txn.py b/gramps/gen/db/txn.py
index 52620c6dd..fe07e5390 100644
--- a/gramps/gen/db/txn.py
+++ b/gramps/gen/db/txn.py
@@ -78,15 +78,13 @@ class DbTxn(defaultdict):
elapsed_time = time.time() - self.start_time
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, "
- "line %s, in %s **** %.2f seconds" %
- ((hex(id(self)),)+
- (os.path.split(caller_frame[1])[1],)+
- tuple(caller_frame[i] for i in range(2, 4))+
- (elapsed_time,)
- )
- )
+ "line %s, in %s **** %.2f seconds",
+ hex(id(self)), c_code.co_filename, c_frame.f_lineno,
+ c_code.co_name, elapsed_time)
return False
diff --git a/gramps/gen/db/utils.py b/gramps/gen/db/utils.py
index b5a1336f7..ad9c87dc1 100644
--- a/gramps/gen/db/utils.py
+++ b/gramps/gen/db/utils.py
@@ -42,6 +42,8 @@ from ..const import PLUGINS_DIR, USER_PLUGINS
from ..constfunc import win, get_env_var
from ..config import config
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)
db = database()
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. "
- "Called from File %s, line %s, in %s"
- % ((db.__class__.__name__, hex(id(db)))
- + (os.path.split(caller_frame[1])[1],)
- + tuple(caller_frame[i] for i in range(2, 4))))
+ "Called from File %s, line %s, in %s",
+ db.__class__.__name__, hex(id(db)), c_code.co_filename,
+ c_frame.f_lineno, c_code.co_name)
+
return db
else:
raise Exception("can't load database backend: '%s'" % plugin_id)
@@ -209,8 +213,8 @@ def write_lock_file(name):
if win():
user = get_env_var('USERNAME')
host = get_env_var('USERDOMAIN')
- if host is None:
- host = ""
+ if not user:
+ user = _("Unknown")
else:
host = os.uname()[1]
# An ugly workaround for os.getlogin() issue with Konsole
diff --git a/gramps/gen/dbstate.py b/gramps/gen/dbstate.py
index 21e7e4a5b..6e748cafe 100644
--- a/gramps/gen/dbstate.py
+++ b/gramps/gen/dbstate.py
@@ -29,7 +29,6 @@ Provide the database state class
#
#------------------------------------------------------------------------
import sys
-import os
import logging
import inspect
@@ -88,10 +87,12 @@ class DbState(Callback):
"""
class_name = self.__class__.__name__
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',
- class_name, func_name, os.path.split(caller_frame[1])[1],
- caller_frame[2], caller_frame[3])
+ class_name, func_name, c_code.co_filename, c_frame.f_lineno,
+ c_code.co_name)
return (self.db is not None) and self.db.is_open()
def change_database(self, database):
diff --git a/gramps/gen/display/name.py b/gramps/gen/display/name.py
index 8012e9c5a..10b269189 100644
--- a/gramps/gen/display/name.py
+++ b/gramps/gen/display/name.py
@@ -999,6 +999,8 @@ class NameDisplay:
1. if group name is defined, use that
2. if group name is defined for the primary surname, use that
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
:type pn: tuple
@@ -1007,8 +1009,25 @@ class NameDisplay:
"""
if pn[_GROUP]:
return pn[_GROUP]
- return db.get_name_group_mapping(_raw_primary_surname_only(
- pn[_SURNAME_LIST]))
+ name = pn[_GROUP]
+ 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):
"""
diff --git a/gramps/gen/filters/rules/media/__init__.py b/gramps/gen/filters/rules/media/__init__.py
index 189383e42..2508347bf 100644
--- a/gramps/gen/filters/rules/media/__init__.py
+++ b/gramps/gen/filters/rules/media/__init__.py
@@ -51,6 +51,7 @@ editor_rule_list = [
MediaPrivate,
MatchesFilter,
MatchesSourceConfidence,
+ HasMedia,
HasAttribute,
ChangedSince,
HasTag,
diff --git a/gramps/gen/filters/rules/person/_matcheseventfilter.py b/gramps/gen/filters/rules/person/_matcheseventfilter.py
index 542cdcbdb..b352a2acf 100644
--- a/gramps/gen/filters/rules/person/_matcheseventfilter.py
+++ b/gramps/gen/filters/rules/person/_matcheseventfilter.py
@@ -52,7 +52,7 @@ class MatchesEventFilter(MatchesEventFilterBase):
name = _('Persons with events matching the ')
description = _("Matches persons who have events that match a certain"
" event filter")
- category = _('General filters')
+ category = _('Event filters')
# we want to have this filter show event filters
namespace = 'Event'
diff --git a/gramps/gen/filters/rules/test/person_rules_test.py b/gramps/gen/filters/rules/test/person_rules_test.py
index e7997b025..beb982f22 100644
--- a/gramps/gen/filters/rules/test/person_rules_test.py
+++ b/gramps/gen/filters/rules/test/person_rules_test.py
@@ -98,9 +98,10 @@ class BaseTest(unittest.TestCase):
filter_.set_invert(invert)
stime = perf_counter()
results = filter_.apply(self.db)
- if __debug__:
- rulename = inspect.stack()[1][3]
- print("%s: %.2f\n" % (rulename, perf_counter() - stime))
+ # if __debug__:
+ # frame = inspect.currentframe()
+ # rulename = frame.f_back.f_code.co_name
+ # print("%s: %.2f\n" % (rulename, perf_counter() - stime))
return set(results)
def test_Complex_1(self):
@@ -346,7 +347,7 @@ class BaseTest(unittest.TestCase):
"""
rule = ProbablyAlive(['1900'])
res = self.filter_with_rule(rule)
- self.assertEqual(len(res), 766)
+ self.assertEqual(len(res), 733)
def test_RegExpName(self):
"""
diff --git a/gramps/gen/lib/date.py b/gramps/gen/lib/date.py
index 83917de72..d2a7fdbf8 100644
--- a/gramps/gen/lib/date.py
+++ b/gramps/gen/lib/date.py
@@ -77,14 +77,14 @@ class Span:
self.precision = 2
self.negative = False
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:
self.date1 = date2
self.date2 = date1
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.date2.get_modifier() == Date.MOD_NONE:
val = self.date1.sortval - self.date2.sortval
diff --git a/gramps/gen/lib/test/date_test.py b/gramps/gen/lib/test/date_test.py
index d4312637b..13517224a 100644
--- a/gramps/gen/lib/test/date_test.py
+++ b/gramps/gen/lib/test/date_test.py
@@ -38,7 +38,7 @@ from ...datehandler import get_date_formats, set_format
from ...datehandler import parser as _dp
from ...datehandler import displayer as _dd
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 = {}
@@ -432,6 +432,36 @@ class ArithmeticDateTest(BaseDateTest):
self.assertEqual(val1, val2,
"'%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
diff --git a/gramps/gen/merge/mergepersonquery.py b/gramps/gen/merge/mergepersonquery.py
index f7162819c..93f134945 100644
--- a/gramps/gen/merge/mergepersonquery.py
+++ b/gramps/gen/merge/mergepersonquery.py
@@ -31,8 +31,8 @@ Provide merge capabilities for persons.
#-------------------------------------------------------------------------
from ..db import DbTxn
from ..const import GRAMPS_LOCALE as glocale
-_ = glocale.translation.sgettext
from ..errors import MergeError
+_ = glocale.translation.sgettext
#-------------------------------------------------------------------------
#
@@ -49,11 +49,12 @@ class MergePersonQuery:
self.titanic = titanic
if self.check_for_spouse(self.phoenix, self.titanic):
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):
raise MergeError(_("A parent and child cannot be merged. To merge "
- "these people, you must first break the relationship between "
- "them."))
+ "these people, you must first break the relatio"
+ "nship between them."))
def check_for_spouse(self, person1, person2):
"""Return if person1 and person2 are spouses of eachother."""
@@ -80,12 +81,12 @@ class MergePersonQuery:
main_family.merge(family)
for childref in family.get_child_ref_list():
child = self.database.get_person_from_handle(
- childref.get_reference_handle())
+ childref.get_reference_handle())
if main_family_handle in child.parent_family_list:
child.remove_handle_references('Family', [family_handle])
else:
child.replace_handle_reference('Family', family_handle,
- main_family_handle)
+ main_family_handle)
self.database.commit_person(child, trans)
if self.phoenix:
self.phoenix.remove_family_handle(family_handle)
@@ -143,7 +144,8 @@ class MergePersonQuery:
for family_handle in self.phoenix.get_parent_family_handle_list():
family = self.database.get_family_from_handle(family_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)
family_merge_guard = False
@@ -182,7 +184,10 @@ class MergePersonQuery:
self.database.commit_family(family, trans)
parent_list.append(parents)
- if self.database.get_default_handle() == old_handle:
- self.database.set_default_person_handle(None)
+ hp_hdl = self.database.get_default_handle()
+ 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)
return family_merge_ok
diff --git a/gramps/gen/plug/docgen/graphdoc.py b/gramps/gen/plug/docgen/graphdoc.py
index ea3ed242f..670e88128 100644
--- a/gramps/gen/plug/docgen/graphdoc.py
+++ b/gramps/gen/plug/docgen/graphdoc.py
@@ -113,6 +113,10 @@ else:
_GS_CMD = where_is("gs")
+def esc(id_txt):
+ return id_txt.replace('"', '\\"')
+
+
#------------------------------------------------------------------------------
#
# GVOptions
@@ -575,7 +579,7 @@ class GVDocBase(BaseDoc, GVDoc):
text += ' URL="%s"' % url
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=""):
"""
@@ -583,7 +587,7 @@ class GVDocBase(BaseDoc, GVDoc):
Implements GVDocBase.add_link().
"""
- self.write(' "%s" -> "%s"' % (id1, id2))
+ self.write(' "%s" -> "%s"' % (esc(id1), esc(id2)))
if style or head or tail:
self.write(' [')
@@ -635,7 +639,7 @@ class GVDocBase(BaseDoc, GVDoc):
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):
"""
@@ -643,7 +647,7 @@ class GVDocBase(BaseDoc, GVDoc):
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):
""" Implement GVDocBase.start_subgraph() """
diff --git a/gramps/gen/utils/alive.py b/gramps/gen/utils/alive.py
index 84d8b62a6..240db5930 100644
--- a/gramps/gen/utils/alive.py
+++ b/gramps/gen/utils/alive.py
@@ -142,6 +142,8 @@ class ProbablyAlive:
# person died more than MAX after current year
if death_date.is_valid():
birth_date = death_date.copy_offset_ymd(year=-self.MAX_AGE_PROB_ALIVE)
+ else:
+ birth_date = death_date
explain = _("death date")
if not death_date and birth_date:
diff --git a/gramps/gen/utils/callback.py b/gramps/gen/utils/callback.py
index b2f801cd7..a3f94e444 100644
--- a/gramps/gen/utils/callback.py
+++ b/gramps/gen/utils/callback.py
@@ -324,12 +324,16 @@ class Callback:
return
# 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:
self._warn("Attempt to emit to unknown signal: %s\n"
" from: file: %s\n"
" line: %d\n"
" func: %s\n"
- % ((str(signal_name), ) + inspect.stack()[1][1:4]))
+ % ((str(signal_name), ) + frame_info))
return
# check that the signal is not already being emitted. This prevents
@@ -340,7 +344,7 @@ class Callback:
" from: file: %s\n"
" line: %d\n"
" func: %s\n"
- % ((str(signal_name), ) + inspect.stack()[1][1:4]))
+ % ((str(signal_name), ) + frame_info))
return
try:
@@ -358,7 +362,7 @@ class Callback:
" from: file: %s\n"
" line: %d\n"
" func: %s\n"
- % ((str(signal_name), ) + inspect.stack()[1][1:4]))
+ % ((str(signal_name), ) + frame_info))
return
# type check arguments
@@ -369,7 +373,7 @@ class Callback:
" from: file: %s\n"
" line: %d\n"
" func: %s\n"
- % ((str(signal_name), ) + inspect.stack()[1][1:4]))
+ % ((str(signal_name), ) + frame_info))
return
if len(args) > 0:
@@ -379,7 +383,7 @@ class Callback:
" from: file: %s\n"
" line: %d\n"
" func: %s\n"
- % ((str(signal_name), ) + inspect.stack()[1][1:4]))
+ % ((str(signal_name), ) + frame_info))
return
if arg_types is not None:
@@ -391,7 +395,7 @@ class Callback:
" line: %d\n"
" func: %s\n"
" arg passed was: %s, type of arg passed %s, type should be: %s\n"
- % ((str(signal_name), ) + inspect.stack()[1][1:4] +\
+ % ((str(signal_name), ) + frame_info +\
(args[i], repr(type(args[i])), repr(arg_types[i]))))
return
if signal_name in self.__callback_map:
diff --git a/gramps/gen/utils/docgen/csvtab.py b/gramps/gen/utils/docgen/csvtab.py
index 01822ebf4..7899081cf 100644
--- a/gramps/gen/utils/docgen/csvtab.py
+++ b/gramps/gen/utils/docgen/csvtab.py
@@ -49,7 +49,7 @@ class CSVTab(TabbedDoc):
else:
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')
self.writer = csv.writer(self.f)
diff --git a/gramps/gen/utils/grampslocale.py b/gramps/gen/utils/grampslocale.py
index 77c430894..c5b4a4faf 100644
--- a/gramps/gen/utils/grampslocale.py
+++ b/gramps/gen/utils/grampslocale.py
@@ -526,6 +526,8 @@ class GrampsLocale:
# with locale instead of gettext. Win32 doesn't support bindtextdomain.
if self.localedir:
if not sys.platform == 'win32':
+ # bug12278, _build_popup_ui() under linux and macOS
+ locale.textdomain(self.localedomain)
locale.bindtextdomain(self.localedomain, self.localedir)
else:
self._win_bindtextdomain(self.localedomain.encode('utf-8'),
diff --git a/gramps/grampsapp.py b/gramps/grampsapp.py
index be28cfd28..bc0f36ae9 100644
--- a/gramps/grampsapp.py
+++ b/gramps/grampsapp.py
@@ -127,15 +127,32 @@ if win():
elif not os.path.isdir(HOME_DIR):
os.makedirs(HOME_DIR)
sys.stdout = sys.stderr = open(logfile, "w", encoding='utf-8')
-stderrh = logging.StreamHandler(sys.stderr)
-stderrh.setFormatter(form)
-stderrh.setLevel(logging.DEBUG)
+# macOS sets stderr to /dev/null when running without a terminal,
+# e.g. if Gramps.app is lauched by double-clicking on it in
+# 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
-# everything.
-l = logging.getLogger()
-l.setLevel(logging.WARNING)
-l.addHandler(stderrh)
+ log_file_name = 'gramps-' + str(os.getpid()) + '.log'
+ log_file_path = os.path.join(gettempdir(), log_file_name)
+ log_file_handler = logging.FileHandler(log_file_path, mode='a',
+ encoding='utf-8')
+ 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):
diff --git a/gramps/gui/clipboard.py b/gramps/gui/clipboard.py
index 7d33b95c2..e04f88f41 100644
--- a/gramps/gui/clipboard.py
+++ b/gramps/gui/clipboard.py
@@ -471,27 +471,36 @@ class ClipCitation(ClipHandleWrapper):
def refresh(self):
if self._handle:
- citation = clipdb.get_citation_from_handle(self._handle)
- if citation:
- self._title = citation.get_gramps_id()
- notelist = list(map(clipdb.get_note_from_handle,
- citation.get_note_list()))
- srctxtlist = [note for note in notelist
- if note.get_type() == NoteType.SOURCE_TEXT]
- page = citation.get_page()
- if not page:
- page = _('NA', 'not available')
- text = ""
- if srctxtlist:
- text = " ".join(srctxtlist[0].get().split())
- #String must be unicode for truncation to work for non
- #ascii characters
- text = str(text)
- if len(text) > 60:
- text = text[:60] + "..."
- self._value = _("Volume/Page: %(pag)s -- %(sourcetext)s") % {
- 'pag' : page,
- 'sourcetext' : text}
+ try:
+ citation = clipdb.get_citation_from_handle(self._handle)
+ if citation:
+ self._title = citation.get_gramps_id()
+ notelist = list(map(clipdb.get_note_from_handle,
+ citation.get_note_list()))
+ srctxtlist = [note for note in notelist
+ if note.get_type() == NoteType.SOURCE_TEXT]
+ page = citation.get_page()
+ if not page:
+ page = _('NA', 'not available')
+ text = ""
+ if srctxtlist:
+ text = " ".join(srctxtlist[0].get().split())
+ #String must be unicode for truncation to work for non
+ #ascii characters
+ text = str(text)
+ if len(text) > 60:
+ text = text[:60] + "..."
+ self._value = _("Volume/Page: %(pag)s -- %(sourcetext)s"
+ ) % { '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):
@@ -1281,6 +1290,14 @@ class ClipboardListView:
model.insert_before(node, data)
else:
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:
model.append(data)
diff --git a/gramps/gui/dbloader.py b/gramps/gui/dbloader.py
index 9c62e6d35..ff8b589e7 100644
--- a/gramps/gui/dbloader.py
+++ b/gramps/gui/dbloader.py
@@ -469,7 +469,7 @@ class GrampsImportFileDialog(ManagedWindow):
return True
else:
try:
- f = open(filename,'w')
+ f = open(filename, 'w')
f.close()
os.remove(filename)
except IOError:
@@ -485,7 +485,6 @@ class GrampsImportFileDialog(ManagedWindow):
self.import_info = None
self._begin_progress()
self.uistate.set_sensitive(False)
- self.uistate.viewmanager.enable_menu(False)
try:
#an importer can return an object with info, object.info_text()
@@ -506,7 +505,6 @@ class GrampsImportFileDialog(ManagedWindow):
except Exception:
_LOG.error("Failed to import database.", exc_info=True)
self.uistate.set_sensitive(True)
- self.uistate.viewmanager.enable_menu(True)
self._end_progress()
def build_menu_names(self, obj): # this is meaningless since it's modal
diff --git a/gramps/gui/dbman.py b/gramps/gui/dbman.py
index 4fcecd371..7656affbb 100644
--- a/gramps/gui/dbman.py
+++ b/gramps/gui/dbman.py
@@ -1013,7 +1013,7 @@ class DbManager(CLIDbManager, ManagedWindow):
"""
Handle the reception of drag data
"""
- drag_value = selection.get_data().decode()
+ drag_value = selection.get_data().decode().strip(' \r\n\x00')
fname = None
type = None
title = None
diff --git a/gramps/gui/displaystate.py b/gramps/gui/displaystate.py
index 904b2d102..9be76ba42 100644
--- a/gramps/gui/displaystate.py
+++ b/gramps/gui/displaystate.py
@@ -538,7 +538,10 @@ class DisplayState(Callback):
history.push(handle)
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):
db.connect('long-op-start', self.progress_monitor.add_op)
diff --git a/gramps/gui/editors/editname.py b/gramps/gui/editors/editname.py
index dc81d4864..ccb5c35d2 100644
--- a/gramps/gui/editors/editname.py
+++ b/gramps/gui/editors/editname.py
@@ -366,6 +366,7 @@ class EditName(EditSecondary):
5/ local set, not global set --> set (change local)
6/ local set, global set --> set (set to global if possible)
"""
+ ngm = False # name group mapping setting
closeit = True
surname = self.obj.get_primary_surname().get_surname()
group_as= self.obj.get_group_as()
@@ -388,7 +389,7 @@ class EditName(EditSecondary):
val = q.run()
if val:
#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("")
else :
closeit = False
@@ -421,9 +422,9 @@ class EditName(EditSecondary):
val = q.run()
if val:
if group_as == surname :
- self.db.set_name_group_mapping(surname, None)
+ ngm = None # delay setting until dialog closes
else:
- self.db.set_name_group_mapping(surname, group_as)
+ ngm = group_as # delay setting until dialog closes
self.obj.set_group_as("")
else:
if self.global_group_set :
@@ -455,10 +456,15 @@ class EditName(EditSecondary):
pass
if closeit:
+ db = self.db # close cleanup loses self.db, so save for later
if self.callback:
self.callback(self.obj)
self.callback = None
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):
"""
diff --git a/gramps/gui/editors/editplace.py b/gramps/gui/editors/editplace.py
index ff9c1fd64..d141bca62 100644
--- a/gramps/gui/editors/editplace.py
+++ b/gramps/gui/editors/editplace.py
@@ -186,13 +186,40 @@ class EditPlace(EditPrimary):
self.db.readonly)
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 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 V
+
+ """
try:
- parts = value.index(', ')
+ # Bug 12349, 12374
+ parts = value.split(', ')
if len(parts) == 2:
- longitude = parts[0].strip().replace(',', '.')
- latitude = parts[1].strip().replace(',', '.')
+ latitude = parts[0].strip().replace(',', '.')
+ longitude = parts[1].strip().replace(',', '.')
else:
- longitude, latitude = value.split(',')
+ latitude, longitude = value.split(',')
self.longitude.set_text(longitude)
self.latitude.set_text(latitude)
diff --git a/gramps/gui/editors/editplaceref.py b/gramps/gui/editors/editplaceref.py
index 4aee31212..30c41ffc7 100644
--- a/gramps/gui/editors/editplaceref.py
+++ b/gramps/gui/editors/editplaceref.py
@@ -181,12 +181,13 @@ class EditPlaceRef(EditReference):
def set_latlongitude(self, value):
try:
- parts = value.index(', ')
+ # Bug 12349, 12374
+ parts = value.split(', ')
if len(parts) == 2:
- longitude = parts[0].strip().replace(',', '.')
- latitude = parts[1].strip().replace(',', '.')
+ latitude = parts[0].strip().replace(',', '.')
+ longitude = parts[1].strip().replace(',', '.')
else:
- longitude, latitude = value.split(',')
+ latitude, longitude = value.split(',')
self.longitude.set_text(longitude)
self.latitude.set_text(latitude)
diff --git a/gramps/gui/glade/editplace.glade b/gramps/gui/glade/editplace.glade
index 32e97ac93..685c7965e 100644
--- a/gramps/gui/glade/editplace.glade
+++ b/gramps/gui/glade/editplace.glade
@@ -1,11 +1,13 @@
-
+
-