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

View File

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

View File

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

View File

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

View File

@ -318,6 +318,7 @@ class CLIManager:
and self.dbstate.db.get_total() == 0): and self.dbstate.db.get_total() == 0):
self.dbstate.db.set_researcher(owner) self.dbstate.db.set_researcher(owner)
name_displayer.clear_custom_formats()
name_displayer.set_name_format(self.dbstate.db.name_formats) name_displayer.set_name_format(self.dbstate.db.name_formats)
fmt_default = config.get('preferences.name-format') fmt_default = config.get('preferences.name-format')
name_displayer.set_default_format(fmt_default) 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 import BasePluginManager
from gramps.gen.plug.docgen import (StyleSheet, StyleSheetList, PaperStyle, 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, from gramps.gen.plug.menu import (FamilyOption, PersonOption, NoteOption,
MediaOption, PersonListOption, NumberOption, MediaOption, PersonListOption, NumberOption,
BooleanOption, DestinationOption, Option, 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.display.name import displayer as name_displayer
from gramps.gen.errors import ReportError, FilterError from gramps.gen.errors import ReportError, FilterError
from gramps.gen.plug.report import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_BOOK, from gramps.gen.plug.report import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_BOOK,
CATEGORY_GRAPHVIZ, CATEGORY_CODE, CATEGORY_GRAPHVIZ, CATEGORY_TREE,
ReportOptions, append_styles) CATEGORY_CODE, ReportOptions, append_styles)
from gramps.gen.plug.report._paper import paper_sizes from gramps.gen.plug.report._paper import paper_sizes
from gramps.gen.const import USER_HOME, DOCGEN_OPTIONS from gramps.gen.const import USER_HOME, DOCGEN_OPTIONS
from gramps.gen.dbstate import DbState from gramps.gen.dbstate import DbState
@ -250,6 +251,15 @@ class CommandLineReport:
if name not in self.option_class.options_dict: if name not in self.option_class.options_dict:
self.option_class.options_dict[ self.option_class.options_dict[
name] = menu.get_option_by_name(name).get_value() 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() self.option_class.load_previous_values()
_validate_options(self.option_class, database) _validate_options(self.option_class, database)
self.show = options_str_dict.pop('show', None) self.show = options_str_dict.pop('show', None)
@ -320,6 +330,10 @@ class CommandLineReport:
for graph_format in graphdoc.FORMATS: for graph_format in graphdoc.FORMATS:
self.options_help['off'][2].append( self.options_help['off'][2].append(
graph_format["type"] + "\t" + graph_format["descr"]) 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: else:
self.options_help['off'][2] = "NA" self.options_help['off'][2] = "NA"
@ -498,6 +512,15 @@ class CommandLineReport:
# Pick the first one as the default. # Pick the first one as the default.
self.format = graphdoc.FORMATS[0]["class"] self.format = graphdoc.FORMATS[0]["class"]
_chosen_format = graphdoc.FORMATS[0]["type"] _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: else:
self.format = None self.format = None
if _chosen_format and _format_str: if _chosen_format and _format_str:
@ -665,7 +688,7 @@ def cl_report(database, name, category, report_class, options_class,
clr.selected_style, clr.selected_style,
PaperStyle(clr.paper, clr.orien, clr.marginl, PaperStyle(clr.paper, clr.orien, clr.marginl,
clr.marginr, clr.margint, clr.marginb)) 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.handler.doc = clr.format(
clr.option_class, clr.option_class,
PaperStyle(clr.paper, clr.orien, clr.marginl, PaperStyle(clr.paper, clr.orien, clr.marginl,

View File

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

View File

@ -292,7 +292,7 @@ class DateDisplayDE(DateDisplay):
) )
# this definition must agree with its "_display_gregorian" method # 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 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 # 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 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") "mmmm m. mėnesio diena d.", "Mėn diena, metai")
# this definition must agree with its "_display_gregorian" method # 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 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 # 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 display gregorian calendar date in different format
""" """

View File

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

View File

@ -240,7 +240,7 @@ class DateDisplaySR_Base(DateDisplay):
"VII", "VIII", "IX", "X", "XI", "XII" "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 display gregorian calendar date in different format
""" """

View File

@ -418,6 +418,11 @@ class NameDisplay:
result = raw_data[_FIRSTNAME] result = raw_data[_FIRSTNAME]
return ' '.join(result.split()) 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): def set_name_format(self, formats):
raw_func_dict = { raw_func_dict = {

View File

@ -82,7 +82,8 @@ class IsDescendantFamilyOf(Rule):
while expand: while expand:
person = expand.pop(0) 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 continue
self.matches.add(person.handle) self.matches.add(person.handle)
for family_handle in person.get_family_handle_list(): for family_handle in person.get_family_handle_list():

View File

@ -67,7 +67,8 @@ class IsDescendantOf(Rule):
return person.handle in self.map return person.handle in self.map
def init_list(self, person, first): 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 return
if not first: if not first:
self.map.add(person.handle) self.map.add(person.handle)

View File

@ -61,6 +61,9 @@ class IsLessThanNthGenerationAncestorOf(Rule):
queue = [(root_handle, 1)] # generation 1 is root queue = [(root_handle, 1)] # generation 1 is root
while queue: while queue:
handle, gen = queue.pop(0) # pop off front of 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) self.map.add(handle)
gen += 1 gen += 1
if gen <= int(self.list[1]): if gen <= int(self.list[1]):

View File

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

View File

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

View File

@ -65,7 +65,8 @@ class IsLessThanNthGenerationDescendantOf(Rule):
return person.handle in self.map return person.handle in self.map
def init_list(self,person,gen): 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 return
if gen: if gen:
self.map.add(person.handle) self.map.add(person.handle)

View File

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

View File

@ -97,8 +97,10 @@ CATEGORY_CODE = 2
CATEGORY_WEB = 3 CATEGORY_WEB = 3
CATEGORY_BOOK = 4 CATEGORY_BOOK = 4
CATEGORY_GRAPHVIZ = 5 CATEGORY_GRAPHVIZ = 5
CATEGORY_TREE = 6
REPORT_CAT = [ CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_CODE, 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 #possible tool categories
TOOL_DEBUG = -1 TOOL_DEBUG = -1
TOOL_ANAL = 0 TOOL_ANAL = 0
@ -1043,6 +1045,7 @@ def make_environment(**kwargs):
'CATEGORY_WEB': CATEGORY_WEB, 'CATEGORY_WEB': CATEGORY_WEB,
'CATEGORY_BOOK': CATEGORY_BOOK, 'CATEGORY_BOOK': CATEGORY_BOOK,
'CATEGORY_GRAPHVIZ': CATEGORY_GRAPHVIZ, 'CATEGORY_GRAPHVIZ': CATEGORY_GRAPHVIZ,
'CATEGORY_TREE': CATEGORY_TREE,
'TOOL_DEBUG': TOOL_DEBUG, 'TOOL_DEBUG': TOOL_DEBUG,
'TOOL_ANAL': TOOL_ANAL, 'TOOL_ANAL': TOOL_ANAL,
'TOOL_DBPROC': TOOL_DBPROC, 'TOOL_DBPROC': TOOL_DBPROC,
@ -1242,8 +1245,7 @@ class PluginRegister:
""" """
Return a list of :class:`PluginData` that are of type ptype Return a list of :class:`PluginData` that are of type ptype
""" """
return [self.get_plugin(id) for id in return [x for x in self.__plugindata if x.ptype == ptype]
set([x.id for x in self.__plugindata if x.ptype == ptype])]
def report_plugins(self, gui=True): 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 a list of :class:`PluginData` that have load_on_reg == True
""" """
return [self.get_plugin(id) for id in return [x for x in self.__plugindata if x.load_on_reg == True]
set([x.id 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 URL_PATTERN, LOCAL_HYPERLINK, LOCAL_TARGET
from .drawdoc import DrawDoc from .drawdoc import DrawDoc
from .graphdoc import GVDoc 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. 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("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
b_f.write('<booklist>\n') b_f.write('<booklist>\n')
for name in sorted(self.bookmap): # enable a diff of archived copies for name in sorted(self.bookmap): # enable a diff of archived copies
book = self.get_book(name) book = self.get_book(name)
dbname = book.get_dbname() dbname = escape(book.get_dbname())
b_f.write(' <book name="%s" database="%s">' b_f.write(' <book name="%s" database="%s">'
'\n' % (name, dbname)) '\n' % (escape(name), dbname))
for item in book.get_item_list(): for item in book.get_item_list():
b_f.write(' <item name="%s" ' b_f.write(' <item name="%s" '
'trans_name="%s">\n' % ( 'trans_name="%s">\n' % (
@ -566,7 +566,7 @@ class BookList:
'\n' % book.get_format_name()) '\n' % book.get_format_name())
if book.get_output(): if book.get_output():
b_f.write(' <output name="%s"/>' b_f.write(' <output name="%s"/>'
'\n' % book.get_output()) '\n' % escape(book.get_output()))
b_f.write(' </book>\n') b_f.write(' </book>\n')
b_f.write('</booklist>\n') b_f.write('</booklist>\n')
@ -578,8 +578,15 @@ class BookList:
try: try:
parser = make_parser() parser = make_parser()
parser.setContentHandler(BookParser(self, self.dbase)) parser.setContentHandler(BookParser(self, self.dbase))
with open(self.file) as the_file: # bug 10387; XML should be utf8, but was not previously saved
parser.parse(the_file) # 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, except (IOError, OSError, ValueError, SAXParseException, KeyError,
AttributeError): AttributeError):
LOG.debug("Failed to parse book list", exc_info=True) LOG.debug("Failed to parse book list", exc_info=True)

View File

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

View File

@ -31,6 +31,7 @@ import csv
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from .tabbeddoc import * from .tabbeddoc import *
from ...constfunc import win
class CSVTab(TabbedDoc): class CSVTab(TabbedDoc):
@ -48,7 +49,8 @@ class CSVTab(TabbedDoc):
else: else:
self.filename = filename 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) self.writer = csv.writer(self.f)
def close(self): def close(self):

View File

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

View File

@ -35,6 +35,7 @@ _LOG = logging.getLogger(".dialog")
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from gi.repository import GObject from gi.repository import GObject
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GdkPixbuf from gi.repository import GdkPixbuf
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -46,6 +47,7 @@ from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext _ = glocale.translation.gettext
from gramps.gen.const import ICON, URL_BUGHOME from gramps.gen.const import ICON, URL_BUGHOME
from gramps.gen.config import config from gramps.gen.config import config
from gramps.gen.constfunc import is_quartz
from .glade import Glade from .glade import Glade
from .display import display_url from .display import display_url
@ -506,6 +508,12 @@ def main(args):
win = Gtk.Window() win = Gtk.Window()
win.set_title('Dialog test window') win.set_title('Dialog test window')
win.set_position(Gtk.WindowPosition.CENTER) 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): def cb(window, event):
Gtk.main_quit() Gtk.main_quit()
win.connect('delete-event', cb) win.connect('delete-event', cb)

View File

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

View File

@ -45,7 +45,7 @@ _ENTER = Gdk.keyval_from_name("Enter")
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from .surnamemodel import SurnameModel 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 ...ddtargets import DdTargets
from gramps.gen.lib import Surname, NameOriginType from gramps.gen.lib import Surname, NameOriginType
from ...utils import get_primary_mask from ...utils import get_primary_mask
@ -71,9 +71,9 @@ class SurnameTab(EmbeddedList):
#index = column in model. Value = #index = column in model. Value =
# (name, sortcol in model, width, markup/text # (name, sortcol in model, width, markup/text
_column_names = [ _column_names = [
(_('Prefix'), -1, 150, TEXT_COL, -1, None), (_('Prefix'), 0, 150, TEXT_EDIT_COL, -1, None),
(_('Surname'), -1, 250, TEXT_COL, -1, None), (_('Surname'), 1, -1, TEXT_EDIT_COL, -1, None),
(_('Connector'), -1, 100, TEXT_COL, -1, None), (_('Connector'), 2, 100, TEXT_EDIT_COL, -1, None),
] ]
_column_combo = (_('Origin'), -1, 150, 3) # name, sort, width, modelcol _column_combo = (_('Origin'), -1, 150, 3) # name, sort, width, modelcol
_column_toggle = (_('Name|Primary'), -1, 80, 4) _column_toggle = (_('Name|Primary'), -1, 80, 4)
@ -94,14 +94,6 @@ class SurnameTab(EmbeddedList):
#first the standard text columns with normal method #first the standard text columns with normal method
EmbeddedList.build_columns(self) 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 # now we add the two special columns
# combobox for type # combobox for type
colno = len(self.columns) colno = len(self.columns)
@ -133,7 +125,7 @@ class SurnameTab(EmbeddedList):
column.set_resizable(True) column.set_resizable(True)
column.set_sort_column_id(self._column_combo[1]) column.set_sort_column_id(self._column_combo[1])
column.set_min_width(self._column_combo[2]) column.set_min_width(self._column_combo[2])
column.set_expand(True) column.set_expand(False)
self.columns.append(column) self.columns.append(column)
self.tree.append_column(column) self.tree.append_column(column)
# toggle box for primary # toggle box for primary
@ -149,7 +141,7 @@ class SurnameTab(EmbeddedList):
column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
column.set_alignment(0.5) column.set_alignment(0.5)
column.set_sort_column_id(self._column_toggle[1]) 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.columns.append(column)
self.tree.append_column(column) self.tree.append_column(column)
@ -161,6 +153,24 @@ class SurnameTab(EmbeddedList):
## svalue = self.cmborigmap[second] ## svalue = self.cmborigmap[second]
## return glocale.strcoll(fvalue, svalue) ## 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): def get_data(self):
return self.obj.get_surname_list() return self.obj.get_surname_list()
@ -194,6 +204,16 @@ class SurnameTab(EmbeddedList):
if self.on_change: if self.on_change:
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): def column_order(self):
# order of columns for EmbeddedList. Only the text columns here # order of columns for EmbeddedList. Only the text columns here
return ((1, 0), (1, 1), (1, 2)) return ((1, 0), (1, 1), (1, 2))
@ -239,11 +259,13 @@ class SurnameTab(EmbeddedList):
""" """
self.on_edit_start(cellr, celle, path, colnr) self.on_edit_start(cellr, celle, path, colnr)
#set up autocomplete #set up autocomplete
entry = celle.get_child()
entry.set_width_chars(10)
completion = Gtk.EntryCompletion() completion = Gtk.EntryCompletion()
completion.set_model(self.cmborig) completion.set_model(self.cmborig)
completion.set_minimum_key_length(1) completion.set_minimum_key_length(1)
completion.set_text_column(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) celle.connect('changed', self.on_origcmb_change, path, colnr)

View File

@ -197,9 +197,6 @@ class EditPerson(EditPrimary):
self.singsurnfr = SingSurn(self.top) self.singsurnfr = SingSurn(self.top)
self.multsurnfr = self.top.get_object("hboxmultsurnames") self.multsurnfr = self.top.get_object("hboxmultsurnames")
self.singlesurn_active = True 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")) 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 = self.top.get_object("full_name")
self.preview_name.override_font(Pango.FontDescription('sans bold 12')) 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): def get_start_date(self):
""" """
@ -936,7 +936,8 @@ class EditPerson(EditPrimary):
msurhbox = self.top.get_object("hboxmultsurnames") msurhbox = self.top.get_object("hboxmultsurnames")
msurhbox.remove(self.surntab) msurhbox.remove(self.surntab)
self.surntab = SurnameTab(self.dbstate, self.uistate, self.track, 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, self.multsurnfr.set_size_request(-1,
int(config.get('interface.surname-box-height'))) int(config.get('interface.surname-box-height')))
msurhbox.pack_start(self.surntab, True, True, 0) 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.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 # toplevel is given
if toplevel: if toplevel:
loadlist = [toplevel] + also_load 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) self.__toplevel = self.get_object(toplevel)
# toplevel not given # toplevel not given
else: 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 # first, use filename as possible toplevel widget name
self.__toplevel = self.get_object(filename.rpartition('.')[0]) self.__toplevel = self.get_object(filename.rpartition('.')[0])

View File

@ -197,7 +197,7 @@
<child> <child>
<object class="GtkComboBox" id="confidence"> <object class="GtkComboBox" id="confidence">
<property name="visible">True</property> <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. <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 Very Low =Unreliable evidence or estimated data
Low =Questionable reliability of evidence (interviews, census, oral genealogies, or potential for bias for example, an autobiography) 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 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.const import GLADE_FILE, ICON
from gramps.gen.errors import WindowActiveError from gramps.gen.errors import WindowActiveError
from gramps.gen.config import config from gramps.gen.config import config
from gramps.gen.constfunc import is_quartz
from .glade import Glade from .glade import Glade
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -488,6 +490,13 @@ class ManagedWindow:
#closing the Gtk.Window must also close ManagedWindow #closing the Gtk.Window must also close ManagedWindow
self.window = window self.window = window
self.window.connect('delete-event', self.close) 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: if self.modal:
self.window.set_modal(True) self.window.set_modal(True)
# The following makes sure that we only have one modal window open; # 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_margins = self.book.get_margins()
old_format_name = self.book.get_format_name() old_format_name = self.book.get_format_name()
old_output = self.book.get_output() 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_paper_name = self.book.get_paper_name()
new_orientation = self.book.get_orientation() new_orientation = self.book.get_orientation()
new_paper_metric = self.book.get_paper_metric() 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. 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.format_menu = None
self.options = options self.options = options
self.page_html_added = False self.page_html_added = False
@ -926,7 +926,7 @@ class BookDialog(DocReportDialog):
self.title = _('Generate Book') self.title = _('Generate Book')
self.database = dbstate.db self.database = dbstate.db
DocReportDialog.__init__(self, dbstate, uistate, options, DocReportDialog.__init__(self, dbstate, uistate, options,
'book', self.title) 'book', self.title, track=track)
self.options.options_dict['bookname'] = self.book.get_name() self.options.options_dict['bookname'] = self.book.get_name()
response = self.window.run() response = self.window.run()

View File

@ -63,7 +63,7 @@ class DocReportDialog(ReportDialog):
dialogs for docgen derived reports. 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 """Initialize a dialog to request that the user select options
for a basic *stand-alone* report.""" for a basic *stand-alone* report."""
@ -72,7 +72,7 @@ class DocReportDialog(ReportDialog):
self.css = PLUGMAN.process_plugin_data('WEBSTUFF') self.css = PLUGMAN.process_plugin_data('WEBSTUFF')
self.dbname = dbstate.db.get_dbname() self.dbname = dbstate.db.get_dbname()
ReportDialog.__init__(self, dbstate, uistate, option_class, ReportDialog.__init__(self, dbstate, uistate, option_class,
name, trans_name) name, trans_name, track=track)
self.basedocname = None # keep pylint happy self.basedocname = None # keep pylint happy
self.css_filename = None 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 # Gramps - a GTK+/GNOME based genealogy program
# #
# Copyright (C) 2007-2008 Brian G. Matherly # Copyright (C) 2017 Nick Hall
# 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
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@ -23,174 +18,42 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
# #
""" a ReportDialog customized for Graphviz-based reports """ """class for generating dialogs for graphviz-based reports """
#------------------------------------------------------------------------
#
# python modules
#
#------------------------------------------------------------------------
import os
#-------------------------------------------------------------------------------
#
# GTK+ modules
#
#-------------------------------------------------------------------------------
from gi.repository import Gtk
from gi.repository import GObject
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# #
# Gramps modules # Gramps modules
# #
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
from gramps.gen.const import GRAMPS_LOCALE as glocale from ._graphreportdialog import GraphReportDialog, BaseFormatComboBox
_ = glocale.translation.gettext
from gramps.gen.config import config
from gramps.gen.plug.report import CATEGORY_GRAPHVIZ from gramps.gen.plug.report import CATEGORY_GRAPHVIZ
from ._reportdialog import ReportDialog
from ._papermenu import PaperFrame
import gramps.gen.plug.docgen.graphdoc as graphdoc 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 # GraphvizReportDialog
# #
#----------------------------------------------------------------------- #-----------------------------------------------------------------------
class GraphvizReportDialog(ReportDialog): class GraphvizReportDialog(GraphReportDialog):
"""A class of ReportDialog customized for Graphviz-based reports."""
def __init__(self, dbstate, uistate, opt, name, translated_name): def make_doc_menu(self):
"""Initialize a dialog to request that the user select options """
for a Graphviz report. See the ReportDialog class for Build a menu of document types that are appropriate for
more information.""" this graph report.
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."""
self.format_menu = GraphvizFormatComboBox() 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( def get_category(self):
label=_("Open with default viewer")) """
self.open_with_app.set_active( Return the report category.
config.get('interface.open-with-default-viewer')) """
self.grid.attach(self.open_with_app, 2, self.row, 2, 1) return CATEGORY_GRAPHVIZ
self.row += 1
ext = self.format_menu.get_ext() def get_options(self):
if ext is None: """
ext = "" Return the graph options.
else: """
spath = self.get_default_directory() return graphdoc.GVOptions()
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): def doc_type_changed(self, obj):
""" """
@ -201,84 +64,31 @@ class GraphvizReportDialog(ReportDialog):
paper size/orientation options, but it does need a template paper size/orientation options, but it does need a template
file. Those changes are made here. file. Those changes are made here.
""" """
self.open_with_app.set_sensitive(True) GraphReportDialog.doc_type_changed(self, obj)
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)
output_format_str = obj.get_clname() output_format_str = obj.get_clname()
if output_format_str in ['gvpdf', 'gspdf', 'ps']: if output_format_str in ['gvpdf', 'gspdf', 'ps']:
# Always use 72 DPI for PostScript and PDF files. # Always use 72 DPI for PostScript and PDF files.
self.__gvoptions.dpi.set_value(72) self._goptions.dpi.set_value(72)
self.__gvoptions.dpi.set_available(False) self._goptions.dpi.set_available(False)
else: else:
self.__gvoptions.dpi.set_available(True) self._goptions.dpi.set_available(True)
if output_format_str in ['gspdf', 'dot']: if output_format_str in ['gspdf', 'dot']:
# Multiple pages only valid for dot and PDF via GhostsScript. # Multiple pages only valid for dot and PDF via GhostsScript.
self.__gvoptions.h_pages.set_available(True) self._goptions.h_pages.set_available(True)
self.__gvoptions.v_pages.set_available(True) self._goptions.v_pages.set_available(True)
else: else:
self.__gvoptions.h_pages.set_value(1) self._goptions.h_pages.set_value(1)
self.__gvoptions.v_pages.set_value(1) self._goptions.v_pages.set_value(1)
self.__gvoptions.h_pages.set_available(False) self._goptions.h_pages.set_available(False)
self.__gvoptions.v_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) # GraphvizFormatComboBox
#
def on_ok_clicked(self, obj): #-------------------------------------------------------------------------------
"""The user is satisfied with the dialog choices. Validate class GraphvizFormatComboBox(BaseFormatComboBox):
the output file name before doing anything else. If there is FORMATS = graphdoc.FORMATS
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

View File

@ -55,7 +55,8 @@ from ...user import User
from ...dialog import ErrorDialog, OptionDialog from ...dialog import ErrorDialog, OptionDialog
from gramps.gen.plug.report import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_BOOK, from gramps.gen.plug.report import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_BOOK,
CATEGORY_CODE, CATEGORY_WEB, CATEGORY_CODE, CATEGORY_WEB,
CATEGORY_GRAPHVIZ, standalone_categories) CATEGORY_GRAPHVIZ, CATEGORY_TREE,
standalone_categories)
from gramps.gen.plug.docgen import StyleSheet, StyleSheetList from gramps.gen.plug.docgen import StyleSheet, StyleSheetList
from ...managedwindow import ManagedWindow from ...managedwindow import ManagedWindow
from ._stylecombobox import StyleComboBox from ._stylecombobox import StyleComboBox
@ -676,6 +677,9 @@ def report(dbstate, uistate, person, report_class, options_class,
elif category == CATEGORY_GRAPHVIZ: elif category == CATEGORY_GRAPHVIZ:
from ._graphvizreportdialog import GraphvizReportDialog from ._graphvizreportdialog import GraphvizReportDialog
dialog_class = GraphvizReportDialog dialog_class = GraphvizReportDialog
elif category == CATEGORY_TREE:
from ._treereportdialog import TreeReportDialog
dialog_class = TreeReportDialog
elif category == CATEGORY_WEB: elif category == CATEGORY_WEB:
from ._webreportdialog import WebReportDialog from ._webreportdialog import WebReportDialog
dialog_class = 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 from gramps.gen.const import GRAMPS_LOCALE as glocale
_ = glocale.translation.gettext _ = glocale.translation.gettext
from gramps.gen.lib import EventType, EventRoleType
from gramps.gen.lib.person import Person from gramps.gen.lib.person import Person
from gramps.gen.constfunc import has_display, is_quartz, mac, win from gramps.gen.constfunc import has_display, is_quartz, mac, win
from gramps.gen.config import config from gramps.gen.config import config
@ -314,6 +315,7 @@ class ProgressMeter:
""" """
Close the progress meter Close the progress meter
""" """
del self.__cancel_callback
self.__dialog.destroy() self.__dialog.destroy()
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -473,33 +475,50 @@ def is_right_click(event):
if Gdk.Event.triggers_context_menu(event): if Gdk.Event.triggers_context_menu(event):
return True 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): def color_graph_box(alive=False, gender=Person.MALE):
""" """
:return: based on the config the color for graph boxes in hex :return: based on the config the color for graph boxes in hex
If gender is None, an empty box is assumed If gender is None, an empty box is assumed
:rtype: tuple (hex color fill, hex color border) :rtype: tuple (hex color fill, hex color border)
""" """
scheme = config.get('colors.scheme')
if gender == Person.MALE: if gender == Person.MALE:
if alive: if alive:
return (config.get('preferences.color-gender-male-alive'), return (config.get('colors.male-alive')[scheme],
config.get('preferences.bordercolor-gender-male-alive')) config.get('colors.border-male-alive')[scheme])
else: else:
return (config.get('preferences.color-gender-male-death'), return (config.get('colors.male-dead')[scheme],
config.get('preferences.bordercolor-gender-male-death')) config.get('colors.border-male-dead')[scheme])
elif gender == Person.FEMALE: elif gender == Person.FEMALE:
if alive: if alive:
return (config.get('preferences.color-gender-female-alive'), return (config.get('colors.female-alive')[scheme],
config.get('preferences.bordercolor-gender-female-alive')) config.get('colors.border-female-alive')[scheme])
else: else:
return (config.get('preferences.color-gender-female-death'), return (config.get('colors.female-dead')[scheme],
config.get('preferences.bordercolor-gender-female-death')) config.get('colors.border-female-dead')[scheme])
elif gender == Person.UNKNOWN: elif gender == Person.UNKNOWN:
if alive: if alive:
return (config.get('preferences.color-gender-unknown-alive'), return (config.get('colors.unknown-alive')[scheme],
config.get('preferences.bordercolor-gender-unknown-alive')) config.get('colors.border-unknown-alive')[scheme])
else: else:
return (config.get('preferences.color-gender-unknown-death'), return (config.get('colors.unknown-dead')[scheme],
config.get('preferences.bordercolor-gender-unknown-death')) config.get('colors.border-unknown-dead')[scheme])
#empty box, no gender #empty box, no gender
return ('#d2d6ce', '#000000') return ('#d2d6ce', '#000000')
## print 'male alive', rgb_to_hex((185/256.0, 207/256.0, 231/256.0)) ## 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)) rgbint = (int(rgb[0] * 255), int(rgb[1] * 255), int(rgb[2] * 255))
return '#%02x%02x%02x' % rgbint 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): def edit_object(dbstate, uistate, reftype, ref):
""" """
Invokes the appropriate editor for an object type and given handle. Invokes the appropriate editor for an object type and given handle.

View File

@ -39,6 +39,7 @@ import time
import datetime import datetime
from io import StringIO from io import StringIO
import posixpath import posixpath
import gc
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -54,6 +55,7 @@ LOG = logging.getLogger(".")
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from gi.repository import Gtk from gi.repository import Gtk
from gi.repository import Gdk
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@ -136,8 +138,6 @@ UIDEFAULT = '''<ui>
<menuitem action="Quit"/> <menuitem action="Quit"/>
</menu> </menu>
<menu action="AddMenu"> <menu action="AddMenu">
<menu action="AddNewMenu">
<separator/>
<menuitem action="PersonAdd"/> <menuitem action="PersonAdd"/>
<separator/> <separator/>
<menuitem action="FamilyAdd"/> <menuitem action="FamilyAdd"/>
@ -150,7 +150,6 @@ UIDEFAULT = '''<ui>
<menuitem action="RepositoryAdd"/> <menuitem action="RepositoryAdd"/>
<menuitem action="MediaAdd"/> <menuitem action="MediaAdd"/>
<menuitem action="NoteAdd"/> <menuitem action="NoteAdd"/>
</menu>
</menu> </menu>
<menu action="EditMenu"> <menu action="EditMenu">
<menuitem action="Undo"/> <menuitem action="Undo"/>
@ -396,7 +395,12 @@ class ViewManager(CLIManager):
self.window.set_icon_from_file(ICON) self.window.set_icon_from_file(ICON)
self.window.set_default_size(width, height) self.window.set_default_size(width, height)
self.window.move(horiz_position, vert_position) 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) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self.window.add(vbox) self.window.add(vbox)
hpane = Gtk.Paned() hpane = Gtk.Paned()
@ -599,20 +603,20 @@ class ViewManager(CLIManager):
('Clipboard', 'edit-paste', _('Clip_board'), "<PRIMARY>b", ('Clipboard', 'edit-paste', _('Clip_board'), "<PRIMARY>b",
_("Open the Clipboard dialog"), self.clipboard), _("Open the Clipboard dialog"), self.clipboard),
('AddMenu', None, _('_Add')), ('AddMenu', None, _('_Add')),
('AddNewMenu', None, _('New')), #('AddNewMenu', None, _('New')),
('PersonAdd', None, _('Person'), "<Alt>p", None, ('PersonAdd', None, _('Person'), "<shift><Alt>p", None,
self.add_new_person), self.add_new_person),
('FamilyAdd', None, _('Family'), "<Alt>y", None, ('FamilyAdd', None, _('Family'), "<shift><Alt>f", None,
self.add_new_family), self.add_new_family),
('EventAdd', None, _('Event'), "<shift>e", None, ('EventAdd', None, _('Event'), "<shift><Alt>e", None,
self.add_new_event), self.add_new_event),
('PlaceAdd', None, _('Place'), "<shift><Alt>p", None, ('PlaceAdd', None, _('Place'), "<shift><Alt>l", None,
self.add_new_place), self.add_new_place),
('SourceAdd', None, _('Source'), "<shift><Alt>s", None, ('SourceAdd', None, _('Source'), "<shift><Alt>s", None,
self.add_new_source), self.add_new_source),
('CitationAdd', None, _('Citation'), "<shift><Alt>c", None, ('CitationAdd', None, _('Citation'), "<shift><Alt>c", None,
self.add_new_citation), self.add_new_citation),
('RepositoryAdd', None, _('Repository'), "<shift><Alt>y", None, ('RepositoryAdd', None, _('Repository'), "<shift><Alt>r", None,
self.add_new_repository), self.add_new_repository),
('MediaAdd', None, _('Media'), "<shift><Alt>m", None, ('MediaAdd', None, _('Media'), "<shift><Alt>m", None,
self.add_new_media), self.add_new_media),
@ -1769,6 +1773,7 @@ def run_plugin(pdata, dbstate, uistate):
name=pdata.id, name=pdata.id,
category=pdata.category, category=pdata.category,
callback=dbstate.db.request_rebuild) callback=dbstate.db.request_rebuild)
gc.collect(2)
def make_plugin_callback(pdata, dbstate, uistate): 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): def foreground_color(self, column, renderer, model, iter_, data=None):
''' '''
Set the foreground color of the cell renderer. We use a cell data 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()) fg_color = model.get_value(iter_, model.color_column())
#for color errors, typically color column is badly set if fg_color == '':
if fg_color: fg_color = None
renderer.set_property('foreground', fg_color) renderer.set_property('foreground', fg_color)
else:
LOG.debug('Bad color set: ' + str(fg_color))
def set_active(self): def set_active(self):
""" """

View File

@ -156,8 +156,7 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
hpane = Gtk.Paned() hpane = Gtk.Paned()
vpane = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL) vpane = Gtk.Paned(orientation=Gtk.Orientation.VERTICAL)
hpane.pack1(vpane, resize=True, shrink=False) hpane.pack1(vpane, resize=True, shrink=False)
hpane.pack2(self.sidebar, resize=False, shrink=True) hpane.pack2(self.sidebar, resize=False, shrink=False)
self._setup_slider_config(hpane, 'hpane.slider-position')
hpane.show() hpane.show()
vpane.show() vpane.show()
@ -168,14 +167,31 @@ class PageView(DbGUIElement, metaclass=ABCMeta):
self._setup_slider_config(vpane, 'vpane.slider-position') self._setup_slider_config(vpane, 'vpane.slider-position')
self.sidebar_toggled(self.sidebar.get_property('visible')) self.sidebar_toggled(self.sidebar.get_property('visible'))
self.hpane_sig = hpane.connect("draw", self.set_page_slider)
return hpane 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. Setup the slider configuration setting.
""" """
self._config.register(setting, -1) self._config.register(setting, position)
widget.set_position(self._config.get(setting)) widget.set_position(self._config.get(setting))
widget.connect('notify::position', self._position_changed, setting) widget.connect('notify::position', self._position_changed, setting)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -143,7 +143,7 @@ class SourceModel(FlatBaseModel):
tag_handle = data[0] tag_handle = data[0]
cached, value = self.get_cached_value(tag_handle, "TAG_COLOR") cached, value = self.get_cached_value(tag_handle, "TAG_COLOR")
if not cached: if not cached:
tag_color = "#000000000000" tag_color = ""
tag_priority = None tag_priority = None
for handle in data[11]: for handle in data[11]:
tag = self.db.get_tag_from_handle(handle) 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: if node.handle is None:
# Header rows dont get the foreground color set # Header rows dont get the foreground color set
if col == self.color_column(): if col == self.color_column():
return "#000000000000" #color must not be utf-8
return ""
# Return the node name for the first column # Return the node name for the first column
if col == 0: if col == 0:

View File

@ -32,6 +32,7 @@ from .photo import *
from .placeentry import * from .placeentry import *
from .monitoredwidgets import * from .monitoredwidgets import *
from .selectionwidget import SelectionWidget, Region from .selectionwidget import SelectionWidget, Region
from .shadebox import *
from .shortlistcomboentry import * from .shortlistcomboentry import *
from .springseparator import * from .springseparator import *
from .statusbar import Statusbar 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) cr.scale(scale, scale)
if widget: if widget:
self.center_xy = self.center_xy_from_delta() 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.save()
cr.rotate(math.radians(self.rotate_value)) cr.rotate(math.radians(self.rotate_value))
@ -1596,6 +1598,8 @@ class FanChartGrampsGUI:
siblings.append(sib_id) siblings.append(sib_id)
# Collect a list of per-step-family step-siblings # Collect a list of per-step-family step-siblings
for parent_h in [fam.get_father_handle(), fam.get_mother_handle()]: 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) parent = self.dbstate.db.get_person_from_handle(parent_h)
other_families = [self.dbstate.db.get_family_from_handle(fam_id) other_families = [self.dbstate.db.get_family_from_handle(fam_id)
for fam_id in parent.get_family_handle_list() for fam_id in parent.get_family_handle_list()

View File

@ -374,7 +374,9 @@ class FanChart2WayWidget(FanChartWidget, FanChartDescWidget):
cr.scale(scale, scale) cr.scale(scale, scale)
if widget: if widget:
self.center_xy = self.center_xy_from_delta() 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.save()
# Draw background # Draw background

View File

@ -370,7 +370,7 @@ class GrampletBar(Gtk.Notebook):
""" """
Add a tab to the notebook for the given gramplet. Add a tab to the notebook for the given gramplet.
""" """
width = 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) height = min(int(self.uistate.screen_height() * 0.20), 400)
gramplet.set_size_request(width, height) 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 gramps.gen.const import URL_MANUAL_PAGE, VERSION_DIR, COLON
from ..editors import EditPerson, EditFamily from ..editors import EditPerson, EditFamily
from ..managedwindow import ManagedWindow 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 .menuitem import add_menuitem
from ..plug import make_gui_option from ..plug import make_gui_option
from ..plug.quick import run_quick_report_by_name from ..plug.quick import run_quick_report_by_name
@ -196,12 +196,7 @@ class LinkTag(Gtk.TextTag):
lid = 0 lid = 0
#obtaining the theme link color once. Restart needed on theme change! #obtaining the theme link color once. Restart needed on theme change!
linkcolor = Gtk.Label(label='test') #needed to avoid label destroyed to early linkcolor = Gtk.Label(label='test') #needed to avoid label destroyed to early
linkcolor = linkcolor.get_style_context().lookup_color('link_color') linkcolor = get_link_color(linkcolor.get_style_context())
if linkcolor[0]:
linkcolor = rgb_to_hex((linkcolor[1].red, linkcolor[1].green,
linkcolor[1].blue))
else:
linkcolor = 'blue'
def __init__(self, buffer): def __init__(self, buffer):
LinkTag.lid += 1 LinkTag.lid += 1

View File

@ -48,7 +48,7 @@ from gi.repository import Pango
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
from gramps.gen.constfunc import has_display, win 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) Gtk.EventBox.__init__(self)
st_cont = self.get_style_context() st_cont = self.get_style_context()
col = st_cont.lookup_color('link_color') self.color = get_link_color(st_cont)
if col[0]:
self.color = rgb_to_hex((col[1].red, col[1].green, col[1].blue))
else:
self.color = 'blue'
if emph: if emph:
#emphasize a link #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 .springseparator import SpringSeparatorAction
from ..spell import Spell from ..spell import Spell
from ..display import display_url 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.config import config
from gramps.gen.constfunc import has_display from gramps.gen.constfunc import has_display, mac
from ..actiongroup import ActionGroup from ..actiongroup import ActionGroup
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -186,11 +186,7 @@ class StyledTextEditor(Gtk.TextView):
self.set_buffer(self.textbuffer) self.set_buffer(self.textbuffer)
st_cont = self.get_style_context() st_cont = self.get_style_context()
col = st_cont.lookup_color('link_color') self.linkcolor = get_link_color(st_cont)
if col[0]:
self.linkcolor = rgb_to_hex((col[1].red, col[1].green, col[1].blue))
else:
self.linkcolor = 'blue'
self.textbuffer.linkcolor = self.linkcolor self.textbuffer.linkcolor = self.linkcolor
self.match = None self.match = None
@ -319,7 +315,9 @@ class StyledTextEditor(Gtk.TextView):
if url.startswith("gramps://"): if url.startswith("gramps://"):
obj_class, prop, value = url[9:].split("/") obj_class, prop, value = url[9:].split("/")
display = simple_access.display(obj_class, prop, value) or url 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): 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 gramps.gen.errors import MaskError, ValidationError, WindowActiveError
from .undoableentry import UndoableEntry from .undoableentry import UndoableEntry
from gramps.gen.constfunc import is_quartz
#============================================================================ #============================================================================
# #
# MaskedEntry and ValidatableMaskedEntry copied and merged from the Kiwi # MaskedEntry and ValidatableMaskedEntry copied and merged from the Kiwi
@ -1248,6 +1248,12 @@ def main(args):
win = Gtk.Window() win = Gtk.Window()
win.set_title('ValidatableMaskedEntry test window') win.set_title('ValidatableMaskedEntry test window')
win.set_position(Gtk.WindowPosition.CENTER) 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): def cb(window, event):
Gtk.main_quit() Gtk.main_quit()
win.connect('delete-event', cb) win.connect('delete-event', cb)

View File

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

View File

@ -27,7 +27,6 @@
# standard python modules # standard python modules
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
import os
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
@ -43,9 +42,12 @@ log = logging.getLogger(".WriteFtree")
# Gramps modules # 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.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): def writeData(database, filename, user, option_box=None):
""" function to export Web Family Tree file """
writer = FtreeWriter(database, filename, user, option_box) writer = FtreeWriter(database, filename, user, option_box)
return writer.export_data() return writer.export_data()
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# FtreeWriter # FtreeWriter
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
class FtreeWriter: class FtreeWriter:
""" Export a Web Family Tree format file """
def __init__(self, database, filename, user, option_box=None): def __init__(self, database, filename, user, option_box=None):
self.db = database self.db = database
self.filename = filename self.filename = filename
self.user = user self.user = user
self.option_box = option_box 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 self.update = self.update_real
else: else:
self.update = self.update_empty self.update = self.update_empty
@ -78,121 +83,132 @@ class FtreeWriter:
self.db = option_box.get_filtered_database(self.db) self.db = option_box.get_filtered_database(self.db)
self.plist = [x for x in self.db.iter_person_handles()] 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): def update_empty(self):
""" used when no callback is present """
pass pass
def update_real(self): def update_real(self):
""" Progress update """
self.count += 1 self.count += 1
newval = int(100*self.count/self.total) newval = int(100 * self.count / self.total)
if newval != self.oldval: if newval != self.oldval:
self.user.callback(newval) self.user.callback(newval)
self.oldval = newval self.oldval = newval
def export_data(self): def export_data(self):
""" main export processing """
name_map = {} name_map = {}
id_map = {} id_map = {}
id_name = {} id_name = {}
self.count = 0
self.oldval = 0
self.total = 2*len(self.plist)
for key in self.plist: for key in self.plist:
self.update() self.update()
pn = self.db.get_person_from_handle(key).get_primary_name() pnam = self.db.get_person_from_handle(key).get_primary_name()
sn = pn.get_surname() snam = pnam.get_surname()
items = pn.get_first_name().split() items = pnam.get_first_name().split()
n = ("%s %s" % (items[0], sn)) if items else sn nam = ("%s %s" % (items[0], snam)) if items else snam
count = -1 count = -1
if n in name_map: if nam in name_map:
count = 0 count = 0
while 1: while 1:
nn = "%s%d" % (n, count) nam_num = "%s%d" % (nam, count)
if nn not in name_map: if nam_num not in name_map:
break; break
count += 1 count += 1
name_map[nn] = key name_map[nam_num] = key
id_map[key] = nn id_map[key] = nam_num
else: else:
name_map[n] = key name_map[nam] = key
id_map[key] = n id_map[key] = nam
id_name[key] = get_name(pn, sn, count) 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: def _export_data(self, file, id_name, id_map):
self.update() """ file export processing """
p = self.db.get_person_from_handle(key) for key in self.plist:
name = id_name[key] self.update()
father = mother = email = web = "" pers = self.db.get_person_from_handle(key)
name = id_name[key]
father = mother = email = web = ""
family_handle = p.get_main_parents_family_handle() family_handle = pers.get_main_parents_family_handle()
if family_handle: if family_handle:
family = self.db.get_family_from_handle(family_handle) family = self.db.get_family_from_handle(family_handle)
if family.get_father_handle() and \ if family.get_father_handle() and \
family.get_father_handle() in id_map: family.get_father_handle() in id_map:
father = id_map[family.get_father_handle()] father = id_map[family.get_father_handle()]
if family.get_mother_handle() and \ if family.get_mother_handle() and \
family.get_mother_handle() in id_map: family.get_mother_handle() in id_map:
mother = id_map[family.get_mother_handle()] mother = id_map[family.get_mother_handle()]
# #
# Calculate Date # Calculate Date
# #
birth_ref = p.get_birth_ref() birth_ref = pers.get_birth_ref()
death_ref = p.get_death_ref() death_ref = pers.get_death_ref()
if birth_ref: if birth_ref:
birth_event = self.db.get_event_from_handle(birth_ref.ref) birth_event = self.db.get_event_from_handle(birth_ref.ref)
birth = birth_event.get_date_object() 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: else:
birth = None dates = fdate(birth)
if death_ref: else:
death_event = self.db.get_event_from_handle(death_ref.ref) if death:
death = death_event.get_date_object() dates = fdate(death)
else: else:
death = None dates = ""
#if self.restrict: file.write('%s;%s;%s;%s;%s;%s\n' %
# alive = probably_alive(p, self.db) (name, father, mother, email, web, dates))
#else:
# alive = 0
if birth: return True
if death:
dates = "%s-%s" % (fdate(birth), fdate(death))
else:
dates = fdate(birth)
else:
if death:
dates = fdate(death)
else:
dates = ""
f.write('%s;%s;%s;%s;%s;%s\n' % (name, father, mother, email, web,
dates))
return True
def fdate(val): def fdate(val):
""" return properly formatted date """
if val.get_year_valid(): if val.get_year_valid():
if val.get_month_valid(): if val.get_month_valid():
if val.get_day_valid(): if val.get_day_valid():
return "%d/%d/%d" % (val.get_day(), val.get_month(), return "%d/%d/%d" % (val.get_day(), val.get_month(),
val.get_year()) val.get_year())
else: return "%d/%d" % (val.get_month(), val.get_year())
return "%d/%d" % (val.get_month(), val.get_year()) return "%d" % val.get_year()
else: return ""
return "%d" % val.get_year()
else:
return ""
def get_name(name, surname, count): def get_name(name, surname, count):
"""returns a name string built from the components of the Name """returns a name string built from the components of the Name
instance, in the form of Firstname Surname""" instance, in the form of Firstname Surname"""
return (name.first_name + ' ' + return (name.first_name + ' ' +
surname + surname +
(str(count) if count != -1 else '') + (str(count) if count != -1 else '') +
(', ' +name.suffix if name.suffix else '') (', ' + name.suffix if name.suffix else ''))
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -316,15 +316,6 @@ class RelationshipView(NavigationView):
self.child = None self.child = None
self.scroll = Gtk.ScrolledWindow() 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, self.scroll.set_policy(Gtk.PolicyType.AUTOMATIC,
Gtk.PolicyType.AUTOMATIC) Gtk.PolicyType.AUTOMATIC)
self.scroll.show() self.scroll.show()
@ -589,9 +580,7 @@ class RelationshipView(NavigationView):
grid.attach(eventbox, 0, 0, 2, 1) grid.attach(eventbox, 0, 0, 2, 1)
eventbox = Gtk.EventBox() eventbox = widgets.ShadeBox(self.use_shade)
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
grid.attach(eventbox, 1, 1, 1, 1) grid.attach(eventbox, 1, 1, 1, 1)
subgrid = Gtk.Grid() subgrid = Gtk.Grid()
subgrid.set_column_spacing(12) subgrid.set_column_spacing(12)
@ -888,9 +877,7 @@ class RelationshipView(NavigationView):
box = self.get_people_box(family.get_father_handle(), box = self.get_people_box(family.get_father_handle(),
family.get_mother_handle(), family.get_mother_handle(),
post_msg=childmsg) post_msg=childmsg)
eventbox = Gtk.EventBox() eventbox = widgets.ShadeBox(self.use_shade)
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox.add(box) eventbox.add(box)
self.child.attach(eventbox, _PDATA_START, self.row, self.child.attach(eventbox, _PDATA_START, self.row,
_PDATA_STOP-_PDATA_START, 1) _PDATA_STOP-_PDATA_START, 1)
@ -942,9 +929,7 @@ class RelationshipView(NavigationView):
else : else :
childmsg = _(" (only child)") childmsg = _(" (only child)")
box = self.get_people_box(post_msg=childmsg) box = self.get_people_box(post_msg=childmsg)
eventbox = Gtk.EventBox() eventbox = widgets.ShadeBox(self.use_shade)
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox.add(box) eventbox.add(box)
self.child.attach(eventbox, _PDATA_START, self.row, self.child.attach(eventbox, _PDATA_START, self.row,
_PDATA_STOP-_PDATA_START, 1) _PDATA_STOP-_PDATA_START, 1)
@ -972,9 +957,7 @@ class RelationshipView(NavigationView):
child_should_be_linked = (child_handle != active) child_should_be_linked = (child_handle != active)
self.write_child(vbox, child_handle, i, child_should_be_linked) self.write_child(vbox, child_handle, i, child_should_be_linked)
i += 1 i += 1
eventbox = Gtk.EventBox() eventbox = widgets.ShadeBox(self.use_shade)
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox.add(vbox) eventbox.add(vbox)
self.child.attach(eventbox, _CDATA_START-1, self.row, self.child.attach(eventbox, _CDATA_START-1, self.row,
_CDATA_STOP-_CDATA_START+1, 1) _CDATA_STOP-_CDATA_START+1, 1)
@ -994,9 +977,6 @@ class RelationshipView(NavigationView):
name = self.get_name(handle, True) name = self.get_name(handle, True)
link_label = widgets.LinkLabel(name, self._button_press, link_label = widgets.LinkLabel(name, self._button_press,
handle, theme=self.theme) handle, theme=self.theme)
if self.use_shade:
link_label.override_background_color(Gtk.StateType.NORMAL,
self.color)
if self._config.get('preferences.releditbtn'): if self._config.get('preferences.releditbtn'):
button = widgets.IconButton(self.edit_button_press, button = widgets.IconButton(self.edit_button_press,
handle) handle)
@ -1039,7 +1019,7 @@ class RelationshipView(NavigationView):
_PLABEL_STOP-_PLABEL_START, 1) _PLABEL_STOP-_PLABEL_START, 1)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
eventbox = Gtk.EventBox() eventbox = widgets.ShadeBox(self.use_shade)
if handle: if handle:
name = self.get_name(handle, True) name = self.get_name(handle, True)
person = self.dbstate.db.get_person_from_handle(handle) person = self.dbstate.db.get_person_from_handle(handle)
@ -1053,8 +1033,6 @@ class RelationshipView(NavigationView):
emph = False emph = False
link_label = widgets.LinkLabel(name, self._button_press, link_label = widgets.LinkLabel(name, self._button_press,
handle, emph, theme=self.theme) 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'): if self._config.get('preferences.releditbtn'):
button = widgets.IconButton(self.edit_button_press, handle) button = widgets.IconButton(self.edit_button_press, handle)
button.set_tooltip_text(_('Edit Person (%s)') % name[0]) button.set_tooltip_text(_('Edit Person (%s)') % name[0])
@ -1073,8 +1051,6 @@ class RelationshipView(NavigationView):
if value: if value:
vbox.pack_start(widgets.MarkupLabel(value), True, True, 0) 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) eventbox.add(vbox)
self.child.attach(eventbox, _PDATA_START, self.row, self.child.attach(eventbox, _PDATA_START, self.row,
@ -1174,9 +1150,6 @@ class RelationshipView(NavigationView):
name = self.get_name(handle, True) name = self.get_name(handle, True)
link_label = widgets.LinkLabel(name, link_func, handle, emph, link_label = widgets.LinkLabel(name, link_func, handle, emph,
theme=self.theme) theme=self.theme)
if self.use_shade:
link_label.override_background_color(Gtk.StateType.NORMAL, self.color)
link_label.set_padding(3, 0) link_label.set_padding(3, 0)
if child_should_be_linked and self._config.get( if child_should_be_linked and self._config.get(
'preferences.releditbtn'): 'preferences.releditbtn'):
@ -1391,9 +1364,7 @@ class RelationshipView(NavigationView):
else : else :
childmsg = _(" (no children)") childmsg = _(" (no children)")
box = self.get_people_box(handle, post_msg=childmsg) box = self.get_people_box(handle, post_msg=childmsg)
eventbox = Gtk.EventBox() eventbox = widgets.ShadeBox(self.use_shade)
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox.add(box) eventbox.add(box)
self.child.attach(eventbox, _PDATA_START, self.row, self.child.attach(eventbox, _PDATA_START, self.row,
_PDATA_STOP-_PDATA_START, 1) _PDATA_STOP-_PDATA_START, 1)
@ -1438,9 +1409,7 @@ class RelationshipView(NavigationView):
else : else :
childmsg = _(" (no children)") childmsg = _(" (no children)")
box = self.get_people_box(post_msg=childmsg) box = self.get_people_box(post_msg=childmsg)
eventbox = Gtk.EventBox() eventbox = widgets.ShadeBox(self.use_shade)
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox.add(box) eventbox.add(box)
self.child.attach(eventbox, _PDATA_START, self.row, self.child.attach(eventbox, _PDATA_START, self.row,
_PDATA_STOP-_PDATA_START, 1) _PDATA_STOP-_PDATA_START, 1)
@ -1468,9 +1437,7 @@ class RelationshipView(NavigationView):
i += 1 i += 1
self.row += 1 self.row += 1
eventbox = Gtk.EventBox() eventbox = widgets.ShadeBox(self.use_shade)
if self.use_shade:
eventbox.override_background_color(Gtk.StateType.NORMAL, self.color)
eventbox.add(vbox) eventbox.add(vbox)
self.child.attach(eventbox, _CDATA_START-1, self.row, self.child.attach(eventbox, _CDATA_START-1, self.row,
_CDATA_STOP-_CDATA_START+1, 1) _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 creates the event header row for all events
""" """
trow = Html("tr") trow = Html("tr", close=None)
trow.extend( trow.extend(
Html("th", trans, class_=colclass, inline=True) Html("th", trans, class_=colclass, inline=True)
for trans, colclass in [ for trans, colclass in [
(self._("Event"), "ColumnEvent"), (self._("Event"), "ColumnEvent"),
(self._("Date"), "ColumnDate"), (self._("Date"), "ColumnDate"),
(self._("Place"), "ColumnPlace"), (self._("Place"), "ColumnPlace"),
(self._("Description"), "ColumnDescription"), (self._("Description"), "ColumnDescription")]
(self._("Notes"), "ColumnNotes"),
(self._("Sources"), "ColumnSources")]
) )
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 return trow
def display_event_row(self, event, event_ref, place_lat_long, 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 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 # get event notes
notelist = event.get_note_list() notelist = event.get_note_list()
notelist.extend(event_ref.get_note_list()) notelist.extend(event_ref.get_note_list())
@ -709,12 +723,9 @@ class BasePage: # pylint: disable=C1001
if notelist: if notelist:
htmllist.extend(self.dump_notes(notelist)) htmllist.extend(self.dump_notes(notelist))
trow += Html("td", htmllist, class_="ColumnNotes") trow2 += Html("td", htmllist, class_="ColumnNotes", colspan=2)
# get event source references
srcrefs = self.get_citation_links(event.get_citation_list()) or "&nbsp;"
trow += Html("td", srcrefs, class_="ColumnSources")
trow += trow2
# return events table row to its callers # return events table row to its callers
return trow return trow
@ -1502,7 +1513,7 @@ class BasePage: # pylint: disable=C1001
("addressbook", self._("Address Book"), ("addressbook", self._("Address Book"),
self.report.inc_addressbook), self.report.inc_addressbook),
('contact', self._("Contact"), self.report.use_contact), ('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) (self.target_cal_uri, self._("Web Calendar"), self.usecal)
] ]

View File

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

View File

@ -110,17 +110,18 @@ class EventPages(BasePage):
for event_handle in event_handle_list: for event_handle in event_handle_list:
event = self.r_db.get_event_from_handle(event_handle) event = self.r_db.get_event_from_handle(event_handle)
event_types.append(self._(event.get_type().xml_str())) event_types.append(self._(event.get_type().xml_str()))
with self.r_user.progress(_("Narrated Web Site Report"), message = _("Creating event pages")
_("Creating event pages"), with self.r_user.progress(_("Narrated Web Site Report"), message,
len(event_handle_list) + 1 len(event_handle_list) + 1
) as step: ) as step:
self.eventlistpage(self.report, title, event_types, index = 1
event_handle_list)
for event_handle in event_handle_list: for event_handle in event_handle_list:
step() step()
index += 1
self.eventpage(self.report, title, event_handle) 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): 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(): for item in self.report.obj_dict[Family].items():
LOG.debug(" %s", str(item)) LOG.debug(" %s", str(item))
with self.r_user.progress(_("Narrated Web Site Report"), message = _("Creating family pages...")
_("Creating family pages..."), index = 1
with self.r_user.progress(_("Narrated Web Site Report"), message,
len(self.report.obj_dict[Family]) + 1 len(self.report.obj_dict[Family]) + 1
) as step: ) as step:
self.familylistpage(self.report, title,
self.report.obj_dict[Family].keys())
for family_handle in self.report.obj_dict[Family]: for family_handle in self.report.obj_dict[Family]:
step() step()
index += 1
self.familypage(self.report, title, family_handle) 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): def familylistpage(self, report, title, fam_list):
""" """

View File

@ -94,6 +94,7 @@ class MediaPages(BasePage):
""" """
BasePage.__init__(self, report, title="") BasePage.__init__(self, report, title="")
self.media_dict = defaultdict(set) self.media_dict = defaultdict(set)
self.unused_media_handles = []
def display_pages(self, title): def display_pages(self, title):
""" """
@ -105,9 +106,13 @@ class MediaPages(BasePage):
LOG.debug("obj_dict[Media]") LOG.debug("obj_dict[Media]")
for item in self.report.obj_dict[Media].items(): for item in self.report.obj_dict[Media].items():
LOG.debug(" %s", str(item)) LOG.debug(" %s", str(item))
with self.r_user.progress(_("Narrated Web Site Report"), if self.create_unused_media:
_("Creating media pages"), media_count = len(self.r_db.get_media_handles())
len(self.report.obj_dict[Media]) + 1 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: ) as step:
# bug 8950 : it seems it's better to sort on desc + gid. # bug 8950 : it seems it's better to sort on desc + gid.
def sort_by_desc_and_gid(obj): def sort_by_desc_and_gid(obj):
@ -116,24 +121,62 @@ class MediaPages(BasePage):
""" """
return (obj.desc.lower(), obj.gramps_id) 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( sorted_media_handles = sorted(
self.report.obj_dict[Media].keys(), self.report.obj_dict[Media].keys(),
key=lambda x: sort_by_desc_and_gid( key=lambda x: sort_by_desc_and_gid(
self.r_db.get_media_from_handle(x))) self.r_db.get_media_from_handle(x)))
self.medialistpage(self.report, title, sorted_media_handles)
prev = None prev = None
total = len(sorted_media_handles) total = len(sorted_media_handles)
index = 1 index = 1
for handle in sorted_media_handles: for handle in sorted_media_handles:
gc.collect() # Reduce memory usage when there are many images. gc.collect() # Reduce memory usage when there are many images.
next_ = None if index == total else sorted_media_handles[index] if index == media_count:
step() 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, self.mediapage(self.report, title,
handle, (prev, next_, index, total)) handle, (prev, next_, index, media_count))
prev = handle prev = handle
step()
index += 1 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): def medialistpage(self, report, title, sorted_media_handles):
""" """
Generate and output the Media index page. Generate and output the Media index page.
@ -191,85 +234,84 @@ class MediaPages(BasePage):
table += tbody table += tbody
index = 1 index = 1
for media_handle in sorted_media_handles: if self.create_unused_media:
media = self.r_db.get_media_from_handle(media_handle) media_count = len(self.r_db.get_media_handles())
if media: else:
if media.get_change_time() > ldatec: media_count = len(self.report.obj_dict[Media])
ldatec = media.get_change_time() message = _("Creating list of media pages")
title = media.get_description() or "[untitled]" 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") trow = Html("tr")
tbody += trow tbody += trow
media_data_row = [ media_data_row = [
[index, "ColumnRowLabel"], [index, "ColumnRowLabel"],
[self.media_ref_link(media_handle, [self.media_ref_link(media_handle,
title), "ColumnName"], title), "ColumnName"],
[self.rlocale.get_date(media.get_date_object()), [self.rlocale.get_date(media.get_date_object()),
"ColumnDate"], "ColumnDate"],
[media.get_mime_type(), "ColumnMime"]] [media.get_mime_type(), "ColumnMime"]]
trow.extend( trow.extend(
Html("td", data, class_=colclass) Html("td", data, class_=colclass)
for data, colclass in media_data_row for data, colclass in media_data_row
) )
step()
index += 1 index += 1
def sort_by_desc_and_gid(obj): def sort_by_desc_and_gid(obj):
""" """
Sort by media description and gramps ID Sort by media description and gramps ID
""" """
return (obj.desc, obj.gramps_id) return (obj.desc, obj.gramps_id)
unused_media_handles = [] idx = 1
if self.create_unused_media: prev = None
# add unused media total = len(self.unused_media_handles)
media_list = self.r_db.get_media_handles() if total > 0:
for media_ref in media_list: trow += Html("tr")
if media_ref not in self.report.obj_dict[Media]: trow.extend(
unused_media_handles.append(media_ref) Html("td", Html("h4", " "), inline=True) +
unused_media_handles = sorted( Html("td",
unused_media_handles, Html("h4",
key=lambda x: sort_by_desc_and_gid( self._("Below unused media objects"),
self.r_db.get_media_from_handle(x))) inline=True),
class_="") +
idx = 1 Html("td", Html("h4", " "), inline=True) +
prev = None Html("td", Html("h4", " "), inline=True)
total = len(unused_media_handles) )
if total > 0: for media_handle in self.unused_media_handles:
trow += Html("tr") media = self.r_db.get_media_from_handle(media_handle)
trow.extend( gc.collect() # Reduce memory usage when many images.
Html("td", Html("h4", " "), inline=True) + if idx == total:
Html("td", next_ = None
Html("h4", else:
self._("Below unused media objects"), self.unused_media_handles[idx]
inline=True), trow += Html("tr")
class_="") + media_data_row = [
Html("td", Html("h4", " "), inline=True) + [index, "ColumnRowLabel"],
Html("td", Html("h4", " "), inline=True) [self.media_ref_link(media_handle,
) media.get_description()),
for media_handle in unused_media_handles: "ColumnName"],
media = self.r_db.get_media_from_handle(media_handle) [self.rlocale.get_date(media.get_date_object()),
gc.collect() # Reduce memory usage when many images. "ColumnDate"],
next_ = None if idx == total else unused_media_handles[idx] [media.get_mime_type(), "ColumnMime"]]
trow += Html("tr") trow.extend(
media_data_row = [ Html("td", data, class_=colclass)
[index, "ColumnRowLabel"], for data, colclass in media_data_row
[self.media_ref_link(media_handle, )
media.get_description()), prev = media_handle
"ColumnName"], step()
[self.rlocale.get_date(media.get_date_object()), index += 1
"ColumnDate"], idx += 1
[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
# add footer section # add footer section
# add clearline for proper styling # 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_intro = self.options['intronote'] or self.options['introimg']
self.use_home = self.options['homenote'] or self.options['homeimg'] self.use_home = self.options['homenote'] or self.options['homeimg']
self.use_contact = self.opts['contactnote'] or self.opts['contactimg'] 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 ? # Do we need to include this in a cms ?
self.usecms = self.options['usecms'] self.usecms = self.options['usecms']
@ -441,7 +443,8 @@ class NavWebReport(Report):
self.tab["Source"].display_pages(self.title) self.tab["Source"].display_pages(self.title)
# build classes StatisticsPage # 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 # copy all of the neccessary files
self.copy_narrated_files() self.copy_narrated_files()
@ -458,6 +461,7 @@ class NavWebReport(Report):
if len(_WRONGMEDIAPATH) > 10: if len(_WRONGMEDIAPATH) > 10:
error += '\n ...' error += '\n ...'
self.user.warn(_("Missing media objects:"), error) self.user.warn(_("Missing media objects:"), error)
self.database.clear_cache()
def _build_obj_dict(self): def _build_obj_dict(self):
""" """
@ -488,12 +492,14 @@ class NavWebReport(Report):
ind_list = self._db.iter_person_handles() ind_list = self._db.iter_person_handles()
ind_list = self.filter.apply(self._db, ind_list, user=self.user) ind_list = self.filter.apply(self._db, ind_list, user=self.user)
with self.user.progress(_("Narrated Web Site Report"), message = _('Constructing list of other objects...')
_('Constructing list of other objects...'), with self.user.progress(_("Narrated Web Site Report"), message,
sum(1 for _ in ind_list)) as step: sum(1 for _ in ind_list)) as step:
index = 1
for handle in ind_list: for handle in ind_list:
step()
self._add_person(handle, "", "") self._add_person(handle, "", "")
step()
index += 1
LOG.debug("final object dictionary \n" + LOG.debug("final object dictionary \n" +
"".join(("%s: %s\n" % item) "".join(("%s: %s\n" % item)
@ -1057,13 +1063,15 @@ class NavWebReport(Report):
@param: ind_list -- The list of person to use @param: ind_list -- The list of person to use
""" """
if self.inc_gendex: if self.inc_gendex:
with self.user.progress(_("Narrated Web Site Report"), message = _('Creating GENDEX file')
_('Creating GENDEX file'), with self.user.progress(_("Narrated Web Site Report"), message,
len(ind_list)) as step: len(ind_list)) as step:
fp_gendex, gendex_io = self.create_file("gendex", ext=".txt") fp_gendex, gendex_io = self.create_file("gendex", ext=".txt")
date = 0 date = 0
index = 1
for person_handle in ind_list: for person_handle in ind_list:
step() step()
index += 1
person = self._db.get_person_from_handle(person_handle) person = self._db.get_person_from_handle(person_handle)
datex = person.get_change_time() datex = person.get_change_time()
if datex > date: if datex > date:
@ -1113,29 +1121,35 @@ class NavWebReport(Report):
""" """
local_list = sort_people(self._db, ind_list, self.rlocale) local_list = sort_people(self._db, ind_list, self.rlocale)
with self.user.progress(_("Narrated Web Site Report"), message = _("Creating surname pages")
_("Creating surname pages"), with self.user.progress(_("Narrated Web Site Report"), message,
len(local_list)) as step: len(local_list)) as step:
SurnameListPage(self, self.title, ind_list, SurnameListPage(self, self.title, ind_list,
SurnameListPage.ORDER_BY_NAME, SurnameListPage.ORDER_BY_NAME,
self.surname_fname) self.surname_fname)
SurnameListPage(self, self.title, ind_list, SurnameListPage(self, self.title, ind_list,
SurnameListPage.ORDER_BY_COUNT, SurnameListPage.ORDER_BY_COUNT,
"surnames_count") "surnames_count")
index = 1
for (surname, handle_list) in local_list: for (surname, handle_list) in local_list:
SurnamePage(self, self.title, surname, sorted(handle_list)) SurnamePage(self, self.title, surname, sorted(handle_list))
step() step()
index += 1
def thumbnail_preview_page(self): def thumbnail_preview_page(self):
""" """
creates the thumbnail preview page 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"), with self.user.progress(_("Narrated Web Site Report"),
_("Creating thumbnail preview page..."), _("Creating thumbnail preview page..."),
len(self.obj_dict[Media])) as step: media_count) as step:
ThumbnailPreviewPage(self, self.title, step) ThumbnailPreviewPage(self, self.title, step)
def statistics_preview_page(self, title): def statistics_preview_page(self, title):
@ -1144,7 +1158,7 @@ class NavWebReport(Report):
""" """
with self.user.progress(_("Narrated Web Site Report"), with self.user.progress(_("Narrated Web Site Report"),
_("Creating statistics page..."), _("Creating statistics page..."),
len(self.obj_dict[Media])) as step: 1) as step:
StatisticsPage(self, title, step) StatisticsPage(self, title, step)
def addressbook_pages(self, ind_list): def addressbook_pages(self, ind_list):
@ -1184,12 +1198,14 @@ class NavWebReport(Report):
# begin Address Book pages # begin Address Book pages
addr_size = len(url_addr_res) addr_size = len(url_addr_res)
with self.user.progress(_("Narrated Web Site Report"), message = _("Creating address book pages ...")
_("Creating address book pages ..."), with self.user.progress(_("Narrated Web Site Report"), message,
addr_size) as step: addr_size) as step:
index = 1
for (sort_name, person_handle, add, res, url) in url_addr_res: for (sort_name, person_handle, add, res, url) in url_addr_res:
AddressBookPage(self, self.title, person_handle, add, res, url) AddressBookPage(self, self.title, person_handle, add, res, url)
step() step()
index += 1
def base_pages(self): def base_pages(self):
""" """
@ -1968,6 +1984,10 @@ class NavWebOptions(MenuReportOptions):
"events.")) "events."))
addopt("inc_addressbook", inc_addressbook) 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): def __add_place_map_options(self, menu):
""" """
options for the Place Map tab. options for the Place Map tab.

View File

@ -130,16 +130,19 @@ class PersonPages(BasePage):
LOG.debug("obj_dict[Person]") LOG.debug("obj_dict[Person]")
for item in self.report.obj_dict[Person].items(): for item in self.report.obj_dict[Person].items():
LOG.debug(" %s", str(item)) LOG.debug(" %s", str(item))
with self.r_user.progress(_("Narrated Web Site Report"), message = _('Creating individual pages')
_('Creating individual pages'), with self.r_user.progress(_("Narrated Web Site Report"), message,
len(self.report.obj_dict[Person]) + 1 len(self.report.obj_dict[Person]) + 1
) as step: ) as step:
self.individuallistpage(self.report, title, index = 1
self.report.obj_dict[Person].keys())
for person_handle in sorted(self.report.obj_dict[Person]): for person_handle in sorted(self.report.obj_dict[Person]):
step() step()
index += 1
person = self.r_db.get_person_from_handle(person_handle) person = self.r_db.get_person_from_handle(person_handle)
self.individualpage(self.report, title, person) 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]") LOG.debug("obj_dict[Place]")
for item in self.report.obj_dict[Place].items(): for item in self.report.obj_dict[Place].items():
LOG.debug(" %s", str(item)) LOG.debug(" %s", str(item))
with self.r_user.progress(_("Narrated Web Site Report"), message = _("Creating place pages")
_("Creating place pages"), with self.r_user.progress(_("Narrated Web Site Report"), message,
len(self.report.obj_dict[Place]) + 1 len(self.report.obj_dict[Place]) + 1
) as step: ) as step:
index = 1
self.placelistpage(self.report, title,
self.report.obj_dict[Place].keys())
for place_handle in self.report.obj_dict[Place]: for place_handle in self.report.obj_dict[Place]:
step() step()
index += 1
self.placepage(self.report, title, place_handle) 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): def placelistpage(self, report, title, place_handles):
""" """

View File

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

View File

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

View File

@ -86,6 +86,7 @@ class StatisticsPage(BasePage):
females, females,
unknown) = self.get_gender(report.database.iter_person_handles()) unknown) = self.get_gender(report.database.iter_person_handles())
step()
mobjects = report.database.get_number_of_media() mobjects = report.database.get_number_of_media()
npersons = report.database.get_number_of_people() npersons = report.database.get_number_of_people()
nfamilies = report.database.get_number_of_families() 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.") "will take you to that image&#8217;s page.")
previewpage += Html("p", msg, id="description") previewpage += Html("p", msg, id="description")
with Html("table", class_="calendar") as table: with Html("table", class_="calendar thumbnails") as table:
previewpage += table previewpage += table
thead = Html("thead") thead = Html("thead")
@ -153,7 +153,7 @@ class ThumbnailPreviewPage(BasePage):
num_of_cols = 7 num_of_cols = 7
grid_row = 0 grid_row = 0
while grid_row < num_of_rows: 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 tbody += trow
cols = 0 cols = 0
@ -163,7 +163,7 @@ class ThumbnailPreviewPage(BasePage):
photo = media_list[indexpos][2] photo = media_list[indexpos][2]
# begin table cell and attach to table row(trow)... # begin table cell and attach to table row(trow)...
tcell = Html("td", class_="highlight weekend") tcell = Html("td", class_="highlight weekend thumbnail")
trow += tcell trow += tcell
# attach index number... # attach index number...
@ -203,6 +203,7 @@ class ThumbnailPreviewPage(BasePage):
for emptycols in range(cols, num_of_cols): for emptycols in range(cols, num_of_cols):
trow += Html("td", class_="emptyDays", inline=True) trow += Html("td", class_="emptyDays", inline=True)
message = _("Creating thumbnail preview page...")
# begin Thumbnail Reference section... # begin Thumbnail Reference section...
with Html("div", class_="subsection", id="references") as section: with Html("div", class_="subsection", id="references") as section:
body += section body += section
@ -225,11 +226,12 @@ class ThumbnailPreviewPage(BasePage):
tcell2 = Html("td", ptitle, class_="ColumnName") tcell2 = Html("td", ptitle, class_="ColumnName")
trow += (tcell1, tcell2) trow += (tcell1, tcell2)
# increase progress meter...
cb_progress()
# increase index for row number... # increase index for row number...
index += 1 index += 1
# increase progress meter...
cb_progress()
# add body id element # add body id element
body.attr = 'id ="ThumbnailPreview"' 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 ; 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>/ToolWindow/relcalc" "")
(gtk_accel_path "<Actions>/AllMainWindow/Export" "<Meta>e") ; (gtk_accel_path "<Actions>/ReportWindow/place_report" "")
(gtk_accel_path "<Actions>/Pedigree/Backward/Back" "<Alt>Left") ; (gtk_accel_path "<Actions>/ToolWindow/mediaman" "")
(gtk_accel_path "<Actions>/Relationships/Bookmark/EditBook" "<Shift><Meta>d") (gtk_accel_path "<Actions>/MainWindow/SourceAdd" "<Shift><ctrl><alt>s")
; (gtk_accel_path "<Actions>/ToolWindow/reorder_ids" "") ; (gtk_accel_path "<Actions>/ReportWindow/summary" "")
(gtk_accel_path "<Actions>/Place Tree View/Bookmark/EditBook" "<Shift><Meta>d") ; (gtk_accel_path "<Actions>/ToolWindow/rebuild_refmap" "")
; (gtk_accel_path "<Actions>/RecentFiles/RecentMenu0" "") ; (gtk_accel_path "<Actions>/Redo/Redo" "<Primary><Shift>z")
(gtk_accel_path "<Actions>/Person View/PersonAll/Edit" "<Meta>Return") ; (gtk_accel_path "<Actions>/ToolWindow/ToolAnExp" "")
; (gtk_accel_path "<Actions>/FileWindow/MailingLists" "") ; (gtk_accel_path "<Actions>/FileWindow/Toolbar" "")
(gtk_accel_path "<Actions>/Place View/Forward/Forward" "<Alt>Right") ; (gtk_accel_path "<Actions>/ToolWindow/editowner" "")
; (gtk_accel_path "<Actions>/ReportWindow/kinship_report" "") ; (gtk_accel_path "<Actions>/FileWindow/Preferences" "")
; (gtk_accel_path "<Actions>/MainWindow/BookMenu" "") (gtk_accel_path "<Actions>/MainWindow/MediaAdd" "<Shift><ctrl><alt>m")
; (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>/ToolWindow/sortevents" "") ; (gtk_accel_path "<Actions>/ToolWindow/sortevents" "")
(gtk_accel_path "<Actions>/Fan Chart/Backward/Back" "<Alt>Left") ; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>Delete" "<Primary>Delete")
; (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>/FileWindow/ReportBug" "") ; (gtk_accel_path "<Actions>/FileWindow/ReportBug" "")
(gtk_accel_path "<Actions>/AllMainWindow/<CONTROL>Insert" "<Alt><Meta>i") ; (gtk_accel_path "<Actions>/ReportWindow/hourglass_graph" "")
(gtk_accel_path "<Actions>/Notes/Bookmark/AddBook" "<Meta>d") ; (gtk_accel_path "<Actions>/Undo/Undo" "<Primary>z")
(gtk_accel_path "<Actions>/People Tree View/ChangeOrder/Add" "<Alt><Meta>i") ; (gtk_accel_path "<Actions>/ToolWindow/reorder_ids" "")
; (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/rel_graph" "") ; (gtk_accel_path "<Actions>/ReportWindow/rel_graph" "")
; (gtk_accel_path "<Actions>/ReportWindow/Web-Pages" "") ; (gtk_accel_path "<Actions>/MainWindow/ConfigView" "<Primary><Shift>c")
; (gtk_accel_path "<Actions>/ReportWindow/WebCal" "") ; (gtk_accel_path "<Actions>/ReportWindow/descend_report" "")
; (gtk_accel_path "<Actions>/ReportWindow/Text-Reports" "") ; (gtk_accel_path "<Actions>/ReportWindow/ancestor_chart" "")
; (gtk_accel_path "<Actions>/Person View/PersonAll/QuickReport" "") ; (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>/FileWindow/HomePage" "")
(gtk_accel_path "<Actions>/Relationships/Family/Edit" "<Meta>Return") ; (gtk_accel_path "<Actions>/ToolWindow/populatesources" "")
; (gtk_accel_path "<Actions>/ToolWindow/patchnames" "") ; (gtk_accel_path "<Actions>/FileWindow/Open" "<Primary>o")
(gtk_accel_path "<Actions>/Relationships/Backward/Back" "<Alt>Left") ; (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>/ReportWindow/det_ancestor_report" "")
(gtk_accel_path "<Actions>/AllMainWindow/<CONTROL>BackSpace" "<Meta>BackSpace") ; (gtk_accel_path "<Actions>/ReportWindow/timeline" "")
; (gtk_accel_path "<Actions>/ToolWindow/Utilities" "") ; (gtk_accel_path "<Actions>/ToolWindow/eventcmp" "")
; (gtk_accel_path "<Actions>/AllMainWindow/WindowsMenu" "") ; (gtk_accel_path "<Actions>/AllMainWindow/ReportsMenu" "")
(gtk_accel_path "<Actions>/Families/Bookmark/EditBook" "<Shift><Meta>d") ; (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/F9" "F9")
; (gtk_accel_path "<Actions>/AllMainWindow/F8" "F8") ; (gtk_accel_path "<Actions>/AllMainWindow/F8" "F8")
; (gtk_accel_path "<Actions>/AllMainWindow/F7" "F7") ; (gtk_accel_path "<Actions>/AllMainWindow/F7" "F7")
; (gtk_accel_path "<Actions>/AllMainWindow/F6" "F6") ; (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/F5" "F5")
; (gtk_accel_path "<Actions>/AllMainWindow/F4" "F4") ; (gtk_accel_path "<Actions>/AllMainWindow/F4" "F4")
; (gtk_accel_path "<Actions>/AllMainWindow/F3" "F3") ; (gtk_accel_path "<Actions>/AllMainWindow/F3" "F3")
; (gtk_accel_path "<Actions>/AllMainWindow/F2" "F2") ; (gtk_accel_path "<Actions>/AllMainWindow/F2" "F2")
(gtk_accel_path "<Actions>/Notes/Bookmark/EditBook" "<Shift><Meta>d") ; (gtk_accel_path "<Actions>/FileWindow/Navigator" "<Primary>m")
(gtk_accel_path "<Actions>/Sources/ChangeOrder/Add" "<Alt><Meta>i") ; (gtk_accel_path "<Actions>/FileWindow/PluginStatus" "")
; (gtk_accel_path "<Actions>/ReportWindow/Books" "") ; (gtk_accel_path "<Actions>/AllMainWindow/F12" "F12")
; (gtk_accel_path "<Actions>/FileWindow/About" "") ; (gtk_accel_path "<Actions>/AllMainWindow/F11" "F11")
(gtk_accel_path "<Actions>/Notes/Backward/Back" "<Alt>Left") ; (gtk_accel_path "<Actions>/ToolWindow/ToolUtil" "")
; (gtk_accel_path "<Actions>/ReportWindow/endofline_report" "") ; (gtk_accel_path "<Actions>/MainWindow/Import" "<Primary>i")
(gtk_accel_path "<Actions>/People Tree View/PersonEdit/Add" "<Alt><Meta>i") ; (gtk_accel_path "<Actions>/ReportWindow/statistics_chart" "")
; (gtk_accel_path "<Actions>/ToolWindow/dbrowse" "") ; (gtk_accel_path "<Actions>/FileWindow/UserManual" "F1")
(gtk_accel_path "<Actions>/Pedigree/Bookmark/EditBook" "<Shift><Meta>d") ; (gtk_accel_path "<Actions>/AllMainWindow/Books" "")
; (gtk_accel_path "<Actions>/ToolWindow/soundgen" "") ; (gtk_accel_path "<Actions>/FileWindow/OpenRecent" "")
; (gtk_accel_path "<Actions>/FileWindow/ExtraPlugins" "") ; (gtk_accel_path "<Actions>/Dashboard/RestoreGramplet" "")
; (gtk_accel_path "<Actions>/AllMainWindow/ReportsMenu" "") ; (gtk_accel_path "<Actions>/WindowManger/4722902520" "")
(gtk_accel_path "<Actions>/categoryviews/personlistview_0" "<Meta>1") ; (gtk_accel_path "<Actions>/ReportWindow/RepGraph" "")
; (gtk_accel_path "<Actions>/ReportWindow/descend_report" "") ; (gtk_accel_path "<Actions>/ReportWindow/familylines_graph" "")
; (gtk_accel_path "<Actions>/ReportWindow/fan_chart" "") ; (gtk_accel_path "<Actions>/ReportWindow/kinship_report" "")
(gtk_accel_path "<Actions>/MainWindow/ScratchPad" "<Meta>b") ; (gtk_accel_path "<Actions>/ToolWindow/testcasegenerator" "")
(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/KeyBindings" "") ; (gtk_accel_path "<Actions>/FileWindow/KeyBindings" "")
(gtk_accel_path "<Actions>/Repositories/Backward/Back" "<Alt>Left") ; (gtk_accel_path "<Actions>/ReportWindow/tag_report" "")
(gtk_accel_path "<Actions>/Events/Bookmark/AddBook" "<Meta>d") ; (gtk_accel_path "<Actions>/ToolWindow/dgenstats" "")
(gtk_accel_path "<Actions>/People Tree View/ChangeOrder/Remove" "<Meta>Delete") ; (gtk_accel_path "<Actions>/FileWindow/Quit" "<Primary>q")
(gtk_accel_path "<Actions>/AllMainWindow/<CONTROL>P" "<Meta>p") ; (gtk_accel_path "<Actions>/FileWindow/TipOfDay" "")
(gtk_accel_path "<Actions>/Person View/ChangeOrder/Add" "<Alt><Meta>i") ; (gtk_accel_path "<Actions>/ReportWindow/ancestor_report" "")
(gtk_accel_path "<Actions>/AllMainWindow/<CONTROL>N" "<Meta>n") ; (gtk_accel_path "<Actions>/ToolWindow/check" "")
(gtk_accel_path "<Actions>/Place Tree View/ChangeOrder/Remove" "<Meta>Delete") ; (gtk_accel_path "<Actions>/FileWindow/Fullscreen" "F11")
; (gtk_accel_path "<Actions>/AllMainWindow/Abandon" "") (gtk_accel_path "<Actions>/MainWindow/PersonAdd" "<Shift><ctrl><alt>p")
(gtk_accel_path "<Actions>/Events/ChangeOrder/Remove" "<Meta>Delete") ; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>P" "<Primary>p")
(gtk_accel_path "<Actions>/AllMainWindow/<CONTROL>J" "<Meta>j")
(gtk_accel_path "<Actions>/Media/Bookmark/AddBook" "<Meta>d")
; (gtk_accel_path "<Actions>/ToolWindow/remove_unused" "") ; (gtk_accel_path "<Actions>/ToolWindow/remove_unused" "")
; (gtk_accel_path "<Actions>/Person View/PersonOther/SetActive" "") ; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>N" "<Primary>n")
(gtk_accel_path "<Actions>/categoryviews/personview_1" "<Meta>2") ; (gtk_accel_path "<Actions>/ReportWindow/WebCal" "")
(gtk_accel_path "<Actions>/Sources/Bookmark/AddBook" "<Meta>d") ; (gtk_accel_path "<Actions>/ReportWindow/records" "")
(gtk_accel_path "<Actions>/Place View/ChangeOrder/Add" "<Alt><Meta>i") ; (gtk_accel_path "<Actions>/AllMainWindow/<PRIMARY>J" "<Primary>j")
(gtk_accel_path "<Actions>/Person View/PersonEdit/Add" "<Alt><Meta>i") ; (gtk_accel_path "<Actions>/ReportWindow/number_of_ancestors" "")
(gtk_accel_path "<Actions>/Sources/Forward/Forward" "<Alt>Right") ; (gtk_accel_path "<Actions>/ToolWindow/evname" "")
(gtk_accel_path "<Actions>/Person View/Bookmark/AddBook" "<Meta>d") ; (gtk_accel_path "<Actions>/Dashboard/AddGramplet" "")
; (gtk_accel_path "<Actions>/FileWindow/Preferences" "") ; (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/docbackend/docbackend.py
gramps/gen/plug/docgen/graphdoc.py gramps/gen/plug/docgen/graphdoc.py
gramps/gen/plug/docgen/paperstyle.py gramps/gen/plug/docgen/paperstyle.py
gramps/gen/plug/docgen/treedoc.py
gramps/gen/plug/menu/_enumeratedlist.py gramps/gen/plug/menu/_enumeratedlist.py
gramps/gen/plug/report/_book.py gramps/gen/plug/report/_book.py
gramps/gen/plug/report/_constants.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/__init__.py
gramps/gui/widgets/basicentry.py gramps/gui/widgets/basicentry.py
gramps/gui/widgets/cellrenderertextedit.py
gramps/gui/widgets/dateentry.py gramps/gui/widgets/dateentry.py
gramps/gui/widgets/fanchart2way.py gramps/gui/widgets/fanchart2way.py
gramps/gui/widgets/fanchartdesc.py gramps/gui/widgets/fanchartdesc.py
@ -441,6 +442,7 @@ gramps/gui/widgets/menuitem.py
gramps/gui/widgets/multitreeview.py gramps/gui/widgets/multitreeview.py
gramps/gui/widgets/placeentry.py gramps/gui/widgets/placeentry.py
gramps/gui/widgets/selectionwidget.py gramps/gui/widgets/selectionwidget.py
gramps/gui/widgets/shadebox.py
gramps/gui/widgets/shortlistcomboentry.py gramps/gui/widgets/shortlistcomboentry.py
gramps/gui/widgets/springseparator.py gramps/gui/widgets/springseparator.py
gramps/gui/widgets/statusbar.py gramps/gui/widgets/statusbar.py