Merge branch 'master' of github.com:gramps-project/gramps

This commit is contained in:
erikdrgm 2017-02-11 11:11:52 +01:00
commit 30cd5f885b
41 changed files with 11655 additions and 10443 deletions

View File

@ -11,33 +11,6 @@ GrampsDbBase
:undoc-members:
:show-inheritance:
GrampsDbRead
====================================
.. automodule:: gramps.gen.db.read
:members:
:show-inheritance:
GrampsDbWrite
====================================
.. automodule:: gramps.gen.db.write
:members:
:undoc-members:
:show-inheritance:
GrampsCursor
====================================
.. automodule:: gramps.gen.db.cursor
:members:
:undoc-members:
:show-inheritance:
BSDDBtxn
====================================
.. automodule:: gramps.gen.db.bsddbtxn
:members:
:undoc-members:
:show-inheritance:
GrampsDbTxn
====================================
.. automodule:: gramps.gen.db.txn
@ -45,13 +18,6 @@ GrampsDbTxn
:undoc-members:
:show-inheritance:
GrampsDbUndo
====================================
.. automodule:: gramps.gen.db.undoredo
:members:
:undoc-members:
:show-inheritance:
DbConst
====================================
.. automodule:: gramps.gen.db.dbconst
@ -64,15 +30,74 @@ GrampsDbException
:undoc-members:
:show-inheritance:
Upgrade utilities
GrampsDbUndo
====================================
.. automodule:: gramps.gen.db.upgrade
:members:
:undoc-members:
Backup
====================================
.. automodule:: gramps.gen.db.backup
.. automodule:: gramps.gen.db.undoredo
:members:
:undoc-members:
:show-inheritance:
Generic
====================================
.. automodule:: gramps.gen.db.generic
:members:
:undoc-members:
:show-inheritance:
DummyDb
====================================
.. automodule:: gramps.plugins.db.dummydb
:members:
:undoc-members:
:show-inheritance:
#####################################
The :mod:`gramps.gen.db` bsddb Module
#####################################
.. automodule:: gramps.plugins.db.bsddb
GrampsDbRead
====================================
.. automodule:: gramps.plugins.db.bsddb.read
:members:
:show-inheritance:
GrampsDbWrite
====================================
.. automodule:: gramps.plugins.db.bsddb.write
:members:
:undoc-members:
:show-inheritance:
GrampsCursor
====================================
.. automodule:: gramps.plugins.db.bsddb.cursor
:members:
:undoc-members:
:show-inheritance:
BSDDBtxn
====================================
.. automodule:: gramps.plugins.db.bsddb.bsddbtxn
:members:
:undoc-members:
:show-inheritance:
#####################################
The :mod:`gramps.gen.db` dbapi Module
#####################################
.. automodule:: gramps.plugins.db.dbapi
DBAPI
====================================
.. automodule:: gramps.plugins.db.dbapi.dbapi
:members:
:show-inheritance:
Sqlite
====================================
.. automodule:: gramps.plugins.db.dbapi.sqlite
:members:
:show-inheritance:

View File

@ -10,3 +10,10 @@ Name
:members:
:undoc-members:
:show-inheritance:
Place
====================================
.. automodule:: gramps.gen.display.place
:members:
:undoc-members:
:show-inheritance:

View File

@ -53,14 +53,14 @@ CitationBase
:members:
:undoc-members:
:show-inheritance:
IndirectCitationBase
====================================
.. autoclass:: IndirectCitationBase
:members:
:undoc-members:
:show-inheritance:
DateBase
====================================
.. automodule:: gramps.gen.lib.datebase
@ -68,7 +68,7 @@ DateBase
:members:
:undoc-members:
:show-inheritance:
LdsOrdBase
====================================
.. automodule:: gramps.gen.lib.ldsordbase
@ -76,7 +76,7 @@ LdsOrdBase
:members:
:undoc-members:
:show-inheritance:
LocationBase
====================================
.. automodule:: gramps.gen.lib.locationbase
@ -84,7 +84,7 @@ LocationBase
:members:
:undoc-members:
:show-inheritance:
MediaBase
====================================
.. automodule:: gramps.gen.lib.mediabase
@ -116,7 +116,7 @@ PrivacyBase
:members:
:undoc-members:
:show-inheritance:
RefBase
====================================
.. automodule:: gramps.gen.lib.refbase
@ -132,7 +132,7 @@ SurnameBase
:members:
:undoc-members:
:show-inheritance:
TagBase
====================================
.. automodule:: gramps.gen.lib.tagbase
@ -216,7 +216,7 @@ Citation
:undoc-members:
:show-inheritance:
Media Object
Media
====================================
.. automodule:: gramps.gen.lib.media
.. autoclass:: Media
@ -366,7 +366,7 @@ RepoRef
:members:
:undoc-members:
:show-inheritance:
*****************************
Table objects
*****************************
@ -487,7 +487,7 @@ EventType
:members:
:undoc-members:
:show-inheritance:
EventRoleType
==============
.. automodule:: gramps.gen.lib.eventroletype
@ -543,7 +543,7 @@ RepositoryType
:members:
:undoc-members:
:show-inheritance:
SourceMediaType
================
.. automodule:: gramps.gen.lib.srcmediatype
@ -557,7 +557,7 @@ StyledTextTagType
:members:
:undoc-members:
:show-inheritance:
UrlType
========
.. automodule:: gramps.gen.lib.urltype

View File

@ -1,4 +1,4 @@
#! /usr/bin/env python
#! /usr/bin/env python3
#
# update_po - a gramps tool to update translations
#
@ -102,8 +102,9 @@ def build():
# testing stage
os.system('''%(program)s -b html . _build/html''' % {'program': sphinxCmd})
os.system('''%(program)s -b changes . _build/changes''' % {'program': sphinxCmd})
os.system('''%(program)s -b linkcheck . _build/linkcheck''' % {'program': sphinxCmd})
#os.system('''%(program)s -b changes . _build/changes''' % {'program': sphinxCmd})
#os.system('''%(program)s -b linkcheck . _build/linkcheck''' % {'program': sphinxCmd})
#os.system('''%(program)s -b devhelp . _build/devhelp''' % {'program': sphinxCmd})
if __name__ == "__main__":
main()

View File

@ -70,3 +70,4 @@ from .txn import *
from .exceptions import *
from .undoredo import *
from .utils import *
from .generic import *

View File

@ -43,7 +43,7 @@ from .proxy.proxybase import ProxyDbBase
from .utils.callback import Callback
from .config import config
from gramps.gen.db.dbconst import DBLOGNAME
from gramps.gen.db.utils import make_database
from gramps.gen.db.dummydb import DummyDb
#-------------------------------------------------------------------------
#
@ -69,7 +69,7 @@ class DbState(Callback):
place holder until a real DB is assigned.
"""
Callback.__init__(self)
self.db = make_database("dummydb")
self.db = DummyDb()
self.open = False # Deprecated - use DbState.is_open()
self.stack = []
@ -135,7 +135,7 @@ class DbState(Callback):
self.emit('no-database', ())
if self.is_open():
self.db.close()
self.db = make_database("dummydb")
self.db = DummyDb()
self.open = False
self.emit('database-changed', (self.db, ))

View File

@ -109,6 +109,7 @@ from ._matchidof import MatchIdOf
from ._regexpidof import RegExpIdOf
from ._changedsince import ChangedSince
from ._isrelatedwith import IsRelatedWith
from ._hassoundexname import HasSoundexName
#-------------------------------------------------------------------------
#
@ -189,5 +190,6 @@ editor_rule_list = [
Disconnected,
ChangedSince,
IsRelatedWith,
HasSoundexName,
]

View File

@ -0,0 +1,86 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2017 Paul Culley <paulr2787_at_gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#-------------------------------------------------------------------------
#
# Standard Python modules
#
#-------------------------------------------------------------------------
from ....const import GRAMPS_LOCALE as glocale
_ = glocale.translation.sgettext
#-------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------
from .. import Rule
from ....lib.nameorigintype import NameOriginType
from gramps.gen.soundex import soundex
#-------------------------------------------------------------------------
#
# HasNameOf
#
#-------------------------------------------------------------------------
class HasSoundexName(Rule):
"""Rule that checks for full or partial name matches"""
labels = [_('Name:')]
name = _('Soundex match of People with the <name>')
description = _("Soundex Match of people with a specified name. First "
"name, Surname, Call name, and Nickname are searched in "
"primary and alternate names.")
category = _('General filters')
allow_regex = False
def apply(self, db, person):
self.sndx = soundex(self.list[0])
for name in [person.get_primary_name()] + person.get_alternate_names():
if self._match_name(name):
return True
return False
def _match_name(self, name):
if self.list[0]:
if soundex(str(name.get_first_name())) == self.sndx:
return True
elif soundex(str(name.get_surname())) == self.sndx:
return True
elif soundex(str(name.get_call_name())) == self.sndx:
return True
elif soundex(str(name.get_nick_name())) == self.sndx:
return True
elif soundex(str(name.get_family_nick_name())) == self.sndx:
return True
else:
for surn in name.get_surname_list():
if self._match_surname(surn):
return True
return False
def _match_surname(self, surn):
if soundex(str(surn.get_surname())) == self.sndx:
return True
if surn.get_origintype().value == NameOriginType.PATRONYMIC:
if soundex(str(surn.get_surname())) == self.sndx:
return True
return False

View File

@ -36,7 +36,7 @@ from gramps.gen.filters.rules.person import (
IsDuplicatedAncestorOf, IsRelatedWith, HasIdOf, IsDefaultPerson, IsFemale,
IsMale, MissingParent, MultipleMarriages, NeverMarried, NoBirthdate,
NoDeathdate, PeoplePrivate, PeoplePublic, PersonWithIncompleteEvent,
RelationshipPathBetweenBookmarks)
RelationshipPathBetweenBookmarks, HasNameOf, HasSoundexName)
TEST_DIR = os.path.abspath(os.path.join(DATA_DIR, "tests"))
EXAMPLE = os.path.join(TEST_DIR, "example.gramps")
@ -564,6 +564,22 @@ class BaseTest(unittest.TestCase):
b'D3WJQCCGV58IP8PNHZ', b'Q8HKQC3VMRM1M6M7ES',
]))
def test_hassoundexname(self):
"""
Test HasSoundexName rule.
"""
rule = HasSoundexName(['garner'])
self.assertEqual(len(self.filter_with_rule(rule)), 73)
def test_hasnameof(self):
"""
Test HasNameOf rule.
"""
rule = HasNameOf(['Lewis', 'Garner', 'Dr.', 'Sr', 'Anderson',
'Big Louie', 'von', 'Zieliński', None, None, None])
self.assertEqual(self.filter_with_rule(rule), set([
b'GNUJQCL9MD64AM56OH']))
if __name__ == "__main__":
unittest.main()

View File

@ -39,7 +39,7 @@ import os
import sys
import re
import logging
LOG = logging.getLogger('.' + __name__)
LOG = logging.getLogger('._manager')
LOG.progagate = True
from ..const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
@ -100,8 +100,8 @@ class BasePluginManager:
self.__modules = {}
self.__pgr = PluginRegister.get_instance()
self.__registereddir_set = set()
self.__loaded_plugins = {}
self.__scanned_dirs = []
def reg_plugins(self, direct, dbstate=None, uistate=None,
load_on_reg=False):
@ -112,23 +112,24 @@ class BasePluginManager:
If a relationship calculator for env var LANG is present, it is
immediately loaded so it is available for all.
"""
# if the directory does not exist, do nothing
if not os.path.isdir(direct):
return False # return value is True for error
# if we've already scanned this directory or if the directory does not
# exist, we are done. Should only happen in tests.
for (dirpath, dirnames, filenames) in os.walk(direct):
root, subdir = os.path.split(dirpath)
if subdir.startswith("."):
dirnames[:] = []
continue
for dirname in dirnames:
# Skip hidden and system directories:
if dirname.startswith(".") or dirname in ["po", "locale"]:
dirnames.remove(dirname)
# if the path has not already been loaded, save it in the
# registereddir_list list for use on reloading.
self.__registereddir_set.add(dirpath)
self.__pgr.scan_dir(dirpath, uistate=uistate)
# LOG.warning("\nPlugin manager registration: %s, load_on_reg=%s,"
# " been_here=%s, pahte exists:%s", direct, load_on_reg,
# direct in self.__scanned_dirs, os.path.isdir(direct))
if os.path.isdir(direct) and direct not in self.__scanned_dirs:
self.__scanned_dirs.append(direct)
for (dirpath, dirnames, filenames) in os.walk(direct,
topdown=True):
for dirname in dirnames[:]:
# Skip hidden and system directories:
if dirname.startswith(".") or dirname in ["po", "locale",
"__pycache__"]:
dirnames.remove(dirname)
# LOG.warning("Plugin dir scanned: %s", dirpath)
self.__pgr.scan_dir(dirpath, filenames, uistate=uistate)
if load_on_reg:
# Run plugins that request to be loaded on startup and
@ -136,6 +137,7 @@ class BasePluginManager:
# first, remove hidden
plugins_to_load = []
for plugin in self.__pgr.filter_load_on_reg():
# LOG.warning("\nFound %s at registration", plugin.id)
if plugin.id in config.get("plugin.hiddenplugins"):
continue
plugins_to_load.append(plugin)
@ -146,6 +148,8 @@ class BasePluginManager:
max_count = len(plugins_to_load)
while plugins_to_load:
for plugin in plugins_to_load[:]: # copy of list
# LOG.warning("\nDependencies for %s at registration",
# plugin.id)
delay = False
for depend in plugin.depends_on:
if depend not in [p.id for p in plugins_sorted]:
@ -167,8 +171,12 @@ class BasePluginManager:
break
# now load them:
for plugin in plugins_sorted:
# next line shouldn't be necessary, but this gets called a lot
# of times during Travis test; so avoid multiple copies
plugin.data = []
mod = self.load_plugin(plugin)
if hasattr(mod, "load_on_reg"):
# LOG.warning("\nRun %s at registration", plugin.id)
try:
results = mod.load_on_reg(dbstate, uistate, plugin)
except:
@ -496,6 +504,8 @@ class BasePluginManager:
retval.extend(data)
except:
retval.append(data)
# LOG.warning("Process plugin data=%s, %s, items=%s",
# process is not None, category, len(retval))
if process:
return process(retval)
return retval

View File

@ -43,6 +43,8 @@ from gramps.version import VERSION as GRAMPSVERSION, VERSION_TUPLE
from ..const import IMAGE_DIR
from ..const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
import logging
LOG = logging.getLogger('._manager')
#-------------------------------------------------------------------------
#
@ -1104,11 +1106,16 @@ class PluginRegister:
if __debug__:
self.stable_only = False
self.__plugindata = []
self.__id_to_pdata = {}
def add_plugindata(self, plugindata):
""" This is used to add an entry to the registration list. The way it
is used, this entry is not yet filled in, so we cannot use the id to
add to the __id_to_pdata dict at this time. """
self.__plugindata.append(plugindata)
def scan_dir(self, dir, uistate=None):
def scan_dir(self, dir, filenames, uistate=None):
"""
The dir name will be scanned for plugin registration code, which will
be loaded in :class:`PluginData` objects if they satisfy some checks.
@ -1123,9 +1130,8 @@ class PluginRegister:
extlen = -len(ext)
pymod = re.compile(r"^(.*)\.py$")
for filename in os.listdir(dir):
name = os.path.split(filename)[1]
if not name[extlen:] == ext:
for filename in filenames:
if not filename[extlen:] == ext:
continue
lenpd = len(self.__plugindata)
full_filename = os.path.join(dir, filename)
@ -1150,9 +1156,14 @@ class PluginRegister:
else:
local_gettext = glocale.translation.gettext
try:
#execfile(full_filename,
exec (compile(stream, filename, 'exec'),
make_environment(_=local_gettext), {'uistate': uistate})
for pdata in self.__plugindata[lenpd:]:
# should not be duplicate IDs in different plugins
assert pdata.id not in self.__id_to_pdata
# if pdata.id in self.__id_to_pdata:
# print("Error: %s is duplicated!" % pdata.id)
self.__id_to_pdata[pdata.id] = pdata
except ValueError as msg:
print(_('ERROR: Failed reading plugin registration %(filename)s') % \
{'filename' : filename})
@ -1170,6 +1181,7 @@ class PluginRegister:
rmlist = []
ind = lenpd-1
for plugin in self.__plugindata[lenpd:]:
#LOG.warning("\nPlugin scanned %s at registration", plugin.id)
ind += 1
plugin.directory = dir
if not valid_plugin_version(plugin.gramps_target_version):
@ -1211,19 +1223,20 @@ class PluginRegister:
module = match.groups()[0]
plugin.mod_name = module
plugin.fpath = dir
#LOG.warning("\nPlugin added %s at registration", plugin.id)
rmlist.reverse()
for ind in rmlist:
del self.__id_to_pdata[self.__plugindata[ind].id]
del self.__plugindata[ind]
def get_plugin(self, id):
"""
Return the :class:`PluginData` for the plugin with id
"""
matches = [x for x in self.__plugindata if x.id == id]
matches.sort(key=lambda x: version(x.version))
if len(matches) > 0:
return matches[-1]
return None
assert(len(self.__id_to_pdata) == len(self.__plugindata))
# if len(self.__id_to_pdata) != len(self.__plugindata):
# print(len(self.__id_to_pdata), len(self.__plugindata))
return self.__id_to_pdata.get(id, None)
def type_plugins(self, ptype):
"""

View File

@ -36,7 +36,7 @@ from ..docgen import StyleSheetList
# StyleOption class
#
#-------------------------------------------------------------------------
class StyleOption(EnumeratedListOption):
class StyleOption(EnumeratedListOption): # TODO this is likely dead code
"""
This class describes an option that allows the use to select a style sheet.
"""

View File

@ -90,7 +90,7 @@
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="destroy_passed_object" object="editor" swapped="yes"/>
<signal name="clicked" handler="on_cancel_style_clicked" object="editor" swapped="yes"/>
</object>
<packing>
<property name="expand">False</property>
@ -1705,8 +1705,6 @@
</object>
<object class="GtkDialog" id="styles">
<property name="can_focus">False</property>
<property name="default_width">400</property>
<property name="default_height">300</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox1">
@ -1727,6 +1725,7 @@
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="on_cancel_clicked" object="styles" swapped="yes"/>
</object>
<packing>
<property name="expand">False</property>

View File

@ -488,7 +488,9 @@ class ManagedWindow:
self.window.set_modal(True)
# The following makes sure that we only have one modal window open;
# if more the older ones get temporarily made non-modal.
self.other_modal_window = self.uistate.gwm.find_modal_window(window)
if self.uistate:
self.other_modal_window = self.uistate.gwm.find_modal_window(
window)
if self.other_modal_window:
self.other_modal_window.set_modal(False)
self.window.set_modal(True)
@ -623,7 +625,8 @@ class ManagedWindow:
def setup_configs(self, config_base,
default_width, default_height,
default_horiz_position=None, default_vert_position=None):
default_horiz_position=None, default_vert_position=None,
p_width=None, p_height=None): # for fullscreen
"""
Helper method to setup the window's configuration settings
@ -634,13 +637,18 @@ class ManagedWindow:
@param default_horiz_position, default_vert_position: if either is None
then that position is centered on the parent, else explicitly set
@type default_horiz_position, default_vert_position: int or None
@param p_width, p_height: the parent's width and height
@type p_width, p_height: int or None
"""
self.width_key = config_base + '-width'
self.height_key = config_base + '-height'
self.horiz_position_key = config_base + '-horiz-position'
self.vert_position_key = config_base + '-vert-position'
(p_width, p_height) = self.parent_window.get_size()
(p_horiz, p_vert) = self.parent_window.get_position()
if p_width is None and p_height is None: # default case
(p_width, p_height) = self.parent_window.get_size()
(p_horiz, p_vert) = self.parent_window.get_position()
else:
p_horiz = p_vert = 0 # fullscreen
if default_horiz_position is None:
default_horiz_position = p_horiz + ((p_width - default_width) // 2)
if default_vert_position is None:

View File

@ -1790,7 +1790,7 @@ class GuiDestinationOption(Gtk.Box):
# GuiStyleOption class
#
#-------------------------------------------------------------------------
class GuiStyleOption(GuiEnumeratedListOption):
class GuiStyleOption(GuiEnumeratedListOption): # TODO this is likely dead code
"""
This class displays a StyleOption.
"""
@ -1808,6 +1808,8 @@ class GuiStyleOption(GuiEnumeratedListOption):
self.__button.connect('clicked', self.__on_style_edit_clicked)
self.pack_end(self.__button, False, False)
self.uistate = uistate
self.track = track
def __on_style_edit_clicked(self, *obj):
"""The user has clicked on the 'Edit Styles' button. Create a
@ -1817,7 +1819,7 @@ class GuiStyleOption(GuiEnumeratedListOption):
from .report._styleeditor import StyleListDisplay
style_list = StyleSheetList(self.__option.get_style_file(),
self.__option.get_default_style())
StyleListDisplay(style_list, None, None)
StyleListDisplay(style_list, self.uistate, self.track)
new_items = []
for style_name in style_list.get_style_names():

View File

@ -588,8 +588,8 @@ class ReportDialog(ManagedWindow):
style sheet editor object and let them play. When they are
done, the previous routine will be called to update the dialog
menu for selecting a style."""
StyleListDisplay(self.style_sheet_list, self.build_style_menu,
self.window)
StyleListDisplay(self.style_sheet_list, self.uistate, self.track,
callback=self.build_style_menu)
#----------------------------------------------------------------------
#

View File

@ -55,63 +55,73 @@ from gramps.gen.plug.docgen import (StyleSheet, FONT_SERIF, FONT_SANS_SERIF,
PARA_ALIGN_JUSTIFY, ParagraphStyle, TableStyle, TableCellStyle,
GraphicsStyle)
from ...listmodel import ListModel
from ...managedwindow import set_titles
from ...managedwindow import ManagedWindow
from ...glade import Glade
from ...dialog import ErrorDialog
#------------------------------------------------------------------------
#
# StyleListDisplay class
#
#------------------------------------------------------------------------
class StyleListDisplay:
class StyleListDisplay(ManagedWindow):
"""
Shows the available paragraph/font styles. Allows the user to select,
add, edit, and delete styles from a StyleSheet.
add, edit, and delete styles from a StyleSheetList.
"""
def __init__(self, stylesheetlist, callback, parent_window):
def __init__(self, stylesheetlist, uistate, track, callback=None):
"""
Create a StyleListDisplay object that displays the styles in the
StyleSheet.
StyleSheetList.
stylesheetlist - styles that can be editied
callback - task called with an object has been added.
stylesheetlist - styles for editing: a :class:`.StyleSheetList` instance
callback - task called when an object has been added.
"""
ManagedWindow.__init__(self, uistate, track, self.__class__, modal=True)
# the self.window.run() below makes Gtk make it modal, so any change
# to the previous line's "modal" would require that line to be changed
self.callback = callback
self.sheetlist = stylesheetlist
self.parent_window = parent_window
self.top = Glade(toplevel='styles')
self.window = self.top.toplevel
set_titles(self.window, self.top.get_object('title'),
_('Document Styles'))
self.set_window(self.top.toplevel, self.top.get_object('title'),
_('Document Styles'))
self.setup_configs('interface.stylelistdisplay', 400, 300)
self.show()
self.top.connect_signals({
"destroy_passed_object" : self.__close,
"on_ok_clicked" : self.on_ok_clicked,
"on_add_clicked" : self.on_add_clicked,
"on_delete_clicked" : self.on_delete_clicked,
"on_button_press" : self.on_button_press,
"on_edit_clicked" : self.on_edit_clicked,
"on_cancel_clicked" : self.__cancel,
"on_cancel_style_clicked" : dummy_callback,
"on_save_style_clicked" : dummy_callback,
})
self.list = ListModel(self.top.get_object("list"),
[(_('Style'), -1, 10)], )
self.redraw()
if parent_window:
self.window.set_transient_for(parent_window)
# the self.window.run() makes Gtk make it modal, so any change to that
# line would require the ManagedWindow.__init__ to be changed also
self.window.run()
self.window.destroy()
if self.opened:
self.close()
def __close(self, obj):
self.top.destroy()
def build_menu_names(self, obj): # meaningless while it's modal
"""Override :class:`.ManagedWindow` method."""
return (_('Document Styles'), ' ')
def __cancel(self, obj):
pass
def redraw(self):
"""Redraws the list of styles that are current available"""
"""Redraws the list of styles that are currently available"""
self.list.model.clear()
self.list.add([_("default")])
@ -124,22 +134,21 @@ class StyleListDisplay:
index += 1
def on_add_clicked(self, obj):
"""Called with the ADD button is clicked. Invokes the StyleEditor to
"""Called when the ADD button is clicked. Invokes the StyleEditor to
create a new style"""
style = self.sheetlist.get_style_sheet("default")
StyleEditor(_("New Style"), style, self)
def on_ok_clicked(self, obj):
"""Called with the OK button is clicked; Calls the callback task,
"""Called when the OK button is clicked; Calls the callback task,
then saves the stylesheet."""
if self.callback is not None:
self.callback()
try:
self.sheetlist.save()
except IOError as msg:
from ...dialog import ErrorDialog
ErrorDialog(_("Error saving stylesheet"), str(msg),
parent=self.parent_window)
parent=self.window)
except:
log.error("Failed to save stylesheet", exc_info=True)
@ -149,11 +158,13 @@ class StyleListDisplay:
def on_edit_clicked(self, obj):
"""
Called with the EDIT button is clicked.
Called when the EDIT button is clicked.
Calls the StyleEditor to edit the selected style.
"""
store, node = self.list.selection.get_selected()
if not node:
ErrorDialog(_("Missing information"), _("Select a style"),
parent=self.window)
return
name = str(self.list.model.get_value(node, 0))
@ -166,6 +177,8 @@ class StyleListDisplay:
"""Deletes the selected style."""
store, node = self.list.selection.get_selected()
if not node:
ErrorDialog(_("Missing information"), _("Select a style"),
parent=self.window)
return
name = str(self.list.model.get_value(node, 0))
if name == _('default'): # the default style cannot be removed
@ -178,7 +191,7 @@ class StyleListDisplay:
# StyleEditor class
#
#------------------------------------------------------------------------
class StyleEditor:
class StyleEditor(ManagedWindow):
"""
Edits the current style definition. Presents a dialog allowing the values
of the paragraphs in the style to be altered.
@ -189,20 +202,30 @@ class StyleEditor:
Create the StyleEditor.
name - name of the style that is to be edited
style - style object that is to be edited
style - style object to be edited: a :class:`.StyleSheet` instance
parent - StyleListDisplay object that called the editor
"""
ManagedWindow.__init__(self, parent.uistate, parent.track,
self.__class__, modal=True)
# the self.window.run() below makes Gtk make it modal, so any change
# to the previous line's "modal" would require that line to be changed
self.current_style = None
self.current_name = None
self.style = StyleSheet(style)
self.parent = parent
self.top = Glade(toplevel='editor')
self.window = self.top.toplevel
self.set_window(self.top.toplevel, self.top.get_object('title'),
_('Style editor'))
self.setup_configs('interface.styleeditor', 550, 610)
self.show()
self.top.connect_signals({
"on_save_style_clicked" : self.on_save_style_clicked,
"destroy_passed_object" : self.__close,
"on_cancel_style_clicked" : self.__cancel,
"on_cancel_clicked" : dummy_callback,
"on_ok_clicked" : dummy_callback,
"on_add_clicked" : dummy_callback,
"on_delete_clicked" : dummy_callback,
@ -226,8 +249,6 @@ class StyleEditor:
self.line_style.pack_start(renderer_text, True)
self.line_style.add_attribute(renderer_text, "text", 1)
set_titles(self.window, self.top.get_object('title'),
_('Style editor'))
self.top.get_object("label6").set_text(_("point size|pt"))
titles = [(_('Style'), 0, 130)]
@ -261,13 +282,18 @@ class StyleEditor:
self.plist.add([d_name], self.style.get_draw_style(d_name))
self.plist.select_row(0)
if self.parent:
self.window.set_transient_for(parent.window)
# the self.window.run() makes Gtk make it modal, so any change to that
# line would require the ManagedWindow.__init__ to be changed also
self.window.run()
self.window.destroy()
if self.opened:
self.close()
def __close(self, obj):
self.window.destroy()
def build_menu_names(self, obj): # meaningless while it's modal
"""Override :class:`.ManagedWindow` method."""
return (_('Style editor'), None)
def __cancel(self, obj):
pass
def show_pages(self, show_pages):
"""
@ -525,7 +551,6 @@ class StyleEditor:
self.style.set_name(name)
self.parent.sheetlist.set_style_sheet(name, self.style)
self.parent.redraw()
self.window.destroy()
def change_display(self, obj):
"""

View File

@ -236,8 +236,9 @@ class GrampletWindow(ManagedWindow):
Gtk.DialogFlags.DESTROY_WITH_PARENT,
(_('_Close'), Gtk.ResponseType.CLOSE)),
None, self.title)
self.window.set_size_request(gramplet.detached_width,
gramplet.detached_height)
cfg_name = gramplet.gname.replace(' ', '').lower() + '-gramplet'
self.setup_configs('interface.' + cfg_name,
gramplet.detached_width, gramplet.detached_height)
self.window.add_button(_('_Help'), Gtk.ResponseType.HELP)
# add gramplet:
if self.gramplet.pui:
@ -1585,20 +1586,6 @@ class GrampletPane(Gtk.ScrolledWindow):
"%s.height" % gramplet.title,
self._config.set,
config=self._config)
# Detached height
configdialog.add_pos_int_entry(grid,
_('Detached width'),
3,
"%s.detached_width" % gramplet.title,
self._config.set,
config=self._config)
# Detached width
configdialog.add_pos_int_entry(grid,
_('Detached height'),
4,
"%s.detached_height" % gramplet.title,
self._config.set,
config=self._config)
# Options:
options = gramplet.make_gui_options()
if options:

View File

@ -51,7 +51,7 @@ from .undoablebuffer import Stack
class UndoableInsertEntry:
"""something that has been inserted into our Gtk.editable"""
def __init__(self, text, length, position, editable):
def __init__(self, text, length, position):
self.offset = position
self.text = text
#unicode char can have length > 1 as it points in the buffer
@ -80,7 +80,7 @@ class UndoableDeleteEntry:
else:
self.mergeable = True
class UndoableEntry(Gtk.Entry):
class UndoableEntry(Gtk.Entry, Gtk.Editable):
"""
The UndoableEntry is an Entry subclass with additional features.
@ -102,7 +102,6 @@ class UndoableEntry(Gtk.Entry):
self.not_undoable_action = False
self.undo_in_progress = False
self.connect('insert-text', self._on_insert_text)
self.connect('delete-text', self._on_delete_text)
self.connect('key-press-event', self._on_key_press_event)
@ -134,7 +133,7 @@ class UndoableEntry(Gtk.Entry):
def __empty_redo_stack(self):
self.redo_stack = []
def _on_insert_text(self, editable, text, length, positionptr):
def do_insert_text(self, text, length, position):
def can_be_merged(prev, cur):
"""
see if we can merge multiple inserts here
@ -159,26 +158,27 @@ class UndoableEntry(Gtk.Entry):
if not self.undo_in_progress:
self.__empty_redo_stack()
if self.not_undoable_action:
return
undo_action = self.insertclass(text, length, editable.get_position(),
editable)
try:
prev_insert = self.undo_stack.pop()
except IndexError:
self.undo_stack.append(undo_action)
return
if not isinstance(prev_insert, self.insertclass):
self.undo_stack.append(prev_insert)
self.undo_stack.append(undo_action)
return
if can_be_merged(prev_insert, undo_action):
prev_insert.length += undo_action.length
prev_insert.text += undo_action.text
self.undo_stack.append(prev_insert)
else:
self.undo_stack.append(prev_insert)
self.undo_stack.append(undo_action)
while not self.not_undoable_action:
undo_action = self.insertclass(text, length, self.get_position())
try:
prev_insert = self.undo_stack.pop()
except IndexError:
self.undo_stack.append(undo_action)
break
if not isinstance(prev_insert, self.insertclass):
self.undo_stack.append(prev_insert)
self.undo_stack.append(undo_action)
break
if can_be_merged(prev_insert, undo_action):
prev_insert.length += undo_action.length
prev_insert.text += undo_action.text
self.undo_stack.append(prev_insert)
else:
self.undo_stack.append(prev_insert)
self.undo_stack.append(undo_action)
break
self.get_buffer().insert_text(position, text, length)
return position + length
def _on_delete_text(self, editable, start, end):
def can_be_merged(prev, cur):

View File

@ -1,36 +0,0 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2016 Tim G L Lyons
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
from gramps.gen.plug._pluginreg import register, STABLE, DATABASE
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
register(DATABASE,
id = 'dummydb',
name = _("Dummy database"),
name_accell = _("Dummy Database"),
description = _("Dummy Database"),
version = '1.0.0',
gramps_target_version = "5.0",
status = STABLE,
fname = 'dummydb.py',
databaseclass = 'DummyDb',
authors=['Tim Lyons'],
authors_email=[""],
)

View File

@ -144,6 +144,7 @@ class CalcItems:
"""
def __init__(self, dbase):
_gui = GUIConnect()
self._gui = _gui
#calculate the printed lines for each box
#str = ""
@ -172,12 +173,14 @@ class CalcItems:
working_lines = ""
if index[1] % 2 == 0 or (index[1] == 1 and self.center_use == 0):
if indi_handle == fams_handle == None:
working_lines = self.__blank_father
working_lines = self.__calc_l.calc_lines(
None, None, self._gui.get_val("father_disp"))
else:
working_lines = self.disp_father
else:
if indi_handle == fams_handle == None:
working_lines = self.__blank_mother
working_lines = self.__calc_l.calc_lines(
None, None, self._gui.get_val("mother_disp"))
else:
working_lines = self.disp_mother
@ -230,9 +233,11 @@ class MakeAncestorTree(AscendPerson):
myself.text = self.calc_items.calc_person(index,
indi_handle, fams_handle)
# myself.text[0] = myself.text[0] + ' ' + repr(index) # for debugging
myself.add_mark(self.database,
self.database.get_person_from_handle(indi_handle))
if indi_handle is not None: # None is legal for an empty box
myself.add_mark(self.database,
self.database.get_person_from_handle(indi_handle))
self.canvas.add_box(myself)

View File

@ -114,8 +114,9 @@ class CSVWriterOptionBox(WriterOptionBox):
the options.
"""
def __init__(self, person, dbstate, uistate):
WriterOptionBox.__init__(self, person, dbstate, uistate)
def __init__(self, person, dbstate, uistate, track=[], window=None):
WriterOptionBox.__init__(self, person, dbstate, uistate, track=track,
window=window)
## TODO: add place filter selection
self.include_individuals = 1
self.include_marriages = 1

View File

@ -74,6 +74,11 @@ _COLORS = [{'name' : _("B&W outline"), 'value' : "outline"},
{'name' : _("Colored outline"), 'value' : "colored"},
{'name' : _("Color fill"), 'value' : "filled"}]
_ARROWS = [ { 'name' : _("Descendants <- Ancestors"), 'value' : 'd' },
{ 'name' : _("Descendants -> Ancestors"), 'value' : 'a' },
{ 'name' : _("Descendants <-> Ancestors"), 'value' : 'da' },
{ 'name' : _("Descendants - Ancestors"), 'value' : '' }]
#------------------------------------------------------------------------
#
# A quick overview of the classes we'll be using:
@ -149,6 +154,12 @@ class FamilyLinesOptions(MenuReportOptions):
"is unknown it will be shown with gray."))
add_option("color", color)
arrow = EnumeratedListOption(_("Arrowhead direction"), 'd')
for i in range( 0, len(_ARROWS) ):
arrow.add_item(_ARROWS[i]["value"], _ARROWS[i]["name"])
arrow.set_help(_("Choose the direction that the arrows point."))
add_option("arrow", arrow)
stdoptions.add_localization_option(menu, category_name)
# --------------------------------
@ -366,6 +377,16 @@ class FamilyLinesReport(Report):
self._incchildcount = get_value('incchildcnt')
self.includeid = get_value('incid')
arrow_str = get_value('arrow')
if 'd' in arrow_str:
self._arrowheadstyle = 'normal'
else:
self._arrowheadstyle = 'none'
if 'a' in arrow_str:
self._arrowtailstyle = 'normal'
else:
self._arrowtailstyle = 'none'
# the gidlist is annoying for us to use since we always have to convert
# the GIDs to either Person or to handles, so we may as well convert the
# entire list right now and not have to deal with it ever again
@ -1015,8 +1036,9 @@ class FamilyLinesReport(Report):
father = self._db.get_person_from_handle(father_handle)
father_rn = father.get_primary_name().get_regular_name()
comment = self._("father: %s") % father_rn
self.doc.add_link(father.get_gramps_id(),
fgid, comment=comment)
self.doc.add_link(father.get_gramps_id(), fgid, "",
self._arrowheadstyle, self._arrowtailstyle,
comment=comment)
# see if we have a mother to link to this family
if mother_handle:
@ -1024,8 +1046,9 @@ class FamilyLinesReport(Report):
mother = self._db.get_person_from_handle(mother_handle)
mother_rn = mother.get_primary_name().get_regular_name()
comment = self._("mother: %s") % mother_rn
self.doc.add_link(mother.get_gramps_id(),
fgid, comment=comment)
self.doc.add_link(mother.get_gramps_id(), fgid, "",
self._arrowheadstyle, self._arrowtailstyle,
comment=comment)
if self._usesubgraphs and father_handle and mother_handle:
self.doc.end_subgraph()
@ -1036,7 +1059,8 @@ class FamilyLinesReport(Report):
child = self._db.get_person_from_handle(childref.ref)
child_rn = child.get_primary_name().get_regular_name()
comment = self._("child: %s") % child_rn
self.doc.add_link(fgid, child.get_gramps_id(),
self.doc.add_link(fgid, child.get_gramps_id(), "",
self._arrowheadstyle, self._arrowtailstyle,
comment=comment)
def get_event_place(self, event):

View File

@ -58,6 +58,11 @@ _COLORS = [{'name' : _("B&W outline"), 'value' : "outline"},
{'name' : _("Colored outline"), 'value' : "colored"},
{'name' : _("Color fill"), 'value' : "filled"}]
_ARROWS = [ { 'name' : _("Center -> Others"), 'value' : 'o' },
{ 'name' : _("Center <- Others"), 'value' : 'c' },
{ 'name' : _("Center <-> Other"), 'value' : 'co' },
{ 'name' : _("Center - Other"), 'value' : '' }]
#------------------------------------------------------------------------
#
# HourGlassReport
@ -109,6 +114,16 @@ class HourGlassReport(Report):
self.includeid = menu.get_option_by_name('incid').get_value()
arrow_str = menu.get_option_by_name('arrow').get_value()
if 'o' in arrow_str:
self.arrowheadstyle = 'normal'
else:
self.arrowheadstyle = 'none'
if 'c' in arrow_str:
self.arrowtailstyle = 'normal'
else:
self.arrowtailstyle = 'none'
stdoptions.run_name_format_option(self, menu)
def write_report(self):
@ -128,7 +143,9 @@ class HourGlassReport(Report):
for family_handle in person.get_family_handle_list():
family = self.__db.get_family_from_handle(family_handle)
self.add_family(family)
self.doc.add_link(person.get_gramps_id(), family.get_gramps_id())
self.doc.add_link(person.get_gramps_id(), family.get_gramps_id(),
head=self.arrowheadstyle,
tail=self.arrowtailstyle)
for child_ref in family.get_child_ref_list():
child_handle = child_ref.get_reference_handle()
if child_handle not in self.__used_people:
@ -137,7 +154,9 @@ class HourGlassReport(Report):
child = self.__db.get_person_from_handle(child_handle)
self.add_person(child)
self.doc.add_link(family.get_gramps_id(),
child.get_gramps_id())
child.get_gramps_id(),
head=self.arrowheadstyle,
tail=self.arrowtailstyle)
self.traverse_down(child, gen+1)
def traverse_up(self, person, gen):
@ -152,7 +171,8 @@ class HourGlassReport(Report):
family_id = family.get_gramps_id()
self.add_family(family)
self.doc.add_link(family_id, person.get_gramps_id(),
head='none', tail='normal')
head=self.arrowtailstyle,
tail=self.arrowheadstyle )
# create link from family to father
father_handle = family.get_father_handle()
@ -162,7 +182,8 @@ class HourGlassReport(Report):
father = self.__db.get_person_from_handle(father_handle)
self.add_person(father)
self.doc.add_link(father.get_gramps_id(), family_id,
head='none', tail='normal')
head=self.arrowtailstyle,
tail=self.arrowheadstyle )
# no need to go up if he is a father in another family
if father_handle not in self.__used_people:
self.__used_people.append(father_handle)
@ -176,7 +197,8 @@ class HourGlassReport(Report):
mother = self.__db.get_person_from_handle(mother_handle)
self.add_person(mother)
self.doc.add_link(mother.get_gramps_id(), family_id,
head='none', tail='normal')
head=self.arrowtailstyle,
tail=self.arrowheadstyle)
# no need to go up if she is a mother in another family
if mother_handle not in self.__used_people:
self.__used_people.append(mother_handle)
@ -347,6 +369,12 @@ class HourGlassOptions(MenuReportOptions):
color_family.set_help(_('The color to use to display families.'))
menu.add_option(category_name, 'colorfamilies', color_family)
arrow = EnumeratedListOption(_("Arrowhead direction"), 'o')
for i in range( 0, len(_ARROWS) ):
arrow.add_item(_ARROWS[i]["value"], _ARROWS[i]["name"])
arrow.set_help(_("Choose the direction that the arrows point."))
menu.add_option(category_name, "arrow", arrow)
roundedcorners = BooleanOption(_("Use rounded corners"), False) # 2180
roundedcorners.set_help(
_("Use rounded corners to differentiate between women and men."))

View File

@ -446,13 +446,13 @@ class AscendPerson(_StopRecurse, _PersonSeen):
# Recursively call the function. It is okay if the handle is None,
# since routine handles a handle of None
self.__fill(index*2, generation+1, mx_fill-1)
self.__fill(generation+1, index*2, mx_fill-1)
if mx_fill > 1: # marriage of parents
self.add_marriage((generation+1, index*2), None, None)
if not self.can_recurse():
self.continue_recursion()
return
self.__fill((index*2)+1, generation+1, mx_fill-1)
self.__fill(generation+1, (index*2)+1, mx_fill-1)
def __iterate(self, generation, index, person_handle, full_family_handle):
"""

View File

@ -1,4 +1,4 @@
#! /usr/bin/env python3
#! /usr/bin/env python3
""" Test program for import modules
"""
#

View File

@ -12,6 +12,7 @@
# Copyright (C) 2011 Tim G L Lyons
# Copyright (C) 2013-2014 Paul Franklin
# Copyright (C) 2014 Gerald Kunzmann <g.kunzmann@arcor.de>
# Copyright (C) 2017 Robert Carnell <bertcarnell_at_gmail.com>
#
# 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
@ -96,6 +97,7 @@ class DetAncestorReport(Report):
firstName - Whether to use first names instead of pronouns.
fulldate - Whether to use full dates instead of just year.
listchildren - Whether to list children.
list_children_spouses - Whether to list the spouses of the children
includenotes - Whether to include notes.
incattrs - Whether to include attributes
blankplace - Whether to replace missing Places with ___________.
@ -136,6 +138,7 @@ class DetAncestorReport(Report):
self.fulldate = get_value('fulldates')
use_fulldate = self.fulldate
self.listchildren = get_value('listc')
self.list_children_spouses = get_value('listc_spouses')
self.includenotes = get_value('incnotes')
use_call = get_value('usecall')
blankplace = get_value('repplace')
@ -556,7 +559,10 @@ class DetAncestorReport(Report):
is_first = False
def write_children(self, family):
""" List children.
"""
List children.
:param family: Family
:return:
"""
if not family.get_child_ref_list():
@ -614,6 +620,25 @@ class DetAncestorReport(Report):
self.doc.write_text_citation(
self.__narrator.get_died_string() or
self.__narrator.get_buried_string())
# if the list_children_spouses option is selected:
if self.list_children_spouses:
# get the family of the child that contains the spouse
# of the child. There may be more than one spouse for each
# child
family_handle_list = child.get_family_handle_list()
# for the first spouse, this is true.
# For subsequent spouses, make it false
is_first_family = True
for family_handle in family_handle_list:
child_family = self.database.get_family_from_handle(
family_handle
)
self.doc.write_text_citation(
self.__narrator.get_married_string(
child_family, is_first_family, self._name_display
)
)
is_first_family = False
self.doc.end_paragraph()
def write_family_events(self, family):
@ -692,7 +717,7 @@ class DetAncestorReport(Report):
if self.addimages and len(plist) > 0:
photo = plist[0]
utils.insert_image(self._db, self.doc,
photo, self._user)
photo, self._user)
name = self._nd.display(ind)
if not name:
@ -773,6 +798,9 @@ class DetAncestorOptions(MenuReportOptions):
return _nd.display(person)
def add_menu_options(self, menu):
"""
Add Menu Options
"""
from functools import partial
# Report Options
@ -818,6 +846,11 @@ class DetAncestorOptions(MenuReportOptions):
listc.set_help(_("Whether to list children."))
addopt("listc", listc)
listc_spouses = BooleanOption(_("List Spouses of Children"), False)
listc_spouses.set_help(
_("Whether to list the spouses of the children."))
addopt("listc_spouses", listc_spouses)
computeage = BooleanOption(_("Compute death age"), True)
computeage.set_help(_("Whether to compute a person's age at death."))
addopt("computeage", computeage)

View File

@ -15,6 +15,7 @@
# Copyright (C) 2012 lcc <lcc@6zap.com>
# Copyright (C) 2013-2014 Paul Franklin
# Copyright (C) 2015 Craig J. Anderson
# Copyright (C) 2017 Robert Carnell <bertcarnell_at_gmail.com>
#
# 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
@ -98,6 +99,7 @@ class DetDescendantReport(Report):
pageben - Whether to include page break before End Notes.
fulldates - Whether to use full dates instead of just year.
listc - Whether to list children.
list_children_spouses - Whether to list the spouses of the children
incnotes - Whether to include notes.
usecall - Whether to use the call name as the first name.
repplace - Whether to replace missing Places with ___________.
@ -151,6 +153,7 @@ class DetDescendantReport(Report):
self.fulldate = get_value('fulldates')
use_fulldate = self.fulldate
self.listchildren = get_value('listc')
self.list_children_spouses = get_value('listc_spouses')
self.inc_notes = get_value('incnotes')
use_call = get_value('usecall')
blankplace = get_value('repplace')
@ -665,6 +668,8 @@ class DetDescendantReport(Report):
def __write_children(self, family):
"""
List the children for the given family.
:param family: Family
:return:
"""
if not family.get_child_ref_list():
return
@ -724,6 +729,25 @@ class DetDescendantReport(Report):
self.doc.write_text_citation(
self.__narrator.get_died_string() or
self.__narrator.get_buried_string())
# if the list_children_spouses option is selected:
if self.list_children_spouses:
# get the family of the child that contains the spouse
# of the child. There may be more than one spouse for each
# child
family_handle_list = child.get_family_handle_list()
# for the first spouse, this is true.
# For subsequent spouses, make it false
is_first_family = True
for family_handle in family_handle_list:
child_family = self.database.get_family_from_handle(
family_handle
)
self.doc.write_text_citation(
self.__narrator.get_married_string(
child_family, is_first_family, self._name_display
)
)
is_first_family = False
self.doc.end_paragraph()
def __write_family_notes(self, family):
@ -1029,6 +1053,11 @@ class DetDescendantOptions(MenuReportOptions):
listc.set_help(_("Whether to list children."))
add_option("listc", listc)
listc_spouses = BooleanOption(_("List Spouses of Children"), False)
listc_spouses.set_help(
_("Whether to list the spouses of the children."))
add_option("listc_spouses", listc_spouses)
computeage = BooleanOption(_("Compute death age"), True)
computeage.set_help(_("Whether to compute a person's age at death."))
add_option("computeage", computeage)

View File

@ -12,6 +12,7 @@
<property name="can_focus">False</property>
<property name="border_width">6</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkLabel" id="title">
<property name="visible">True</property>

View File

@ -299,7 +299,8 @@ class GeoEvents(GeoGraphyView):
progress.step()
progress.close()
elif self.generic_filter:
events_list = self.generic_filter.apply(dbstate.db)
user=self.uistate.viewmanager.user
events_list = self.generic_filter.apply(dbstate.db, user=user)
progress = ProgressMeter(self.window_name,
can_cancel=False,
parent=self.uistate.window)

View File

@ -349,7 +349,8 @@ class GeoPlaces(GeoGraphyView):
progress.step()
progress.close()
elif self.generic_filter:
place_list = self.generic_filter.apply(dbstate.db)
user=self.uistate.viewmanager.user
place_list = self.generic_filter.apply(dbstate.db, user=user)
progress = ProgressMeter(self.window_name,
can_cancel=False,
parent=self.uistate.window)

View File

@ -36,6 +36,7 @@ from gramps.cli.user import User
from gramps.cli.grampscli import CLIManager
from gramps.cli.argparser import ArgParser
from gramps.cli.arghandler import ArgHandler
from gramps.gen.const import USER_DIRLIST
# _caller_context is primarily here to support and document the process
# of determining the test-module's directory.
@ -254,21 +255,36 @@ class Gramps:
def run(self, *args, stdin=None, bytesio=False):
with capture(stdin, bytesio=bytesio) as output:
#load the plugins
self.climanager.do_reg_plugins(self.dbstate, uistate=None)
# handle the arguments
args = [sys.executable] + list(args)
argparser = ArgParser(args)
argparser.need_gui() # initializes some variables
if argparser.errors:
print(argparser.errors, file=sys.stderr)
argparser.print_help()
argparser.print_usage()
handler = ArgHandler(self.dbstate, argparser, self.climanager)
# create a manager to manage the database
handler.handle_args_cli()
if handler.dbstate.is_open():
handler.dbstate.db.close()
try:
try: # make sure we have user directories
for path in USER_DIRLIST:
if not os.path.isdir(path):
os.makedirs(path)
except OSError as msg:
print("Error creating user directories: " + str(msg))
except:
print("Error reading configuration.", exc_info=True)
#load the plugins
self.climanager.do_reg_plugins(self.dbstate, uistate=None)
# handle the arguments
args = [sys.executable] + list(args)
argparser = ArgParser(args)
argparser.need_gui() # initializes some variables
if argparser.errors:
print(argparser.errors, file=sys.stderr)
argparser.print_help()
argparser.print_usage()
handler = ArgHandler(self.dbstate, argparser, self.climanager)
# create a manager to manage the database
handler.handle_args_cli()
if handler.dbstate.is_open():
handler.dbstate.db.close()
except:
print("Exception in test:")
print("-" * 60)
traceback.print_exc(file=sys.stdout)
print("-" * 60)
return output
#===eof===

View File

@ -19,7 +19,7 @@
(gtk_accel_path "<Actions>/Events/Backward/Back" "<Alt>Left")
; (gtk_accel_path "<Actions>/ToolWindow/rebuild_refmap" "")
; (gtk_accel_path "<Actions>/ToolWindow/Database-Processing" "")
(gtk_accel_path "<Actions>/Events/Bookmark/EditBook" "<Shift><Meta>b")
(gtk_accel_path "<Actions>/Events/Bookmark/EditBook" "<Shift><Meta>d")
(gtk_accel_path "<Actions>/People Tree View/PersonEdit/Remove" "<Meta>Delete")
(gtk_accel_path "<Actions>/Notes/Forward/Forward" "<Alt>Right")
(gtk_accel_path "<Actions>/Undo/Undo" "<Meta>z")
@ -29,7 +29,7 @@
(gtk_accel_path "<Actions>/Media/ChangeOrder/Remove" "<Meta>Delete")
; (gtk_accel_path "<Actions>/FileWindow/HelpMenu" "")
(gtk_accel_path "<Actions>/Place View/Bookmark/AddBook" "<Meta>d")
(gtk_accel_path "<Actions>/Repositories/Bookmark/EditBook" "<Shift><Meta>b")
(gtk_accel_path "<Actions>/Repositories/Bookmark/EditBook" "<Shift><Meta>d")
; (gtk_accel_path "<Actions>/ReportWindow/book" "")
; (gtk_accel_path "<Actions>/FileWindow/FileMenu" "")
(gtk_accel_path "<Actions>/Person View/Backward/Back" "<Alt>Left")
@ -49,7 +49,7 @@
(gtk_accel_path "<Actions>/Place Tree View/ChangeOrder/Add" "<Alt><Meta>i")
; (gtk_accel_path "<Actions>/ReportWindow/number_of_ancestors" "")
(gtk_accel_path "<Actions>/Families/ChangeOrder/Add" "<Alt><Meta>i")
(gtk_accel_path "<Actions>/Person View/Bookmark/EditBook" "<Shift><Meta>b")
(gtk_accel_path "<Actions>/Person View/Bookmark/EditBook" "<Shift><Meta>d")
(gtk_accel_path "<Actions>/Relationships/Bookmark/AddBook" "<Meta>d")
; (gtk_accel_path "<Actions>/ReportWindow/familylines_graph" "")
(gtk_accel_path "<Actions>/Person View/Forward/Forward" "<Alt>Right")
@ -59,9 +59,9 @@
; (gtk_accel_path "<Actions>/ToolWindow/relcalc" "")
(gtk_accel_path "<Actions>/AllMainWindow/Export" "<Meta>e")
(gtk_accel_path "<Actions>/Pedigree/Backward/Back" "<Alt>Left")
(gtk_accel_path "<Actions>/Relationships/Bookmark/EditBook" "<Shift><Meta>b")
(gtk_accel_path "<Actions>/Relationships/Bookmark/EditBook" "<Shift><Meta>d")
; (gtk_accel_path "<Actions>/ToolWindow/reorder_ids" "")
(gtk_accel_path "<Actions>/Place Tree View/Bookmark/EditBook" "<Shift><Meta>b")
(gtk_accel_path "<Actions>/Place Tree View/Bookmark/EditBook" "<Shift><Meta>d")
; (gtk_accel_path "<Actions>/RecentFiles/RecentMenu0" "")
(gtk_accel_path "<Actions>/Person View/PersonAll/Edit" "<Meta>Return")
; (gtk_accel_path "<Actions>/FileWindow/MailingLists" "")
@ -87,7 +87,7 @@
; (gtk_accel_path "<Actions>/ToolWindow/dupfind" "")
; (gtk_accel_path "<Actions>/MainWindow/EditMenu" "")
(gtk_accel_path "<Actions>/UndoHistory/UndoHistory" "<Meta>h")
(gtk_accel_path "<Actions>/Sources/Bookmark/EditBook" "<Shift><Meta>b")
(gtk_accel_path "<Actions>/Sources/Bookmark/EditBook" "<Shift><Meta>d")
; (gtk_accel_path "<Actions>/FileWindow/ReportBug" "")
(gtk_accel_path "<Actions>/AllMainWindow/<CONTROL>Insert" "<Alt><Meta>i")
(gtk_accel_path "<Actions>/Notes/Bookmark/AddBook" "<Meta>d")
@ -117,7 +117,7 @@
(gtk_accel_path "<Actions>/AllMainWindow/<CONTROL>BackSpace" "<Meta>BackSpace")
; (gtk_accel_path "<Actions>/ToolWindow/Utilities" "")
; (gtk_accel_path "<Actions>/AllMainWindow/WindowsMenu" "")
(gtk_accel_path "<Actions>/Families/Bookmark/EditBook" "<Shift><Meta>b")
(gtk_accel_path "<Actions>/Families/Bookmark/EditBook" "<Shift><Meta>d")
; (gtk_accel_path "<Actions>/AllMainWindow/F9" "F9")
; (gtk_accel_path "<Actions>/AllMainWindow/F8" "F8")
; (gtk_accel_path "<Actions>/AllMainWindow/F7" "F7")
@ -127,7 +127,7 @@
; (gtk_accel_path "<Actions>/AllMainWindow/F4" "F4")
; (gtk_accel_path "<Actions>/AllMainWindow/F3" "F3")
; (gtk_accel_path "<Actions>/AllMainWindow/F2" "F2")
(gtk_accel_path "<Actions>/Notes/Bookmark/EditBook" "<Shift><Meta>b")
(gtk_accel_path "<Actions>/Notes/Bookmark/EditBook" "<Shift><Meta>d")
(gtk_accel_path "<Actions>/Sources/ChangeOrder/Add" "<Alt><Meta>i")
; (gtk_accel_path "<Actions>/ReportWindow/Books" "")
; (gtk_accel_path "<Actions>/FileWindow/About" "")
@ -135,7 +135,7 @@
; (gtk_accel_path "<Actions>/ReportWindow/endofline_report" "")
(gtk_accel_path "<Actions>/People Tree View/PersonEdit/Add" "<Alt><Meta>i")
; (gtk_accel_path "<Actions>/ToolWindow/dbrowse" "")
(gtk_accel_path "<Actions>/Pedigree/Bookmark/EditBook" "<Shift><Meta>b")
(gtk_accel_path "<Actions>/Pedigree/Bookmark/EditBook" "<Shift><Meta>d")
; (gtk_accel_path "<Actions>/ToolWindow/soundgen" "")
; (gtk_accel_path "<Actions>/FileWindow/ExtraPlugins" "")
; (gtk_accel_path "<Actions>/AllMainWindow/ReportsMenu" "")
@ -158,7 +158,7 @@
(gtk_accel_path "<Actions>/Notes/ChangeOrder/Add" "<Alt><Meta>i")
; (gtk_accel_path "<Actions>/ReportWindow/calendar" "")
; (gtk_accel_path "<Actions>/FileWindow/Fullscreen" "F11")
(gtk_accel_path "<Actions>/Fan Chart/Bookmark/EditBook" "<Shift><Meta>b")
(gtk_accel_path "<Actions>/Fan Chart/Bookmark/EditBook" "<Shift><Meta>d")
; (gtk_accel_path "<Actions>/ReportWindow/navwebpage" "")
(gtk_accel_path "<Actions>/Repositories/Bookmark/AddBook" "<Meta>d")
(gtk_accel_path "<Actions>/Families/ChangeOrder/Remove" "<Meta>Delete")
@ -170,11 +170,11 @@
; (gtk_accel_path "<Actions>/FileWindow/TipOfDay" "")
(gtk_accel_path "<Actions>/Media/ChangeOrder/Add" "<Alt><Meta>i")
(gtk_accel_path "<Actions>/FileWindow/Quit" "<Meta>q")
(gtk_accel_path "<Actions>/People Tree View/Bookmark/EditBook" "<Shift><Meta>b")
(gtk_accel_path "<Actions>/People Tree View/Bookmark/EditBook" "<Shift><Meta>d")
(gtk_accel_path "<Actions>/Place Tree View/Backward/Back" "<Alt>Left")
(gtk_accel_path "<Actions>/FileWindow/Open" "<Meta>o")
(gtk_accel_path "<Actions>/Place View/Bookmark/EditBook" "<Shift><Meta>b")
(gtk_accel_path "<Actions>/Media/Bookmark/EditBook" "<Shift><Meta>b")
(gtk_accel_path "<Actions>/Place View/Bookmark/EditBook" "<Shift><Meta>d")
(gtk_accel_path "<Actions>/Media/Bookmark/EditBook" "<Shift><Meta>d")
(gtk_accel_path "<Actions>/MainWindow/ConfigView" "<Shift><Meta>c")
(gtk_accel_path "<Actions>/People Tree View/Backward/Back" "<Alt>Left")
; (gtk_accel_path "<Actions>/FileWindow/KeyBindings" "")

View File

@ -542,7 +542,6 @@ gramps/plugins/db/bsddb/upgrade.py
gramps/plugins/db/bsddb/write.py
gramps/plugins/db/dbapi/inmemorydb.gpr.py
gramps/plugins/db/dbapi/inmemorydb.py
gramps/plugins/db/dummydb.gpr.py
gramps/plugins/docgen/asciidoc.py
gramps/plugins/docgen/docgen.gpr.py
gramps/plugins/docgen/gtkprint.glade

796
po/cs.po

File diff suppressed because it is too large Load Diff

6866
po/hu.po

File diff suppressed because it is too large Load Diff

981
po/ru.po

File diff suppressed because it is too large Load Diff

12515
po/sv.po

File diff suppressed because it is too large Load Diff

View File

@ -10,48 +10,49 @@ FMT="txt"
TOP_DIR=`dirname $PWD`
TEST_DIR=$TOP_DIR/test
SRC_DIR=$TOP_DIR/src
PRG="python gramps.py"
SRC_DIR=$TOP_DIR
PRG="python3 Gramps.py"
EXAMPLE_XML=$TOP_DIR/example/gramps/example.gramps
EXAMPLE_GED=$TOP_DIR/example/gedcom/sample.ged
REP_DIR=$TEST_DIR/reports/$REP
mkdir -p $REP_DIR
DATA_DIR=$TEST_DIR/data
mkdir -p $DATA_DIR
if [ -f $DATA_DIR/example.grdb ]; then
rm $DATA_DIR/example.grdb
if [ -f $DATA_DIR/example.gramps ]; then
rm $DATA_DIR/example.gramps
fi
echo ""
echo "+--------------------------------------------------------------"
echo "| Import XML, write GRDB"
echo "| Import XML, write .gramps"
echo "+--------------------------------------------------------------"
OPTS="-i $EXAMPLE_XML -o $DATA_DIR/example.grdb"
OPTS="-i $EXAMPLE_XML -e $DATA_DIR/example.gramps"
(cd $SRC_DIR; $PRG $OPTS)
OPTS="-O $DATA_DIR/example.grdb"
OPTS="-i $DATA_DIR/example.gramps"
echo ""
echo "+--------------------------------------------------------------"
echo "| Export Test Files"
echo "| Text Report: "$REP
echo "| Text Format: "$FMT
echo "+--------------------------------------------------------------"
for desref in {0,1}; do
for incphotos in {0,1}; do
for omitda in {0,1}; do
for incsources in {0,1}; do
for usenick in {0,1}; do
for fulldates in {0,1}; do
for incnotes in {0,1}; do
for repplace in {0,1}; do
for repdate in {0,1}; do
for computeage in {0,1}; do
for incnames in {0,1}; do
for incevents in {0,1}; do
for listc in {0,1}; do
output="$desref$incphotos$omitda$incsources$usenick$fulldates$incnotes$repplace$repdate$computeage$incnames$incevents$listc"
action="-a report -p name=$REP,id=I44,off=$FMT,of=$REP_DIR/$output.$FMT,desref=$desref,incphotos=$incphotos,omitda=$omitda,incsources=$incsources,usenick=$usenick,fulldates=$fulldates,incnotes=$incnotes,repplace=$repplace,repdate=$repdate,computeage=$computeage,incnames=$incnames,incevents=$incevents,listc=$listc"
for desref in 'True' 'False'; do
for incphotos in 'True' 'False'; do
for omitda in 'True' 'False'; do
for incsources in 'True' 'False'; do
for fulldates in 'True' 'False'; do
for incnotes in 'True' 'False'; do
for repplace in 'True' 'False'; do
for repdate in 'True' 'False'; do
for computeage in 'True' 'False'; do
for incnames in 'True' 'False'; do
for incevents in 'True' 'False'; do
for listc in 'True' 'False'; do
output="$desref$incphotos$omitda$incsources$fulldates$incnotes$repplace$repdate$computeage$incnames$incevents$listc"
action="-a report -p name=$REP,off=$FMT,of=$REP_DIR/$output.$FMT,desref=$desref,incphotos=$incphotos,omitda=$omitda,incsources=$incsources,fulldates=$fulldates,incnotes=$incnotes,repplace=$repplace,repdate=$repdate,computeage=$computeage,incnames=$incnames,incevents=$incevents,listc=$listc"
(cd $SRC_DIR; $PRG $OPTS $action)
done
done
@ -65,4 +66,20 @@ done
done
done
done
done
echo "+--------------------------------------------------------------"
echo "| Export file based on sample.ged"
echo "| Text Report: "$REP
echo "| Text Format: "$FMT
echo "+--------------------------------------------------------------"
(cd $SRC_DIR; $PRG -i $EXAMPLE_GED -e $DATA_DIR/example.gramps)
output="NoChildren"
action="-a report -p name=$REP,off=$FMT,of=$REP_DIR/$output.$FMT,listc=False,listc_spouses=False"
(cd $SRC_DIR; $PRG $OPTS $action)
output="ChildrenNoSpouse"
action="-a report -p name=$REP,off=$FMT,of=$REP_DIR/$output.$FMT,listc=True,listc_spouses=False"
(cd $SRC_DIR; $PRG $OPTS $action)
output="ChildrenSpouse"
action="-a report -p name=$REP,off=$FMT,of=$REP_DIR/$output.$FMT,listc=True,listc_spouses=True"
(cd $SRC_DIR; $PRG $OPTS $action)

View File

@ -5,55 +5,55 @@
# $Id$
REP="det_ancestor_report"
REP="det_descendant_report"
FMT="txt"
TOP_DIR=`dirname $PWD`
TEST_DIR=$TOP_DIR/test
SRC_DIR=$TOP_DIR/src
PRG="python gramps.py"
SRC_DIR=$TOP_DIR
PRG="python3 Gramps.py"
EXAMPLE_XML=$TOP_DIR/example/gramps/example.gramps
EXAMPLE_GED=$TOP_DIR/example/gedcom/sample.ged
REP_DIR=$TEST_DIR/reports/$REP
mkdir -p $REP_DIR
DATA_DIR=$TEST_DIR/data
mkdir -p $DATA_DIR
if [ -f $DATA_DIR/example.grdb ]; then
rm $DATA_DIR/example.grdb
if [ -f $DATA_DIR/example.gramps ]; then
rm $DATA_DIR/example.gramps
fi
echo ""
echo "+--------------------------------------------------------------"
echo "| Import XML, write GRDB"
echo "| Import XML, write .gramps"
echo "+--------------------------------------------------------------"
OPTS="-i $EXAMPLE_XML -o $DATA_DIR/example.grdb"
(cd $SRC_DIR; $PRG $OPTS)
OPTS="-i $EXAMPLE_XML -e $DATA_DIR/example.gramps"
#(cd $SRC_DIR; $PRG $OPTS)
OPTS="-O $DATA_DIR/example.grdb"
OPTS="-i $DATA_DIR/example.gramps"
echo ""
echo "+--------------------------------------------------------------"
echo "| Export Test Files"
echo "| Text Report: "$REP
echo "| Text Format: "$FMT
echo "+--------------------------------------------------------------"
for desref in {0,1}; do
for incphotos in {0,1}; do
for omitda in {0,1}; do
for incsources in {0,1}; do
for usenick in {0,1}; do
for fulldates in {0,1}; do
for incnotes in {0,1}; do
for repplace in {0,1}; do
for repdate in {0,1}; do
for computeage in {0,1}; do
for incnames in {0,1}; do
for incevents in {0,1}; do
for listc in {0,1}; do
for desref in 'True' 'False'; do
for incphotos in 'True' 'False'; do
for omitda in 'True' 'False'; do
for incsources in 'True' 'False'; do
for fulldates in 'True' 'False'; do
for incnotes in 'True' 'False'; do
for repplace in 'True' 'False'; do
for repdate in 'True' 'False'; do
for computeage in 'True' 'False'; do
for incnames in 'True' 'False'; do
for incevents in 'True' 'False'; do
for listc in 'True' 'False'; do
output="$desref$incphotos$omitda$incsources$usenick$fulldates$incnotes$repplace$repdate$computeage$incnames$incevents$listc"
action="-a report -p name=$REP,id=I44,off=$FMT,of=$REP_DIR/$output.$FMT,desref=$desref,incphotos=$incphotos,omitda=$omitda,incsources=$incsources,usenick=$usenick,fulldates=$fulldates,incnotes=$incnotes,repplace=$repplace,repdate=$repdate,computeage=$computeage,incnames=$incnames,incevents=$incevents,listc=$listc"
(cd $SRC_DIR; $PRG $OPTS $action)
done
action="-a report -p name=$REP,off=$FMT,of=$REP_DIR/$output.$FMT,desref=$desref,incphotos=$incphotos,omitda=$omitda,incsources=$incsources,fulldates=$fulldates,incnotes=$incnotes,repplace=$repplace,repdate=$repdate,computeage=$computeage,incnames=$incnames,incevents=$incevents,listc=$listc"
#(cd $SRC_DIR; $PRG $OPTS $action)
done
done
done
@ -66,3 +66,14 @@ done
done
done
done
(cd $SRC_DIR; $PRG -i $EXAMPLE_GED -e $DATA_DIR/example.gramps)
output="NoChildren"
action="-a report -p name=$REP,off=$FMT,of=$REP_DIR/$output.$FMT,listc=False,listc_spouses=False"
(cd $SRC_DIR; $PRG $OPTS $action)
output="ChildrenNoSpouse"
action="-a report -p name=$REP,off=$FMT,of=$REP_DIR/$output.$FMT,listc=True,listc_spouses=False"
(cd $SRC_DIR; $PRG $OPTS $action)
output="ChildrenSpouse"
action="-a report -p name=$REP,off=$FMT,of=$REP_DIR/$output.$FMT,listc=True,listc_spouses=True"
(cd $SRC_DIR; $PRG $OPTS $action)