Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Petr Hejl 2016-09-02 12:16:17 +02:00
commit 639ca24ffb
24 changed files with 76611 additions and 15462 deletions

1822
data/tests/data.gramps Normal file

File diff suppressed because it is too large Load Diff

65712
data/tests/example.gramps Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
"http://gramps-project.org/xml/1.7.1/grampsxml.dtd"> "http://gramps-project.org/xml/1.7.1/grampsxml.dtd">
<database xmlns="http://gramps-project.org/xml/1.7.1/"> <database xmlns="http://gramps-project.org/xml/1.7.1/">
<header> <header>
<created date="2016-06-29" version="5.0.0"/> <created date="2016-08-31" version="5.0.0"/>
<researcher> <researcher>
<resname>Alex Roitman,,,</resname> <resname>Alex Roitman,,,</resname>
</researcher> </researcher>
@ -40537,6 +40537,250 @@
<eventref hlink="_d583a5b8de520210f77" role="Primary"/> <eventref hlink="_d583a5b8de520210f77" role="Primary"/>
<childof hlink="_d583a5b9c2011be735e"/> <childof hlink="_d583a5b9c2011be735e"/>
</person> </person>
<person handle="_d64cc45225909a9f8e4" change="1471261290" id="I2128">
<gender>M</gender>
<name type="Birth Name">
<first>演</first>
<surname>賈</surname>
<title>寧國公</title>
</name>
<parentin hlink="_d64cc45226a0dfb300f"/>
</person>
<person handle="_d64cc4522a25541863a" change="1471261530" id="I2129">
<gender>M</gender>
<name type="Birth Name">
<first>代化</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc45226a0dfb300f"/>
<parentin hlink="_d64cc4522b06749ba4c"/>
</person>
<person handle="_d64cc4522c47c1ef24b" change="1471261530" id="I2130">
<gender>M</gender>
<name type="Birth Name">
<first>敷</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc4522b06749ba4c"/>
</person>
<person handle="_d64cc4522e6663313ec" change="1471261583" id="I2131">
<gender>M</gender>
<name type="Birth Name">
<first>敬</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc4522b06749ba4c"/>
<parentin hlink="_d64cc4522f47c94569c"/>
</person>
<person handle="_d64cc4523087ccd3035" change="1471262021" id="I2132">
<gender>M</gender>
<name type="Birth Name">
<first>珍</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc4522f47c94569c"/>
<parentin hlink="_d64cc4523142408321f"/>
</person>
<person handle="_d64cc45234f188bf949" change="1471261583" id="I2133">
<gender>F</gender>
<name type="Birth Name">
<first>惜春</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc4522f47c94569c"/>
</person>
<person handle="_d64cc45236a783dbbf6" change="1471262021" id="I2134">
<gender>F</gender>
<name type="Birth Name">
<surname>尤</surname>
<suffix>氏</suffix>
</name>
<parentin hlink="_d64cc4523142408321f"/>
</person>
<person handle="_d64cc45238476e9d26a" change="1471262124" id="I2135">
<gender>M</gender>
<name type="Birth Name">
<first>蓉</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc4523142408321f"/>
<parentin hlink="_d64cc45239001cdf947"/>
</person>
<person handle="_d64cc4523a4611260bf" change="1471262124" id="I2136">
<gender>F</gender>
<name type="Birth Name">
<first>可卿</first>
<surname>秦</surname>
</name>
<parentin hlink="_d64cc45239001cdf947"/>
</person>
<person handle="_d64cc4523be0c1791d5" change="1471262210" id="I2137">
<gender>M</gender>
<name type="Birth Name">
<first>源</first>
<surname>賈</surname>
</name>
<parentin hlink="_d64cc4523c966e01266"/>
</person>
<person handle="_d64cc452402720737d5" change="1471262354" id="I2138">
<gender>M</gender>
<name type="Birth Name">
<first>代善</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc4523c966e01266"/>
<parentin hlink="_d64cc452410372bc064"/>
</person>
<person handle="_d64cc4524240e0ea6ff" change="1471262354" id="I2139">
<gender>F</gender>
<name type="Birth Name">
<surname>史</surname>
<suffix>太君</suffix>
<nick>賈母</nick>
</name>
<parentin hlink="_d64cc452410372bc064"/>
</person>
<person handle="_d64cc45243f29eeabeb" change="1471262469" id="I2140">
<gender>M</gender>
<name type="Birth Name">
<first>赦</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc452410372bc064"/>
<parentin hlink="_d64cc45244b4e1a8567"/>
</person>
<person handle="_d64cc45246078d746fa" change="1471262876" id="I2141">
<gender>M</gender>
<name type="Birth Name">
<first>政</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc452410372bc064"/>
<parentin hlink="_d64cc45246e02fe0334"/>
<parentin hlink="_d64cc4524747894466e"/>
</person>
<person handle="_d64cc4524ae5d46fe71" change="1471262377" id="I2142">
<gender>M</gender>
<name type="Birth Name">
<first>敏</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc452410372bc064"/>
</person>
<person handle="_d64cc4524c9414ca537" change="1471262469" id="I2143">
<gender>F</gender>
<name type="Birth Name">
<surname>邢</surname>
<suffix>夫人</suffix>
</name>
<parentin hlink="_d64cc45244b4e1a8567"/>
</person>
<person handle="_d64cc4524e20ba8c5d6" change="1471262627" id="I2144">
<gender>M</gender>
<name type="Birth Name">
<first>璉</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc45244b4e1a8567"/>
<parentin hlink="_d64cc4524ef256e2df7"/>
</person>
<person handle="_d64cc45250328111b9b" change="1471262469" id="I2145">
<gender>F</gender>
<name type="Birth Name">
<first>迎春</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc45244b4e1a8567"/>
</person>
<person handle="_d64cc45251c7930ed38" change="1471262627" id="I2146">
<gender>F</gender>
<name type="Birth Name">
<first>熙鳳</first>
<surname>王</surname>
</name>
<parentin hlink="_d64cc4524ef256e2df7"/>
</person>
<person handle="_d64cc45255a74180535" change="1471262627" id="I2147">
<gender>F</gender>
<name type="Birth Name">
<first>巧姊</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc4524ef256e2df7"/>
</person>
<person handle="_d64cc4525764d82e6ba" change="1471262779" id="I2148">
<gender>F</gender>
<name type="Birth Name">
<surname>王</surname>
<suffix>夫人</suffix>
</name>
<parentin hlink="_d64cc45246e02fe0334"/>
</person>
<person handle="_d64cc45258f454e7dac" change="1471262968" id="I2149">
<gender>M</gender>
<name type="Birth Name">
<first>珠</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc45246e02fe0334"/>
<parentin hlink="_d64cc45259c01f324b4"/>
</person>
<person handle="_d64cc4525af3a331cd9" change="1471262779" id="I2150">
<gender>F</gender>
<name type="Birth Name">
<first>元春</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc45246e02fe0334"/>
</person>
<person handle="_d64cc4525c94ed2c938" change="1471262779" id="I2151">
<gender>M</gender>
<name type="Birth Name">
<first>寶玉</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc45246e02fe0334"/>
</person>
<person handle="_d64cc4526074d046198" change="1471262876" id="I2152">
<gender>F</gender>
<name type="Birth Name">
<surname>趙</surname>
<suffix>姨娘</suffix>
</name>
<parentin hlink="_d64cc4524747894466e"/>
</person>
<person handle="_d64cc452621787a9a8a" change="1471262891" id="I2153">
<gender>F</gender>
<name type="Birth Name">
<first>探春</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc4524747894466e"/>
</person>
<person handle="_d64cc45263b36486ac0" change="1471262876" id="I2154">
<gender>M</gender>
<name type="Birth Name">
<first>環</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc4524747894466e"/>
</person>
<person handle="_d64cc452655308a46f8" change="1471262968" id="I2155">
<gender>F</gender>
<name type="Birth Name">
<first>紈</first>
<surname>李</surname>
</name>
<parentin hlink="_d64cc45259c01f324b4"/>
</person>
<person handle="_d64cc45266e3ae4c5fd" change="1471263007" id="I2156">
<gender>M</gender>
<name type="Birth Name">
<first>蘭</first>
<surname>賈</surname>
</name>
<childof hlink="_d64cc45259c01f324b4"/>
</person>
</people> </people>
<families> <families>
<family handle="_03GKQCH37C1SL9C5B3" change="1185438865" id="F0372"> <family handle="_03GKQCH37C1SL9C5B3" change="1185438865" id="F0372">
@ -47000,6 +47244,81 @@
<mother hlink="_d583a5ba4be3acdd312"/> <mother hlink="_d583a5ba4be3acdd312"/>
<childref hlink="_d583a5b9ced473a7e6a"/> <childref hlink="_d583a5b9ced473a7e6a"/>
</family> </family>
<family handle="_d64cc45226a0dfb300f" change="1471261290" id="F0750">
<rel type="Married"/>
<father hlink="_d64cc45225909a9f8e4"/>
<childref hlink="_d64cc4522a25541863a"/>
</family>
<family handle="_d64cc4522b06749ba4c" change="1471261530" id="F0751">
<rel type="Unknown"/>
<father hlink="_d64cc4522a25541863a"/>
<childref hlink="_d64cc4522c47c1ef24b"/>
<childref hlink="_d64cc4522e6663313ec"/>
</family>
<family handle="_d64cc4522f47c94569c" change="1471261583" id="F0752">
<rel type="Unknown"/>
<father hlink="_d64cc4522e6663313ec"/>
<childref hlink="_d64cc4523087ccd3035"/>
<childref hlink="_d64cc45234f188bf949"/>
</family>
<family handle="_d64cc4523142408321f" change="1471262070" id="F0753">
<rel type="Married"/>
<father hlink="_d64cc4523087ccd3035"/>
<mother hlink="_d64cc45236a783dbbf6"/>
<childref hlink="_d64cc45238476e9d26a"/>
</family>
<family handle="_d64cc45239001cdf947" change="1471262124" id="F0754">
<rel type="Unknown"/>
<father hlink="_d64cc45238476e9d26a"/>
<mother hlink="_d64cc4523a4611260bf"/>
</family>
<family handle="_d64cc4523c966e01266" change="1471262210" id="F0755">
<rel type="Unknown"/>
<father hlink="_d64cc4523be0c1791d5"/>
<childref hlink="_d64cc452402720737d5"/>
</family>
<family handle="_d64cc452410372bc064" change="1471262377" id="F0756">
<rel type="Married"/>
<father hlink="_d64cc452402720737d5"/>
<mother hlink="_d64cc4524240e0ea6ff"/>
<childref hlink="_d64cc45243f29eeabeb"/>
<childref hlink="_d64cc45246078d746fa"/>
<childref hlink="_d64cc4524ae5d46fe71"/>
</family>
<family handle="_d64cc45244b4e1a8567" change="1471262469" id="F0757">
<rel type="Married"/>
<father hlink="_d64cc45243f29eeabeb"/>
<mother hlink="_d64cc4524c9414ca537"/>
<childref hlink="_d64cc4524e20ba8c5d6"/>
<childref hlink="_d64cc45250328111b9b"/>
</family>
<family handle="_d64cc45246e02fe0334" change="1471262779" id="F0759">
<rel type="Married"/>
<father hlink="_d64cc45246078d746fa"/>
<mother hlink="_d64cc4525764d82e6ba"/>
<childref hlink="_d64cc45258f454e7dac"/>
<childref hlink="_d64cc4525af3a331cd9"/>
<childref hlink="_d64cc4525c94ed2c938"/>
</family>
<family handle="_d64cc4524747894466e" change="1471262876" id="F0760">
<rel type="Unknown"/>
<father hlink="_d64cc45246078d746fa"/>
<mother hlink="_d64cc4526074d046198"/>
<childref hlink="_d64cc452621787a9a8a"/>
<childref hlink="_d64cc45263b36486ac0"/>
</family>
<family handle="_d64cc4524ef256e2df7" change="1471262627" id="F0758">
<rel type="Married"/>
<father hlink="_d64cc4524e20ba8c5d6"/>
<mother hlink="_d64cc45251c7930ed38"/>
<childref hlink="_d64cc45255a74180535"/>
</family>
<family handle="_d64cc45259c01f324b4" change="1471263007" id="F0761">
<rel type="Married"/>
<father hlink="_d64cc45258f454e7dac"/>
<mother hlink="_d64cc452655308a46f8"/>
<childref hlink="_d64cc45266e3ae4c5fd"/>
</family>
</families> </families>
<citations> <citations>
<citation handle="_c140d2362f25a92643b" change="1328025930" id="C0000"> <citation handle="_c140d2362f25a92643b" change="1328025930" id="C0000">

View File

@ -36,6 +36,7 @@ import collections
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from ._filterparser import FilterParser from ._filterparser import FilterParser
from ..plug import BasePluginManager from ..plug import BasePluginManager
from ..const import GRAMPS_LOCALE as glocale
PLUGMAN = BasePluginManager.get_instance() PLUGMAN = BasePluginManager.get_instance()
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -129,7 +130,8 @@ class FilterList:
file.write(' <object type="%s">\n' % namespace) file.write(' <object type="%s">\n' % namespace)
filter_list = self.filter_namespaces[namespace] filter_list = self.filter_namespaces[namespace]
sorted_filters = sorted([(filter.get_name(), filter) sorted_filters = sorted([(filter.get_name(), filter)
for filter in filter_list]) for filter in filter_list],
key=lambda x: glocale.sort_key(x[0]))
for (name, the_filter) in sorted_filters: # enable a diff for (name, the_filter) in sorted_filters: # enable a diff
file.write(' <filter name="%s"' % self.fix(name)) file.write(' <filter name="%s"' % self.fix(name))
file.write(' function="%s"' % the_filter.get_logical_op()) file.write(' function="%s"' % the_filter.get_logical_op())

View File

@ -22,10 +22,12 @@
Unittest that tests event-specific filter rules Unittest that tests event-specific filter rules
""" """
import unittest import unittest
import os
from gramps.gen.merge.diff import import_as_dict from gramps.gen.merge.diff import import_as_dict
from gramps.cli.user import User from gramps.cli.user import User
from gramps.gen.filters import GenericFilterFactory from gramps.gen.filters import GenericFilterFactory
from gramps.gen.const import DATA_DIR
from gramps.gen.filters.rules.event import ( from gramps.gen.filters.rules.event import (
AllEvents, HasType, HasIdOf, HasGallery, RegExpIdOf, HasCitation, HasNote, AllEvents, HasType, HasIdOf, HasGallery, RegExpIdOf, HasCitation, HasNote,
@ -33,6 +35,8 @@ from gramps.gen.filters.rules.event import (
MatchesSourceConfidence, HasAttribute, HasData, ChangedSince, HasTag, MatchesSourceConfidence, HasAttribute, HasData, ChangedSince, HasTag,
HasDayOfWeek) HasDayOfWeek)
TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
EXAMPLE = os.path.join(TEST_DIR, "example.gramps")
GenericEventFilter = GenericFilterFactory('Event') GenericEventFilter = GenericFilterFactory('Event')
class BaseTest(unittest.TestCase): class BaseTest(unittest.TestCase):
@ -45,7 +49,7 @@ class BaseTest(unittest.TestCase):
""" """
Import example database. Import example database.
""" """
cls.db = import_as_dict("example/gramps/example.gramps", User()) cls.db = import_as_dict(EXAMPLE, User())
def filter_with_rule(self, rule): def filter_with_rule(self, rule):
""" """

View File

@ -22,10 +22,12 @@
Unittest that tests family-specific filter rules Unittest that tests family-specific filter rules
""" """
import unittest import unittest
import os
from gramps.gen.merge.diff import import_as_dict from gramps.gen.merge.diff import import_as_dict
from gramps.cli.user import User from gramps.cli.user import User
from gramps.gen.filters import GenericFilterFactory from gramps.gen.filters import GenericFilterFactory
from gramps.gen.const import DATA_DIR
from gramps.gen.filters.rules.family import ( from gramps.gen.filters.rules.family import (
AllFamilies, HasRelType, HasGallery, HasIdOf, HasLDS, HasNote, RegExpIdOf, AllFamilies, HasRelType, HasGallery, HasIdOf, HasLDS, HasNote, RegExpIdOf,
@ -35,6 +37,8 @@ from gramps.gen.filters.rules.family import (
MotherHasIdOf, ChildHasNameOf, ChildHasIdOf, ChangedSince, HasTag, MotherHasIdOf, ChildHasNameOf, ChildHasIdOf, ChangedSince, HasTag,
HasTwins, IsAncestorOf, IsDescendantOf) HasTwins, IsAncestorOf, IsDescendantOf)
TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
EXAMPLE = os.path.join(TEST_DIR, "example.gramps")
GenericFamilyFilter = GenericFilterFactory('Family') GenericFamilyFilter = GenericFilterFactory('Family')
class BaseTest(unittest.TestCase): class BaseTest(unittest.TestCase):
@ -47,7 +51,7 @@ class BaseTest(unittest.TestCase):
""" """
Import example database. Import example database.
""" """
cls.db = import_as_dict("example/gramps/example.gramps", User()) cls.db = import_as_dict(EXAMPLE, User())
def filter_with_rule(self, rule): def filter_with_rule(self, rule):
""" """

View File

@ -22,10 +22,12 @@
Unittest that tests media-specific filter rules Unittest that tests media-specific filter rules
""" """
import unittest import unittest
import os
from gramps.gen.merge.diff import import_as_dict from gramps.gen.merge.diff import import_as_dict
from gramps.cli.user import User from gramps.cli.user import User
from gramps.gen.filters import GenericFilterFactory from gramps.gen.filters import GenericFilterFactory
from gramps.gen.const import DATA_DIR
from gramps.gen.filters.rules.media import ( from gramps.gen.filters.rules.media import (
AllMedia, HasIdOf, RegExpIdOf, HasCitation, HasNoteRegexp, AllMedia, HasIdOf, RegExpIdOf, HasCitation, HasNoteRegexp,
@ -33,6 +35,8 @@ from gramps.gen.filters.rules.media import (
HasSourceOf, MediaPrivate, MatchesSourceConfidence, HasMedia, HasSourceOf, MediaPrivate, MatchesSourceConfidence, HasMedia,
HasAttribute, ChangedSince, HasTag) HasAttribute, ChangedSince, HasTag)
TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
EXAMPLE = os.path.join(TEST_DIR, "example.gramps")
GenericMediaFilter = GenericFilterFactory('Media') GenericMediaFilter = GenericFilterFactory('Media')
class BaseTest(unittest.TestCase): class BaseTest(unittest.TestCase):
@ -45,7 +49,7 @@ class BaseTest(unittest.TestCase):
""" """
Import example database. Import example database.
""" """
cls.db = import_as_dict("example/gramps/example.gramps", User()) cls.db = import_as_dict(EXAMPLE, User())
def filter_with_rule(self, rule): def filter_with_rule(self, rule):
""" """

View File

@ -22,15 +22,19 @@
Unittest that tests note-specific filter rules Unittest that tests note-specific filter rules
""" """
import unittest import unittest
import os
from gramps.gen.merge.diff import import_as_dict from gramps.gen.merge.diff import import_as_dict
from gramps.cli.user import User from gramps.cli.user import User
from gramps.gen.filters import GenericFilterFactory from gramps.gen.filters import GenericFilterFactory
from gramps.gen.const import DATA_DIR
from gramps.gen.filters.rules.note import ( from gramps.gen.filters.rules.note import (
AllNotes, HasIdOf, RegExpIdOf, HasNote, MatchesRegexpOf, AllNotes, HasIdOf, RegExpIdOf, HasNote, MatchesRegexpOf,
HasReferenceCountOf, NotePrivate, ChangedSince, HasTag, HasType) HasReferenceCountOf, NotePrivate, ChangedSince, HasTag, HasType)
TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
EXAMPLE = os.path.join(TEST_DIR, "example.gramps")
GenericNoteFilter = GenericFilterFactory('Note') GenericNoteFilter = GenericFilterFactory('Note')
class BaseTest(unittest.TestCase): class BaseTest(unittest.TestCase):
@ -43,7 +47,7 @@ class BaseTest(unittest.TestCase):
""" """
Import example database. Import example database.
""" """
cls.db = import_as_dict("example/gramps/example.gramps", User()) cls.db = import_as_dict(EXAMPLE, User())
def filter_with_rule(self, rule): def filter_with_rule(self, rule):
""" """

View File

@ -22,10 +22,12 @@
Unittest that tests person-specific filter rules Unittest that tests person-specific filter rules
""" """
import unittest import unittest
import os
from gramps.gen.merge.diff import import_as_dict from gramps.gen.merge.diff import import_as_dict
from gramps.cli.user import User from gramps.cli.user import User
from gramps.gen.filters import GenericFilter from gramps.gen.filters import GenericFilter
from gramps.gen.const import DATA_DIR
from gramps.gen.filters.rules.person import ( from gramps.gen.filters.rules.person import (
Disconnected, Everyone, FamilyWithIncompleteEvent, HasAlternateName, Disconnected, Everyone, FamilyWithIncompleteEvent, HasAlternateName,
@ -36,6 +38,9 @@ from gramps.gen.filters.rules.person import (
NoDeathdate, PeoplePrivate, PeoplePublic, PersonWithIncompleteEvent, NoDeathdate, PeoplePrivate, PeoplePublic, PersonWithIncompleteEvent,
RelationshipPathBetweenBookmarks) RelationshipPathBetweenBookmarks)
TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
EXAMPLE = os.path.join(TEST_DIR, "example.gramps")
class BaseTest(unittest.TestCase): class BaseTest(unittest.TestCase):
""" """
Person rule tests. Person rule tests.
@ -46,7 +51,7 @@ class BaseTest(unittest.TestCase):
""" """
Import example database. Import example database.
""" """
cls.db = import_as_dict("example/gramps/example.gramps", User()) cls.db = import_as_dict(EXAMPLE, User())
def filter_with_rule(self, rule): def filter_with_rule(self, rule):
""" """

View File

@ -22,10 +22,12 @@
Unittest that tests place-specific filter rules Unittest that tests place-specific filter rules
""" """
import unittest import unittest
import os
from gramps.gen.merge.diff import import_as_dict from gramps.gen.merge.diff import import_as_dict
from gramps.cli.user import User from gramps.cli.user import User
from gramps.gen.filters import GenericFilterFactory from gramps.gen.filters import GenericFilterFactory
from gramps.gen.const import DATA_DIR
from gramps.gen.filters.rules.place import ( from gramps.gen.filters.rules.place import (
AllPlaces, HasCitation, HasGallery, HasIdOf, RegExpIdOf, HasNote, AllPlaces, HasCitation, HasGallery, HasIdOf, RegExpIdOf, HasNote,
@ -33,6 +35,8 @@ from gramps.gen.filters.rules.place import (
PlacePrivate, MatchesSourceConfidence, HasData, HasNoLatOrLon, PlacePrivate, MatchesSourceConfidence, HasData, HasNoLatOrLon,
InLatLonNeighborhood, ChangedSince, HasTag, HasTitle, IsEnclosedBy) InLatLonNeighborhood, ChangedSince, HasTag, HasTitle, IsEnclosedBy)
TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
EXAMPLE = os.path.join(TEST_DIR, "example.gramps")
GenericPlaceFilter = GenericFilterFactory('Place') GenericPlaceFilter = GenericFilterFactory('Place')
class BaseTest(unittest.TestCase): class BaseTest(unittest.TestCase):
@ -45,7 +49,7 @@ class BaseTest(unittest.TestCase):
""" """
Import example database. Import example database.
""" """
cls.db = import_as_dict("example/gramps/example.gramps", User()) cls.db = import_as_dict(EXAMPLE, User())
def filter_with_rule(self, rule): def filter_with_rule(self, rule):
""" """

View File

@ -22,15 +22,19 @@
Unittest that tests repository-specific filter rules Unittest that tests repository-specific filter rules
""" """
import unittest import unittest
import os
from gramps.gen.merge.diff import import_as_dict from gramps.gen.merge.diff import import_as_dict
from gramps.cli.user import User from gramps.cli.user import User
from gramps.gen.filters import GenericFilterFactory from gramps.gen.filters import GenericFilterFactory
from gramps.gen.const import DATA_DIR
from gramps.gen.filters.rules.repository import ( from gramps.gen.filters.rules.repository import (
AllRepos, HasIdOf, RegExpIdOf, HasNoteRegexp, HasReferenceCountOf, AllRepos, HasIdOf, RegExpIdOf, HasNoteRegexp, HasReferenceCountOf,
RepoPrivate, ChangedSince, MatchesNameSubstringOf, HasTag) RepoPrivate, ChangedSince, MatchesNameSubstringOf, HasTag)
TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
EXAMPLE = os.path.join(TEST_DIR, "example.gramps")
GenericRepositoryFilter = GenericFilterFactory('Repository') GenericRepositoryFilter = GenericFilterFactory('Repository')
class BaseTest(unittest.TestCase): class BaseTest(unittest.TestCase):
@ -43,7 +47,7 @@ class BaseTest(unittest.TestCase):
""" """
Import example database. Import example database.
""" """
cls.db = import_as_dict("example/gramps/example.gramps", User()) cls.db = import_as_dict(EXAMPLE, User())
def filter_with_rule(self, rule): def filter_with_rule(self, rule):
""" """

View File

@ -21,6 +21,7 @@
""" Unittest for to_struct, from_struct """ """ Unittest for to_struct, from_struct """
import unittest import unittest
import os
from .. import (Person, Family, Event, Source, Place, Citation, from .. import (Person, Family, Event, Source, Place, Citation,
Repository, Media, Note, Tag) Repository, Media, Note, Tag)
@ -28,6 +29,10 @@ from gramps.gen.lib.struct import Struct
from gramps.gen.merge.diff import import_as_dict from gramps.gen.merge.diff import import_as_dict
from gramps.cli.user import User from gramps.cli.user import User
from gramps.gen.merge.diff import * from gramps.gen.merge.diff import *
from gramps.gen.const import DATA_DIR
TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
EXAMPLE = os.path.join(TEST_DIR, "example.gramps")
class BaseCheck: class BaseCheck:
def test_from_struct(self): def test_from_struct(self):
@ -108,7 +113,7 @@ def generate_case(obj):
#name = "test_create_%s_%s" % (obj.__class__.__name__, obj.handle) #name = "test_create_%s_%s" % (obj.__class__.__name__, obj.handle)
#setattr(DatabaseCheck, name, test2) #setattr(DatabaseCheck, name, test2)
db = import_as_dict("example/gramps/example.gramps", User()) db = import_as_dict(EXAMPLE, User())
for table in db.get_table_func(): for table in db.get_table_func():
for handle in db.get_table_func(table,"handles_func")(): for handle in db.get_table_func(table,"handles_func")():
obj = db.get_table_func(table,"handle_func")(handle) obj = db.get_table_func(table,"handle_func")(handle)

View File

@ -49,10 +49,6 @@ class MockEditReference(EditReference):
self.window = MockWindow() self.window = MockWindow()
super().__init__(dbstate, uistate, track, source, source_ref, update) super().__init__(dbstate, uistate, track, source, source_ref, update)
example = os.path.abspath(
os.path.join(os.path.dirname(os.path.abspath(__file__)),
"../../../..",
"example/gramps/example.gramps"))
class TestEditReference(unittest.TestCase): class TestEditReference(unittest.TestCase):

View File

@ -24,10 +24,10 @@ import os
from gramps.test.test_util import Gramps from gramps.test.test_util import Gramps
from gramps.gen.db import open_database from gramps.gen.db import open_database
from gramps.gen.lib import * from gramps.gen.lib import *
from gramps.gen.const import DATA_DIR
ddir = os.path.dirname(__file__) TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
example = os.path.join(ddir, "..", "..", "..", "..", example = os.path.join(TEST_DIR, "data.gramps")
"example", "gramps", "data.gramps")
class BSDDB: class BSDDB:
NAME = "Example BSDDB Test" NAME = "Example BSDDB Test"

View File

@ -174,7 +174,7 @@ class _PersonWidgetBase(Gtk.DrawingArea):
class PersonBoxWidgetCairo(_PersonWidgetBase): class PersonBoxWidgetCairo(_PersonWidgetBase):
"""Draw person box using cairo library""" """Draw person box using cairo library"""
def __init__(self, view, format_helper, dbstate, person, alive, maxlines, def __init__(self, view, format_helper, dbstate, person, alive, maxlines,
image=None): image=None, tags=False):
_PersonWidgetBase.__init__(self, view, format_helper, person) _PersonWidgetBase.__init__(self, view, format_helper, person)
self.set_size_request(120, 25) self.set_size_request(120, 25)
# Required for tooltip and mouse-over # Required for tooltip and mouse-over
@ -193,6 +193,13 @@ class PersonBoxWidgetCairo(_PersonWidgetBase):
else: else:
gender = None gender = None
self.bgcolor, self.bordercolor = color_graph_box(alive, gender) self.bgcolor, self.bordercolor = color_graph_box(alive, gender)
if tags and person:
for tag_handle in person.get_tag_list():
# For the complete tag, don't modify the default color
# which is black (#000000000000)
tag = dbstate.db.get_tag_from_handle(tag_handle)
if tag.get_color() != "#000000000000": # only if the color
self.bgcolor = tag.get_color() # is not black
self.bgcolor = hex_to_rgb_float(self.bgcolor) self.bgcolor = hex_to_rgb_float(self.bgcolor)
self.bordercolor = hex_to_rgb_float(self.bordercolor) self.bordercolor = hex_to_rgb_float(self.bordercolor)
@ -504,6 +511,7 @@ class PedigreeView(NavigationView):
('interface.pedview-layout', 0), ('interface.pedview-layout', 0),
('interface.pedview-show-images', True), ('interface.pedview-show-images', True),
('interface.pedview-show-marriage', True), ('interface.pedview-show-marriage', True),
('interface.pedview-show-tags', False),
('interface.pedview-tree-direction', 2), ('interface.pedview-tree-direction', 2),
('interface.pedview-show-unknown-people', True), ('interface.pedview-show-unknown-people', True),
) )
@ -549,6 +557,8 @@ class PedigreeView(NavigationView):
# Hide marriage data by default # Hide marriage data by default
self.show_marriage_data = self._config.get( self.show_marriage_data = self._config.get(
'interface.pedview-show-marriage') 'interface.pedview-show-marriage')
# Show person with tag color
self.show_tag_color = self._config.get('interface.pedview-show-tags')
# Tree draw direction # Tree draw direction
self.tree_direction = self._config.get('interface.pedview-tree-direction') self.tree_direction = self._config.get('interface.pedview-tree-direction')
self.cb_change_scroll_direction(None, self.tree_direction < 2) self.cb_change_scroll_direction(None, self.tree_direction < 2)
@ -929,7 +939,8 @@ class PedigreeView(NavigationView):
# No person -> show empty box # No person -> show empty box
# #
pbw = PersonBoxWidgetCairo(self, self.format_helper, pbw = PersonBoxWidgetCairo(self, self.format_helper,
self.dbstate, None, False, 0, None) self.dbstate, None, False, 0, None,
tags=self.show_tag_color)
if i > 0 and lst[((i+1) // 2) - 1]: if i > 0 and lst[((i+1) // 2) - 1]:
fam_h = None fam_h = None
@ -952,7 +963,8 @@ class PedigreeView(NavigationView):
image = True image = True
pbw = PersonBoxWidgetCairo(self, self.format_helper, pbw = PersonBoxWidgetCairo(self, self.format_helper,
self.dbstate, lst[i][0], lst[i][3], height, image) self.dbstate, lst[i][0], lst[i][3], height, image,
tags=self.show_tag_color)
lst[i][4] = pbw lst[i][4] = pbw
if height < 7: if height < 7:
pbw.set_tooltip_text(self.format_helper.format_person( pbw.set_tooltip_text(self.format_helper.format_person(
@ -1917,6 +1929,16 @@ class PedigreeView(NavigationView):
self.menu.popup(None, None, None, None, 0, event.time) self.menu.popup(None, None, None, None, 0, event.time)
return 1 return 1
def cb_update_show_tags(self, client, cnxn_id, entry, data):
"""
Called when the configuration menu changes the tags setting.
"""
if entry == 'True':
self.show_tag_color = True
else:
self.show_tag_color = False
self.rebuild_trees(self.get_active())
def cb_update_show_images(self, client, cnxn_id, entry, data): def cb_update_show_images(self, client, cnxn_id, entry, data):
""" """
Called when the configuration menu changes the images setting. Called when the configuration menu changes the images setting.
@ -1989,6 +2011,8 @@ class PedigreeView(NavigationView):
self.cb_update_show_images) self.cb_update_show_images)
self._config.connect('interface.pedview-show-marriage', self._config.connect('interface.pedview-show-marriage',
self.cb_update_show_marriage) self.cb_update_show_marriage)
self._config.connect('interface.pedview-show-tags',
self.cb_update_show_tags)
self._config.connect('interface.pedview-show-unknown-people', self._config.connect('interface.pedview-show-unknown-people',
self.cb_update_show_unknown_people) self.cb_update_show_unknown_people)
self._config.connect('interface.pedview-tree-direction', self._config.connect('interface.pedview-tree-direction',
@ -2023,6 +2047,9 @@ class PedigreeView(NavigationView):
configdialog.add_checkbox(grid, configdialog.add_checkbox(grid,
_('Show unknown people'), _('Show unknown people'),
2, 'interface.pedview-show-unknown-people') 2, 'interface.pedview-show-unknown-people')
configdialog.add_checkbox(grid,
_('Show tags'),
3, 'interface.pedview-show-tags')
configdialog.add_combo(grid, configdialog.add_combo(grid,
_('Tree style'), _('Tree style'),
4, 'interface.pedview-layout', 4, 'interface.pedview-layout',

View File

@ -1711,6 +1711,8 @@ class BasePage:
else: else:
msg += _(' on %(date)s') % {'date' : _dd.display(Today())} msg += _(' on %(date)s') % {'date' : _dd.display(Today())}
origin1 = self.report.filter.get_name()
filt_number = self.report.options['filter']
# optional "link-home" feature; see bug report #2736 # optional "link-home" feature; see bug report #2736
if self.report.options['linkhome']: if self.report.options['linkhome']:
center_person = self.r_db.get_person_from_gramps_id( center_person = self.r_db.get_person_from_gramps_id(
@ -1721,12 +1723,20 @@ class BasePage:
center_person.handle, "ppl", self.uplink) center_person.handle, "ppl", self.uplink)
person_name = self.get_name(center_person) person_name = self.get_name(center_person)
subject_url = '<a href="' + center_person_url + '">' if filt_number > 0 and filt_number < 5:
subject_url += person_name + '</a>' subject_url = '<a href="' + center_person_url + '">'
subject_url += origin1 + '</a>'
else:
subject_url = origin1
msg += _( msg += _(
'%(http_break)sCreated for %(subject_url)s') % { '%(http_break)sCreated for %(subject_url)s') % {
'http_break' : '<br />', 'http_break' : '<br />',
'subject_url' : subject_url} 'subject_url' : subject_url}
else:
msg += _(
'%(http_break)sCreated for %(subject_url)s') % {
'http_break' : '<br />',
'subject_url' : origin1}
# creation author # creation author
footer += Html("p", msg, id='createdate') footer += Html("p", msg, id='createdate')
@ -1893,6 +1903,7 @@ class BasePage:
('download', _("Download"), self.report.inc_download), ('download', _("Download"), self.report.inc_download),
("addressbook", _("Address Book"), self.report.inc_addressbook), ("addressbook", _("Address Book"), self.report.inc_addressbook),
('contact', _("Contact"), self.report.use_contact), ('contact', _("Contact"), self.report.use_contact),
("stats", _("Statistics"), True),
(self.target_cal_uri, _("Web Calendar"), self.usecal) (self.target_cal_uri, _("Web Calendar"), self.usecal)
] ]
@ -1971,6 +1982,13 @@ class BasePage:
index += 1 index += 1
cols += 1 cols += 1
if rows == num_rows - 1:
prv = Html('<a onclick="history.go(-1);">%s</a>' %
_("Previous"))
nxt = Html('<a onclick="history.go(+1);">%s</a>' %
_("Next"))
unordered.extend(Html("li", prv, inline=True))
unordered.extend(Html("li", nxt, inline=True))
container += unordered container += unordered
navigation += container navigation += container
return navigation return navigation
@ -8013,6 +8031,180 @@ class AddressBookPage(BasePage):
# and close the file # and close the file
self.xhtml_writer(addressbookpage, output_file, sio, 0) self.xhtml_writer(addressbookpage, output_file, sio, 0)
class StatisticsPage(BasePage):
"""
Create one page for statistics
"""
def __init__(self, report, title, step):
"""
@param: report -- The instance of the main report class
for this report
@param: title -- Is the title of the web page
"""
import posixpath
BasePage.__init__(self, report, title)
self.bibli = Bibliography()
self.uplink = False
self.report = report
# set the file name and open file
output_file, sio = self.report.create_file("stats")
addressbookpage, head, body = self.write_header(_("Statistics"))
(males,
females,
unknown) = self.get_gender(report.database.iter_person_handles())
mobjects = report.database.get_number_of_media()
npersons = report.database.get_number_of_people()
nfamilies = report.database.get_number_of_families()
nsurnames = len(set(report.database.surname_list))
notfound = []
total_media = 0
mbytes = "0"
bytes = 0
for media in report.database.iter_media():
total_media += 1
fullname = media_path_full(report.database, media.get_path())
try:
bytes += posixpath.getsize(fullname)
length = len(str(bytes))
if bytes <= 999999:
mbytes = _("less than 1")
else:
mbytes = str(bytes)[:(length-6)]
except OSError:
notfound.append(media.get_path())
with Html("div", class_="content", id='EventDetail') as section:
section += Html("h3", _("Database overview"), inline=True)
body += section
with Html("div", class_="content", id='subsection narrative') as sec11:
sec11 += Html("h4", _("Individuals"), inline=True)
body += sec11
with Html("div", class_="content", id='subsection narrative') as sec1:
sec1 += Html("br", _("Number of individuals") + ":" +
"%d" % npersons, inline=True)
sec1 += Html("br", _("Males") + ":" +
"%d" % males, inline=True)
sec1 += Html("br", _("Females") + ":" +
"%d" % females, inline=True)
sec1 += Html("br", _("Individuals with unknown gender") + ":" +
"%d" % unknown, inline=True)
body += sec1
with Html("div", class_="content", id='subsection narrative') as sec2:
sec2 += Html("h4", _("Family Information"), inline=True)
sec2 += Html("br", _("Number of families") + ":" +
"%d" % nfamilies, inline=True)
sec2 += Html("br", _("Unique surnames") + ":" +
"%d" % nsurnames, inline=True)
body += sec2
with Html("div", class_="content", id='subsection narrative') as sec3:
sec3 += Html("h4", _("Media Objects"), inline=True)
sec3 += Html("br", _("Total number of media object references") +
":" + "%d" % total_media, inline=True)
sec3 += Html("br", _("Number of unique media objects") +
":" + "%d" % mobjects, inline=True)
sec3 += Html("br", _("Total size of media objects") +
":" + "%8s %s" % (mbytes, _("Megabyte|MB")),
inline=True)
sec3 += Html("br", _("Missing Media Objects") +
":" + "%d" % len(notfound), inline=True)
body += sec3
with Html("div", class_="content", id='subsection narrative') as sec4:
sec4 += Html("h4", _("Miscellaneous"), inline=True)
sec4 += Html("br", _("Number of events") +
":" + "%d" % report.database.get_number_of_events(),
inline=True)
sec4 += Html("br", _("Number of places") +
":" + "%d" % report.database.get_number_of_places(),
inline=True)
nsources = report.database.get_number_of_sources()
sec4 += Html("br", _("Number of sources") +
":" + "%d" % nsources,
inline=True)
ncitations = report.database.get_number_of_citations()
sec4 += Html("br", _("Number of citations") +
":" + "%d" % ncitations,
inline=True)
nrepo = report.database.get_number_of_repositories()
sec4 += Html("br", _("Number of repositories") +
":" + "%d" % nrepo,
inline=True)
body += sec4
(males,
females,
unknown) = self.get_gender(self.report.bkref_dict[Person].keys())
center_person = self.report.database.get_person_from_gramps_id(
self.report.options['pid'])
origin = " :<br/>" + report.filter.get_name()
with Html("div", class_="content", id='EventDetail') as section:
section += Html("h3", _("Narrative web content report for") +
origin,
inline=True)
body += section
with Html("div", class_="content", id='subsection narrative') as sec5:
sec5 += Html("h4", _("Individuals"), inline=True)
sec5 += Html("br", _("Number of individuals") + ":" +
"%d" % len(self.report.bkref_dict[Person]),
inline=True)
sec5 += Html("br", _("Males") + ":" +
"%d" % males, inline=True)
sec5 += Html("br", _("Females") + ":" +
"%d" % females, inline=True)
sec5 += Html("br", _("Individuals with unknown gender") + ":" +
"%d" % unknown, inline=True)
body += sec5
with Html("div", class_="content", id='subsection narrative') as sec6:
sec6 += Html("h4", _("Family Information"), inline=True)
sec6 += Html("br", _("Number of families") + ":" +
"%d" % len(self.report.bkref_dict[Family]),
inline=True)
body += sec6
with Html("div", class_="content", id='subsection narrative') as sec7:
sec7 += Html("h4", _("Miscellaneous"), inline=True)
sec7 += Html("br", _("Number of events") +
":" + "%d" % len(self.report.bkref_dict[Event]),
inline=True)
sec7 += Html("br", _("Number of places") +
":" + "%d" % len(self.report.bkref_dict[Place]),
inline=True)
sec7 += Html("br", _("Number of sources") +
":" + "%d" % len(self.report.bkref_dict[Source]),
inline=True)
sec7 += Html("br", _("Number of citations") +
":" + "%d" % len(self.report.bkref_dict[Citation]),
inline=True)
sec7 += Html("br", _("Number of repositories") +
":" + "%d" % len(self.report.bkref_dict[Repository]),
inline=True)
body += sec7
# add fullclear for proper styling
# and footer section to page
footer = self.write_footer(None)
body += (FULLCLEAR, footer)
# send page out for processing
# and close the file
self.xhtml_writer(addressbookpage, output_file, sio, 0)
def get_gender(self, person_list):
males = 0
females = 0
unknown = 0
for person_handle in person_list:
person = self.report.database.get_person_from_handle(person_handle)
gender = person.get_gender()
if gender == Person.MALE:
males += 1
elif gender == Person.FEMALE:
females += 1
else:
unknown += 1
return (males, females, unknown)
class NavWebReport(Report): class NavWebReport(Report):
""" """
Create WebReport object that produces the report. Create WebReport object that produces the report.
@ -8314,6 +8506,9 @@ class NavWebReport(Report):
# build classes SourceListPage and SourcePage # build classes SourceListPage and SourcePage
self.tab["Source"].display_pages(self.title) self.tab["Source"].display_pages(self.title)
# build classes StatisticsPage
self.statistics_preview_page(self.title)
# copy all of the neccessary files # copy all of the neccessary files
self.copy_narrated_files() self.copy_narrated_files()
@ -8971,6 +9166,15 @@ class NavWebReport(Report):
len(self.obj_dict[Media])) as step: len(self.obj_dict[Media])) as step:
ThumbnailPreviewPage(self, self.title, step) ThumbnailPreviewPage(self, self.title, step)
def statistics_preview_page(self, title):
"""
creates the statistics preview page
"""
with self.user.progress(_("Narrated Web Site Report"),
_("Creating statistics page..."),
len(self.obj_dict[Media])) as step:
StatisticsPage(self, title, step)
def addressbook_pages(self, ind_list): def addressbook_pages(self, ind_list):
""" """
Create a webpage with a list of address availability for each person Create a webpage with a list of address availability for each person

3901
po/cs.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

18179
po/pt_BR.po

File diff suppressed because it is too large Load Diff