Merge branch 'gramps50'

This commit is contained in:
Nick Hall 2018-02-09 00:13:43 +00:00
commit 19f8c3561c
88 changed files with 2065 additions and 903 deletions

View File

@ -288,10 +288,6 @@ table.infolist thead tr th {
table.infolist tr td {
border-bottom: dashed 1px #000;
vertical-align: middle;
padding: 6px 0 6px 10px;
}
table.infolist tr td a {
display: block;
}
table.infolist tr.BeginLetter td, table.infolist tr.BeginSurname td {
border-top: solid 1px #000;
@ -351,15 +347,15 @@ div#Individuals {
margin: 0;
padding: 0;
}
div#Individuals table.individuallist {
div#Individuals table.IndividualList {
border-bottom: solid 1px #000;
}
div#Individuals table.individuallist tbody tr td.ColumnSurname a:hover,
div#Individuals table.individuallist tbody tr td.ColumnSurname a:active {
div#Individuals table.IndividualList tbody tr td.ColumnSurname a:hover,
div#Individuals table.IndividualList tbody tr td.ColumnSurname a:active {
cursor: default;
background: none;
}
div#Individuals table.individuallist tbody tr td.ColumnName a {
div#Individuals table.IndividualList tbody tr td.ColumnName a {
vertical-align: middle;
}
div#Individuals div table.infolist tr td p {
@ -1129,9 +1125,10 @@ div.narrative {
}
.narrative p {
font: normal .9em/1.4em sans-serif;
margin-top: .5em;
margin-bottom: 0;
padding: 0 20px 1em 20px;
margin: 0.1em 0 0.2em 0;
}
i + div.grampsstylednote p {
margin: 0.1em 0 0.2em 0;
}
/* Subsections : References

View File

@ -276,7 +276,6 @@ table.infolist tr th a:hover {
table.infolist tr td {
font:normal 1.1em/1.4em serif;
vertical-align:middle;
padding:.1em 10px;
}
table.infolist tr td a {
display:block;
@ -396,30 +395,30 @@ table.surname thead tr th.ColumnParents, table.surname tbody tr td.ColumnParents
/* Individuals
----------------------------------------------------- */
#Individuals { }
#Individuals table.individuallist {
#Individuals table.IndividualList {
border-bottom:solid 1px #A97;
}
#Individuals table.individuallist tbody tr td {
#Individuals table.IndividualList tbody tr td {
border-bottom:dashed 1px #C1B398;
}
#Individuals table.individuallist tbody tr td a:hover {
#Individuals table.IndividualList tbody tr td a:hover {
text-decoration:none;
}
table.individuallist tbody tr td.ColumnSurname a:hover, table.individuallist tbody tr td.ColumnSurname a:active {
table.IndividualList tbody tr td.ColumnSurname a:hover, table.IndividualList tbody tr td.ColumnSurname a:active {
cursor:default;
color:black;
background:none;
}
table.individuallist tbody tr td.ColumnName {
table.IndividualList tbody tr td.ColumnName {
padding:0;
background-color:#FFF;
}
table.individuallist tbody tr td.ColumnName a {
table.IndividualList tbody tr td.ColumnName a {
display:block;
padding:.6em 10px;
padding:.1em .1em;
vertical-align:middle;
}
table.individuallist tbody tr td.ColumnName a:hover {
table.IndividualList tbody tr td.ColumnName a:hover {
background-color:#C1B398;
}
#Individuals div table.infolist tr td p {
@ -960,11 +959,12 @@ div#Addresses table.infolist tr td a, div#Addresses table.infolist tr td p a {
div.narrative {
padding-bottom:0;
}
i + div.grampsstylednote p {
margin: 0.1em 0 0.2em 0;
}
.narrative p {
margin: 0.1em 0 0.2em 0;
font:normal .9em/1.4em sans-serif;
margin-top:.5em;
margin-bottom:0;
padding:0 20px 1em 20px;
}
/* Subsections : References

View File

@ -454,30 +454,30 @@ div#Individuals {
margin: 0;
padding: 0;
}
div#Individuals table.individuallist {
div#Individuals table.IndividualList {
border-bottom: solid 1px #5D835F;
}
div#Individuals table.individuallist tbody tr td {
div#Individuals table.IndividualList tbody tr td {
border-bottom: dashed 1px #5D835F;
background-color: #D8F3D6;
}
div#Individuals table.individuallist tbody tr td a {
div#Individuals table.IndividualList tbody tr td a {
display: block;
padding: .6em 10px;
}
div#Individuals table.individuallist tbody tr td.ColumnSurname a:hover,
div#Individuals table.individuallist tbody tr td.ColumnSurname a:active {
div#Individuals table.IndividualList tbody tr td.ColumnSurname a:hover,
div#Individuals table.IndividualList tbody tr td.ColumnSurname a:active {
cursor:default;
color: #000;
background:none;
}
div#Individuals table.individuallist tbody tr td.ColumnName {
div#Individuals table.IndividualList tbody tr td.ColumnName {
background-color: #FFF;
}
div#Individuals table.individuallist tbody tr td.ColumnName a {
div#Individuals table.IndividualList tbody tr td.ColumnName a {
vertical-align:middle;
}
div#Individuals table.individuallist tbody tr td.ColumnPartner {
div#Individuals table.IndividualList tbody tr td.ColumnPartner {
background-color: #FFF;
}
div#Individuals div table.infolist tr td p {

View File

@ -33,7 +33,9 @@ body#FamilyMap {
border: solid 4px #000;
margin: 0px auto;
width: 800px;
height: 800px;
height: 400px;
max-width: 90%;
max-height: 90%;
}
/* Place Maps
@ -43,6 +45,8 @@ div#place_canvas {
border: solid 4px #000;
width: 500px;
height: 400px;
max-width: 90%;
max-height: 90%;
}
button#drop {
background-color: purple;

View File

@ -318,6 +318,7 @@ class CLIManager:
and self.dbstate.db.get_total() == 0):
self.dbstate.db.set_researcher(owner)
name_displayer.clear_custom_formats()
name_displayer.set_name_format(self.dbstate.db.name_formats)
fmt_default = config.get('preferences.name-format')
name_displayer.set_default_format(fmt_default)

View File

@ -47,7 +47,8 @@ LOG = logging.getLogger(".")
#-------------------------------------------------------------------------
from gramps.gen.plug import BasePluginManager
from gramps.gen.plug.docgen import (StyleSheet, StyleSheetList, PaperStyle,
PAPER_PORTRAIT, PAPER_LANDSCAPE, graphdoc)
PAPER_PORTRAIT, PAPER_LANDSCAPE, graphdoc,
treedoc)
from gramps.gen.plug.menu import (FamilyOption, PersonOption, NoteOption,
MediaOption, PersonListOption, NumberOption,
BooleanOption, DestinationOption, Option,
@ -56,8 +57,8 @@ from gramps.gen.plug.menu import (FamilyOption, PersonOption, NoteOption,
from gramps.gen.display.name import displayer as name_displayer
from gramps.gen.errors import ReportError, FilterError
from gramps.gen.plug.report import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_BOOK,
CATEGORY_GRAPHVIZ, CATEGORY_CODE,
ReportOptions, append_styles)
CATEGORY_GRAPHVIZ, CATEGORY_TREE,
CATEGORY_CODE, ReportOptions, append_styles)
from gramps.gen.plug.report._paper import paper_sizes
from gramps.gen.const import USER_HOME, DOCGEN_OPTIONS
from gramps.gen.dbstate import DbState
@ -250,6 +251,15 @@ class CommandLineReport:
if name not in self.option_class.options_dict:
self.option_class.options_dict[
name] = menu.get_option_by_name(name).get_value()
if category == CATEGORY_TREE:
# Need to include Genealogy Tree options
self.__toptions = treedoc.TreeOptions()
menu = self.option_class.menu
self.__toptions.add_menu_options(menu)
for name in menu.get_all_option_names():
if name not in self.option_class.options_dict:
self.option_class.options_dict[
name] = menu.get_option_by_name(name).get_value()
self.option_class.load_previous_values()
_validate_options(self.option_class, database)
self.show = options_str_dict.pop('show', None)
@ -320,6 +330,10 @@ class CommandLineReport:
for graph_format in graphdoc.FORMATS:
self.options_help['off'][2].append(
graph_format["type"] + "\t" + graph_format["descr"])
elif self.category == CATEGORY_TREE:
for tree_format in treedoc.FORMATS:
self.options_help['off'][2].append(
tree_format["type"] + "\t" + tree_format["descr"])
else:
self.options_help['off'][2] = "NA"
@ -498,6 +512,15 @@ class CommandLineReport:
# Pick the first one as the default.
self.format = graphdoc.FORMATS[0]["class"]
_chosen_format = graphdoc.FORMATS[0]["type"]
elif self.category == CATEGORY_TREE:
for tree_format in treedoc.FORMATS:
if tree_format['type'] == self.options_dict['off']:
if not self.format: # choose the first one, not the last
self.format = tree_format["class"]
if self.format is None:
# Pick the first one as the default.
self.format = tree_format.FORMATS[0]["class"]
_chosen_format = tree_format.FORMATS[0]["type"]
else:
self.format = None
if _chosen_format and _format_str:
@ -665,7 +688,7 @@ def cl_report(database, name, category, report_class, options_class,
clr.selected_style,
PaperStyle(clr.paper, clr.orien, clr.marginl,
clr.marginr, clr.margint, clr.marginb))
elif category == CATEGORY_GRAPHVIZ:
elif category in [CATEGORY_GRAPHVIZ, CATEGORY_TREE]:
clr.option_class.handler.doc = clr.format(
clr.option_class,
PaperStyle(clr.paper, clr.orien, clr.marginl,

View File

@ -274,22 +274,25 @@ register('preferences.last-view', '')
register('preferences.last-views', [])
register('preferences.family-relation-type', 3) # UNKNOWN
register('preferences.age-display-precision', 1)
register('preferences.color-gender-male-alive', '#b8cee6')
register('preferences.color-gender-male-death', '#b8cee6')
register('preferences.color-gender-female-alive', '#feccf0')
register('preferences.color-gender-female-death', '#feccf0')
register('preferences.color-gender-unknown-alive', '#f3dbb6')
register('preferences.color-gender-unknown-death', '#f3dbb6')
#register('preferences.color-gender-other-alive', '#fcaf3e')
#register('preferences.color-gender-other-death', '#fcaf3e')
register('preferences.bordercolor-gender-male-alive', '#1f4986')
register('preferences.bordercolor-gender-male-death', '#000000')
register('preferences.bordercolor-gender-female-alive', '#861f69')
register('preferences.bordercolor-gender-female-death', '#000000')
register('preferences.bordercolor-gender-unknown-alive', '#8e5801')
register('preferences.bordercolor-gender-unknown-death', '#000000')
#register('preferences.bordercolor-gender-other-alive', '#f57900')
#register('preferences.bordercolor-gender-other-death', '#000000')
register('colors.scheme', 0)
register('colors.male-alive', ['#b8cee6', '#1f344a'])
register('colors.male-dead', ['#b8cee6', '#2d3039'])
register('colors.female-alive', ['#feccf0', '#62242D'])
register('colors.female-dead', ['#feccf0', '#3a292b'])
register('colors.unknown-alive', ['#f3dbb6', '#75507B'])
register('colors.unknown-dead', ['#f3dbb6', '#35103b'])
register('colors.family', ['#eeeeee', '#454545'])
register('colors.family-divorced', ['#ffdede', '#5c3636'])
register('colors.home-person', ['#bbe68a', '#304918'])
register('colors.border-male-alive', ['#1f4986', '#171d26'])
register('colors.border-male-dead', ['#000000', '#000000'])
register('colors.border-female-alive', ['#861f69', '#261111'])
register('colors.border-female-dead', ['#000000', '#000000'])
register('colors.border-unknown-alive', ['#8e5801', '#8e5801'])
register('colors.border-unknown-dead', ['#000000', '#000000'])
register('colors.border-family', ['#cccccc', '#252525'])
register('colors.border-family-divorced', ['#ff7373', '#720b0b'])
register('researcher.researcher-addr', '')
register('researcher.researcher-locality', '')

View File

@ -292,7 +292,7 @@ class DateDisplayDE(DateDisplay):
)
# this definition must agree with its "_display_gregorian" method
def _display_gregorian(self, date_val):
def _display_gregorian(self, date_val, **kwargs):
"""
display gregorian calendar date in different format
"""

View File

@ -155,7 +155,7 @@ class DateDisplayEL(DateDisplay):
)
# this definition must agree with its "_display_gregorian" method
def _display_gregorian(self, date_val):
def _display_gregorian(self, date_val, **kwargs):
"""
display gregorian calendar date in different format
"""

View File

@ -187,7 +187,7 @@ class DateDisplayLT(DateDisplay):
"mmmm m. mėnesio diena d.", "Mėn diena, metai")
# this definition must agree with its "_display_gregorian" method
def _display_gregorian(self, date_val):
def _display_gregorian(self, date_val, **kwargs):
"""
display gregorian calendar date in different format
"""

View File

@ -164,7 +164,7 @@ class DateDisplayNL(DateDisplay):
)
# this definition must agree with its "_display_gregorian" method
def _display_gregorian(self, date_val):
def _display_gregorian(self, date_val, **kwargs):
"""
display gregorian calendar date in different format
"""

View File

@ -215,7 +215,7 @@ class DateDisplayPL(DateDisplay):
"XII"
)
def _display_gregorian(self, date_val):
def _display_gregorian(self, date_val, **kwargs):
"""
display gregorian calendar date in different format
"""

View File

@ -240,7 +240,7 @@ class DateDisplaySR_Base(DateDisplay):
"VII", "VIII", "IX", "X", "XI", "XII"
)
def _display_gregorian(self, date_val):
def _display_gregorian(self, date_val, **kwargs):
"""
display gregorian calendar date in different format
"""

View File

@ -418,6 +418,11 @@ class NameDisplay:
result = raw_data[_FIRSTNAME]
return ' '.join(result.split())
def clear_custom_formats(self):
self.name_formats = {num: value
for num, value in self.name_formats.items()
if num >= 0}
def set_name_format(self, formats):
raw_func_dict = {

View File

@ -82,7 +82,8 @@ class IsDescendantFamilyOf(Rule):
while expand:
person = expand.pop(0)
if person is None:
if person is None or person.handle in self.matches:
# if we have been here before, skip
continue
self.matches.add(person.handle)
for family_handle in person.get_family_handle_list():

View File

@ -67,7 +67,8 @@ class IsDescendantOf(Rule):
return person.handle in self.map
def init_list(self, person, first):
if not person:
if not person or person.handle in self.map:
# if we have been here before, skip
return
if not first:
self.map.add(person.handle)

View File

@ -61,6 +61,9 @@ class IsLessThanNthGenerationAncestorOf(Rule):
queue = [(root_handle, 1)] # generation 1 is root
while queue:
handle, gen = queue.pop(0) # pop off front of queue
if handle in self.map:
# if we have been here before, skip
continue
self.map.add(handle)
gen += 1
if gen <= int(self.list[1]):

View File

@ -71,7 +71,8 @@ class IsLessThanNthGenerationAncestorOfBookmarked(Rule):
def init_ancestor_list(self, handle, gen):
# if p.get_handle() in self.map:
# loop_error(self.orig,p)
if not handle:
if not handle or handle in self.map:
# if been here already, skip
return
if gen:
self.map.add(handle)

View File

@ -64,7 +64,8 @@ class IsLessThanNthGenerationAncestorOfDefaultPerson(Rule):
def init_ancestor_list(self, handle, gen):
# if p.get_handle() in self.map:
# loop_error(self.orig,p)
if not handle:
if not handle or handle in self.map:
# if we have been here before, skip
return
if gen:
self.map.add(handle)

View File

@ -65,7 +65,8 @@ class IsLessThanNthGenerationDescendantOf(Rule):
return person.handle in self.map
def init_list(self,person,gen):
if not person:
if not person or person.handle in self.map:
# if we have been here before, skip
return
if gen:
self.map.add(person.handle)

View File

@ -27,7 +27,7 @@ The "plug" package for handling plugins in Gramps.
from ._plugin import Plugin
from ._pluginreg import (PluginData, PluginRegister, REPORT, TOOL,
CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE,
CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ,
CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ, CATEGORY_TREE,
TOOL_DEBUG, TOOL_ANAL, TOOL_DBPROC, TOOL_DBFIX, TOOL_REVCTL,
TOOL_UTILS, CATEGORY_QR_MISC, CATEGORY_QR_PERSON,
CATEGORY_QR_FAMILY, CATEGORY_QR_EVENT, CATEGORY_QR_SOURCE,
@ -46,14 +46,14 @@ from ._options import (Options, OptionListCollection, OptionList,
OptionHandler, MenuOptions)
__all__ = [ "docbackend", "docgen", "menu", "Plugin", "PluginData",
"PluginRegister", "BasePluginManager",
"ImportPlugin", "ExportPlugin", "DocGenPlugin",
"REPORT", "TOOL", "CATEGORY_TEXT", "CATEGORY_DRAW", "CATEGORY_CODE",
"CATEGORY_WEB", "CATEGORY_BOOK", "CATEGORY_GRAPHVIZ",
"TOOL_DEBUG", "TOOL_ANAL", "TOOL_DBPROC", "TOOL_DBFIX", "TOOL_REVCTL",
"TOOL_UTILS", "CATEGORY_QR_MISC", "CATEGORY_QR_PERSON",
"CATEGORY_QR_FAMILY", "CATEGORY_QR_EVENT", "CATEGORY_QR_SOURCE",
"CATEGORY_QR_PLACE", "CATEGORY_QR_REPOSITORY", "CATEGORY_QR_NOTE",
"CATEGORY_QR_DATE", "PTYPE_STR", "CATEGORY_QR_MEDIA",
"CATEGORY_QR_CITATION", "CATEGORY_QR_SOURCE_OR_CITATION",
"START", "END", "make_environment"]
"PluginRegister", "BasePluginManager", "ImportPlugin",
"ExportPlugin", "DocGenPlugin", "REPORT", "TOOL", "CATEGORY_TEXT",
"CATEGORY_DRAW", "CATEGORY_CODE", "CATEGORY_WEB", "CATEGORY_BOOK",
"CATEGORY_GRAPHVIZ", "CATEGORY_TREE", "TOOL_DEBUG", "TOOL_ANAL",
"TOOL_DBPROC", "TOOL_DBFIX", "TOOL_REVCTL","TOOL_UTILS",
"CATEGORY_QR_MISC", "CATEGORY_QR_PERSON", "CATEGORY_QR_FAMILY",
"CATEGORY_QR_EVENT", "CATEGORY_QR_SOURCE", "CATEGORY_QR_PLACE",
"CATEGORY_QR_REPOSITORY", "CATEGORY_QR_NOTE", "CATEGORY_QR_DATE",
"PTYPE_STR", "CATEGORY_QR_MEDIA", "CATEGORY_QR_CITATION",
"CATEGORY_QR_SOURCE_OR_CITATION", "START", "END",
"make_environment"]

View File

@ -97,8 +97,10 @@ CATEGORY_CODE = 2
CATEGORY_WEB = 3
CATEGORY_BOOK = 4
CATEGORY_GRAPHVIZ = 5
CATEGORY_TREE = 6
REPORT_CAT = [ CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE,
CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ]
CATEGORY_WEB, CATEGORY_BOOK, CATEGORY_GRAPHVIZ,
CATEGORY_TREE]
#possible tool categories
TOOL_DEBUG = -1
TOOL_ANAL = 0
@ -1043,6 +1045,7 @@ def make_environment(**kwargs):
'CATEGORY_WEB': CATEGORY_WEB,
'CATEGORY_BOOK': CATEGORY_BOOK,
'CATEGORY_GRAPHVIZ': CATEGORY_GRAPHVIZ,
'CATEGORY_TREE': CATEGORY_TREE,
'TOOL_DEBUG': TOOL_DEBUG,
'TOOL_ANAL': TOOL_ANAL,
'TOOL_DBPROC': TOOL_DBPROC,
@ -1242,8 +1245,7 @@ class PluginRegister:
"""
Return a list of :class:`PluginData` that are of type ptype
"""
return [self.get_plugin(id) for id in
set([x.id for x in self.__plugindata if x.ptype == ptype])]
return [x for x in self.__plugindata if x.ptype == ptype]
def report_plugins(self, gui=True):
"""
@ -1352,6 +1354,4 @@ class PluginRegister:
"""
Return a list of :class:`PluginData` that have load_on_reg == True
"""
return [self.get_plugin(id) for id in
set([x.id for x in self.__plugindata
if x.load_on_reg == True])]
return [x for x in self.__plugindata if x.load_on_reg == True]

View File

@ -37,3 +37,4 @@ from .textdoc import TextDoc, IndexMark,INDEX_TYPE_ALP, INDEX_TYPE_TOC,\
URL_PATTERN, LOCAL_HYPERLINK, LOCAL_TARGET
from .drawdoc import DrawDoc
from .graphdoc import GVDoc
from .treedoc import TreeDoc

View File

@ -0,0 +1,633 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2017-2018 Nick Hall
#
# 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.
#
""" LaTeX Genealogy Tree adapter for Trees """
#-------------------------------------------------------------------------
#
# Standard Python modules
#
#-------------------------------------------------------------------------
from abc import ABCMeta, abstractmethod
import os
import shutil
from io import StringIO
import tempfile
import logging
#-------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------
from ...utils.file import search_for
from ...lib import Person, EventType, EventRoleType, Date
from ...display.place import displayer as _pd
from ...utils.file import media_path_full
from . import BaseDoc, PAPER_PORTRAIT
from ..menu import NumberOption, TextOption, EnumeratedListOption
from ...constfunc import win
from ...config import config
from ...const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
#-------------------------------------------------------------------------
#
# set up logging
#
#-------------------------------------------------------------------------
LOG = logging.getLogger(".treedoc")
#-------------------------------------------------------------------------
#
# Private Constants
#
#-------------------------------------------------------------------------
_DETAIL = [{'name': _("Full"), 'value': "full"},
{'name': _("Medium"), 'value': "medium"},
{'name': _("Short"), 'value': "short"}]
_MARRIAGE = [{'name': _("Default"), 'value': ""},
{'name': _("Above"), 'value': "marriage above"},
{'name': _("Below"), 'value': "marriage below"},
{'name': _("Not shown"), 'value': "no marriage"}]
_COLOR = [{'name': _("None"), 'value': "none"},
{'name': _("Default"), 'value': "default"},
{'name': _("Preferences"), 'value': "preferences"}]
_TIMEFLOW = [{'name': _("Down (↓)"), 'value': ""},
{'name': _("Up (↑)"), 'value': "up"},
{'name': _("Right (→)"), 'value': "right"},
{'name': _("Left (←)"), 'value': "left"}]
_EDGES = [{'name': _("Perpendicular"), 'value': ""},
{'name': _("Rounded"), 'value': "rounded", },
{'name': _("Swing"), 'value': "swing", },
{'name': _("Mesh"), 'value': 'mesh'}]
_NOTELOC = [{'name': _("Top"), 'value': "t"},
{'name': _("Bottom"), 'value': "b"}]
_NOTESIZE = [{'name': _("Tiny"), 'value': "tiny"},
{'name': _("Script"), 'value': "scriptsize"},
{'name': _("Footnote"), 'value': "footnotesize"},
{'name': _("Small"), 'value': "small"},
{'name': _("Normal"), 'value': "normalsize"},
{'name': _("Large"), 'value': "large"},
{'name': _("Very large"), 'value': "Large"},
{'name': _("Extra large"), 'value': "LARGE"},
{'name': _("Huge"), 'value': "huge"},
{'name': _("Extra huge"), 'value': "Huge"}]
if win():
_LATEX_FOUND = search_for("lualatex.exe")
else:
_LATEX_FOUND = search_for("lualatex")
#------------------------------------------------------------------------------
#
# TreeOptions
#
#------------------------------------------------------------------------------
class TreeOptions:
"""
Defines all of the controls necessary
to configure the genealogy tree reports.
"""
def add_menu_options(self, menu):
"""
Add all graph related options to the menu.
:param menu: The menu the options should be added to.
:type menu: :class:`.Menu`
:return: nothing
"""
################################
category = _("Node Options")
################################
detail = EnumeratedListOption(_("Node detail"), "full")
for item in _DETAIL:
detail.add_item(item["value"], item["name"])
detail.set_help(_("Detail of information to be shown in a node."))
menu.add_option(category, "detail", detail)
marriage = EnumeratedListOption(_("Marriage"), "")
for item in _MARRIAGE:
marriage.add_item(item["value"], item["name"])
marriage.set_help(_("Position of marriage information."))
menu.add_option(category, "marriage", marriage)
nodesize = NumberOption(_("Node size"), 25, 5, 100, 5)
nodesize.set_help(_("One dimension of a node, in mm. If the timeflow "
"is up or down then this is the width, otherwise "
"it is the height."))
menu.add_option(category, "nodesize", nodesize)
levelsize = NumberOption(_("Level size"), 35, 5, 100, 5)
levelsize.set_help(_("One dimension of a node, in mm. If the timeflow "
"is up or down then this is the height, otherwise "
"it is the width."))
menu.add_option(category, "levelsize", levelsize)
nodecolor = EnumeratedListOption(_("Color"), "none")
for item in _COLOR:
nodecolor.add_item(item["value"], item["name"])
nodecolor.set_help(_("Node color."))
menu.add_option(category, "nodecolor", nodecolor)
################################
category = _("Tree Options")
################################
timeflow = EnumeratedListOption(_("Timeflow"), "")
for item in _TIMEFLOW:
timeflow.add_item(item["value"], item["name"])
timeflow.set_help(_("Direction that the graph will grow over time."))
menu.add_option(category, "timeflow", timeflow)
edges = EnumeratedListOption(_("Edge style"), "")
for item in _EDGES:
edges.add_item(item["value"], item["name"])
edges.set_help(_("Style of the edges between nodes."))
menu.add_option(category, "edges", edges)
leveldist = NumberOption(_("Level distance"), 5, 1, 20, 1)
leveldist.set_help(_("The minimum amount of free space, in mm, "
"between levels. For vertical graphs, this "
"corresponds to spacing between rows. For "
"horizontal graphs, this corresponds to spacing "
"between columns."))
menu.add_option(category, "leveldist", leveldist)
################################
category = _("Note")
################################
note = TextOption(_("Note to add to the tree"), [""])
note.set_help(_("This text will be added to the tree."))
menu.add_option(category, "note", note)
noteloc = EnumeratedListOption(_("Note location"), 't')
for item in _NOTELOC:
noteloc.add_item(item["value"], item["name"])
noteloc.set_help(_("Whether note will appear on top "
"or bottom of the page."))
menu.add_option(category, "noteloc", noteloc)
notesize = EnumeratedListOption(_("Note size"), 'normalsize')
for item in _NOTESIZE:
notesize.add_item(item["value"], item["name"])
notesize.set_help(_("The size of note text."))
menu.add_option(category, "notesize", notesize)
#------------------------------------------------------------------------------
#
# TreeDoc
#
#------------------------------------------------------------------------------
class TreeDoc(metaclass=ABCMeta):
"""
Abstract Interface for genealogy tree document generators. Output formats
for genealogy tree reports must implement this interface to be used by the
report system.
"""
@abstractmethod
def start_tree(self, option_list):
"""
Write the start of a tree.
"""
@abstractmethod
def end_tree(self):
"""
Write the end of a tree.
"""
@abstractmethod
def start_subgraph(self, level, subgraph_type, family, option_list=None):
"""
Write the start of a subgraph.
"""
@abstractmethod
def end_subgraph(self, level):
"""
Write the end of a subgraph.
"""
@abstractmethod
def write_node(self, db, level, node_type, person, marriage_flag,
option_list=None):
"""
Write the contents of a node.
"""
#------------------------------------------------------------------------------
#
# TreeDocBase
#
#------------------------------------------------------------------------------
class TreeDocBase(BaseDoc, TreeDoc):
"""
Base document generator for all Graphviz document generators. Classes that
inherit from this class will only need to implement the close function.
The close function will generate the actual file of the appropriate type.
"""
def __init__(self, options, paper_style):
BaseDoc.__init__(self, None, paper_style)
self._filename = None
self._tex = StringIO()
self._paper = paper_style
get_option = options.menu.get_option_by_name
self.detail = get_option('detail').get_value()
self.marriage = get_option('marriage').get_value()
self.nodesize = get_option('nodesize').get_value()
self.levelsize = get_option('levelsize').get_value()
self.nodecolor = get_option('nodecolor').get_value()
self.timeflow = get_option('timeflow').get_value()
self.edges = get_option('edges').get_value()
self.leveldist = get_option('leveldist').get_value()
self.note = get_option('note').get_value()
self.noteloc = get_option('noteloc').get_value()
self.notesize = get_option('notesize').get_value()
def write_start(self):
"""
Write the start of the document.
"""
paper_size = self._paper.get_size()
name = paper_size.get_name().lower()
if name == 'custom size':
width = str(paper_size.get_width())
height = str(paper_size.get_width())
paper = 'papersize={%scm,%scm}' % (width, height)
elif name in ('a', 'b', 'c', 'd', 'e'):
paper = 'ansi' + name + 'paper'
else:
paper = name + 'paper'
if self._paper.get_orientation() == PAPER_PORTRAIT:
orientation = 'portrait'
else:
orientation = 'landscape'
lmargin = self._paper.get_left_margin()
rmargin = self._paper.get_right_margin()
tmargin = self._paper.get_top_margin()
bmargin = self._paper.get_bottom_margin()
if lmargin == rmargin == tmargin == bmargin:
margin = 'margin=%scm'% lmargin
else:
if lmargin == rmargin:
margin = 'hmargin=%scm' % lmargin
else:
margin = 'hmargin={%scm,%scm}' % (lmargin, rmargin)
if tmargin == bmargin:
margin += ',vmargin=%scm' % tmargin
else:
margin += ',vmargin={%scm,%scm}' % (tmargin, bmargin)
self.write(0, '\\documentclass[%s]{article}\n' % orientation)
self.write(0, '\\IfFileExists{libertine.sty}{\n')
self.write(0, ' \\usepackage{libertine}\n')
self.write(0, '}{}\n')
self.write(0, '\\usepackage[%s,%s]{geometry}\n' % (paper, margin))
self.write(0, '\\usepackage[all]{genealogytree}\n')
self.write(0, '\\usepackage{color}\n')
self.write(0, '\\begin{document}\n')
if self.nodecolor == 'preferences':
scheme = config.get('colors.scheme')
male_bg = config.get('colors.male-dead')[scheme][1:]
female_bg = config.get('colors.female-dead')[scheme][1:]
neuter_bg = config.get('colors.unknown-dead')[scheme][1:]
self.write(0, '\\definecolor{male-bg}{HTML}{%s}\n' % male_bg)
self.write(0, '\\definecolor{female-bg}{HTML}{%s}\n' % female_bg)
self.write(0, '\\definecolor{neuter-bg}{HTML}{%s}\n' % neuter_bg)
if ''.join(self.note) != '' and self.noteloc == 't':
for line in self.note:
self.write(0, '{\\%s %s}\\par\n' % (self.notesize, line))
self.write(0, '\\bigskip\n')
self.write(0, '\\begin{tikzpicture}\n')
def start_tree(self, option_list):
self.write(0, '\\genealogytree[\n')
self.write(0, 'processing=database,\n')
if self.marriage:
info = self.detail + ' ' + self.marriage
else:
info = self.detail
self.write(0, 'database format=%s,\n' % info)
if self.timeflow:
self.write(0, 'timeflow=%s,\n' % self.timeflow)
if self.edges:
self.write(0, 'edges=%s,\n' % self.edges)
if self.leveldist != 5:
self.write(0, 'level distance=%smm,\n' % self.leveldist)
if self.nodesize != 25:
self.write(0, 'node size=%smm,\n' % self.nodesize)
if self.levelsize != 35:
self.write(0, 'level size=%smm,\n' % self.levelsize)
if self.nodecolor == 'none':
self.write(0, 'tcbset={male/.style={},\n')
self.write(0, ' female/.style={},\n')
self.write(0, ' neuter/.style={}},\n')
if self.nodecolor == 'preferences':
self.write(0, 'tcbset={male/.style={colback=male-bg},\n')
self.write(0, ' female/.style={colback=female-bg},\n')
self.write(0, ' neuter/.style={colback=neuter-bg}},\n')
for option in option_list:
self.write(0, '%s,\n' % option)
self.write(0, ']{\n')
def end_tree(self):
self.write(0, '}\n')
def write_end(self):
"""
Write the end of the document.
"""
self.write(0, '\\end{tikzpicture}\n')
if ''.join(self.note) != '' and self.noteloc == 'b':
self.write(0, '\\bigskip\n')
for line in self.note:
self.write(0, '\\par{\\%s %s}\n' % (self.notesize, line))
self.write(0, '\\end{document}\n')
def start_subgraph(self, level, subgraph_type, family, option_list=None):
options = ['id=%s' % family.gramps_id]
if option_list:
options.extend(option_list)
if subgraph_type == 'sandclock':
self.write(level, 'sandclock{\n')
else:
self.write(level, '%s[%s]{\n' % (subgraph_type, ','.join(options)))
def end_subgraph(self, level):
self.write(level, '}\n')
def write_node(self, db, level, node_type, person, marriage_flag,
option_list=None):
options = ['id=%s' % person.gramps_id]
if option_list:
options.extend(option_list)
self.write(level, '%s[%s]{\n' % (node_type, ','.join(options)))
if person.gender == Person.MALE:
self.write(level+1, 'male,\n')
elif person.gender == Person.FEMALE:
self.write(level+1, 'female,\n')
elif person.gender == Person.UNKNOWN:
self.write(level+1, 'neuter,\n')
name = person.get_primary_name()
nick = name.get_nick_name()
surn = name.get_surname()
name_parts = [self.format_given_names(name),
'\\nick{{{}}}'.format(nick) if nick else '',
'\\surn{{{}}}'.format(surn) if surn else '']
self.write(level+1, 'name = {{{}}},\n'.format(
' '.join([e for e in name_parts if e])))
for eventref in person.get_event_ref_list():
if eventref.role == EventRoleType.PRIMARY:
event = db.get_event_from_handle(eventref.ref)
self.write_event(db, level+1, event)
if marriage_flag:
for handle in person.get_family_handle_list():
family = db.get_family_from_handle(handle)
for eventref in family.get_event_ref_list():
if eventref.role == EventRoleType.FAMILY:
event = db.get_event_from_handle(eventref.ref)
self.write_event(db, level+1, event)
for attr in person.get_attribute_list():
if str(attr.get_type()) == 'Occupation':
self.write(level+1, 'profession = {%s},\n' % attr.get_value())
if str(attr.get_type()) == 'Comment':
self.write(level+1, 'comment = {%s},\n' % attr.get_value())
for mediaref in person.get_media_list():
media = db.get_media_from_handle(mediaref.ref)
path = media_path_full(db, media.get_path())
if os.path.isfile(path):
self.write(level+1, 'image = {%s},\n' % path)
break # first image only
self.write(level, '}\n')
def write_event(self, db, level, event):
"""
Write an event.
"""
modifier = None
if event.type == EventType.BIRTH:
event_type = 'birth'
if 'died' in event.description.lower():
modifier = 'died'
if 'stillborn' in event.description.lower():
modifier = 'stillborn'
# modifier = 'out of wedlock'
elif event.type == EventType.BAPTISM:
event_type = 'baptism'
elif event.type == EventType.ENGAGEMENT:
event_type = 'engagement'
elif event.type == EventType.MARRIAGE:
event_type = 'marriage'
elif event.type == EventType.DIVORCE:
event_type = 'divorce'
elif event.type == EventType.DEATH:
event_type = 'death'
elif event.type == EventType.BURIAL:
event_type = 'burial'
if 'killed' in event.description.lower():
modifier = 'killed'
elif event.type == EventType.CREMATION:
event_type = 'burial'
modifier = 'cremated'
else:
return
date = event.get_date_object()
if date.get_calendar() == Date.CAL_GREGORIAN:
calendar = 'AD' # GR
elif date.get_calendar() == Date.CAL_JULIAN:
calendar = 'JU'
else:
calendar = ''
if date.get_modifier() == Date.MOD_ABOUT:
calendar = 'ca' + calendar
date_str = self.format_iso(date.get_ymd(), calendar)
if date.get_modifier() == Date.MOD_BEFORE:
date_str = '/' + date_str
elif date.get_modifier() == Date.MOD_AFTER:
date_str = date_str + '/'
elif date.is_compound():
stop_date = self.format_iso(date.get_stop_ymd(), calendar)
date_str = date_str + '/' + stop_date
place = _pd.display_event(db, event)
if modifier:
event_type += '+'
self.write(level, '%s = {%s}{%s}{%s},\n' %
(event_type, date_str, place, modifier))
elif place == '':
event_type += '-'
self.write(level, '%s = {%s},\n' % (event_type, date_str))
else:
self.write(level, '%s = {%s}{%s},\n' %
(event_type, date_str, place))
def format_given_names(self, name):
"""
Format given names.
"""
first = name.get_first_name()
call = name.get_call_name()
if call:
if call in first:
where = first.index(call)
return '{before}\\pref{{{call}}}{after}'.format(
before=first[:where],
call=call,
after=first[where+len(call):])
else:
# ignore erroneous call name
return first
else:
return first
def format_iso(self, date_tuple, calendar):
"""
Format an iso date.
"""
year, month, day = date_tuple
if year == 0:
iso_date = ''
elif month == 0:
iso_date = str(year)
elif day == 0:
iso_date = '%s-%s' % (year, month)
else:
iso_date = '%s-%s-%s' % (year, month, day)
if calendar and calendar != 'AD':
iso_date = '(%s)%s' % (calendar, iso_date)
return iso_date
def write(self, level, text):
"""
Write indented text.
"""
self._tex.write(' '*level + text)
def open(self, filename):
""" Implement TreeDocBase.open() """
self._filename = os.path.normpath(os.path.abspath(filename))
self.write_start()
def close(self):
"""
This isn't useful by itself. Other classes need to override this and
actually generate a file.
"""
self.write_end()
#------------------------------------------------------------------------------
#
# TreeTexDoc
#
#------------------------------------------------------------------------------
class TreeTexDoc(TreeDocBase):
"""
TreeTexDoc implementation that generates a .tex file.
"""
def close(self):
""" Implements TreeDocBase.close() """
TreeDocBase.close(self)
# Make sure the extension is correct
if self._filename[-4:] != ".tex":
self._filename += ".tex"
with open(self._filename, "w") as texfile:
texfile.write(self._tex.getvalue())
#------------------------------------------------------------------------------
#
# TreePdfDoc
#
#------------------------------------------------------------------------------
class TreePdfDoc(TreeDocBase):
"""
TreePdfDoc implementation that generates a .pdf file.
"""
def close(self):
""" Implements TreeDocBase.close() """
TreeDocBase.close(self)
# Make sure the extension is correct
if self._filename[-4:] != ".pdf":
self._filename += ".pdf"
with tempfile.TemporaryDirectory() as tmpdir:
with open(os.path.join(tmpdir, 'temp.tex'), "w") as texfile:
texfile.write(self._tex.getvalue())
os.system('lualatex -output-directory %s temp.tex >/dev/null'
% tmpdir)
shutil.copy(os.path.join(tmpdir, 'temp.pdf'), self._filename)
#------------------------------------------------------------------------------
#
# Various Genealogy Tree formats.
#
#------------------------------------------------------------------------------
FORMATS = []
if _LATEX_FOUND:
FORMATS += [{'type' : "pdf",
'ext' : "pdf",
'descr': _("PDF"),
'mime' : "application/pdf",
'class': TreePdfDoc}]
FORMATS += [{'type' : "tex",
'ext' : "tex",
'descr': _("LaTeX File"),
'mime' : "application/x-latex",
'class': TreeTexDoc}]

View File

@ -495,14 +495,14 @@ class BookList:
"""
Saves the current BookList to the associated file.
"""
with open(self.file, "w") as b_f:
with open(self.file, "w", encoding="utf-8") as b_f:
b_f.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
b_f.write('<booklist>\n')
for name in sorted(self.bookmap): # enable a diff of archived copies
book = self.get_book(name)
dbname = book.get_dbname()
dbname = escape(book.get_dbname())
b_f.write(' <book name="%s" database="%s">'
'\n' % (name, dbname))
'\n' % (escape(name), dbname))
for item in book.get_item_list():
b_f.write(' <item name="%s" '
'trans_name="%s">\n' % (
@ -566,7 +566,7 @@ class BookList:
'\n' % book.get_format_name())
if book.get_output():
b_f.write(' <output name="%s"/>'
'\n' % book.get_output())
'\n' % escape(book.get_output()))
b_f.write(' </book>\n')
b_f.write('</booklist>\n')
@ -578,8 +578,15 @@ class BookList:
try:
parser = make_parser()
parser.setContentHandler(BookParser(self, self.dbase))
with open(self.file) as the_file:
parser.parse(the_file)
# bug 10387; XML should be utf8, but was not previously saved
# that way. So try to read utf8, if fails, try with system
# encoding. Only an issue on non-utf8 systems.
try:
with open(self.file, encoding="utf-8") as the_file:
parser.parse(the_file)
except UnicodeDecodeError:
with open(self.file) as the_file:
parser.parse(the_file)
except (IOError, OSError, ValueError, SAXParseException, KeyError,
AttributeError):
LOG.debug("Failed to parse book list", exc_info=True)

View File

@ -39,7 +39,7 @@ import os
# Report categories
from .. import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE, CATEGORY_WEB,
CATEGORY_BOOK, CATEGORY_GRAPHVIZ)
CATEGORY_BOOK, CATEGORY_GRAPHVIZ, CATEGORY_TREE)
standalone_categories = {
CATEGORY_TEXT : ("RepText", _("Text Reports")),
@ -48,6 +48,7 @@ standalone_categories = {
CATEGORY_WEB : ("RepWeb", _("Web Pages")),
CATEGORY_BOOK : ("RepBook", _("Books")),
CATEGORY_GRAPHVIZ : ("Graphs", _("Graphs")),
CATEGORY_TREE : ("Trees", _("Trees")),
}
book_categories = {
CATEGORY_TEXT : _("Text"),

View File

@ -31,6 +31,7 @@ import csv
#
#-------------------------------------------------------------------------
from .tabbeddoc import *
from ...constfunc import win
class CSVTab(TabbedDoc):
@ -48,7 +49,8 @@ class CSVTab(TabbedDoc):
else:
self.filename = filename
self.f = open(self.filename, "w")
self.f = open(self.filename, "w",
encoding='utf_8_sig' if win() else 'utf_8')
self.writer = csv.writer(self.f)
def close(self):

View File

@ -249,13 +249,23 @@ class ConfigureDialog(ManagedWindow):
"""
self.__config.set(constant, obj.get_text())
def update_color(self, obj, constant, color_hex_label):
def update_color(self, obj, pspec, constant, color_hex_label):
"""
Called on changing some color.
Either on programmatically color change.
"""
rgba = obj.get_rgba()
hexval = "#%02x%02x%02x" % (int(rgba.red * 255),
int(rgba.green * 255),
int(rgba.blue * 255))
color_hex_label.set_text(hexval)
self.__config.set(constant, hexval)
colors = self.__config.get(constant)
if isinstance(colors, list):
scheme = self.__config.get('colors.scheme')
colors[scheme] = hexval
self.__config.set(constant, colors)
else:
self.__config.set(constant, hexval)
def update_checkbox(self, obj, constant, config=None):
if not config:
@ -383,15 +393,24 @@ class ConfigureDialog(ManagedWindow):
grid.attach(entry, col_attach+1, index, 1, 1)
def add_color(self, grid, label, index, constant, config=None, col=0):
"""
Add color chooser widget with label to the grid.
"""
if not config:
config = self.__config
lwidget = BasicLabel(_("%s: ") % label) # needed for French, else ignore
hexval = config.get(constant)
colors = config.get(constant)
if isinstance(colors, list):
scheme = config.get('colors.scheme')
hexval = colors[scheme]
else:
hexval = colors
color = Gdk.color_parse(hexval)
entry = Gtk.ColorButton(color=color)
color_hex_label = BasicLabel(hexval)
color_hex_label.set_hexpand(True)
entry.connect('color-set', self.update_color, constant, color_hex_label)
entry.connect('notify::color', self.update_color, constant,
color_hex_label)
grid.attach(lwidget, col, index, 1, 1)
grid.attach(entry, col+1, index, 1, 1)
grid.attach(color_hex_label, col+2, index, 1, 1)
@ -554,7 +573,7 @@ class GrampsPreferences(ConfigureDialog):
def add_color_panel(self, configdialog):
"""
Add the tab to set defaults colors for graph boxes
Add the tab to set defaults colors for graph boxes.
"""
grid = Gtk.Grid()
grid.set_border_width(12)
@ -562,40 +581,62 @@ class GrampsPreferences(ConfigureDialog):
grid.set_row_spacing(6)
self.add_text(grid, _('Set the colors used for boxes in the graphical views'),
0, line_wrap=False)
self.add_color(grid, _('Gender Male Alive'), 1,
'preferences.color-gender-male-alive')
self.add_color(grid, _('Border Male Alive'), 2,
'preferences.bordercolor-gender-male-alive')
self.add_color(grid, _('Gender Male Death'), 3,
'preferences.color-gender-male-death')
self.add_color(grid, _('Border Male Death'), 4,
'preferences.bordercolor-gender-male-death')
self.add_color(grid, _('Gender Female Alive'), 1,
'preferences.color-gender-female-alive', col=4)
self.add_color(grid, _('Border Female Alive'), 2,
'preferences.bordercolor-gender-female-alive', col=4)
self.add_color(grid, _('Gender Female Death'), 3,
'preferences.color-gender-female-death', col=4)
self.add_color(grid, _('Border Female Death'), 4,
'preferences.bordercolor-gender-female-death', col=4)
## self.add_color(grid, _('Gender Other Alive'), 5,
## 'preferences.color-gender-other-alive')
## self.add_color(grid, _('Border Other Alive'), 6,
## 'preferences.bordercolor-gender-other-alive')
## self.add_color(grid, _('Gender Other Death'), 7,
## 'preferences.color-gender-other-death')
## self.add_color(grid, _('Border Other Death'), 8,
## 'preferences.bordercolor-gender-other-death')
self.add_color(grid, _('Gender Unknown Alive'), 5,
'preferences.color-gender-unknown-alive', col=4)
self.add_color(grid, _('Border Unknown Alive'), 6,
'preferences.bordercolor-gender-unknown-alive', col=4)
self.add_color(grid, _('Gender Unknown Death'), 7,
'preferences.color-gender-unknown-death', col=4)
self.add_color(grid, _('Border Unknown Death'), 8,
'preferences.bordercolor-gender-unknown-death', col=4)
hbox = Gtk.Box(spacing=12)
self.color_scheme_box = Gtk.ComboBoxText()
formats = [_("Light colors"),
_("Dark colors"),]
list(map(self.color_scheme_box.append_text, formats))
scheme = config.get('colors.scheme')
self.color_scheme_box.set_active(scheme)
self.color_scheme_box.connect('changed', self.color_scheme_changed)
lwidget = BasicLabel(_("%s: ") % _('Color scheme'))
hbox.pack_start(lwidget, False, False, 0)
hbox.pack_start(self.color_scheme_box, False, False, 0)
restore_btn = Gtk.Button(_('Restore to defaults'))
restore_btn.connect('clicked', self.restore_colors)
hbox.pack_start(restore_btn, False, False, 0)
grid.attach(hbox, 1, 1, 6, 1)
color_list = [
(_('Male Alive'), 'male-alive', 2, 0),
(_('Male Dead'), 'male-dead', 4, 0),
(_('Female Alive'), 'female-alive', 2, 4),
(_('Female Dead'), 'female-dead', 4, 4),
(_('Unknown Alive'), 'unknown-alive', 6, 4),
(_('Unknown Dead'), 'unknown-dead', 8, 4),
(_('Family Node'), 'family', 7, 0),
(_('Family Divorced'), 'family-divorced', 9, 0),
(_('Home Person'), 'home-person', 6, 0),
(_('Border Male Alive'), 'border-male-alive', 3, 0),
(_('Border Male Dead'), 'border-male-dead', 5, 0),
(_('Border Female Alive'), 'border-female-alive', 3, 4),
(_('Border Female Dead'), 'border-female-dead', 5, 4),
(_('Border Unknown Alive'), 'border-unknown-alive', 7, 4),
(_('Border Unknown Dead'), 'border-unknown-dead', 9, 4),
(_('Border Family'), 'border-family', 8, 0),
(_('Border Family Divorced'), 'border-family-divorced', 10, 0),
]
self.colors = {}
for color in color_list:
pref_name = 'colors.' + color[1]
self.colors[pref_name] = self.add_color(grid, color[0], color[2],
pref_name, col=color[3])
return _('Colors'), grid
def restore_colors(self, widget=None):
"""
Restore colors of selected scheme to default.
"""
scheme = config.get('colors.scheme')
for key, widget in self.colors.items():
color = Gdk.RGBA()
hexval = config.get_default(key)[scheme]
Gdk.RGBA.parse(color, hexval)
widget.set_rgba(color)
def add_advanced_panel(self, configdialog):
grid = Gtk.Grid()
grid.set_border_width(12)
@ -1205,6 +1246,18 @@ class GrampsPreferences(ConfigureDialog):
self.old_format = the_list.get_value(the_iter, COL_FMT)
win = DisplayNameEditor(self.uistate, self.dbstate, self.track, self)
def color_scheme_changed(self, obj):
"""
Called on swiching color scheme.
"""
scheme = obj.get_active()
config.set('colors.scheme', scheme)
for key, widget in self.colors.items():
color = Gdk.RGBA()
hexval = config.get(key)[scheme]
Gdk.RGBA.parse(color, hexval)
widget.set_rgba(color)
def check_for_type_changed(self, obj):
active = obj.get_active()
if active == 0: # update

View File

@ -35,6 +35,7 @@ _LOG = logging.getLogger(".dialog")
#-------------------------------------------------------------------------
from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GdkPixbuf
#-------------------------------------------------------------------------
@ -46,6 +47,7 @@ from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from gramps.gen.const import ICON, URL_BUGHOME
from gramps.gen.config import config
from gramps.gen.constfunc import is_quartz
from .glade import Glade
from .display import display_url
@ -506,6 +508,12 @@ def main(args):
win = Gtk.Window()
win.set_title('Dialog test window')
win.set_position(Gtk.WindowPosition.CENTER)
#Set the mnemonic modifier on Macs to alt-ctrl so that it
#doesn't interfere with the extended keyboard, see
#https://gramps-project.org/bugs/view.php?id=6943
if is_quartz():
win.set_mnemonic_modifier(
Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.MOD1_MASK)
def cb(window, event):
Gtk.main_quit()
win.connect('delete-event', cb)

View File

@ -42,6 +42,7 @@ from gi.repository import Pango
# Gramps classes
#
#-------------------------------------------------------------------------
from ...widgets.cellrenderertextedit import CellRendererTextEdit
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from ...utils import is_right_click
@ -482,7 +483,10 @@ class EmbeddedList(ButtonTab):
type_col = self._column_names[pair[1]][3]
if (type_col in [TEXT_COL, MARKUP_COL, TEXT_EDIT_COL]):
renderer = Gtk.CellRendererText()
if type_col == TEXT_EDIT_COL:
renderer = CellRendererTextEdit()
else:
renderer = Gtk.CellRendererText()
renderer.set_property('ellipsize', Pango.EllipsizeMode.END)
if type_col == TEXT_COL or type_col == TEXT_EDIT_COL:
column = Gtk.TreeViewColumn(name, renderer, text=pair[1])
@ -519,9 +523,12 @@ class EmbeddedList(ButtonTab):
# insert the colum into the tree
column.set_resizable(True)
column.set_clickable(True)
column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
#column.set_min_width(self._column_names[pair[1]][2])
column.set_fixed_width(self._column_names[pair[1]][2])
if self._column_names[pair[1]][2] != -1:
column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
#column.set_min_width(self._column_names[pair[1]][2])
column.set_fixed_width(self._column_names[pair[1]][2])
else:
column.set_expand(True)
column.set_sort_column_id(self._column_names[pair[1]][1])
self.columns.append(column)

View File

@ -45,7 +45,7 @@ _ENTER = Gdk.keyval_from_name("Enter")
#
#-------------------------------------------------------------------------
from .surnamemodel import SurnameModel
from .embeddedlist import EmbeddedList, TEXT_COL, MARKUP_COL, ICON_COL
from .embeddedlist import EmbeddedList, TEXT_EDIT_COL
from ...ddtargets import DdTargets
from gramps.gen.lib import Surname, NameOriginType
from ...utils import get_primary_mask
@ -71,9 +71,9 @@ class SurnameTab(EmbeddedList):
#index = column in model. Value =
# (name, sortcol in model, width, markup/text
_column_names = [
(_('Prefix'), -1, 150, TEXT_COL, -1, None),
(_('Surname'), -1, 250, TEXT_COL, -1, None),
(_('Connector'), -1, 100, TEXT_COL, -1, None),
(_('Prefix'), 0, 150, TEXT_EDIT_COL, -1, None),
(_('Surname'), 1, -1, TEXT_EDIT_COL, -1, None),
(_('Connector'), 2, 100, TEXT_EDIT_COL, -1, None),
]
_column_combo = (_('Origin'), -1, 150, 3) # name, sort, width, modelcol
_column_toggle = (_('Name|Primary'), -1, 80, 4)
@ -94,14 +94,6 @@ class SurnameTab(EmbeddedList):
#first the standard text columns with normal method
EmbeddedList.build_columns(self)
# Need to add attributes to renderers
# and connect renderers to the 'edited' signal
for colno in range(len(self.columns)):
for renderer in self.columns[colno].get_cells():
renderer.set_property('editable', not self.dbstate.db.readonly)
renderer.connect('editing_started', self.on_edit_start, colno)
renderer.connect('edited', self.on_edit_inline, self.column_order()[colno][1])
# now we add the two special columns
# combobox for type
colno = len(self.columns)
@ -133,7 +125,7 @@ class SurnameTab(EmbeddedList):
column.set_resizable(True)
column.set_sort_column_id(self._column_combo[1])
column.set_min_width(self._column_combo[2])
column.set_expand(True)
column.set_expand(False)
self.columns.append(column)
self.tree.append_column(column)
# toggle box for primary
@ -149,7 +141,7 @@ class SurnameTab(EmbeddedList):
column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
column.set_alignment(0.5)
column.set_sort_column_id(self._column_toggle[1])
column.set_min_width(self._column_toggle[2])
column.set_max_width(self._column_toggle[2])
self.columns.append(column)
self.tree.append_column(column)
@ -161,6 +153,24 @@ class SurnameTab(EmbeddedList):
## svalue = self.cmborigmap[second]
## return glocale.strcoll(fvalue, svalue)
def setup_editable_col(self):
"""
inherit this and set the variables needed for editable columns
Variable edit_col_funcs needs to be a dictionary from model col_nr to
function to call for
Example:
self.edit_col_funcs ={1: {'edit_start': self.on_edit_start,
'edited': self.on_edited
}}
"""
self.edit_col_funcs = {
0: {'edit_start': self.on_edit_start,
'edited': self.on_edit_inline},
1: {'edit_start': self.on_edit_start,
'edited': self.on_edit_inline},
2: {'edit_start': self.on_edit_start,
'edited': self.on_edit_inline}}
def get_data(self):
return self.obj.get_surname_list()
@ -194,6 +204,16 @@ class SurnameTab(EmbeddedList):
if self.on_change:
self.on_change()
def post_rebuild(self, prebuildpath):
"""
Called when data model has changed, in particular necessary when row
order is updated.
@param prebuildpath: path selected before rebuild, None if none
@type prebuildpath: tree path
"""
if self.on_change:
self.on_change()
def column_order(self):
# order of columns for EmbeddedList. Only the text columns here
return ((1, 0), (1, 1), (1, 2))
@ -239,11 +259,13 @@ class SurnameTab(EmbeddedList):
"""
self.on_edit_start(cellr, celle, path, colnr)
#set up autocomplete
entry = celle.get_child()
entry.set_width_chars(10)
completion = Gtk.EntryCompletion()
completion.set_model(self.cmborig)
completion.set_minimum_key_length(1)
completion.set_text_column(1)
celle.get_child().set_completion(completion)
entry.set_completion(completion)
#
celle.connect('changed', self.on_origcmb_change, path, colnr)

View File

@ -197,9 +197,6 @@ class EditPerson(EditPrimary):
self.singsurnfr = SingSurn(self.top)
self.multsurnfr = self.top.get_object("hboxmultsurnames")
self.singlesurn_active = True
self.surntab = SurnameTab(self.dbstate, self.uistate, self.track,
self.obj.get_primary_name(),
on_change=self._changed_name)
self.set_contexteventbox(self.top.get_object("eventboxtop"))
@ -445,6 +442,9 @@ class EditPerson(EditPrimary):
self.preview_name = self.top.get_object("full_name")
self.preview_name.override_font(Pango.FontDescription('sans bold 12'))
self.surntab = SurnameTab(self.dbstate, self.uistate, self.track,
self.obj.get_primary_name(),
on_change=self._changed_name)
def get_start_date(self):
"""
@ -936,7 +936,8 @@ class EditPerson(EditPrimary):
msurhbox = self.top.get_object("hboxmultsurnames")
msurhbox.remove(self.surntab)
self.surntab = SurnameTab(self.dbstate, self.uistate, self.track,
self.obj.get_primary_name())
self.obj.get_primary_name(),
on_change=self._changed_name)
self.multsurnfr.set_size_request(-1,
int(config.get('interface.surname-box-height')))
msurhbox.pack_start(self.surntab, True, True, 0)

View File

@ -46,6 +46,7 @@ from gi.repository import Gtk
#
#------------------------------------------------------------------------
from gramps.gen.const import GLADE_DIR, GRAMPS_LOCALE as glocale
from gramps.gen.constfunc import is_quartz
#------------------------------------------------------------------------
#
@ -142,11 +143,19 @@ class Glade(Gtk.Builder):
# toplevel is given
if toplevel:
loadlist = [toplevel] + also_load
self.add_objects_from_file(path, loadlist)
with open(path, 'r', encoding='utf-8') as builder_file:
data = builder_file.read().replace('\n', '')
if is_quartz():
data = data.replace('GDK_CONTROL_MASK', 'GDK_META_MASK')
self.add_objects_from_string(data, loadlist)
self.__toplevel = self.get_object(toplevel)
# toplevel not given
else:
self.add_from_file(path)
with open(path, 'r', encoding='utf-8') as builder_file:
data = builder_file.read().replace('\n', '')
if is_quartz():
data = data.replace('GDK_CONTROL_MASK', 'GDK_META_MASK')
self.add_from_string(data)
# first, use filename as possible toplevel widget name
self.__toplevel = self.get_object(filename.rpartition('.')[0])

View File

@ -197,7 +197,7 @@
<child>
<object class="GtkComboBox" id="confidence">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Conveys the submitter's quantitative evaluation of the credibility of a piece of information, based upon its supporting evidence. It is not intended to eliminate the receiver's need to evaluate the evidence for themselves.
Very Low =Unreliable evidence or estimated data
Low =Questionable reliability of evidence (interviews, census, oral genealogies, or potential for bias for example, an autobiography)

View File

@ -38,6 +38,7 @@ from io import StringIO
#
#-------------------------------------------------------------------------
from gi.repository import Gtk
from gi.repository import Gdk
#-------------------------------------------------------------------------
#
@ -47,6 +48,7 @@ from gi.repository import Gtk
from gramps.gen.const import GLADE_FILE, ICON
from gramps.gen.errors import WindowActiveError
from gramps.gen.config import config
from gramps.gen.constfunc import is_quartz
from .glade import Glade
#-------------------------------------------------------------------------
@ -488,6 +490,13 @@ class ManagedWindow:
#closing the Gtk.Window must also close ManagedWindow
self.window = window
self.window.connect('delete-event', self.close)
#Set the mnemonic modifier on Macs to alt-ctrl so that it
#doesn't interfere with the extended keyboard, see
#https://gramps-project.org/bugs/view.php?id=6943
if is_quartz():
self.window.set_mnemonic_modifier(
Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.MOD1_MASK)
if self.modal:
self.window.set_modal(True)
# The following makes sure that we only have one modal window open;

View File

@ -684,7 +684,7 @@ class BookSelector(ManagedWindow):
old_margins = self.book.get_margins()
old_format_name = self.book.get_format_name()
old_output = self.book.get_output()
BookDialog(self.dbstate, self.uistate, self.book, BookOptions)
BookDialog(self.dbstate, self.uistate, self.book, BookOptions, track=self.track)
new_paper_name = self.book.get_paper_name()
new_orientation = self.book.get_orientation()
new_paper_metric = self.book.get_paper_metric()
@ -918,7 +918,7 @@ class BookDialog(DocReportDialog):
Create a dialog selecting target, format, and paper/HTML options.
"""
def __init__(self, dbstate, uistate, book, options):
def __init__(self, dbstate, uistate, book, options, track=[]):
self.format_menu = None
self.options = options
self.page_html_added = False
@ -926,7 +926,7 @@ class BookDialog(DocReportDialog):
self.title = _('Generate Book')
self.database = dbstate.db
DocReportDialog.__init__(self, dbstate, uistate, options,
'book', self.title)
'book', self.title, track=track)
self.options.options_dict['bookname'] = self.book.get_name()
response = self.window.run()

View File

@ -63,7 +63,7 @@ class DocReportDialog(ReportDialog):
dialogs for docgen derived reports.
"""
def __init__(self, dbstate, uistate, option_class, name, trans_name):
def __init__(self, dbstate, uistate, option_class, name, trans_name, track=[]):
"""Initialize a dialog to request that the user select options
for a basic *stand-alone* report."""
@ -72,7 +72,7 @@ class DocReportDialog(ReportDialog):
self.css = PLUGMAN.process_plugin_data('WEBSTUFF')
self.dbname = dbstate.db.get_dbname()
ReportDialog.__init__(self, dbstate, uistate, option_class,
name, trans_name)
name, trans_name, track=track)
self.basedocname = None # keep pylint happy
self.css_filename = None

View File

@ -0,0 +1,289 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2007-2008 Brian G. Matherly
# Copyright (C) 2007-2009 Stephane Charette
# Copyright (C) 2009 Gary Burton
# Contribution 2009 by Bob Ham <rah@bash.sh>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2012-2013 Paul Franklin
# Copyright (C) 2017 Nick Hall
#
# 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.
#
"""base class for generating dialogs for graph-based reports """
#------------------------------------------------------------------------
#
# python modules
#
#------------------------------------------------------------------------
from abc import ABCMeta, abstractmethod
import os
#-------------------------------------------------------------------------------
#
# GTK+ modules
#
#-------------------------------------------------------------------------------
from gi.repository import Gtk
from gi.repository import GObject
#-------------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from gramps.gen.config import config
from gramps.gen.plug.report import CATEGORY_GRAPHVIZ
from ._reportdialog import ReportDialog
from ._papermenu import PaperFrame
import gramps.gen.plug.docgen.graphdoc as graphdoc
from gramps.gen.plug.menu import Menu
#-------------------------------------------------------------------------------
#
# GraphvizFormatComboBox
#
#-------------------------------------------------------------------------------
class BaseFormatComboBox(Gtk.ComboBox):
"""
Combo box base class for graph-based report format choices.
"""
FORMATS = []
def set(self, active=None):
""" initialize the Graphviz choices """
store = Gtk.ListStore(GObject.TYPE_STRING)
self.set_model(store)
cell = Gtk.CellRendererText()
self.pack_start(cell, True)
self.add_attribute(cell, 'text', 0)
index = 0
active_index = 0
for item in self.FORMATS:
name = item["descr"]
store.append(row=[name])
if item['type'] == active:
active_index = index
index += 1
self.set_active(active_index)
def get_label(self):
""" get the format description """
return self.FORMATS[self.get_active()]["descr"]
def get_reference(self):
""" get the format class """
return self.FORMATS[self.get_active()]["class"]
def get_ext(self):
""" get the format extension """
return '.%s' % self.FORMATS[self.get_active()]['ext']
def get_clname(self):
""" get the report's output format type"""
return self.FORMATS[self.get_active()]["type"]
#-----------------------------------------------------------------------
#
# GraphReportDialog
#
#-----------------------------------------------------------------------
class GraphReportDialog(ReportDialog, metaclass=ABCMeta):
"""A base class of ReportDialog customized for graph-based reports."""
def __init__(self, dbstate, uistate, opt, name, translated_name):
"""Initialize a dialog to request that the user select options
for a Graphviz report. See the ReportDialog class for
more information."""
self.category = self.get_category()
self._goptions = self.get_options()
self.dbname = dbstate.db.get_dbname()
ReportDialog.__init__(self, dbstate, uistate, opt,
name, translated_name)
self.doc = None # keep pylint happy
self.format = None
self.paper_label = None
def init_options(self, option_class):
try:
if issubclass(option_class, object): # Old-style class
self.options = option_class(self.raw_name,
self.dbstate.get_database())
except TypeError:
self.options = option_class
menu = Menu()
self._goptions.add_menu_options(menu)
for category in menu.get_categories():
for name in menu.get_option_names(category):
option = menu.get_option(category, name)
self.options.add_menu_option(category, name, option)
self.options.load_previous_values()
def init_interface(self):
ReportDialog.init_interface(self)
self.doc_type_changed(self.format_menu)
self.notebook.set_current_page(1) # don't start on "Paper Options"
def setup_format_frame(self):
"""Set up the format frame of the dialog."""
self.make_doc_menu()
self.format_menu.set(self.options.handler.get_format_name())
self.format_menu.connect('changed', self.doc_type_changed)
label = Gtk.Label(label=_("%s:") % _("Output Format"))
label.set_halign(Gtk.Align.START)
self.grid.attach(label, 1, self.row, 1, 1)
self.format_menu.set_hexpand(True)
self.grid.attach(self.format_menu, 2, self.row, 2, 1)
self.row += 1
self.open_with_app = Gtk.CheckButton(
label=_("Open with default viewer"))
self.open_with_app.set_active(
config.get('interface.open-with-default-viewer'))
self.grid.attach(self.open_with_app, 2, self.row, 2, 1)
self.row += 1
ext = self.format_menu.get_ext()
if ext is None:
ext = ""
else:
spath = self.get_default_directory()
if self.options.get_output():
base = os.path.basename(self.options.get_output())
else:
if self.dbname is None:
default_name = self.raw_name
else:
default_name = self.dbname + "_" + self.raw_name
base = "%s%s" % (default_name, ext) # "ext" already has a dot
spath = os.path.normpath(os.path.join(spath, base))
self.target_fileentry.set_filename(spath)
def setup_report_options_frame(self):
self.paper_label = Gtk.Label(label='<b>%s</b>' % _("Paper Options"))
self.paper_label.set_use_markup(True)
handler = self.options.handler
self.paper_frame = PaperFrame(
handler.get_paper_metric(),
handler.get_paper_name(),
handler.get_orientation(),
handler.get_margins(),
handler.get_custom_paper_size())
self.notebook.insert_page(self.paper_frame, self.paper_label, 0)
self.paper_frame.show_all()
ReportDialog.setup_report_options_frame(self)
def doc_type_changed(self, obj):
"""
This routine is called when the user selects a new file
format for the report. It adjusts the various dialog sections
to reflect the appropriate values for the currently selected
file format. For example, a HTML document doesn't need any
paper size/orientation options, but it does need a template
file. Those changes are made here.
"""
self.open_with_app.set_sensitive(True)
fname = self.target_fileentry.get_full_path(0)
(spath, ext) = os.path.splitext(fname)
ext_val = obj.get_ext()
if ext_val:
fname = spath + ext_val
else:
fname = spath
self.target_fileentry.set_filename(fname)
def make_document(self):
"""Create a document of the type requested by the user.
"""
pstyle = self.paper_frame.get_paper_style()
self.doc = self.format(self.options, pstyle)
self.options.set_document(self.doc)
def on_ok_clicked(self, obj):
"""The user is satisfied with the dialog choices. Validate
the output file name before doing anything else. If there is
a file name, gather the options and create the report."""
# Is there a filename? This should also test file permissions, etc.
if not self.parse_target_frame():
self.window.run()
# Preparation
self.parse_format_frame()
self.parse_user_options()
self.options.handler.set_paper_metric(
self.paper_frame.get_paper_metric())
self.options.handler.set_paper_name(
self.paper_frame.get_paper_name())
self.options.handler.set_orientation(
self.paper_frame.get_orientation())
self.options.handler.set_margins(
self.paper_frame.get_paper_margins())
self.options.handler.set_custom_paper_size(
self.paper_frame.get_custom_paper_size())
# Create the output document.
self.make_document()
# Save options
self.options.handler.save_options()
config.set('interface.open-with-default-viewer',
self.open_with_app.get_active())
def parse_format_frame(self):
"""Parse the format frame of the dialog. Save the user
selected output format for later use."""
self.format = self.format_menu.get_reference()
format_name = self.format_menu.get_clname()
self.options.handler.set_format_name(format_name)
def setup_style_frame(self):
"""Required by ReportDialog"""
pass
@abstractmethod
def make_doc_menu(self):
"""
Build a menu of document types that are appropriate for
this graph report.
"""
@abstractmethod
def get_category(self):
"""
Return the report category.
"""
@abstractmethod
def get_options(self):
"""
Return the graph options.
"""

View File

@ -1,12 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2007-2008 Brian G. Matherly
# Copyright (C) 2007-2009 Stephane Charette
# Copyright (C) 2009 Gary Burton
# Contribution 2009 by Bob Ham <rah@bash.sh>
# Copyright (C) 2010 Jakim Friant
# Copyright (C) 2012-2013 Paul Franklin
# Copyright (C) 2017 Nick Hall
#
# 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
@ -23,174 +18,42 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
""" a ReportDialog customized for Graphviz-based reports """
#------------------------------------------------------------------------
#
# python modules
#
#------------------------------------------------------------------------
import os
#-------------------------------------------------------------------------------
#
# GTK+ modules
#
#-------------------------------------------------------------------------------
from gi.repository import Gtk
from gi.repository import GObject
"""class for generating dialogs for graphviz-based reports """
#-------------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from gramps.gen.config import config
from ._graphreportdialog import GraphReportDialog, BaseFormatComboBox
from gramps.gen.plug.report import CATEGORY_GRAPHVIZ
from ._reportdialog import ReportDialog
from ._papermenu import PaperFrame
import gramps.gen.plug.docgen.graphdoc as graphdoc
from gramps.gen.plug.menu import Menu
#-------------------------------------------------------------------------------
#
# GraphvizFormatComboBox
#
#-------------------------------------------------------------------------------
class GraphvizFormatComboBox(Gtk.ComboBox):
"""
Combo box class for Graphviz report format choices.
"""
def set(self, active=None):
""" initialize the Graphviz choices """
store = Gtk.ListStore(GObject.TYPE_STRING)
self.set_model(store)
cell = Gtk.CellRendererText()
self.pack_start(cell, True)
self.add_attribute(cell, 'text', 0)
index = 0
active_index = 0
for item in graphdoc.FORMATS:
name = item["descr"]
store.append(row=[name])
if item['type'] == active:
active_index = index
index += 1
self.set_active(active_index)
def get_label(self):
""" get the format description """
return graphdoc.FORMATS[self.get_active()]["descr"]
def get_reference(self):
""" get the format class """
return graphdoc.FORMATS[self.get_active()]["class"]
def get_ext(self):
""" get the format extension """
return '.%s' % graphdoc.FORMATS[self.get_active()]['ext']
def get_clname(self):
""" get the report's output format type"""
return graphdoc.FORMATS[self.get_active()]["type"]
#-----------------------------------------------------------------------
#
# GraphvizReportDialog
#
#-----------------------------------------------------------------------
class GraphvizReportDialog(ReportDialog):
"""A class of ReportDialog customized for Graphviz-based reports."""
class GraphvizReportDialog(GraphReportDialog):
def __init__(self, dbstate, uistate, opt, name, translated_name):
"""Initialize a dialog to request that the user select options
for a Graphviz report. See the ReportDialog class for
more information."""
self.category = CATEGORY_GRAPHVIZ
self.__gvoptions = graphdoc.GVOptions()
self.dbname = dbstate.db.get_dbname()
ReportDialog.__init__(self, dbstate, uistate, opt,
name, translated_name)
self.doc = None # keep pylint happy
self.format = None
self.paper_label = None
def init_options(self, option_class):
try:
if issubclass(option_class, object): # Old-style class
self.options = option_class(self.raw_name,
self.dbstate.get_database())
except TypeError:
self.options = option_class
menu = Menu()
self.__gvoptions.add_menu_options(menu)
for category in menu.get_categories():
for name in menu.get_option_names(category):
option = menu.get_option(category, name)
self.options.add_menu_option(category, name, option)
self.options.load_previous_values()
def init_interface(self):
ReportDialog.init_interface(self)
self.doc_type_changed(self.format_menu)
self.notebook.set_current_page(1) # don't start on "Paper Options"
def setup_format_frame(self):
"""Set up the format frame of the dialog."""
def make_doc_menu(self):
"""
Build a menu of document types that are appropriate for
this graph report.
"""
self.format_menu = GraphvizFormatComboBox()
self.format_menu.set(self.options.handler.get_format_name())
self.format_menu.connect('changed', self.doc_type_changed)
label = Gtk.Label(label=_("%s:") % _("Output Format"))
label.set_halign(Gtk.Align.START)
self.grid.attach(label, 1, self.row, 1, 1)
self.format_menu.set_hexpand(True)
self.grid.attach(self.format_menu, 2, self.row, 2, 1)
self.row += 1
self.open_with_app = Gtk.CheckButton(
label=_("Open with default viewer"))
self.open_with_app.set_active(
config.get('interface.open-with-default-viewer'))
self.grid.attach(self.open_with_app, 2, self.row, 2, 1)
self.row += 1
def get_category(self):
"""
Return the report category.
"""
return CATEGORY_GRAPHVIZ
ext = self.format_menu.get_ext()
if ext is None:
ext = ""
else:
spath = self.get_default_directory()
if self.options.get_output():
base = os.path.basename(self.options.get_output())
else:
if self.dbname is None:
default_name = self.raw_name
else:
default_name = self.dbname + "_" + self.raw_name
base = "%s%s" % (default_name, ext) # "ext" already has a dot
spath = os.path.normpath(os.path.join(spath, base))
self.target_fileentry.set_filename(spath)
def setup_report_options_frame(self):
self.paper_label = Gtk.Label(label='<b>%s</b>' % _("Paper Options"))
self.paper_label.set_use_markup(True)
handler = self.options.handler
self.paper_frame = PaperFrame(
handler.get_paper_metric(),
handler.get_paper_name(),
handler.get_orientation(),
handler.get_margins(),
handler.get_custom_paper_size())
self.notebook.insert_page(self.paper_frame, self.paper_label, 0)
self.paper_frame.show_all()
ReportDialog.setup_report_options_frame(self)
def get_options(self):
"""
Return the graph options.
"""
return graphdoc.GVOptions()
def doc_type_changed(self, obj):
"""
@ -201,84 +64,31 @@ class GraphvizReportDialog(ReportDialog):
paper size/orientation options, but it does need a template
file. Those changes are made here.
"""
self.open_with_app.set_sensitive(True)
fname = self.target_fileentry.get_full_path(0)
(spath, ext) = os.path.splitext(fname)
ext_val = obj.get_ext()
if ext_val:
fname = spath + ext_val
else:
fname = spath
self.target_fileentry.set_filename(fname)
GraphReportDialog.doc_type_changed(self, obj)
output_format_str = obj.get_clname()
if output_format_str in ['gvpdf', 'gspdf', 'ps']:
# Always use 72 DPI for PostScript and PDF files.
self.__gvoptions.dpi.set_value(72)
self.__gvoptions.dpi.set_available(False)
self._goptions.dpi.set_value(72)
self._goptions.dpi.set_available(False)
else:
self.__gvoptions.dpi.set_available(True)
self._goptions.dpi.set_available(True)
if output_format_str in ['gspdf', 'dot']:
# Multiple pages only valid for dot and PDF via GhostsScript.
self.__gvoptions.h_pages.set_available(True)
self.__gvoptions.v_pages.set_available(True)
self._goptions.h_pages.set_available(True)
self._goptions.v_pages.set_available(True)
else:
self.__gvoptions.h_pages.set_value(1)
self.__gvoptions.v_pages.set_value(1)
self.__gvoptions.h_pages.set_available(False)
self.__gvoptions.v_pages.set_available(False)
self._goptions.h_pages.set_value(1)
self._goptions.v_pages.set_value(1)
self._goptions.h_pages.set_available(False)
self._goptions.v_pages.set_available(False)
def make_document(self):
"""Create a document of the type requested by the user.
"""
pstyle = self.paper_frame.get_paper_style()
self.doc = self.format(self.options, pstyle)
self.options.set_document(self.doc)
def on_ok_clicked(self, obj):
"""The user is satisfied with the dialog choices. Validate
the output file name before doing anything else. If there is
a file name, gather the options and create the report."""
# Is there a filename? This should also test file permissions, etc.
if not self.parse_target_frame():
self.window.run()
# Preparation
self.parse_format_frame()
self.parse_user_options()
self.options.handler.set_paper_metric(
self.paper_frame.get_paper_metric())
self.options.handler.set_paper_name(
self.paper_frame.get_paper_name())
self.options.handler.set_orientation(
self.paper_frame.get_orientation())
self.options.handler.set_margins(
self.paper_frame.get_paper_margins())
self.options.handler.set_custom_paper_size(
self.paper_frame.get_custom_paper_size())
# Create the output document.
self.make_document()
# Save options
self.options.handler.save_options()
config.set('interface.open-with-default-viewer',
self.open_with_app.get_active())
def parse_format_frame(self):
"""Parse the format frame of the dialog. Save the user
selected output format for later use."""
self.format = self.format_menu.get_reference()
format_name = self.format_menu.get_clname()
self.options.handler.set_format_name(format_name)
def setup_style_frame(self):
"""Required by ReportDialog"""
pass
#-------------------------------------------------------------------------------
#
# GraphvizFormatComboBox
#
#-------------------------------------------------------------------------------
class GraphvizFormatComboBox(BaseFormatComboBox):
FORMATS = graphdoc.FORMATS

View File

@ -55,7 +55,8 @@ from ...user import User
from ...dialog import ErrorDialog, OptionDialog
from gramps.gen.plug.report import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_BOOK,
CATEGORY_CODE, CATEGORY_WEB,
CATEGORY_GRAPHVIZ, standalone_categories)
CATEGORY_GRAPHVIZ, CATEGORY_TREE,
standalone_categories)
from gramps.gen.plug.docgen import StyleSheet, StyleSheetList
from ...managedwindow import ManagedWindow
from ._stylecombobox import StyleComboBox
@ -676,6 +677,9 @@ def report(dbstate, uistate, person, report_class, options_class,
elif category == CATEGORY_GRAPHVIZ:
from ._graphvizreportdialog import GraphvizReportDialog
dialog_class = GraphvizReportDialog
elif category == CATEGORY_TREE:
from ._treereportdialog import TreeReportDialog
dialog_class = TreeReportDialog
elif category == CATEGORY_WEB:
from ._webreportdialog import WebReportDialog
dialog_class = WebReportDialog

View File

@ -0,0 +1,64 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2017 Nick Hall
#
# 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.
#
"""class for generating dialogs for graphviz-based reports """
#-------------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------------
from ._graphreportdialog import GraphReportDialog, BaseFormatComboBox
from gramps.gen.plug.report import CATEGORY_TREE
import gramps.gen.plug.docgen.treedoc as treedoc
#-----------------------------------------------------------------------
#
# TreeReportDialog
#
#-----------------------------------------------------------------------
class TreeReportDialog(GraphReportDialog):
def make_doc_menu(self):
"""
Build a menu of document types that are appropriate for
this graph report.
"""
self.format_menu = TreeFormatComboBox()
def get_category(self):
"""
Return the report category.
"""
return CATEGORY_TREE
def get_options(self):
"""
Return the graph options.
"""
return treedoc.TreeOptions()
#-------------------------------------------------------------------------------
#
# TreeFormatComboBox
#
#-------------------------------------------------------------------------------
class TreeFormatComboBox(BaseFormatComboBox):
FORMATS = treedoc.FORMATS

View File

@ -53,6 +53,7 @@ from gi.repository import Gdk
#-------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
from gramps.gen.lib import EventType, EventRoleType
from gramps.gen.lib.person import Person
from gramps.gen.constfunc import has_display, is_quartz, mac, win
from gramps.gen.config import config
@ -314,6 +315,7 @@ class ProgressMeter:
"""
Close the progress meter
"""
del self.__cancel_callback
self.__dialog.destroy()
#-------------------------------------------------------------------------
@ -473,33 +475,50 @@ def is_right_click(event):
if Gdk.Event.triggers_context_menu(event):
return True
def color_graph_family(family, dbstate):
"""
:return: based on the config the color for graph family node in hex
:rtype: tuple (hex color fill, hex color border)
"""
scheme = config.get('colors.scheme')
for event_ref in family.get_event_ref_list():
event = dbstate.db.get_event_from_handle(event_ref.ref)
if (event.type == EventType.DIVORCE and
event_ref.get_role() in (EventRoleType.FAMILY,
EventRoleType.PRIMARY)):
return (config.get('colors.family-divorced')[scheme],
config.get('colors.border-family-divorced')[scheme])
return (config.get('colors.family')[scheme],
config.get('colors.border-family')[scheme])
def color_graph_box(alive=False, gender=Person.MALE):
"""
:return: based on the config the color for graph boxes in hex
If gender is None, an empty box is assumed
:rtype: tuple (hex color fill, hex color border)
"""
scheme = config.get('colors.scheme')
if gender == Person.MALE:
if alive:
return (config.get('preferences.color-gender-male-alive'),
config.get('preferences.bordercolor-gender-male-alive'))
return (config.get('colors.male-alive')[scheme],
config.get('colors.border-male-alive')[scheme])
else:
return (config.get('preferences.color-gender-male-death'),
config.get('preferences.bordercolor-gender-male-death'))
return (config.get('colors.male-dead')[scheme],
config.get('colors.border-male-dead')[scheme])
elif gender == Person.FEMALE:
if alive:
return (config.get('preferences.color-gender-female-alive'),
config.get('preferences.bordercolor-gender-female-alive'))
return (config.get('colors.female-alive')[scheme],
config.get('colors.border-female-alive')[scheme])
else:
return (config.get('preferences.color-gender-female-death'),
config.get('preferences.bordercolor-gender-female-death'))
return (config.get('colors.female-dead')[scheme],
config.get('colors.border-female-dead')[scheme])
elif gender == Person.UNKNOWN:
if alive:
return (config.get('preferences.color-gender-unknown-alive'),
config.get('preferences.bordercolor-gender-unknown-alive'))
return (config.get('colors.unknown-alive')[scheme],
config.get('colors.border-unknown-alive')[scheme])
else:
return (config.get('preferences.color-gender-unknown-death'),
config.get('preferences.bordercolor-gender-unknown-death'))
return (config.get('colors.unknown-dead')[scheme],
config.get('colors.border-unknown-dead')[scheme])
#empty box, no gender
return ('#d2d6ce', '#000000')
## print 'male alive', rgb_to_hex((185/256.0, 207/256.0, 231/256.0))
@ -543,6 +562,21 @@ def rgb_to_hex(rgb):
rgbint = (int(rgb[0] * 255), int(rgb[1] * 255), int(rgb[2] * 255))
return '#%02x%02x%02x' % rgbint
def get_link_color(context):
"""
Find the link color for the current theme.
"""
from gi.repository import Gtk
if Gtk.get_minor_version() > 11:
col = context.get_color(Gtk.StateFlags.LINK)
else:
found, col = context.lookup_color('link_color')
if not found:
col.parse('blue')
return rgb_to_hex((col.red, col.green, col.blue))
def edit_object(dbstate, uistate, reftype, ref):
"""
Invokes the appropriate editor for an object type and given handle.

View File

@ -39,6 +39,7 @@ import time
import datetime
from io import StringIO
import posixpath
import gc
#-------------------------------------------------------------------------
#
@ -54,6 +55,7 @@ LOG = logging.getLogger(".")
#
#-------------------------------------------------------------------------
from gi.repository import Gtk
from gi.repository import Gdk
#-------------------------------------------------------------------------
#
@ -136,8 +138,6 @@ UIDEFAULT = '''<ui>
<menuitem action="Quit"/>
</menu>
<menu action="AddMenu">
<menu action="AddNewMenu">
<separator/>
<menuitem action="PersonAdd"/>
<separator/>
<menuitem action="FamilyAdd"/>
@ -150,7 +150,6 @@ UIDEFAULT = '''<ui>
<menuitem action="RepositoryAdd"/>
<menuitem action="MediaAdd"/>
<menuitem action="NoteAdd"/>
</menu>
</menu>
<menu action="EditMenu">
<menuitem action="Undo"/>
@ -396,7 +395,12 @@ class ViewManager(CLIManager):
self.window.set_icon_from_file(ICON)
self.window.set_default_size(width, height)
self.window.move(horiz_position, vert_position)
#Set the mnemonic modifier on Macs to alt-ctrl so that it
#doesn't interfere with the extended keyboard, see
#https://gramps-project.org/bugs/view.php?id=6943
if is_quartz():
self.window.set_mnemonic_modifier(
Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.MOD1_MASK)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.window.add(vbox)
hpane = Gtk.Paned()
@ -599,20 +603,20 @@ class ViewManager(CLIManager):
('Clipboard', 'edit-paste', _('Clip_board'), "<PRIMARY>b",
_("Open the Clipboard dialog"), self.clipboard),
('AddMenu', None, _('_Add')),
('AddNewMenu', None, _('New')),
('PersonAdd', None, _('Person'), "<Alt>p", None,
#('AddNewMenu', None, _('New')),
('PersonAdd', None, _('Person'), "<shift><Alt>p", None,
self.add_new_person),
('FamilyAdd', None, _('Family'), "<Alt>y", None,
('FamilyAdd', None, _('Family'), "<shift><Alt>f", None,
self.add_new_family),
('EventAdd', None, _('Event'), "<shift>e", None,
('EventAdd', None, _('Event'), "<shift><Alt>e", None,
self.add_new_event),
('PlaceAdd', None, _('Place'), "<shift><Alt>p", None,
('PlaceAdd', None, _('Place'), "<shift><Alt>l", None,
self.add_new_place),
('SourceAdd', None, _('Source'), "<shift><Alt>s", None,
self.add_new_source),
('CitationAdd', None, _('Citation'), "<shift><Alt>c", None,
self.add_new_citation),
('RepositoryAdd', None, _('Repository'), "<shift><Alt>y", None,
('RepositoryAdd', None, _('Repository'), "<shift><Alt>r", None,
self.add_new_repository),
('MediaAdd', None, _('Media'), "<shift><Alt>m", None,
self.add_new_media),
@ -1769,6 +1773,7 @@ def run_plugin(pdata, dbstate, uistate):
name=pdata.id,
category=pdata.category,
callback=dbstate.db.request_rebuild)
gc.collect(2)
def make_plugin_callback(pdata, dbstate, uistate):
"""

View File

@ -278,14 +278,12 @@ class ListView(NavigationView):
def foreground_color(self, column, renderer, model, iter_, data=None):
'''
Set the foreground color of the cell renderer. We use a cell data
function because we don't want to set the color of untagged rows.
function because there is a problem returning None from a model.
'''
fg_color = model.get_value(iter_, model.color_column())
#for color errors, typically color column is badly set
if fg_color:
renderer.set_property('foreground', fg_color)
else:
LOG.debug('Bad color set: ' + str(fg_color))
if fg_color == '':
fg_color = None
renderer.set_property('foreground', fg_color)
def set_active(self):
"""

View File

@ -156,8 +156,7 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
hpane = Gtk.Paned()
vpane = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL)
hpane.pack1(vpane, resize=True, shrink=False)
hpane.pack2(self.sidebar, resize=False, shrink=True)
self._setup_slider_config(hpane, 'hpane.slider-position')
hpane.pack2(self.sidebar, resize=False, shrink=False)
hpane.show()
vpane.show()
@ -168,14 +167,31 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
self._setup_slider_config(vpane, 'vpane.slider-position')
self.sidebar_toggled(self.sidebar.get_property('visible'))
self.hpane_sig = hpane.connect("draw", self.set_page_slider)
return hpane
def _setup_slider_config(self, widget, setting):
def set_page_slider(self, widget, dummy):
""" Setup slider. We have the page realized at this point. """
widget.disconnect(self.hpane_sig)
# get current width of pane
width = widget.get_allocated_width()
# default will use natural size for sidebar until it gets to 400 pix
side_ch = self.sidebar.get_children() # Gtk Notebook
try:
vp_ch = side_ch[0].get_children() # Gtk Viewport child
ch_width = vp_ch[0].get_preferred_width()[0] + 3
except AttributeError:
ch_width = 300 # needed if no Gramplet installed
pos = width - min(ch_width, 400)
self._setup_slider_config(widget, 'hpane.slider-position',
position=pos)
def _setup_slider_config(self, widget, setting, position=-1):
"""
Setup the slider configuration setting.
"""
self._config.register(setting, -1)
self._config.register(setting, position)
widget.set_position(self._config.get(setting))
widget.connect('notify::position', self._position_changed, setting)

View File

@ -139,7 +139,7 @@ class CitationBaseModel:
tag_handle = data[0]
cached, tag_color = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[COLUMN_TAGS]:
tag = self.db.get_tag_from_handle(handle)
@ -300,7 +300,7 @@ class CitationBaseModel:
tag_handle = data[0]
cached, tag_color = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[COLUMN2_TAGS]:
tag = self.db.get_tag_from_handle(handle)

View File

@ -208,7 +208,7 @@ class EventModel(FlatBaseModel):
tag_handle = data[0]
cached, tag_color = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[COLUMN_TAGS]:
tag = self.db.get_tag_from_handle(handle)

View File

@ -220,7 +220,7 @@ class FamilyModel(FlatBaseModel):
tag_handle = data[0]
cached, tag_color = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[13]:
tag = self.db.get_tag_from_handle(handle)

View File

@ -171,7 +171,7 @@ class MediaModel(FlatBaseModel):
tag_handle = data[0]
cached, tag_color = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[11]:
tag = self.db.get_tag_from_handle(handle)

View File

@ -148,7 +148,7 @@ class NoteModel(FlatBaseModel):
tag_handle = data[0]
cached, value = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[Note.POS_TAGS]:
tag = self.db.get_tag_from_handle(handle)

View File

@ -538,7 +538,7 @@ class PeopleBaseModel(BaseModel):
tag_handle = data[0]
cached, value = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[COLUMN_TAGS]:
tag = self.db.get_tag_from_handle(handle)

View File

@ -201,7 +201,7 @@ class PlaceBaseModel:
tag_handle = data[0]
cached, value = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[16]:
tag = self.db.get_tag_from_handle(handle)

View File

@ -253,7 +253,7 @@ class RepositoryModel(FlatBaseModel):
tag_handle = data[0]
cached, tag_color = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[8]:
tag = self.db.get_tag_from_handle(handle)

View File

@ -143,7 +143,7 @@ class SourceModel(FlatBaseModel):
tag_handle = data[0]
cached, value = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached:
tag_color = "#000000000000"
tag_color = ""
tag_priority = None
for handle in data[11]:
tag = self.db.get_tag_from_handle(handle)

View File

@ -898,7 +898,8 @@ class TreeBaseModel(GObject.GObject, Gtk.TreeModel, BaseModel):
if node.handle is None:
# Header rows dont get the foreground color set
if col == self.color_column():
return "#000000000000"
#color must not be utf-8
return ""
# Return the node name for the first column
if col == 0:

View File

@ -32,6 +32,7 @@ from .photo import *
from .placeentry import *
from .monitoredwidgets import *
from .selectionwidget import SelectionWidget, Region
from .shadebox import *
from .shortlistcomboentry import *
from .springseparator import *
from .statusbar import Statusbar

View File

@ -0,0 +1,70 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2017 Paul Culley
#
# 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.
#
#------------------------------------------------------------------------
#
# Python Modules
#
#------------------------------------------------------------------------
from gi.repository import Gdk
from gi.repository import Gtk
#------------------------------------------------------------------------
#
# Gramps Modules
#
#------------------------------------------------------------------------
class CellRendererTextEdit(Gtk.CellRendererText):
""" To be used where you normally use Gtk.CellRendererText and you want to
avoid losing the text if the user clicks outside the cell (Like an 'OK'
button. """
__gtype_name__ = 'CellRendererTextEdit'
def __init__(self):
Gtk.CellRendererText.__init__(self)
def do_start_editing(
self, event, treeview, path, background_area, cell_area, flags):
if not self.get_property('editable'):
return
entry = Gtk.Entry()
entry.set_has_frame(False)
xalign, yalign = self.get_alignment()
entry.set_alignment(xalign)
entry.set_width_chars(5)
entry.set_text(self.get_property("text")) # get original cell text
entry.add_events(Gdk.EventMask.FOCUS_CHANGE_MASK)
entry.connect('focus-out-event', self.focus_out, path)
entry.connect('key-press-event', self._key_press)
entry.show()
return entry
def focus_out(self, entry, event, path):
self.emit('edited', path, entry.get_text())
return False
def _key_press(self, entry, event):
if event.type == Gdk.EventType.KEY_PRESS:
if event.keyval == Gdk.KEY_Escape:
# get original cell text
entry.set_text(self.get_property("text"))
return False

View File

@ -1221,7 +1221,9 @@ class FanChartWidget(FanChartBaseWidget):
cr.scale(scale, scale)
if widget:
self.center_xy = self.center_xy_from_delta()
cr.translate(*self.center_xy)
cr.translate(*self.center_xy)
else:
cr.translate(halfdist, halfdist)
cr.save()
cr.rotate(math.radians(self.rotate_value))
@ -1596,6 +1598,8 @@ class FanChartGrampsGUI:
siblings.append(sib_id)
# Collect a list of per-step-family step-siblings
for parent_h in [fam.get_father_handle(), fam.get_mother_handle()]:
if not parent_h:
continue
parent = self.dbstate.db.get_person_from_handle(parent_h)
other_families = [self.dbstate.db.get_family_from_handle(fam_id)
for fam_id in parent.get_family_handle_list()

View File

@ -374,7 +374,9 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
cr.scale(scale, scale)
if widget:
self.center_xy = self.center_xy_from_delta()
cr.translate(*self.center_xy)
cr.translate(*self.center_xy)
else:
cr.translate(halfdist, halfdist)
cr.save()
# Draw background

View File

@ -370,7 +370,7 @@ class GrampletBar(Gtk.Notebook):
"""
Add a tab to the notebook for the given gramplet.
"""
width = min(int(self.uistate.screen_width() * 0.25), 400)
width = -1 # Allow tab width to adjust (smaller) to sidebar
height = min(int(self.uistate.screen_height() * 0.20), 400)
gramplet.set_size_request(width, height)

View File

@ -48,7 +48,7 @@ from gramps.gen.errors import WindowActiveError
from gramps.gen.const import URL_MANUAL_PAGE, VERSION_DIR, COLON
from ..editors import EditPerson, EditFamily
from ..managedwindow import ManagedWindow
from ..utils import is_right_click, rgb_to_hex, get_primary_mask
from ..utils import is_right_click, get_primary_mask, get_link_color
from .menuitem import add_menuitem
from ..plug import make_gui_option
from ..plug.quick import run_quick_report_by_name
@ -196,12 +196,7 @@ class LinkTag(Gtk.TextTag):
lid = 0
#obtaining the theme link color once. Restart needed on theme change!
linkcolor = Gtk.Label(label='test') #needed to avoid label destroyed to early
linkcolor = linkcolor.get_style_context().lookup_color('link_color')
if linkcolor[0]:
linkcolor = rgb_to_hex((linkcolor[1].red, linkcolor[1].green,
linkcolor[1].blue))
else:
linkcolor = 'blue'
linkcolor = get_link_color(linkcolor.get_style_context())
def __init__(self, buffer):
LinkTag.lid += 1

View File

@ -48,7 +48,7 @@ from gi.repository import Pango
#
#-------------------------------------------------------------------------
from gramps.gen.constfunc import has_display, win
from ..utils import rgb_to_hex
from ..utils import get_link_color
#-------------------------------------------------------------------------
#
@ -81,11 +81,7 @@ class LinkLabel(Gtk.EventBox):
Gtk.EventBox.__init__(self)
st_cont = self.get_style_context()
col = st_cont.lookup_color('link_color')
if col[0]:
self.color = rgb_to_hex((col[1].red, col[1].green, col[1].blue))
else:
self.color = 'blue'
self.color = get_link_color(st_cont)
if emph:
#emphasize a link

View File

@ -0,0 +1,58 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2018 Nick Hall
#
# 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.
#
__all__ = ["ShadeBox"]
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import logging
_LOG = logging.getLogger(".widgets.shadebox")
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
from gi.repository import Gtk
#-------------------------------------------------------------------------
#
# ShadeBox class
#
#-------------------------------------------------------------------------
class ShadeBox(Gtk.EventBox):
"""
An EventBox with a shaded background.
"""
def __init__(self, use_shade):
Gtk.EventBox.__init__(self)
self.use_shade = use_shade
def do_draw(self, cr):
if self.use_shade:
tv = Gtk.TextView()
tv_context = tv.get_style_context()
width = self.get_allocated_width()
height = self.get_allocated_height()
Gtk.render_background(tv_context, cr, 0, 0, width, height)
self.get_child().draw(cr)

View File

@ -60,9 +60,9 @@ from .toolcomboentry import ToolComboEntry
from .springseparator import SpringSeparatorAction
from ..spell import Spell
from ..display import display_url
from ..utils import SystemFonts, rgb_to_hex, get_primary_mask
from ..utils import SystemFonts, get_primary_mask, get_link_color
from gramps.gen.config import config
from gramps.gen.constfunc import has_display
from gramps.gen.constfunc import has_display, mac
from ..actiongroup import ActionGroup
#-------------------------------------------------------------------------
@ -186,11 +186,7 @@ class StyledTextEditor(Gtk.TextView):
self.set_buffer(self.textbuffer)
st_cont = self.get_style_context()
col = st_cont.lookup_color('link_color')
if col[0]:
self.linkcolor = rgb_to_hex((col[1].red, col[1].green, col[1].blue))
else:
self.linkcolor = 'blue'
self.linkcolor = get_link_color(st_cont)
self.textbuffer.linkcolor = self.linkcolor
self.match = None
@ -319,7 +315,9 @@ class StyledTextEditor(Gtk.TextView):
if url.startswith("gramps://"):
obj_class, prop, value = url[9:].split("/")
display = simple_access.display(obj_class, prop, value) or url
return display
return display + ((_("\nCommand-Click to follow link") if mac() else
_("\nCtrl-Click to follow link"))
if self.get_editable() else '')
def on_button_release_event(self, widget, event):
"""

View File

@ -52,7 +52,7 @@ from gi.repository import Pango
#-------------------------------------------------------------------------
from gramps.gen.errors import MaskError, ValidationError, WindowActiveError
from .undoableentry import UndoableEntry
from gramps.gen.constfunc import is_quartz
#============================================================================
#
# MaskedEntry and ValidatableMaskedEntry copied and merged from the Kiwi
@ -1248,6 +1248,12 @@ def main(args):
win = Gtk.Window()
win.set_title('ValidatableMaskedEntry test window')
win.set_position(Gtk.WindowPosition.CENTER)
#Set the mnemonic modifier on Macs to alt-ctrl so that it
#doesn't interfere with the extended keyboard, see
#https://gramps-project.org/bugs/view.php?id=6943
if is_quartz():
win.set_mnemonic_modifier(
Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.MOD1_MASK)
def cb(window, event):
Gtk.main_quit()
win.connect('delete-event', cb)

View File

@ -468,8 +468,9 @@ class RecurseDown:
#calculate the text.
myself.calc_text(self.database, indi_handle, fams_handle)
myself.add_mark(self.database,
self.database.get_person_from_handle(indi_handle))
if indi_handle:
myself.add_mark(self.database,
self.database.get_person_from_handle(indi_handle))
self.add_to_col(myself)
@ -692,7 +693,8 @@ class MakePersonTree(RecurseDown):
family2 = family2_h = None
if self.do_parents:
family2_h = center1.get_main_parents_family_handle()
family2 = self.database.get_family_from_handle(family2_h)
if family2_h:
family2 = self.database.get_family_from_handle(family2_h)
mother2_h = father2_h = None
if family2:

View File

@ -27,7 +27,6 @@
# standard python modules
#
#-------------------------------------------------------------------------
import os
#------------------------------------------------------------------------
#
@ -43,9 +42,12 @@ log = logging.getLogger(".WriteFtree")
# Gramps modules
#
#-------------------------------------------------------------------------
from gramps.gen.utils.alive import probably_alive
# keep the following line even though not obviously used (works on import)
from gramps.gui.plug.export import WriterOptionBox
from gramps.gui.glade import Glade
from gramps.gui.dialog import ErrorDialog
from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext
#-------------------------------------------------------------------------
#
@ -53,22 +55,25 @@ from gramps.gui.glade import Glade
#
#-------------------------------------------------------------------------
def writeData(database, filename, user, option_box=None):
""" function to export Web Family Tree file """
writer = FtreeWriter(database, filename, user, option_box)
return writer.export_data()
#-------------------------------------------------------------------------
#
# FtreeWriter
#
#-------------------------------------------------------------------------
class FtreeWriter:
""" Export a Web Family Tree format file """
def __init__(self, database, filename, user, option_box=None):
self.db = database
self.filename = filename
self.user = user
self.option_box = option_box
if isinstance(self.user.callback, collections.Callable): # callback is really callable
# is callback is really callable?
if isinstance(self.user.callback, collections.Callable):
self.update = self.update_real
else:
self.update = self.update_empty
@ -78,121 +83,132 @@ class FtreeWriter:
self.db = option_box.get_filtered_database(self.db)
self.plist = [x for x in self.db.iter_person_handles()]
# the following are used to update the progress meter
self.total = 2 * len(self.plist)
self.count = 0
self.oldval = 0 # we only update when percentage changes
def update_empty(self):
""" used when no callback is present """
pass
def update_real(self):
""" Progress update """
self.count += 1
newval = int(100*self.count/self.total)
newval = int(100 * self.count / self.total)
if newval != self.oldval:
self.user.callback(newval)
self.oldval = newval
def export_data(self):
""" main export processing """
name_map = {}
id_map = {}
id_name = {}
self.count = 0
self.oldval = 0
self.total = 2*len(self.plist)
for key in self.plist:
self.update()
pn = self.db.get_person_from_handle(key).get_primary_name()
sn = pn.get_surname()
items = pn.get_first_name().split()
n = ("%s %s" % (items[0], sn)) if items else sn
pnam = self.db.get_person_from_handle(key).get_primary_name()
snam = pnam.get_surname()
items = pnam.get_first_name().split()
nam = ("%s %s" % (items[0], snam)) if items else snam
count = -1
if n in name_map:
if nam in name_map:
count = 0
while 1:
nn = "%s%d" % (n, count)
if nn not in name_map:
break;
nam_num = "%s%d" % (nam, count)
if nam_num not in name_map:
break
count += 1
name_map[nn] = key
id_map[key] = nn
name_map[nam_num] = key
id_map[key] = nam_num
else:
name_map[n] = key
id_map[key] = n
id_name[key] = get_name(pn, sn, count)
name_map[nam] = key
id_map[key] = nam
id_name[key] = get_name(pnam, snam, count)
with open(self.filename, "w", encoding='utf_8') as f:
try:
with open(self.filename, "w", encoding='utf_8') as file:
return self._export_data(file, id_name, id_map)
except IOError as msg:
msg2 = _("Could not create %s") % self.filename
ErrorDialog(msg2, str(msg), parent=self.option_box.window)
return False
for key in self.plist:
self.update()
p = self.db.get_person_from_handle(key)
name = id_name[key]
father = mother = email = web = ""
def _export_data(self, file, id_name, id_map):
""" file export processing """
for key in self.plist:
self.update()
pers = self.db.get_person_from_handle(key)
name = id_name[key]
father = mother = email = web = ""
family_handle = p.get_main_parents_family_handle()
if family_handle:
family = self.db.get_family_from_handle(family_handle)
if family.get_father_handle() and \
family.get_father_handle() in id_map:
father = id_map[family.get_father_handle()]
if family.get_mother_handle() and \
family.get_mother_handle() in id_map:
mother = id_map[family.get_mother_handle()]
family_handle = pers.get_main_parents_family_handle()
if family_handle:
family = self.db.get_family_from_handle(family_handle)
if family.get_father_handle() and \
family.get_father_handle() in id_map:
father = id_map[family.get_father_handle()]
if family.get_mother_handle() and \
family.get_mother_handle() in id_map:
mother = id_map[family.get_mother_handle()]
#
# Calculate Date
#
birth_ref = p.get_birth_ref()
death_ref = p.get_death_ref()
if birth_ref:
birth_event = self.db.get_event_from_handle(birth_ref.ref)
birth = birth_event.get_date_object()
#
# Calculate Date
#
birth_ref = pers.get_birth_ref()
death_ref = pers.get_death_ref()
if birth_ref:
birth_event = self.db.get_event_from_handle(birth_ref.ref)
birth = birth_event.get_date_object()
else:
birth = None
if death_ref:
death_event = self.db.get_event_from_handle(death_ref.ref)
death = death_event.get_date_object()
else:
death = None
#if self.restrict:
# alive = probably_alive(pers, self.db)
#else:
# alive = 0
if birth:
if death:
dates = "%s-%s" % (fdate(birth), fdate(death))
else:
birth = None
if death_ref:
death_event = self.db.get_event_from_handle(death_ref.ref)
death = death_event.get_date_object()
dates = fdate(birth)
else:
if death:
dates = fdate(death)
else:
death = None
dates = ""
#if self.restrict:
# alive = probably_alive(p, self.db)
#else:
# alive = 0
file.write('%s;%s;%s;%s;%s;%s\n' %
(name, father, mother, email, web, dates))
if birth:
if death:
dates = "%s-%s" % (fdate(birth), fdate(death))
else:
dates = fdate(birth)
else:
if death:
dates = fdate(death)
else:
dates = ""
return True
f.write('%s;%s;%s;%s;%s;%s\n' % (name, father, mother, email, web,
dates))
return True
def fdate(val):
""" return properly formatted date """
if val.get_year_valid():
if val.get_month_valid():
if val.get_day_valid():
return "%d/%d/%d" % (val.get_day(), val.get_month(),
val.get_year())
else:
return "%d/%d" % (val.get_month(), val.get_year())
else:
return "%d" % val.get_year()
else:
return ""
return "%d/%d" % (val.get_month(), val.get_year())
return "%d" % val.get_year()
return ""
def get_name(name, surname, count):
"""returns a name string built from the components of the Name
instance, in the form of Firstname Surname"""
return (name.first_name + ' ' +
surname +
(str(count) if count != -1 else '') +
(', ' +name.suffix if name.suffix else '')
)
surname +
(str(count) if count != -1 else '') +
(', ' + name.suffix if name.suffix else ''))

View File

@ -1072,7 +1072,7 @@ class FamilyLinesReport(Report):
def get_event_place(self, event):
""" get the place of the event """
place_text = None
place_text = ''
place_handle = event.get_place_handle()
if place_handle:
place = self._db.get_place_from_handle(place_handle)

View File

@ -669,7 +669,7 @@ class TitleBox(BoxBase):
return
#fix me. width should be the printable area
self.width = PT2CM(self.doc.string_width(self.font, self.text))
self.height = PT2CM(self.font.get_size() * 1.2)
self.height = PT2CM(self.font.get_size() * 2)
def _get_names(self, persons, name_displayer):
""" A helper function that receives a list of persons and

View File

@ -528,8 +528,6 @@ class CairoPrintSave():
pxwidth = round(context.get_width())
pxheight = round(context.get_height())
scale = min(pxwidth/self.widthpx, pxheight/self.heightpx)
if scale > 1:
scale = 1
self.drawfunc(None, cr, scale=scale)
def on_paginate(self, operation, context):

View File

@ -516,8 +516,6 @@ class CairoPrintSave:
pxwidth = round(context.get_width())
pxheight = round(context.get_height())
scale = min(pxwidth/self.widthpx, pxheight/self.heightpx)
if scale > 1:
scale = 1
self.drawfunc(None, cr, scale=scale)
def on_paginate(self, operation, context):

View File

@ -523,8 +523,6 @@ class CairoPrintSave:
pxwidth = round(context.get_width())
pxheight = round(context.get_height())
scale = min(pxwidth/self.widthpx, pxheight/self.heightpx)
if scale > 1:
scale = 1
self.drawfunc(None, cr, scale=scale)
def on_paginate(self, operation, context):

View File

@ -316,15 +316,6 @@ class RelationshipView(NavigationView):
self.child = None
self.scroll = Gtk.ScrolledWindow()
st_cont = self.scroll.get_style_context()
col = st_cont.lookup_color('base_color')
if col[0]:
self.color = col[1]
else:
self.color = Gdk.RGBA()
self.color.parse("White")
self.scroll.set_policy(Gtk.PolicyType.AUTOMATIC,
Gtk.PolicyType.AUTOMATIC)
self.scroll.show()
@ -589,9 +580,7 @@ class RelationshipView(NavigationView):
grid.attach(eventbox, 0, 0, 2, 1)
eventbox = Gtk.EventBox()
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox = widgets.ShadeBox(self.use_shade)
grid.attach(eventbox, 1, 1, 1, 1)
subgrid = Gtk.Grid()
subgrid.set_column_spacing(12)
@ -888,9 +877,7 @@ class RelationshipView(NavigationView):
box = self.get_people_box(family.get_father_handle(),
family.get_mother_handle(),
post_msg=childmsg)
eventbox = Gtk.EventBox()
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox = widgets.ShadeBox(self.use_shade)
eventbox.add(box)
self.child.attach(eventbox, _PDATA_START, self.row,
_PDATA_STOP-_PDATA_START, 1)
@ -942,9 +929,7 @@ class RelationshipView(NavigationView):
else :
childmsg = _(" (only child)")
box = self.get_people_box(post_msg=childmsg)
eventbox = Gtk.EventBox()
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox = widgets.ShadeBox(self.use_shade)
eventbox.add(box)
self.child.attach(eventbox, _PDATA_START, self.row,
_PDATA_STOP-_PDATA_START, 1)
@ -972,9 +957,7 @@ class RelationshipView(NavigationView):
child_should_be_linked = (child_handle != active)
self.write_child(vbox, child_handle, i, child_should_be_linked)
i += 1
eventbox = Gtk.EventBox()
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox = widgets.ShadeBox(self.use_shade)
eventbox.add(vbox)
self.child.attach(eventbox, _CDATA_START-1, self.row,
_CDATA_STOP-_CDATA_START+1, 1)
@ -994,9 +977,6 @@ class RelationshipView(NavigationView):
name = self.get_name(handle, True)
link_label = widgets.LinkLabel(name, self._button_press,
handle, theme=self.theme)
if self.use_shade:
link_label.override_background_color(Gtk.StateType.NORMAL,
self.color)
if self._config.get('preferences.releditbtn'):
button = widgets.IconButton(self.edit_button_press,
handle)
@ -1039,7 +1019,7 @@ class RelationshipView(NavigationView):
_PLABEL_STOP-_PLABEL_START, 1)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
eventbox = Gtk.EventBox()
eventbox = widgets.ShadeBox(self.use_shade)
if handle:
name = self.get_name(handle, True)
person = self.dbstate.db.get_person_from_handle(handle)
@ -1053,8 +1033,6 @@ class RelationshipView(NavigationView):
emph = False
link_label = widgets.LinkLabel(name, self._button_press,
handle, emph, theme=self.theme)
if self.use_shade:
link_label.override_background_color(Gtk.StateType.NORMAL, self.color)
if self._config.get('preferences.releditbtn'):
button = widgets.IconButton(self.edit_button_press, handle)
button.set_tooltip_text(_('Edit Person (%s)') % name[0])
@ -1073,8 +1051,6 @@ class RelationshipView(NavigationView):
if value:
vbox.pack_start(widgets.MarkupLabel(value), True, True, 0)
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox.add(vbox)
self.child.attach(eventbox, _PDATA_START, self.row,
@ -1174,9 +1150,6 @@ class RelationshipView(NavigationView):
name = self.get_name(handle, True)
link_label = widgets.LinkLabel(name, link_func, handle, emph,
theme=self.theme)
if self.use_shade:
link_label.override_background_color(Gtk.StateType.NORMAL, self.color)
link_label.set_padding(3, 0)
if child_should_be_linked and self._config.get(
'preferences.releditbtn'):
@ -1391,9 +1364,7 @@ class RelationshipView(NavigationView):
else :
childmsg = _(" (no children)")
box = self.get_people_box(handle, post_msg=childmsg)
eventbox = Gtk.EventBox()
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox = widgets.ShadeBox(self.use_shade)
eventbox.add(box)
self.child.attach(eventbox, _PDATA_START, self.row,
_PDATA_STOP-_PDATA_START, 1)
@ -1438,9 +1409,7 @@ class RelationshipView(NavigationView):
else :
childmsg = _(" (no children)")
box = self.get_people_box(post_msg=childmsg)
eventbox = Gtk.EventBox()
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox = widgets.ShadeBox(self.use_shade)
eventbox.add(box)
self.child.attach(eventbox, _PDATA_START, self.row,
_PDATA_STOP-_PDATA_START, 1)
@ -1468,9 +1437,7 @@ class RelationshipView(NavigationView):
i += 1
self.row += 1
eventbox = Gtk.EventBox()
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox = widgets.ShadeBox(self.use_shade)
eventbox.add(vbox)
self.child.attach(eventbox, _CDATA_START-1, self.row,
_CDATA_STOP-_CDATA_START+1, 1)

View File

@ -628,17 +628,25 @@ class BasePage: # pylint: disable=C1001
"""
creates the event header row for all events
"""
trow = Html("tr")
trow = Html("tr", close=None)
trow.extend(
Html("th", trans, class_=colclass, inline=True)
for trans, colclass in [
(self._("Event"), "ColumnEvent"),
(self._("Date"), "ColumnDate"),
(self._("Place"), "ColumnPlace"),
(self._("Description"), "ColumnDescription"),
(self._("Notes"), "ColumnNotes"),
(self._("Sources"), "ColumnSources")]
(self._("Description"), "ColumnDescription")]
)
trow += Html("/tr", close=None)
trow2 = Html("tr", indent=False)
trow2.extend(
Html("th", trans, class_=colclass, colspan=opt, inline=True)
for trans, colclass, opt in [
("", "ColumnEvent", 1),
(self._("Sources"), "ColumnSources", 1),
(self._("Notes"), "ColumnNotes", 2)]
)
trow.extend(trow2)
return trow
def display_event_row(self, event, event_ref, place_lat_long,
@ -688,6 +696,12 @@ class BasePage: # pylint: disable=C1001
for (label, colclass, data) in event_data
)
trow2 = Html("tr")
trow2 += Html("td", "", class_="ColumnSources")
# get event source references
srcrefs = self.get_citation_links(event.get_citation_list()) or "&nbsp;"
trow2 += Html("td", srcrefs, class_="ColumnSources")
# get event notes
notelist = event.get_note_list()
notelist.extend(event_ref.get_note_list())
@ -709,12 +723,9 @@ class BasePage: # pylint: disable=C1001
if notelist:
htmllist.extend(self.dump_notes(notelist))
trow += Html("td", htmllist, class_="ColumnNotes")
# get event source references
srcrefs = self.get_citation_links(event.get_citation_list()) or "&nbsp;"
trow += Html("td", srcrefs, class_="ColumnSources")
trow2 += Html("td", htmllist, class_="ColumnNotes", colspan=2)
trow += trow2
# return events table row to its callers
return trow
@ -1502,7 +1513,7 @@ class BasePage: # pylint: disable=C1001
("addressbook", self._("Address Book"),
self.report.inc_addressbook),
('contact', self._("Contact"), self.report.use_contact),
('statistics', self._("Statistics"), True),
('statistics', self._("Statistics"), self.report.inc_stats),
(self.target_cal_uri, self._("Web Calendar"), self.usecal)
]

View File

@ -31,6 +31,7 @@ from unicodedata import normalize
from collections import defaultdict
from hashlib import md5
import re
import gc
import logging
from xml.sax.saxutils import escape
@ -859,4 +860,3 @@ def html_escape(text):
text = text.replace("'", '&#39;')
return text

View File

@ -110,17 +110,18 @@ class EventPages(BasePage):
for event_handle in event_handle_list:
event = self.r_db.get_event_from_handle(event_handle)
event_types.append(self._(event.get_type().xml_str()))
with self.r_user.progress(_("Narrated Web Site Report"),
_("Creating event pages"),
message = _("Creating event pages")
with self.r_user.progress(_("Narrated Web Site Report"), message,
len(event_handle_list) + 1
) as step:
self.eventlistpage(self.report, title, event_types,
event_handle_list)
index = 1
for event_handle in event_handle_list:
step()
index += 1
self.eventpage(self.report, title, event_handle)
step()
self.eventlistpage(self.report, title, event_types,
event_handle_list)
def eventlistpage(self, report, title, event_types, event_handle_list):
"""

View File

@ -103,16 +103,18 @@ class FamilyPages(BasePage):
for item in self.report.obj_dict[Family].items():
LOG.debug(" %s", str(item))
with self.r_user.progress(_("Narrated Web Site Report"),
_("Creating family pages..."),
message = _("Creating family pages...")
index = 1
with self.r_user.progress(_("Narrated Web Site Report"), message,
len(self.report.obj_dict[Family]) + 1
) as step:
self.familylistpage(self.report, title,
self.report.obj_dict[Family].keys())
for family_handle in self.report.obj_dict[Family]:
step()
index += 1
self.familypage(self.report, title, family_handle)
step()
self.familylistpage(self.report, title,
self.report.obj_dict[Family].keys())
def familylistpage(self, report, title, fam_list):
"""

View File

@ -94,6 +94,7 @@ class MediaPages(BasePage):
"""
BasePage.__init__(self, report, title="")
self.media_dict = defaultdict(set)
self.unused_media_handles = []
def display_pages(self, title):
"""
@ -105,9 +106,13 @@ class MediaPages(BasePage):
LOG.debug("obj_dict[Media]")
for item in self.report.obj_dict[Media].items():
LOG.debug(" %s", str(item))
with self.r_user.progress(_("Narrated Web Site Report"),
_("Creating media pages"),
len(self.report.obj_dict[Media]) + 1
if self.create_unused_media:
media_count = len(self.r_db.get_media_handles())
else:
media_count = len(self.report.obj_dict[Media])
message = _("Creating media pages")
with self.r_user.progress(_("Narrated Web Site Report"), message,
media_count + 1
) as step:
# bug 8950 : it seems it's better to sort on desc + gid.
def sort_by_desc_and_gid(obj):
@ -116,24 +121,62 @@ class MediaPages(BasePage):
"""
return (obj.desc.lower(), obj.gramps_id)
self.unused_media_handles = []
if self.create_unused_media:
# add unused media
media_list = self.r_db.get_media_handles()
for media_ref in media_list:
if media_ref not in self.report.obj_dict[Media]:
self.unused_media_handles.append(media_ref)
self.unused_media_handles = sorted(
self.unused_media_handles,
key=lambda x: sort_by_desc_and_gid(
self.r_db.get_media_from_handle(x)))
sorted_media_handles = sorted(
self.report.obj_dict[Media].keys(),
key=lambda x: sort_by_desc_and_gid(
self.r_db.get_media_from_handle(x)))
self.medialistpage(self.report, title, sorted_media_handles)
prev = None
total = len(sorted_media_handles)
index = 1
for handle in sorted_media_handles:
gc.collect() # Reduce memory usage when there are many images.
next_ = None if index == total else sorted_media_handles[index]
step()
if index == media_count:
next_ = None
elif index < total:
next_ = sorted_media_handles[index]
elif len(self.unused_media_handles) > 0:
next_ = self.unused_media_handles[0]
else:
next_ = None
self.mediapage(self.report, title,
handle, (prev, next_, index, total))
handle, (prev, next_, index, media_count))
prev = handle
step()
index += 1
total = len(self.unused_media_handles)
idx = 1
prev = sorted_media_handles[len(sorted_media_handles)-1]
if total > 0:
for media_handle in self.unused_media_handles:
media = self.r_db.get_media_from_handle(media_handle)
gc.collect() # Reduce memory usage when many images.
if index == media_count:
next_ = None
else:
next_ = self.unused_media_handles[idx]
self.mediapage(self.report, title,
media_handle,
(prev, next_, index, media_count))
prev = media_handle
step()
index += 1
idx += 1
self.medialistpage(self.report, title, sorted_media_handles)
def medialistpage(self, report, title, sorted_media_handles):
"""
Generate and output the Media index page.
@ -191,85 +234,84 @@ class MediaPages(BasePage):
table += tbody
index = 1
for media_handle in sorted_media_handles:
media = self.r_db.get_media_from_handle(media_handle)
if media:
if media.get_change_time() > ldatec:
ldatec = media.get_change_time()
title = media.get_description() or "[untitled]"
if self.create_unused_media:
media_count = len(self.r_db.get_media_handles())
else:
media_count = len(self.report.obj_dict[Media])
message = _("Creating list of media pages")
with self.r_user.progress(_("Narrated Web Site Report"),
message, media_count + 1
) as step:
for media_handle in sorted_media_handles:
media = self.r_db.get_media_from_handle(media_handle)
if media:
if media.get_change_time() > ldatec:
ldatec = media.get_change_time()
title = media.get_description() or "[untitled]"
trow = Html("tr")
tbody += trow
trow = Html("tr")
tbody += trow
media_data_row = [
[index, "ColumnRowLabel"],
[self.media_ref_link(media_handle,
title), "ColumnName"],
[self.rlocale.get_date(media.get_date_object()),
"ColumnDate"],
[media.get_mime_type(), "ColumnMime"]]
media_data_row = [
[index, "ColumnRowLabel"],
[self.media_ref_link(media_handle,
title), "ColumnName"],
[self.rlocale.get_date(media.get_date_object()),
"ColumnDate"],
[media.get_mime_type(), "ColumnMime"]]
trow.extend(
Html("td", data, class_=colclass)
for data, colclass in media_data_row
)
trow.extend(
Html("td", data, class_=colclass)
for data, colclass in media_data_row
)
step()
index += 1
def sort_by_desc_and_gid(obj):
"""
Sort by media description and gramps ID
"""
return (obj.desc, obj.gramps_id)
def sort_by_desc_and_gid(obj):
"""
Sort by media description and gramps ID
"""
return (obj.desc, obj.gramps_id)
unused_media_handles = []
if self.create_unused_media:
# add unused media
media_list = self.r_db.get_media_handles()
for media_ref in media_list:
if media_ref not in self.report.obj_dict[Media]:
unused_media_handles.append(media_ref)
unused_media_handles = sorted(
unused_media_handles,
key=lambda x: sort_by_desc_and_gid(
self.r_db.get_media_from_handle(x)))
idx = 1
prev = None
total = len(unused_media_handles)
if total > 0:
trow += Html("tr")
trow.extend(
Html("td", Html("h4", " "), inline=True) +
Html("td",
Html("h4",
self._("Below unused media objects"),
inline=True),
class_="") +
Html("td", Html("h4", " "), inline=True) +
Html("td", Html("h4", " "), inline=True)
)
for media_handle in unused_media_handles:
media = self.r_db.get_media_from_handle(media_handle)
gc.collect() # Reduce memory usage when many images.
next_ = None if idx == total else unused_media_handles[idx]
trow += Html("tr")
media_data_row = [
[index, "ColumnRowLabel"],
[self.media_ref_link(media_handle,
media.get_description()),
"ColumnName"],
[self.rlocale.get_date(media.get_date_object()),
"ColumnDate"],
[media.get_mime_type(), "ColumnMime"]]
trow.extend(
Html("td", data, class_=colclass)
for data, colclass in media_data_row
)
self.mediapage(self.report, title,
media_handle, (prev, next_, index, total))
prev = media_handle
index += 1
idx += 1
idx = 1
prev = None
total = len(self.unused_media_handles)
if total > 0:
trow += Html("tr")
trow.extend(
Html("td", Html("h4", " "), inline=True) +
Html("td",
Html("h4",
self._("Below unused media objects"),
inline=True),
class_="") +
Html("td", Html("h4", " "), inline=True) +
Html("td", Html("h4", " "), inline=True)
)
for media_handle in self.unused_media_handles:
media = self.r_db.get_media_from_handle(media_handle)
gc.collect() # Reduce memory usage when many images.
if idx == total:
next_ = None
else:
self.unused_media_handles[idx]
trow += Html("tr")
media_data_row = [
[index, "ColumnRowLabel"],
[self.media_ref_link(media_handle,
media.get_description()),
"ColumnName"],
[self.rlocale.get_date(media.get_date_object()),
"ColumnDate"],
[media.get_mime_type(), "ColumnMime"]]
trow.extend(
Html("td", data, class_=colclass)
for data, colclass in media_data_row
)
prev = media_handle
step()
index += 1
idx += 1
# add footer section
# add clearline for proper styling

View File

@ -200,6 +200,8 @@ class NavWebReport(Report):
self.use_intro = self.options['intronote'] or self.options['introimg']
self.use_home = self.options['homenote'] or self.options['homeimg']
self.use_contact = self.opts['contactnote'] or self.opts['contactimg']
self.inc_stats = self.opts['inc_stats']
self.create_unused_media = self.opts['unused']
# Do we need to include this in a cms ?
self.usecms = self.options['usecms']
@ -441,7 +443,8 @@ class NavWebReport(Report):
self.tab["Source"].display_pages(self.title)
# build classes StatisticsPage
self.statistics_preview_page(self.title)
if self.inc_stats:
self.statistics_preview_page(self.title)
# copy all of the neccessary files
self.copy_narrated_files()
@ -458,6 +461,7 @@ class NavWebReport(Report):
if len(_WRONGMEDIAPATH) > 10:
error += '\n ...'
self.user.warn(_("Missing media objects:"), error)
self.database.clear_cache()
def _build_obj_dict(self):
"""
@ -488,12 +492,14 @@ class NavWebReport(Report):
ind_list = self._db.iter_person_handles()
ind_list = self.filter.apply(self._db, ind_list, user=self.user)
with self.user.progress(_("Narrated Web Site Report"),
_('Constructing list of other objects...'),
message = _('Constructing list of other objects...')
with self.user.progress(_("Narrated Web Site Report"), message,
sum(1 for _ in ind_list)) as step:
index = 1
for handle in ind_list:
step()
self._add_person(handle, "", "")
step()
index += 1
LOG.debug("final object dictionary \n" +
"".join(("%s: %s\n" % item)
@ -1057,13 +1063,15 @@ class NavWebReport(Report):
@param: ind_list -- The list of person to use
"""
if self.inc_gendex:
with self.user.progress(_("Narrated Web Site Report"),
_('Creating GENDEX file'),
message = _('Creating GENDEX file')
with self.user.progress(_("Narrated Web Site Report"), message,
len(ind_list)) as step:
fp_gendex, gendex_io = self.create_file("gendex", ext=".txt")
date = 0
index = 1
for person_handle in ind_list:
step()
index += 1
person = self._db.get_person_from_handle(person_handle)
datex = person.get_change_time()
if datex > date:
@ -1113,29 +1121,35 @@ class NavWebReport(Report):
"""
local_list = sort_people(self._db, ind_list, self.rlocale)
with self.user.progress(_("Narrated Web Site Report"),
_("Creating surname pages"),
message = _("Creating surname pages")
with self.user.progress(_("Narrated Web Site Report"), message,
len(local_list)) as step:
SurnameListPage(self, self.title, ind_list,
SurnameListPage.ORDER_BY_NAME,
self.surname_fname)
SurnameListPage.ORDER_BY_NAME,
self.surname_fname)
SurnameListPage(self, self.title, ind_list,
SurnameListPage.ORDER_BY_COUNT,
"surnames_count")
SurnameListPage.ORDER_BY_COUNT,
"surnames_count")
index = 1
for (surname, handle_list) in local_list:
SurnamePage(self, self.title, surname, sorted(handle_list))
step()
index += 1
def thumbnail_preview_page(self):
"""
creates the thumbnail preview page
"""
if self.create_unused_media:
media_count = len(self._db.get_media_handles())
else:
media_count = len(self.obj_dict[Media])
with self.user.progress(_("Narrated Web Site Report"),
_("Creating thumbnail preview page..."),
len(self.obj_dict[Media])) as step:
media_count) as step:
ThumbnailPreviewPage(self, self.title, step)
def statistics_preview_page(self, title):
@ -1144,7 +1158,7 @@ class NavWebReport(Report):
"""
with self.user.progress(_("Narrated Web Site Report"),
_("Creating statistics page..."),
len(self.obj_dict[Media])) as step:
1) as step:
StatisticsPage(self, title, step)
def addressbook_pages(self, ind_list):
@ -1184,12 +1198,14 @@ class NavWebReport(Report):
# begin Address Book pages
addr_size = len(url_addr_res)
with self.user.progress(_("Narrated Web Site Report"),
_("Creating address book pages ..."),
message = _("Creating address book pages ...")
with self.user.progress(_("Narrated Web Site Report"), message,
addr_size) as step:
index = 1
for (sort_name, person_handle, add, res, url) in url_addr_res:
AddressBookPage(self, self.title, person_handle, add, res, url)
step()
index += 1
def base_pages(self):
"""
@ -1968,6 +1984,10 @@ class NavWebOptions(MenuReportOptions):
"events."))
addopt("inc_addressbook", inc_addressbook)
inc_statistics = BooleanOption(_("Include the statistics page"), False)
inc_statistics.set_help(_("Whether or not to add statistics page"))
addopt("inc_stats", inc_statistics)
def __add_place_map_options(self, menu):
"""
options for the Place Map tab.

View File

@ -130,16 +130,19 @@ class PersonPages(BasePage):
LOG.debug("obj_dict[Person]")
for item in self.report.obj_dict[Person].items():
LOG.debug(" %s", str(item))
with self.r_user.progress(_("Narrated Web Site Report"),
_('Creating individual pages'),
message = _('Creating individual pages')
with self.r_user.progress(_("Narrated Web Site Report"), message,
len(self.report.obj_dict[Person]) + 1
) as step:
self.individuallistpage(self.report, title,
self.report.obj_dict[Person].keys())
index = 1
for person_handle in sorted(self.report.obj_dict[Person]):
step()
index += 1
person = self.r_db.get_person_from_handle(person_handle)
self.individualpage(self.report, title, person)
step()
self.individuallistpage(self.report, title,
self.report.obj_dict[Person].keys())
#################################################
#

View File

@ -113,17 +113,18 @@ class PlacePages(BasePage):
LOG.debug("obj_dict[Place]")
for item in self.report.obj_dict[Place].items():
LOG.debug(" %s", str(item))
with self.r_user.progress(_("Narrated Web Site Report"),
_("Creating place pages"),
message = _("Creating place pages")
with self.r_user.progress(_("Narrated Web Site Report"), message,
len(self.report.obj_dict[Place]) + 1
) as step:
self.placelistpage(self.report, title,
self.report.obj_dict[Place].keys())
index = 1
for place_handle in self.report.obj_dict[Place]:
step()
index += 1
self.placepage(self.report, title, place_handle)
step()
self.placelistpage(self.report, title,
self.report.obj_dict[Place].keys())
def placelistpage(self, report, title, place_handles):
"""

View File

@ -98,8 +98,8 @@ class RepositoryPages(BasePage):
LOG.debug(" %s", str(item))
# set progress bar pass for Repositories
with self.r_user.progress(_("Narrated Web Site Report"),
_('Creating repository pages'),
message = _('Creating repository pages')
with self.r_user.progress(_("Narrated Web Site Report"), message,
len(self.report.obj_dict[Repository]) + 1
) as step:
# Sort the repositories
@ -114,10 +114,11 @@ class RepositoryPages(BasePage):
# RepositoryListPage Class
self.repositorylistpage(self.report, title, repos_dict, keys)
idx = 1
for index, key in enumerate(keys):
(repo, handle) = repos_dict[key]
step()
idx += 1
self.repositorypage(self.report, title, repo, handle)
def repositorylistpage(self, report, title, repos_dict, keys):

View File

@ -99,15 +99,17 @@ class SourcePages(BasePage):
LOG.debug("obj_dict[Source]")
for item in self.report.obj_dict[Source].items():
LOG.debug(" %s", str(item))
with self.r_user.progress(_("Narrated Web Site Report"),
_("Creating source pages"),
message = _("Creating source pages")
with self.r_user.progress(_("Narrated Web Site Report"), message,
len(self.report.obj_dict[Source]) + 1
) as step:
self.sourcelistpage(self.report, title,
self.report.obj_dict[Source].keys())
index = 1
for source_handle in self.report.obj_dict[Source]:
step()
index += 1
self.sourcepage(self.report, title, source_handle)
def sourcelistpage(self, report, title, source_handles):

View File

@ -86,6 +86,7 @@ class StatisticsPage(BasePage):
females,
unknown) = self.get_gender(report.database.iter_person_handles())
step()
mobjects = report.database.get_number_of_media()
npersons = report.database.get_number_of_people()
nfamilies = report.database.get_number_of_families()

View File

@ -122,7 +122,7 @@ class ThumbnailPreviewPage(BasePage):
"will take you to that image&#8217;s page.")
previewpage += Html("p", msg, id="description")
with Html("table", class_="calendar") as table:
with Html("table", class_="calendar thumbnails") as table:
previewpage += table
thead = Html("thead")
@ -153,7 +153,7 @@ class ThumbnailPreviewPage(BasePage):
num_of_cols = 7
grid_row = 0
while grid_row < num_of_rows:
trow = Html("tr", id="RowNumber: %08d" % grid_row)
trow = Html("tr", class_="thumbnail", id="RowNumber: %08d" % grid_row)
tbody += trow
cols = 0
@ -163,7 +163,7 @@ class ThumbnailPreviewPage(BasePage):
photo = media_list[indexpos][2]
# begin table cell and attach to table row(trow)...
tcell = Html("td", class_="highlight weekend")
tcell = Html("td", class_="highlight weekend thumbnail")
trow += tcell
# attach index number...
@ -203,6 +203,7 @@ class ThumbnailPreviewPage(BasePage):
for emptycols in range(cols, num_of_cols):
trow += Html("td", class_="emptyDays", inline=True)
message = _("Creating thumbnail preview page...")
# begin Thumbnail Reference section...
with Html("div", class_="subsection", id="references") as section:
body += section
@ -225,11 +226,12 @@ class ThumbnailPreviewPage(BasePage):
tcell2 = Html("td", ptitle, class_="ColumnName")
trow += (tcell1, tcell2)
# increase progress meter...
cb_progress()
# increase index for row number...
index += 1
# increase progress meter...
cb_progress()
# add body id element
body.attr = 'id ="ThumbnailPreview"'

View File

@ -1,200 +1,149 @@
; gramps.py GtkAccelMap rc-file -*- scheme -*-
; Gramps.py GtkAccelMap rc-file -*- scheme -*-
; this file is an automated accelerator map dump
;
(gtk_accel_path "<Actions>/People Tree View/PersonAll/Edit" "<Meta>Return")
; (gtk_accel_path "<Actions>/FileWindow/PluginStatus" "")
; (gtk_accel_path "<Actions>/ReportWindow/place_report" "")
; (gtk_accel_path "<Actions>/FileWindow/ViewMenu" "")
(gtk_accel_path "<Actions>/Pedigree/Forward/Forward" "<Alt>Right")
; (gtk_accel_path "<Actions>/ReportWindow/birthday_report" "")
; (gtk_accel_path "<Actions>/ReportWindow/marker_report" "")
; (gtk_accel_path "<Actions>/ReportWindow/Graphs" "")
; (gtk_accel_path "<Actions>/FileWindow/FAQ" "")
; (gtk_accel_path "<Actions>/ToolWindow/mediaman" "")
(gtk_accel_path "<Actions>/Families/Forward/Forward" "<Alt>Right")
(gtk_accel_path "<Actions>/Events/ChangeOrder/Add" "<Alt><Meta>i")
; (gtk_accel_path "<Actions>/ReportWindow/det_descendant_report" "")
; (gtk_accel_path "<Actions>/ReportWindow/statistics_chart" "")
; (gtk_accel_path "<Actions>/Person View/PersonAll/FilterEdit" "")
(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>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")
(gtk_accel_path "<Actions>/MainWindow/Import" "<Meta>i")
; (gtk_accel_path "<Actions>/FileWindow/Filter" "")
; (gtk_accel_path "<Actions>/ReportWindow/summary" "")
(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>d")
; (gtk_accel_path "<Actions>/ReportWindow/book" "")
; (gtk_accel_path "<Actions>/FileWindow/FileMenu" "")
(gtk_accel_path "<Actions>/Person View/Backward/Back" "<Alt>Left")
; (gtk_accel_path "<Actions>/ReportWindow/records" "")
; (gtk_accel_path "<Actions>/ReportWindow/ancestor_report" "")
; (gtk_accel_path "<Actions>/ToolWindow/chname" "")
; (gtk_accel_path "<Actions>/Person View/PersonEdit/FastMerge" "")
(gtk_accel_path "<Actions>/Relationships/Forward/Forward" "<Alt>Right")
; (gtk_accel_path "<Actions>/Person View/PersonEdit/ExportTab" "")
(gtk_accel_path "<Actions>/Notes/ChangeOrder/Remove" "<Meta>Delete")
; (gtk_accel_path "<Actions>/ToolWindow/editowner" "")
; (gtk_accel_path "<Actions>/ReportWindow/hourglass_graph" "")
(gtk_accel_path "<Actions>/Repositories/ChangeOrder/Add" "<Alt><Meta>i")
(gtk_accel_path "<Actions>/Media/Forward/Forward" "<Alt>Right")
(gtk_accel_path "<Actions>/AllMainWindow/<CONTROL>Delete" "<Meta>Delete")
; (gtk_accel_path "<Actions>/FileWindow/Toolbar" "")
(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>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")
(gtk_accel_path "<Actions>/Place View/ChangeOrder/Remove" "<Meta>Delete")
(gtk_accel_path "<Actions>/Sources/ChangeOrder/Remove" "<Meta>Delete")
(gtk_accel_path "<Actions>/Person View/ChangeOrder/Remove" "<Meta>Delete")
; (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>d")
; (gtk_accel_path "<Actions>/ToolWindow/reorder_ids" "")
(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" "")
(gtk_accel_path "<Actions>/Place View/Forward/Forward" "<Alt>Right")
; (gtk_accel_path "<Actions>/ReportWindow/kinship_report" "")
; (gtk_accel_path "<Actions>/MainWindow/BookMenu" "")
; (gtk_accel_path "<Actions>/ToolWindow/evname" "")
; (gtk_accel_path "<Actions>/ToolWindow/Analysis-and-Exploration" "")
; (gtk_accel_path "<Actions>/ReportWindow/indiv_complete" "")
; (gtk_accel_path "<Actions>/AllMainWindow/F12" "F12")
(gtk_accel_path "<Actions>/Place Tree View/Bookmark/AddBook" "<Meta>d")
; (gtk_accel_path "<Actions>/AllMainWindow/F11" "F11")
; (gtk_accel_path "<Actions>/ReportWindow/place_report" "")
; (gtk_accel_path "<Actions>/ToolWindow/mediaman" "")
(gtk_accel_path "<Actions>/MainWindow/SourceAdd" "<Shift><ctrl><alt>s")
; (gtk_accel_path "<Actions>/ReportWindow/summary" "")
; (gtk_accel_path "<Actions>/ToolWindow/rebuild_refmap" "")
; (gtk_accel_path "<Actions>/Redo/Redo" "<Primary><Shift>z")
; (gtk_accel_path "<Actions>/ToolWindow/ToolAnExp" "")
; (gtk_accel_path "<Actions>/FileWindow/Toolbar" "")
; (gtk_accel_path "<Actions>/ToolWindow/editowner" "")
; (gtk_accel_path "<Actions>/FileWindow/Preferences" "")
(gtk_accel_path "<Actions>/MainWindow/MediaAdd" "<Shift><ctrl><alt>m")
; (gtk_accel_path "<Actions>/ToolWindow/sortevents" "")
(gtk_accel_path "<Actions>/Fan Chart/Backward/Back" "<Alt>Left")
; (gtk_accel_path "<Actions>/Media/Backward/Back" "<Alt>Left")
; (gtk_accel_path "<Actions>/Fan Chart/Bookmark/AddBook" "<Meta>d")
; (gtk_accel_path "<Actions>/Person View/PersonEdit/CmpMerge" "")
; (gtk_accel_path "<Actions>/MainWindow/ToolsMenu" "")
(gtk_accel_path "<Actions>/Events/Forward/Forward" "<Alt>Right")
(gtk_accel_path "<Actions>/Families/Backward/Back" "<Alt>Left")
(gtk_accel_path "<Actions>/Place View/Backward/Back" "<Alt>Left")
; (gtk_accel_path "<Actions>/ReportWindow/descend_chart" "")
; (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>d")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>Delete" "<Primary>Delete")
; (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")
(gtk_accel_path "<Actions>/People Tree View/ChangeOrder/Add" "<Alt><Meta>i")
; (gtk_accel_path "<Actions>/FileWindow/Sidebar" "")
; (gtk_accel_path "<Actions>/Person View/PersonAll/Dummy" "")
(gtk_accel_path "<Actions>/Redo/Redo" "<Shift><Meta>z")
(gtk_accel_path "<Actions>/Person View/PersonEdit/Remove" "<Meta>Delete")
; (gtk_accel_path "<Actions>/ReportWindow/family_group" "")
; (gtk_accel_path "<Actions>/ToolWindow/excity" "")
(gtk_accel_path "<Actions>/Repositories/ChangeOrder/Remove" "<Meta>Delete")
(gtk_accel_path "<Actions>/Repositories/Forward/Forward" "<Alt>Right")
; (gtk_accel_path "<Actions>/FileWindow/UserManual" "F1")
; (gtk_accel_path "<Actions>/FileWindow/OpenRecent" "")
(gtk_accel_path "<Actions>/Families/Bookmark/AddBook" "<Meta>d")
(gtk_accel_path "<Actions>/Place Tree View/Forward/Forward" "<Alt>Right")
; (gtk_accel_path "<Actions>/ReportWindow/hourglass_graph" "")
; (gtk_accel_path "<Actions>/Undo/Undo" "<Primary>z")
; (gtk_accel_path "<Actions>/ToolWindow/reorder_ids" "")
; (gtk_accel_path "<Actions>/ReportWindow/rel_graph" "")
; (gtk_accel_path "<Actions>/ReportWindow/Web-Pages" "")
; (gtk_accel_path "<Actions>/ReportWindow/WebCal" "")
; (gtk_accel_path "<Actions>/ReportWindow/Text-Reports" "")
; (gtk_accel_path "<Actions>/Person View/PersonAll/QuickReport" "")
; (gtk_accel_path "<Actions>/MainWindow/ConfigView" "<Primary><Shift>c")
; (gtk_accel_path "<Actions>/ReportWindow/descend_report" "")
; (gtk_accel_path "<Actions>/ReportWindow/ancestor_chart" "")
; (gtk_accel_path "<Actions>/MainWindow/Clipboard" "<Primary>b")
; (gtk_accel_path "<Actions>/FileWindow/MailingLists" "")
; (gtk_accel_path "<Actions>/AllMainWindow/GoMenu" "")
; (gtk_accel_path "<Actions>/ToolWindow/verify" "")
; (gtk_accel_path "<Actions>/ToolWindow/mergecitations" "")
; (gtk_accel_path "<Actions>/FileWindow/HomePage" "")
(gtk_accel_path "<Actions>/Relationships/Family/Edit" "<Meta>Return")
; (gtk_accel_path "<Actions>/ToolWindow/patchnames" "")
(gtk_accel_path "<Actions>/Relationships/Backward/Back" "<Alt>Left")
; (gtk_accel_path "<Actions>/ToolWindow/populatesources" "")
; (gtk_accel_path "<Actions>/FileWindow/Open" "<Primary>o")
; (gtk_accel_path "<Actions>/ReportWindow/endofline_report" "")
(gtk_accel_path "<Actions>/MainWindow/CitationAdd" "<Shift><ctrl><alt>c")
; (gtk_accel_path "<Actions>/UndoHistory/UndoHistory" "<Primary>h")
; (gtk_accel_path "<Actions>/ReportWindow/family_descend_chart" "")
(gtk_accel_path "<Actions>/AllMainWindow/Close" "<Primary>w")
; (gtk_accel_path "<Actions>/FileWindow/HelpMenu" "")
; (gtk_accel_path "<Actions>/ToolWindow/loop" "")
; (gtk_accel_path "<Actions>/ReportWindow/descend_chart" "")
(gtk_accel_path "<Actions>/MainWindow/EventAdd" "<Shift><ctrl><alt>e")
; (gtk_accel_path "<Actions>/FileWindow/ExtraPlugins" "")
(gtk_accel_path "<Actions>/MainWindow/RepositoryAdd" "<Shift><ctrl><alt>r")
; (gtk_accel_path "<Actions>/MainWindow/BookMenu" "")
; (gtk_accel_path "<Actions>/ToolWindow/ToolProc" "")
(gtk_accel_path "<Actions>/MainWindow/NoteAdd" "<Shift><ctrl><alt>n")
(gtk_accel_path "<Actions>/MainWindow/PlaceAdd" "<Shift><ctrl><alt>l")
; (gtk_accel_path "<Actions>/ReportWindow/navwebpage" "")
; (gtk_accel_path "<Actions>/ReportWindow/birthday_report" "")
; (gtk_accel_path "<Actions>/RecentFiles/RecentMenu8" "")
; (gtk_accel_path "<Actions>/FileWindow/ViewMenu" "")
; (gtk_accel_path "<Actions>/ReportWindow/fan_chart" "")
; (gtk_accel_path "<Actions>/RecentFiles/RecentMenu7" "")
; (gtk_accel_path "<Actions>/ReportWindow/calendar" "")
; (gtk_accel_path "<Actions>/RecentFiles/RecentMenu6" "")
; (gtk_accel_path "<Actions>/RecentFiles/RecentMenu5" "")
; (gtk_accel_path "<Actions>/RecentFiles/RecentMenu4" "")
; (gtk_accel_path "<Actions>/RecentFiles/RecentMenu3" "")
; (gtk_accel_path "<Actions>/RecentFiles/RecentMenu2" "")
; (gtk_accel_path "<Actions>/RecentFiles/RecentMenu1" "")
; (gtk_accel_path "<Actions>/RecentFiles/RecentMenu0" "")
; (gtk_accel_path "<Actions>/ReportWindow/RepWeb" "")
; (gtk_accel_path "<Actions>/ReportWindow/indiv_complete" "")
; (gtk_accel_path "<Actions>/ToolWindow/rebuild_genstats" "")
; (gtk_accel_path "<Actions>/FileWindow/FAQ" "")
; (gtk_accel_path "<Actions>/ReportWindow/det_ancestor_report" "")
(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>d")
; (gtk_accel_path "<Actions>/ReportWindow/timeline" "")
; (gtk_accel_path "<Actions>/ToolWindow/eventcmp" "")
; (gtk_accel_path "<Actions>/AllMainWindow/ReportsMenu" "")
; (gtk_accel_path "<Actions>/FileWindow/EditMenu" "")
(gtk_accel_path "<Actions>/MainWindow/FamilyAdd" "<Shift><ctrl><alt>f")
; (gtk_accel_path "<Actions>/ToolWindow/chname" "")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>Insert" "<Primary>Insert")
; (gtk_accel_path "<Actions>/AllMainWindow/F9" "F9")
; (gtk_accel_path "<Actions>/AllMainWindow/F8" "F8")
; (gtk_accel_path "<Actions>/AllMainWindow/F7" "F7")
; (gtk_accel_path "<Actions>/AllMainWindow/F6" "F6")
(gtk_accel_path "<Actions>/Pedigree/Bookmark/AddBook" "<Meta>d")
; (gtk_accel_path "<Actions>/AllMainWindow/F5" "F5")
; (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>d")
(gtk_accel_path "<Actions>/Sources/ChangeOrder/Add" "<Alt><Meta>i")
; (gtk_accel_path "<Actions>/ReportWindow/Books" "")
; (gtk_accel_path "<Actions>/FileWindow/About" "")
(gtk_accel_path "<Actions>/Notes/Backward/Back" "<Alt>Left")
; (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>d")
; (gtk_accel_path "<Actions>/ToolWindow/soundgen" "")
; (gtk_accel_path "<Actions>/FileWindow/ExtraPlugins" "")
; (gtk_accel_path "<Actions>/AllMainWindow/ReportsMenu" "")
(gtk_accel_path "<Actions>/categoryviews/personlistview_0" "<Meta>1")
; (gtk_accel_path "<Actions>/ReportWindow/descend_report" "")
; (gtk_accel_path "<Actions>/ReportWindow/fan_chart" "")
(gtk_accel_path "<Actions>/MainWindow/ScratchPad" "<Meta>b")
(gtk_accel_path "<Actions>/Person View/Edit" "<Meta>Return")
; (gtk_accel_path "<Actions>/ToolWindow/rebuild" "")
; (gtk_accel_path "<Actions>/ToolWindow/eventcmp" "")
; (gtk_accel_path "<Actions>/AllMainWindow/GoMenu" "")
; (gtk_accel_path "<Actions>/ReportWindow/timeline" "")
; (gtk_accel_path "<Actions>/ToolWindow/Database-Repair" "")
; (gtk_accel_path "<Actions>/ReportWindow/Graphical-Reports" "")
(gtk_accel_path "<Actions>/Person View/HomePerson" "<Alt>Home")
; (gtk_accel_path "<Actions>/ReportWindow/ancestor_chart" "")
; (gtk_accel_path "<Actions>/ToolWindow/check" "")
(gtk_accel_path "<Actions>/Fan Chart/Forward/Forward" "<Alt>Right")
; (gtk_accel_path "<Actions>/ToolWindow/chtype" "")
(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>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")
; (gtk_accel_path "<Actions>/ToolWindow/verify" "")
(gtk_accel_path "<Actions>/People Tree View/Forward/Forward" "<Alt>Right")
(gtk_accel_path "<Actions>/Sources/Backward/Back" "<Alt>Left")
; (gtk_accel_path "<Actions>/ToolWindow/not_related" "")
(gtk_accel_path "<Actions>/People Tree View/Bookmark/AddBook" "<Meta>d")
; (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>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>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/Navigator" "<Primary>m")
; (gtk_accel_path "<Actions>/FileWindow/PluginStatus" "")
; (gtk_accel_path "<Actions>/AllMainWindow/F12" "F12")
; (gtk_accel_path "<Actions>/AllMainWindow/F11" "F11")
; (gtk_accel_path "<Actions>/ToolWindow/ToolUtil" "")
; (gtk_accel_path "<Actions>/MainWindow/Import" "<Primary>i")
; (gtk_accel_path "<Actions>/ReportWindow/statistics_chart" "")
; (gtk_accel_path "<Actions>/FileWindow/UserManual" "F1")
; (gtk_accel_path "<Actions>/AllMainWindow/Books" "")
; (gtk_accel_path "<Actions>/FileWindow/OpenRecent" "")
; (gtk_accel_path "<Actions>/Dashboard/RestoreGramplet" "")
; (gtk_accel_path "<Actions>/WindowManger/4722902520" "")
; (gtk_accel_path "<Actions>/ReportWindow/RepGraph" "")
; (gtk_accel_path "<Actions>/ReportWindow/familylines_graph" "")
; (gtk_accel_path "<Actions>/ReportWindow/kinship_report" "")
; (gtk_accel_path "<Actions>/ToolWindow/testcasegenerator" "")
; (gtk_accel_path "<Actions>/FileWindow/KeyBindings" "")
(gtk_accel_path "<Actions>/Repositories/Backward/Back" "<Alt>Left")
(gtk_accel_path "<Actions>/Events/Bookmark/AddBook" "<Meta>d")
(gtk_accel_path "<Actions>/People Tree View/ChangeOrder/Remove" "<Meta>Delete")
(gtk_accel_path "<Actions>/AllMainWindow/<CONTROL>P" "<Meta>p")
(gtk_accel_path "<Actions>/Person View/ChangeOrder/Add" "<Alt><Meta>i")
(gtk_accel_path "<Actions>/AllMainWindow/<CONTROL>N" "<Meta>n")
(gtk_accel_path "<Actions>/Place Tree View/ChangeOrder/Remove" "<Meta>Delete")
; (gtk_accel_path "<Actions>/AllMainWindow/Abandon" "")
(gtk_accel_path "<Actions>/Events/ChangeOrder/Remove" "<Meta>Delete")
(gtk_accel_path "<Actions>/AllMainWindow/<CONTROL>J" "<Meta>j")
(gtk_accel_path "<Actions>/Media/Bookmark/AddBook" "<Meta>d")
; (gtk_accel_path "<Actions>/ReportWindow/tag_report" "")
; (gtk_accel_path "<Actions>/ToolWindow/dgenstats" "")
; (gtk_accel_path "<Actions>/FileWindow/Quit" "<Primary>q")
; (gtk_accel_path "<Actions>/FileWindow/TipOfDay" "")
; (gtk_accel_path "<Actions>/ReportWindow/ancestor_report" "")
; (gtk_accel_path "<Actions>/ToolWindow/check" "")
; (gtk_accel_path "<Actions>/FileWindow/Fullscreen" "F11")
(gtk_accel_path "<Actions>/MainWindow/PersonAdd" "<Shift><ctrl><alt>p")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>P" "<Primary>p")
; (gtk_accel_path "<Actions>/ToolWindow/remove_unused" "")
; (gtk_accel_path "<Actions>/Person View/PersonOther/SetActive" "")
(gtk_accel_path "<Actions>/categoryviews/personview_1" "<Meta>2")
(gtk_accel_path "<Actions>/Sources/Bookmark/AddBook" "<Meta>d")
(gtk_accel_path "<Actions>/Place View/ChangeOrder/Add" "<Alt><Meta>i")
(gtk_accel_path "<Actions>/Person View/PersonEdit/Add" "<Alt><Meta>i")
(gtk_accel_path "<Actions>/Sources/Forward/Forward" "<Alt>Right")
(gtk_accel_path "<Actions>/Person View/Bookmark/AddBook" "<Meta>d")
; (gtk_accel_path "<Actions>/FileWindow/Preferences" "")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>N" "<Primary>n")
; (gtk_accel_path "<Actions>/ReportWindow/WebCal" "")
; (gtk_accel_path "<Actions>/ReportWindow/records" "")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>J" "<Primary>j")
; (gtk_accel_path "<Actions>/ReportWindow/number_of_ancestors" "")
; (gtk_accel_path "<Actions>/ToolWindow/evname" "")
; (gtk_accel_path "<Actions>/Dashboard/AddGramplet" "")
; (gtk_accel_path "<Actions>/ReportWindow/notelinkreport" "")
; (gtk_accel_path "<Actions>/ReportWindow/det_descendant_report" "")
; (gtk_accel_path "<Actions>/MainWindow/AddMenu" "")
; (gtk_accel_path "<Actions>/AllMainWindow/WindowsMenu" "")
; (gtk_accel_path "<Actions>/ToolWindow/test_for_date_parser_and_displayer" "")
; (gtk_accel_path "<Actions>/AllMainWindow/Abandon" "")
; (gtk_accel_path "<Actions>/ReportWindow/family_group" "")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>9" "<Primary>9")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>8" "<Primary>8")
; (gtk_accel_path "<Actions>/ToolWindow/not_related" "")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>7" "<Primary>7")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>6" "<Primary>6")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>5" "<Primary>5")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>4" "<Primary>4")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>3" "<Primary>3")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>2" "<Primary>2")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>1" "<Primary>1")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>0" "<Primary>0")
; (gtk_accel_path "<Actions>/WindowManger/M:4722902520" "")
; (gtk_accel_path "<Actions>/FileWindow/About" "")
; (gtk_accel_path "<Actions>/MainWindow/ToolsMenu" "")
; (gtk_accel_path "<Actions>/FileWindow/FileMenu" "")
; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>BackSpace" "<Primary>BackSpace")
; (gtk_accel_path "<Actions>/AllMainWindow/Export" "<Primary>e")
; (gtk_accel_path "<Actions>/AllMainWindow/Backup" "")
; (gtk_accel_path "<Actions>/ToolWindow/ToolDebug" "")
; (gtk_accel_path "<Actions>/ReportWindow/Graphs" "")
; (gtk_accel_path "<Actions>/ReportWindow/RepText" "")
; (gtk_accel_path "<Actions>/ToolWindow/dupfind" "")
; (gtk_accel_path "<Actions>/ToolWindow/rebuild" "")
; (gtk_accel_path "<Actions>/ToolWindow/patchnames" "")
; (gtk_accel_path "<Actions>/ToolWindow/chtype" "")
; (gtk_accel_path "<Actions>/ToolWindow/ToolRep" "")

View File

@ -345,6 +345,7 @@ gramps/gen/plug/_pluginreg.py
gramps/gen/plug/docbackend/docbackend.py
gramps/gen/plug/docgen/graphdoc.py
gramps/gen/plug/docgen/paperstyle.py
gramps/gen/plug/docgen/treedoc.py
gramps/gen/plug/menu/_enumeratedlist.py
gramps/gen/plug/report/_book.py
gramps/gen/plug/report/_constants.py

View File

@ -431,6 +431,7 @@ gramps/gui/views/treemodels/test/node_test.py
#
gramps/gui/widgets/__init__.py
gramps/gui/widgets/basicentry.py
gramps/gui/widgets/cellrenderertextedit.py
gramps/gui/widgets/dateentry.py
gramps/gui/widgets/fanchart2way.py
gramps/gui/widgets/fanchartdesc.py
@ -441,6 +442,7 @@ gramps/gui/widgets/menuitem.py
gramps/gui/widgets/multitreeview.py
gramps/gui/widgets/placeentry.py
gramps/gui/widgets/selectionwidget.py
gramps/gui/widgets/shadebox.py
gramps/gui/widgets/shortlistcomboentry.py
gramps/gui/widgets/springseparator.py
gramps/gui/widgets/statusbar.py