#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2008 Raphael Ackermann
#
# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# $Id$
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import random
from gettext import gettext as _
import os
from xml.sax.saxutils import escape
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
from gtk import glade
import gobject
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import Config
import const
import DateHandler
from BasicUtils import name_displayer as _nd
import Utils
from gen.lib import Name
import ManagedWindow
from widgets import MarkupLabel, BasicLabel
from QuestionDialog import ErrorDialog, QuestionDialog2
from Errors import NameDisplayError
geopresent = True
try:
import DataViews.GeoView
except:
geopresent = False
#experimental feature, don't show in release
if not const.VERSION.find('SVN') == -1:
gepresent = False
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
_surname_styles = [
_("Father's surname"),
_("None"),
_("Combination of mother's and father's surname"),
_("Icelandic style"),
]
# column numbers for the 'name format' model
COL_NUM = 0
COL_NAME = 1
COL_FMT = 2
COL_EXPL = 3
def set_calendar_date_format():
format_list = DateHandler.get_date_formats()
DateHandler.set_format(Config.get_date_format(format_list))
def get_researcher():
import gen.lib
n = Config.get(Config.RESEARCHER_NAME)
a = Config.get(Config.RESEARCHER_ADDR)
c = Config.get(Config.RESEARCHER_CITY)
s = Config.get(Config.RESEARCHER_STATE)
ct = Config.get(Config.RESEARCHER_COUNTRY)
p = Config.get(Config.RESEARCHER_POSTAL)
ph = Config.get(Config.RESEARCHER_PHONE)
e = Config.get(Config.RESEARCHER_EMAIL)
owner = gen.lib.Researcher()
owner.set_name(n)
owner.set_address(a)
owner.set_city(c)
owner.set_state(s)
owner.set_country(ct)
owner.set_postal_code(p)
owner.set_phone(ph)
owner.set_email(e)
return owner
#-------------------------------------------------------------------------
#
#
#
#-------------------------------------------------------------------------
class DisplayNameEditor(ManagedWindow.ManagedWindow):
def __init__(self, uistate, dbstate, track, dialog):
# Assumes that there are two methods: dialog.name_changed_check(),
# and dialog._build_custom_name_ui()
ManagedWindow.ManagedWindow.__init__(self, uistate, [], DisplayNameEditor)
self.dialog = dialog
self.dbstate = dbstate
self.set_window(
gtk.Dialog(_('Display Name Editor'),
flags=gtk.DIALOG_NO_SEPARATOR,
buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)),
None, _('Display Name Editor'), None)
table = self.dialog._build_custom_name_ui()
label = gtk.Label(_("""The following keywords will be replaced with the name:
Given - given name (first name)
Surname - surname (last name)
Title - title (Dr., Mrs.)
Prefix - prefix (von, de, de la)
Suffix - suffix (Jr., Sr.)
Call - call name, or nickname
Common - call name, otherwise first part of Given
Patronymic - patronymic (father's name)
Initials - persons's first letters of given names
Use the same keyword in UPPERCASE to force to upper. Parentheses and commas
will be removed around empty fields. Other text will appear literally."""))
label.set_use_markup(True)
self.window.vbox.add(label)
self.window.vbox.add(table)
self.window.set_default_size(600, 550)
self.window.connect('response', self.close)
self.show()
def close(self, *obj):
self.dialog.name_changed_check()
ManagedWindow.ManagedWindow.close(self, *obj)
def build_menu_names(self, obj):
return (_(" Name Editor"), _("Preferences"))
class GrampsPreferences(ManagedWindow.ManagedWindow):
def __init__(self, uistate, dbstate):
self.dbstate = dbstate
ManagedWindow.ManagedWindow.__init__(self, uistate, [], GrampsPreferences)
self.set_window(
gtk.Dialog(_('Preferences'),
flags=gtk.DIALOG_NO_SEPARATOR,
buttons=(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)),
None, _('Preferences'), None)
panel = gtk.Notebook()
self.window.vbox.add(panel)
self.window.connect('response', self.done)
panel.append_page(self.add_behavior_panel(),
MarkupLabel(_('General')))
panel.append_page(self.add_database_panel(),
MarkupLabel(_('Database')))
panel.append_page(self.add_formats_panel(),
MarkupLabel(_('Display')))
panel.append_page(self.add_text_panel(),
MarkupLabel(_('Text')))
panel.append_page(self.add_prefix_panel(),
MarkupLabel(_('ID Formats')))
panel.append_page(self.add_date_panel(),
MarkupLabel(_('Dates')))
panel.append_page(self.add_advanced_panel(),
MarkupLabel(_('Warnings')))
panel.append_page(self.add_researcher_panel(),
MarkupLabel(_('Researcher')))
panel.append_page(self.add_color_panel(),
MarkupLabel(_('Marker Colors')))
if geopresent:
panel.append_page(self.add_geoview_panel(),
MarkupLabel(_('Internet Maps')))
self.window.show_all()
self.show()
def done(self, obj, value):
self.close()
def add_researcher_panel(self):
table = gtk.Table(3, 8)
table.set_border_width(12)
table.set_col_spacings(6)
table.set_row_spacings(6)
self.add_entry(table, _('Name'), 0, Config.RESEARCHER_NAME)
self.add_entry(table, _('Address'), 1, Config.RESEARCHER_ADDR)
self.add_entry(table, _('City'), 2, Config.RESEARCHER_CITY)
self.add_entry(table, _('State/Province'), 3, Config.RESEARCHER_STATE)
self.add_entry(table, _('Country'), 4, Config.RESEARCHER_COUNTRY)
self.add_entry(table, _('ZIP/Postal Code'), 5, Config.RESEARCHER_POSTAL)
self.add_entry(table, _('Phone'), 6, Config.RESEARCHER_PHONE)
self.add_entry(table, _('Email'), 7, Config.RESEARCHER_EMAIL)
return table
def add_prefix_panel(self):
"""
Add the ID prefix tab to the preferences.
"""
table = gtk.Table(3, 8)
table.set_border_width(12)
table.set_col_spacings(6)
table.set_row_spacings(6)
self.add_entry(table, _('Person'), 0, Config.IPREFIX,
self.update_idformat_entry)
self.add_entry(table, _('Family'), 1, Config.FPREFIX,
self.update_idformat_entry)
self.add_entry(table, _('Place'), 2, Config.PPREFIX,
self.update_idformat_entry)
self.add_entry(table, _('Source'), 3, Config.SPREFIX,
self.update_idformat_entry)
self.add_entry(table, _('Media Object'), 4, Config.OPREFIX,
self.update_idformat_entry)
self.add_entry(table, _('Event'), 5, Config.EPREFIX,
self.update_idformat_entry)
self.add_entry(table, _('Repository'), 6, Config.RPREFIX,
self.update_idformat_entry)
self.add_entry(table, _('Note'), 7, Config.NPREFIX,
self.update_idformat_entry)
return table
def add_advanced_panel(self):
table = gtk.Table(4, 8)
table.set_border_width(12)
table.set_col_spacings(6)
table.set_row_spacings(6)
self.add_checkbox(
table, _('Suppress warning when adding parents to a child'),
0, Config.FAMILY_WARN)
self.add_checkbox(
table, _('Suppress warning when cancelling with changed data'),
1, Config.DONT_ASK)
self.add_checkbox(
table, _('Suppress warning about missing researcher when'
' exporting to GEDCOM'),
2, Config.OWNER_WARN)
self.add_checkbox(
table, _('Show plugin status dialog on plugin load error'),
3, Config.POP_PLUGIN_STATUS)
return table
def add_color_panel(self):
table = gtk.Table(3, 8)
table.set_border_width(12)
table.set_col_spacings(12)
table.set_row_spacings(6)
self.comp_color = self.add_color(table, _("Complete"), 0,
Config.COMPLETE_COLOR)
self.todo_color = self.add_color(table, _("ToDo"), 1,
Config.TODO_COLOR)
self.custom_color = self.add_color(table, _("Custom"), 2,
Config.CUSTOM_MARKER_COLOR)
button = gtk.Button(stock=gtk.STOCK_REVERT_TO_SAVED)
button.connect('clicked', self.reset_colors)
table.attach(button, 1, 2, 3, 4, yoptions=0, xoptions=0)
return table
def reset_colors(self, obj):
def_comp = Config.get_default(Config.COMPLETE_COLOR, '')
def_todo = Config.get_default(Config.TODO_COLOR, '')
def_cust = Config.get_default(Config.CUSTOM_MARKER_COLOR, '')
Config.set(Config.COMPLETE_COLOR, def_comp)
Config.set(Config.TODO_COLOR, def_todo)
Config.set(Config.CUSTOM_MARKER_COLOR, def_cust)
self.comp_color.set_color(gtk.gdk.color_parse(def_comp))
self.todo_color.set_color(gtk.gdk.color_parse(def_todo))
self.custom_color.set_color(gtk.gdk.color_parse(def_cust))
for widget in [self.comp_color, self.todo_color, self.custom_color]:
widget.emit('color-set')
def add_geoview_panel(self):
table = gtk.Table(3, 8)
table.set_border_width(12)
table.set_col_spacings(12)
table.set_row_spacings(6)
self.add_text(
table, _('You need a broadband internet connection to use '
'Internet mapping applications from within GRAMPS')
, 0)
self.add_checkbox(
table, _('Add GeoView to GRAMPS showing internet maps based on '
'your data.'),
1, Config.GEOVIEW)
self.add_text(
table, _('GeoView uses OpenStreetMap and one other map provider.\n'
'Choose one of the following map providers:'),
2)
maps=self.add_radiobox(
table, _('Google Maps'),
3, Config.GEOVIEW_GOOGLEMAPS, None, 1)
self.add_radiobox(
table, _('OpenLayers'),
3, Config.GEOVIEW_OPENLAYERS, maps, 2)
self.add_radiobox(
table, _('Yahoo! Maps'),
4, Config.GEOVIEW_YAHOO, maps, 1)
self.add_radiobox(
table, _('Microsoft Maps'),
4, Config.GEOVIEW_MICROSOFT, maps, 2)
self.add_text(
table, _('You need to restart GRAMPS for above settings to take'
' effect'), 5)
return table
def add_name_panel(self):
"""
Name format settings panel
"""
# a dummy name to be used in the examples
self.examplename = Name()
self.examplename.set_title('Dr.')
self.examplename.set_first_name('Edwin Jose')
self.examplename.set_surname_prefix('von der')
self.examplename.set_surname('Smith')
self.examplename.set_suffix('Sr')
self.examplename.set_patronymic('Wilson')
self.examplename.set_call_name('Ed')
table = gtk.Table(2, 2)
table.set_border_width(12)
table.set_col_spacings(6)
table.set_row_spacings(6)
# get the model for the combo and the treeview
active = _nd.get_default_format()
self.fmt_model, active = self._build_name_format_model(active)
# set up the combo to choose the preset format
self.fmt_obox = gtk.ComboBox()
cell = gtk.CellRendererText()
self.fmt_obox.pack_start(cell, True)
self.fmt_obox.add_attribute(cell, 'text', 1)
self.fmt_obox.set_model(self.fmt_model)
# set the default value as active in the combo
self.fmt_obox.set_active(active)
self.fmt_obox.connect('changed', self.cb_name_changed)
# label for the combo
lwidget = BasicLabel("%s: " % _('_Display format'))
lwidget.set_use_underline(True)
lwidget.set_mnemonic_widget(self.fmt_obox)
# build the format manager ui
custom_ui = self._build_custom_name_ui()
name_exp = gtk.expander_new_with_mnemonic(_('C_ustom format details'))
name_exp.add(custom_ui)
name_exp.set_sensitive(self.dbstate.open)
# put all these together
table.attach(lwidget, 0, 1, 0, 1, yoptions=0)
table.attach(self.fmt_obox, 1, 2, 0, 1, yoptions=0)
table.attach(name_exp, 0, 2, 1, 2, yoptions=gtk.FILL|gtk.EXPAND)
return table
def _build_name_format_model(self, active):
"""
Create a common model for ComboBox and TreeView
"""
name_format_model = gtk.ListStore(gobject.TYPE_INT,
gobject.TYPE_STRING,
gobject.TYPE_STRING,
gobject.TYPE_STRING)
index = 0
the_index = 0
for num, name, fmt_str, act in _nd.get_name_format():
translation = fmt_str
for key in Utils.get_keywords():
if key in translation:
translation = translation.replace(key, Utils.get_translation_from_keyword(key))
self.examplename.set_display_as(num)
name_format_model.append(
row=[num, translation, fmt_str, _nd.display_name(self.examplename)])
if num == active: the_index = index
index += 1
return name_format_model, the_index
def __new_name(self, obj):
lyst = ["%s, %s %s (%s)" % (_("Surname"), _("Given"), _("Suffix"),
_("Common")),
"%s, %s %s (%s)" % (_("Surname"), _("Given"), _("Suffix"),
_("Call")),
"%s, %s %s (%s)" % (_("SURNAME"), _("Given"), _("Suffix"),
_("Call")),
"%s, %s (%s)" % (_("Surname"), _("Given"), _("Common")),
"%s, %s (%s)" % (_("Surname"), _("Given"), _("Call")),
"%s %s" % (_("Given"), _("Surname")),
"%s %s, %s" % (_("Given"), _("Surname"), _("Suffix")),
"%s %s %s" % (_("Given"), _("Surname"), _("Patronymic")),
"%s, %s %s (%s)" % (_("SURNAME"), _("Given"), _("Suffix"),
_("Common")),
"%s, %s (%s)" % (_("SURNAME"), _("Given"), _("Common")),
"%s, %s (%s)" % (_("SURNAME"), _("Given"), _("Call")),
"%s %s" % (_("Given"), _("SURNAME")),
"%s %s, %s" % (_("Given"), _("SURNAME"), _("Suffix")),
"%s /%s/" % (_("Given"), _("SURNAME")),
]
fmtlyst = ["%s, %s %s (%s)" % ("Surname", "Given", "Suffix",
"Common"),
"%s, %s %s (%s)" % ("Surname", "Given", "Suffix",
"Call"),
"%s, %s %s (%s)" % ("SURNAME", "Given", "Suffix",
"Call"),
"%s, %s (%s)" % ("Surname", "Given", "Common"),
"%s, %s (%s)" % ("Surname", "Given", "Call"),
"%s %s" % ("Given", "Surname"),
"%s %s, %s" % ("Given", "Surname", "Suffix"),
"%s %s %s" % ("Given", "Surname", "Patronymic"),
"%s, %s %s (%s)" % ("SURNAME", "Given", "Suffix",
"Common"),
"%s, %s (%s)" % ("SURNAME", "Given", "Common"),
"%s, %s (%s)" % ("SURNAME", "Given", "Call"),
"%s %s" % ("Given", "SURNAME"),
"%s %s, %s" % ("Given", "SURNAME", "Suffix"),
"%s /%s/" % ("Given", "SURNAME"),
]
rand = int(random.random() * len(lyst))
f = lyst[rand]
fmt = fmtlyst[rand]
i = _nd.add_name_format(f, fmt)
node = self.fmt_model.append(row=[i, f, fmt,
_nd.format_str(self.examplename, fmt)])
path = self.fmt_model.get_path(node)
self.format_list.set_cursor(path,
focus_column=self.name_column,
start_editing=True)
self.edit_button.set_sensitive(False)
self.remove_button.set_sensitive(False)
self.insert_button.set_sensitive(False)
self.__current_path = path
self.__current_text = f
def __edit_name(self, obj):
store, node = self.format_list.get_selection().get_selected()
path = self.fmt_model.get_path(node)
self.edit_button.set_sensitive(False)
self.remove_button.set_sensitive(False)
self.insert_button.set_sensitive(False)
self.format_list.set_cursor(path,
focus_column=self.name_column,
start_editing=True)
def __check_for_name(self, name, oldnode):
"""
Check to see if there is another name the same as name
in the format list. Don't compare with self (oldnode).
"""
model = self.fmt_obox.get_model()
iter = model.get_iter_first()
while iter is not None:
othernum = model.get_value(iter, COL_NUM)
oldnum = model.get_value(oldnode, COL_NUM)
if othernum == oldnum:
pass# skip comparison with self
else:
othername = model.get_value(iter, COL_NAME)
if othername == name:
return True
iter = model.iter_next(iter)
return False
def __cancel_change(self, obj):
self.__change_name("", self.__current_path, self.__current_text)
def __change_name(self, text, path, new_text):
"""
If the new string is empty, do nothing. Otherwise, renaming the
database is simply changing the contents of the name file.
"""
if len(new_text) > 0 and text != new_text:
# build a pattern from translated pattern:
pattern = new_text
if (len(new_text) > 2 and
new_text[0] == '"' and
new_text[-1] == '"'):
pass
else:
for key in Utils.get_translations():
if key in pattern:
pattern = pattern.replace(key, Utils.get_keyword_from_translation(key))
# now build up a proper translation:
translation = pattern
if (len(new_text) > 2 and
new_text[0] == '"' and
new_text[-1] == '"'):
pass
else:
for key in Utils.get_keywords():
if key in translation:
translation = translation.replace(key, Utils.get_translation_from_keyword(key))
num, name, fmt = self.selected_fmt[COL_NUM:COL_EXPL]
node = self.fmt_model.get_iter(path)
oldname = self.fmt_model.get_value(node, COL_NAME)
# check to see if this pattern already exists
if self.__check_for_name(translation, node):
ErrorDialog(_("This format exists already"),
translation)
self.edit_button.emit('clicked')
return
# else, change the name
self.edit_button.set_sensitive(True)
self.remove_button.set_sensitive(True)
self.insert_button.set_sensitive(True)
exmpl = _nd.format_str(self.examplename, pattern)
self.fmt_model.set(self.iter, COL_NAME, translation,
COL_FMT, pattern,
COL_EXPL, exmpl)
self.selected_fmt = (num, translation, pattern, exmpl)
_nd.edit_name_format(num, translation, pattern)
self.dbstate.db.name_formats = _nd.get_name_format(only_custom=True,
only_active=False)
def __format_change(self, obj):
try:
t = (_nd.format_str(self.name, escape(obj.get_text())))
self.valid = True
except NameDisplayError:
t = _("Invalid or incomplete format definition")
self.valid = False
self.fmt_model.set(self.iter, COL_EXPL, t)
def _build_custom_name_ui(self):
"""
UI to manage the custom name formats
"""
table = gtk.Table(2, 3)
table.set_border_width(6)
table.set_col_spacings(6)
table.set_row_spacings(6)
# make a treeview for listing all the name formats
format_tree = gtk.TreeView(self.fmt_model)
name_renderer = gtk.CellRendererText()
name_column = gtk.TreeViewColumn(_('Format'),
name_renderer,
text=COL_NAME)
name_renderer.set_property('editable', False)
name_renderer.connect('edited', self.__change_name)
name_renderer.connect('editing-canceled', self.__cancel_change)
self.name_renderer = name_renderer
format_tree.append_column(name_column)
example_renderer = gtk.CellRendererText()
example_column = gtk.TreeViewColumn(_('Example'),
example_renderer,
text=COL_EXPL)
format_tree.append_column(example_column)
format_tree.get_selection().connect('changed',
self.cb_format_tree_select)
format_tree.set_rules_hint(True)
# ... and put it into a scrolled win
format_sw = gtk.ScrolledWindow()
format_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
format_sw.add(format_tree)
format_sw.set_shadow_type(gtk.SHADOW_IN)
table.attach(format_sw, 0, 3, 0, 1, yoptions=gtk.FILL|gtk.EXPAND)
# to hold the values of the selected row of the tree and the iter
self.selected_fmt = ()
self.iter = None
self.insert_button = gtk.Button(stock=gtk.STOCK_ADD)
self.insert_button.connect('clicked', self.__new_name)
#self.cb_insert_fmt_str)
self.edit_button = gtk.Button(stock=gtk.STOCK_EDIT)
self.edit_button.connect('clicked', self.__edit_name)
#self.cb_edit_fmt_str)
self.edit_button.set_sensitive(False)
self.remove_button = gtk.Button(stock=gtk.STOCK_REMOVE)
self.remove_button.connect('clicked', self.cb_del_fmt_str)
self.remove_button.set_sensitive(False)
table.attach(self.insert_button, 0, 1, 1, 2, yoptions=0)
table.attach(self.remove_button, 1, 2, 1, 2, yoptions=0)
table.attach(self.edit_button, 2, 3, 1, 2, yoptions=0)
self.format_list = format_tree
self.name_column = name_column
return table
def name_changed_check(self):
"""
Method to check for a name change. Called by Name Edit Dialog.
"""
obj = self.fmt_obox
the_list = obj.get_model()
the_iter = obj.get_active_iter()
format = the_list.get_value(the_iter, COL_FMT)
if format != self.old_format:
# Yes a change; call the callback
self.cb_name_changed(obj)
def cb_name_changed(self, obj):
"""
Preset name format ComboBox callback
"""
the_list = obj.get_model()
the_iter = obj.get_active_iter()
new_idx = the_list.get_value(the_iter, COL_NUM)
Config.set(Config.NAME_FORMAT, new_idx)
_nd.set_default_format(new_idx)
self.uistate.emit('nameformat-changed')
def cb_format_tree_select(self, tree_selection):
"""
Name format editor TreeView callback
Remember the values of the selected row (self.selected_fmt, self.iter)
and set the Remove and Edit button sensitivity
"""
model, self.iter = tree_selection.get_selected()
if self.iter is None:
tree_selection.select_path(0)
model, self.iter = tree_selection.get_selected()
self.selected_fmt = model.get(self.iter, 0, 1, 2)
idx = self.selected_fmt[COL_NUM] < 0
self.remove_button.set_sensitive(idx)
self.edit_button.set_sensitive(idx)
self.name_renderer.set_property('editable', idx)
def cb_edit_fmt_str(self, obj):
"""
Name format editor Edit button callback
"""
num, name, fmt = self.selected_fmt[COL_NUM:COL_EXPL]
dlg = NameFormatEditDlg(name, fmt, self.examplename)
dlg.dlg.set_transient_for(self.window)
(res, name, fmt) = dlg.run()
if res == gtk.RESPONSE_OK and (name != self.selected_fmt[COL_NAME] or
fmt != self.selected_fmt[COL_FMT]):
exmpl = _nd.format_str(self.examplename, fmt)
self.fmt_model.set(self.iter, COL_NAME, name,
COL_FMT, fmt,
COL_EXPL, exmpl)
self.selected_fmt = (num, name, fmt, exmpl)
_nd.edit_name_format(num, name, fmt)
self.dbstate.db.name_formats = _nd.get_name_format(only_custom=True,
only_active=False)
def cb_insert_fmt_str(self, obj):
"""
Name format editor Insert button callback
"""
dlg = NameFormatEditDlg('', '', self.examplename)
dlg.dlg.set_transient_for(self.window)
(res, n, f) = dlg.run()
if res == gtk.RESPONSE_OK:
i = _nd.add_name_format(n, f)
self.fmt_model.append(row=[i, n, f,
_nd.format_str(self.examplename, f)])
self.dbstate.db.name_formats = _nd.get_name_format(only_custom=True,
only_active=False)
def cb_del_fmt_str(self, obj):
"""
Name format editor Remove button callback
"""
num = self.selected_fmt[COL_NUM]
if _nd.get_default_format() == num:
self.fmt_obox.set_active(0)
self.fmt_model.remove(self.iter)
_nd.set_format_inactive(num)
self.dbstate.db.name_formats = _nd.get_name_format(only_custom=True,
only_active=False)
def add_formats_panel(self):
row = 0
table = gtk.Table(4, 4)
table.set_border_width(12)
table.set_col_spacings(6)
table.set_row_spacings(6)
# Display name:
self.examplename = Name()
self.examplename.set_title('Dr.')
self.examplename.set_first_name('Edwin Jose')
self.examplename.set_surname_prefix('von der')
self.examplename.set_surname('Smith')
self.examplename.set_suffix('Sr')
self.examplename.set_patronymic('Wilson')
self.examplename.set_call_name('Ed')
# get the model for the combo and the treeview
active = _nd.get_default_format()
self.fmt_model, active = self._build_name_format_model(active)
# set up the combo to choose the preset format
self.fmt_obox = gtk.ComboBox()
cell = gtk.CellRendererText()
self.fmt_obox.pack_start(cell, True)
self.fmt_obox.add_attribute(cell, 'text', 1)
self.fmt_obox.set_model(self.fmt_model)
# set the default value as active in the combo
self.fmt_obox.set_active(active)
self.fmt_obox.connect('changed', self.cb_name_changed)
# label for the combo
lwidget = BasicLabel("%s: " % _('Name format'))
lwidget.set_use_underline(True)
lwidget.set_mnemonic_widget(self.fmt_obox)
hbox = gtk.HBox()
btn = gtk.Button("%s..." % _('Edit') )
btn.connect('clicked', self.cb_name_dialog)
hbox.pack_start(self.fmt_obox, expand=True, fill=True)
hbox.pack_start(btn, expand=False, fill=False)
table.attach(lwidget, 0, 1, row, row+1, yoptions=0)
table.attach(hbox, 1, 3, row, row+1, yoptions=0)
row += 1
# Date format:
obox = gtk.combo_box_new_text()
formats = DateHandler.get_date_formats()
for item in formats:
obox.append_text(item)
active = Config.get(Config.DATE_FORMAT)
if active >= len(formats):
active = 0
obox.set_active(active)
obox.connect('changed', self.date_format_changed)
lwidget = BasicLabel("%s: " % _('Date format'))
table.attach(lwidget, 0, 1, row, row+1, yoptions=0)
table.attach(obox, 1, 3, row, row+1, yoptions=0)
row += 1
# Surname guessing:
obox = gtk.combo_box_new_text()
formats = _surname_styles
for item in formats:
obox.append_text(item)
obox.set_active(Config.get(Config.SURNAME_GUESSING))
obox.connect('changed',
lambda obj: Config.set(Config.SURNAME_GUESSING,
obj.get_active()))
lwidget = BasicLabel("%s: " % _('Surname guessing'))
table.attach(lwidget, 0, 1, row, row+1, yoptions=0)
table.attach(obox, 1, 3, row, row+1, yoptions=0)
row += 1
# Status bar:
obox = gtk.combo_box_new_text()
formats = [_("Active person's name and ID"),
_("Relationship to home person")]
for item in formats:
obox.append_text(item)
active = Config.get(Config.STATUSBAR)
if active < 2:
obox.set_active(0)
else:
obox.set_active(1)
obox.connect('changed',
lambda obj: Config.set(Config.STATUSBAR, 2*obj.get_active()))
lwidget = BasicLabel("%s: " % _('Status bar'))
table.attach(lwidget, 0, 1, row, row+1, yoptions=0)
table.attach(obox, 1, 3, row, row+1, yoptions=0)
row += 1
# Text in sidebar:
self.add_checkbox(table,
_("Show text in sidebar buttons (requires restart)"),
row, Config.SIDEBAR_TEXT, stop=3)
row += 1
return table
def add_text_panel(self):
row = 0
table = gtk.Table(6, 8)
table.set_border_width(12)
table.set_col_spacings(6)
table.set_row_spacings(6)
self.add_entry(table, _('Missing surname'), row,
Config.NO_SURNAME_TEXT)
row += 1
self.add_entry(table, _('Missing given name'), row,
Config.NO_GIVEN_TEXT)
row += 1
self.add_entry(table, _('Missing record'), row,
Config.NO_RECORD_TEXT)
row += 1
self.add_entry(table, _('Private surname'), row,
Config.PRIVATE_SURNAME_TEXT)
row += 1
self.add_entry(table, _('Private given name'), row,
Config.PRIVATE_GIVEN_TEXT)
row += 1
self.add_entry(table, _('Private record'), row,
Config.PRIVATE_RECORD_TEXT)
row += 1
return table
def cb_name_dialog(self, obj):
the_list = self.fmt_obox.get_model()
the_iter = self.fmt_obox.get_active_iter()
self.old_format = the_list.get_value(the_iter, COL_FMT)
win = DisplayNameEditor(self.uistate, self.dbstate, self.track, self)
def date_format_changed(self, obj):
from QuestionDialog import OkDialog
Config.set(Config.DATE_FORMAT, obj.get_active())
OkDialog(_('Change is not immediate'),
_('Changing the data format will not take '
'effect until the next time GRAMPS is started.'))
def add_date_panel(self):
table = gtk.Table(2, 7)
table.set_border_width(12)
table.set_col_spacings(6)
table.set_row_spacings(6)
self.add_pos_int_entry(table,
_('Date about range'),
0, Config.DATE_ABOUT_RANGE, self.update_entry)
self.add_pos_int_entry(table,
_('Date after range'),
1, Config.DATE_AFTER_RANGE, self.update_entry)
self.add_pos_int_entry(table,
_('Date before range'),
2, Config.DATE_BEFORE_RANGE, self.update_entry)
self.add_pos_int_entry(table,
_('Maximum age probably alive'),
3, Config.MAX_AGE_PROB_ALIVE, self.update_entry)
self.add_pos_int_entry(table,
_('Maximum sibling age difference'),
4, Config.MAX_SIB_AGE_DIFF, self.update_entry)
self.add_pos_int_entry(table,
_('Minimum years between generations'),
5, Config.MIN_GENERATION_YEARS, self.update_entry)
self.add_pos_int_entry(table,
_('Average years between generations'),
6, Config.AVG_GENERATION_GAP, self.update_entry)
self.add_pos_int_entry(table,
_('Markup for invalid date format'),
7, Config.INVALID_DATE_FORMAT, self.update_entry)
return table
def add_behavior_panel(self):
table = gtk.Table(3, 8)
table.set_border_width(12)
table.set_col_spacings(6)
table.set_row_spacings(6)
self.add_checkbox(table,
_('Add default source on import'),
0, Config.DEFAULT_SOURCE)
self.add_checkbox(table,
_('Enable spelling checker'),
1, Config.SPELLCHECK)
self.add_checkbox(table,
_('Display Tip of the Day'),
2, Config.USE_TIPS)
self.add_checkbox(table,
_('Use shading in Relationship View'),
3, Config.RELATION_SHADE)
self.add_checkbox(table,
_('Display edit buttons on Relationship View'),
4, Config.RELEDITBTN)
self.add_checkbox(table,
_('Remember last view displayed'),
5, Config.USE_LAST_VIEW)
self.add_pos_int_entry(table,
_('Max generations for relationships'),
6, Config.GENERATION_DEPTH, self.update_gen_depth)
self.path_entry = gtk.Entry()
self.add_path_box(table,
_('Base path for relative media paths'),
7, self.path_entry, self.dbstate.db.get_mediapath(),
self.set_mediapath, self.select_mediapath)
return table
def add_database_panel(self):
table = gtk.Table(2, 2)
table.set_border_width(12)
table.set_col_spacings(6)
table.set_row_spacings(6)
self.add_entry(table,
_('Database path'),
0, Config.DATABASE_PATH)
self.add_checkbox(table,
_('Automatically load last database'),
1, Config.AUTOLOAD)
return table
def add_checkbox(self, table, label, index, constant, start=1, stop=9):
checkbox = gtk.CheckButton(label)
checkbox.set_active(Config.get(constant))
checkbox.connect('toggled', self.update_checkbox, constant)
table.attach(checkbox, start, stop, index, index+1, yoptions=0)
def add_radiobox(self, table, label, index, constant, group, column):
radiobox = gtk.RadioButton(group,label)
if Config.get(constant) == True:
radiobox.set_active(True)
radiobox.connect('toggled', self.update_radiobox, constant)
table.attach(radiobox, column, column+1, index, index+1, yoptions=0)
return radiobox
def add_text(self, table, label, index):
text = gtk.Label()
text.set_line_wrap(True)
text.set_alignment(0.,0.)
text.set_text(label)
table.attach(text, 1, 9, index, index+1, yoptions=0)
def add_path_box(self, table, label, index, entry, path, callback_label,
callback_sel):
""" Add an entry to give in path and a select button to open a
dialog.
Changing entry calls callback_label
Clicking open button call callback_sel
"""
lwidget = BasicLabel("%s: " %label)
hbox = gtk.HBox()
if path:
entry.set_text(path)
entry.connect('changed', callback_label)
btn = gtk.Button()
btn.connect('clicked', callback_sel)
image = gtk.Image()
image.set_from_stock(gtk.STOCK_OPEN, gtk.ICON_SIZE_BUTTON)
image.show()
btn.add(image)
hbox.pack_start(entry, expand=True, fill=True)
hbox.pack_start(btn, expand=False, fill=False)
table.attach(lwidget, 1, 2, index, index+1, yoptions=0,
xoptions=gtk.FILL)
table.attach(hbox, 2, 3, index, index+1, yoptions=0)
def add_entry(self, table, label, index, constant, callback=None):
if not callback:
callback = self.update_entry
lwidget = BasicLabel("%s: " % label)
entry = gtk.Entry()
entry.set_text(Config.get(constant))
entry.connect('changed', callback, constant)
table.attach(lwidget, 0, 1, index, index+1, yoptions=0,
xoptions=gtk.FILL)
table.attach(entry, 1, 2, index, index+1, yoptions=0)
def add_pos_int_entry(self, table, label, index, constant, callback=None):
""" entry field for positive integers
"""
lwidget = BasicLabel("%s: " % label)
entry = gtk.Entry()
entry.set_text(str(Config.get(constant)))
if callback:
entry.connect('changed', callback, constant)
table.attach(lwidget, 1, 2, index, index+1, yoptions=0,
xoptions=gtk.FILL)
table.attach(entry, 2, 3, index, index+1, yoptions=0)
def add_color(self, table, label, index, constant):
lwidget = BasicLabel("%s: " % label)
hexval = Config.get(constant)
color = gtk.gdk.color_parse(hexval)
entry = gtk.ColorButton(color=color)
color_hex_label = BasicLabel(hexval)
entry.connect('color-set', self.update_color, constant, color_hex_label)
table.attach(lwidget, 0, 1, index, index+1, yoptions=0,
xoptions=gtk.FILL)
table.attach(entry, 1, 2, index, index+1, yoptions=0, xoptions=0)
table.attach(color_hex_label, 2, 3, index, index+1, yoptions=0)
return entry
def set_mediapath(self, *obj):
if self.path_entry.get_text().strip():
self.dbstate.db.set_mediapath(self.path_entry.get_text())
else:
self.dbstate.db.set_mediapath(None)
def select_mediapath(self, *obj):
f = gtk.FileChooserDialog(
_("Select media directory"),
action=gtk.FILE_CHOOSER_ACTION_CREATE_FOLDER,
buttons=(gtk.STOCK_CANCEL,
gtk.RESPONSE_CANCEL,
gtk.STOCK_APPLY,
gtk.RESPONSE_OK))
mpath = self.dbstate.db.get_mediapath()
if not mpath:
mpath = const.HOME_DIR
f.set_current_folder(os.path.dirname(mpath))
status = f.run()
if status == gtk.RESPONSE_OK:
val = Utils.get_unicode_path(f.get_filename())
if val:
self.path_entry.set_text(val)
f.destroy()
def update_entry(self, obj, constant):
Config.set(constant, unicode(obj.get_text()))
def update_idformat_entry(self, obj, constant):
Config.set(constant, unicode(obj.get_text()))
self.dbstate.db.set_prefixes(
Config.get(Config.IPREFIX),
Config.get(Config.OPREFIX),
Config.get(Config.FPREFIX),
Config.get(Config.SPREFIX),
Config.get(Config.PPREFIX),
Config.get(Config.EPREFIX),
Config.get(Config.RPREFIX),
Config.get(Config.NPREFIX) )
def update_gen_depth(self, obj, constant):
ok = True
if not obj.get_text():
return
try:
intval = int(obj.get_text())
except:
intval = Config.get(constant)
ok = False
if intval < 0 :
intval = Config.get(constant)
ok = False
if ok:
Config.set(constant, intval)
#immediately use this value in displaystate.
self.uistate.set_gendepth(intval)
else:
obj.set_text(str(intval))
def update_color(self, obj, constant, color_hex_label):
color = obj.get_color()
hexval = "#%02x%02x%02x" % (color.red/256,
color.green/256,
color.blue/256)
color_hex_label.set_text(hexval)
Config.set(constant, hexval)
def update_checkbox(self, obj, constant):
Config.set(constant, obj.get_active())
def update_radiobox(self, obj, constant):
Config.set(constant, obj.get_active())
def build_menu_names(self, obj):
return (_('Preferences'), None)
# FIXME: is this needed?
def _set_button(self, stock):
button = gtk.Button()
image = gtk.Image()
image.set_from_stock(stock, gtk.ICON_SIZE_BUTTON)
image.show()
button.add(image)
button.show()
return button
class NameFormatEditDlg:
"""
"""
def __init__(self, fmt_name, fmt_str, name):
self.fmt_name = fmt_name
self.fmt_str = fmt_str
self.name = name
self.valid = True
self.top = glade.XML(const.GLADE_FILE, 'namefmt_edit', 'gramps')
self.dlg = self.top.get_widget('namefmt_edit')
ManagedWindow.set_titles(self.dlg, None, _('Name Format Editor'))
self.examplelabel = self.top.get_widget('example_label')
self.nameentry = self.top.get_widget('name_entry')
self.nameentry.set_text('%s' % self.fmt_name)
self.nameentry.set_use_markup(True)
self.formatentry = self.top.get_widget('format_entry')
self.formatentry.connect('changed', self.cb_format_changed)
self.formatentry.set_text(self.fmt_str)
def run(self):
running = True
while running:
self.response = self.dlg.run()
running = False
self.fmt_name = self.nameentry.get_text()
self.fmt_str = self.formatentry.get_text()
if self.response == gtk.RESPONSE_OK:
if not self.valid:
q = QuestionDialog2(
_('The format definition is invalid'),
_('What would you like to do?'),
_('_Continue anyway'), _('_Modify format'),
parent=self.dlg)
running = not q.run()
self.response = gtk.RESPONSE_CANCEL
elif self.fmt_name == '' and self.fmt_str == '':
self.response = gtk.RESPONSE_CANCEL
elif (self.fmt_name == '') ^ (self.fmt_str == ''):
ErrorDialog(
_('Both Format name and definition have to be defined'),
parent=self.dlg)
running = True
self.dlg.destroy()
return (self.response, self.fmt_name, self.fmt_str)
def cb_format_changed(self, obj):
try:
t = (_nd.format_str(self.name, escape(obj.get_text())))
sample = '%s' % t
self.valid = True
except NameDisplayError:
t = _("Invalid or incomplete format definition")
sample = '%s' % t
self.valid = False
self.examplelabel.set_text(sample)
self.examplelabel.set_use_markup(True)
self.nameentry.set_text('%s' % obj.get_text())
self.nameentry.set_use_markup(True)