svn: r8622

This commit is contained in:
Alex Roitman 2007-06-22 05:57:48 +00:00
parent c70a3c2852
commit cc26961713
4 changed files with 113 additions and 78 deletions

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2004-2006 Donald N. Allingham
# Copyright (C) 2004-2007 Donald N. Allingham
#
# 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
@ -38,6 +38,7 @@ import re
#
#-------------------------------------------------------------------------
from RelLib import Name
from Errors import NameDisplayError
try:
import Config
@ -243,19 +244,19 @@ class NameDisplay:
def _gen_raw_func(self, format_str):
"""The job of building the name from a format string is rather
expensive and it is called lots and lots of times. So it is worth
going to some length to optimise it as much as possible.
"""The job of building the name from a format string is rather
expensive and it is called lots and lots of times. So it is worth
going to some length to optimise it as much as possible.
This method constructs a new function that is specifically written
to format a name given a particualar format string. This is worthwhile
because the format string itself rarely changes, so by caching the new
function and calling it directly when asked to format a name to the
same format string again we can be as quick as possible.
This method constructs a new function that is specifically written
to format a name given a particualar format string. This is worthwhile
because the format string itself rarely changes, so by caching the new
function and calling it directly when asked to format a name to the
same format string again we can be as quick as possible.
The new function is of the form:
The new function is of the form:
def fn(raw_data):
def fn(raw_data):
return "%s %s %s %s %s" % (raw_data[_TITLE],
raw_data[_FIRSTNAME],
raw_data[_PREFIX],
@ -264,15 +265,15 @@ class NameDisplay:
"""
# we need the names of each of the variables or methods that are
# called to fill in each format flag.
# we need the names of each of the variables or methods that are
# called to fill in each format flag.
d = {"%t":"raw_data[_TITLE]",
"%f":"raw_data[_FIRSTNAME]",
"%p":"raw_data[_PREFIX]",
"%l":"raw_data[_SURNAME]",
"%s":"raw_data[_SUFFIX]",
"%y":"raw_data[_PATRONYM]",
"%c":"raw_data[_CALL]",
"%c":"raw_data[_CALL]",
"%T":"raw_data[_TITLE].upper()",
"%F":"raw_data[_FIRSTNAME].upper()",
"%P":"raw_data[_PREFIX].upper()",
@ -284,8 +285,8 @@ class NameDisplay:
new_fmt = format_str
# replace the specific format string flags with a
# flag that works in standard python format strings.
# replace the specific format string flags with a
# flag that works in standard python format strings.
new_fmt = new_fmt.replace("%t","%s")
new_fmt = new_fmt.replace("%f","%s")
new_fmt = new_fmt.replace("%p","%s")
@ -303,10 +304,10 @@ class NameDisplay:
new_fmt = new_fmt.replace("%C","%s")
new_fmt = new_fmt.replace("%%",'%')
# find each format flag in the original format string
# for each one we find the variable name that is needed to
# replace it and add this to a list. This list will be used
# generate the replacement tuple.
# find each format flag in the original format string
# for each one we find the variable name that is needed to
# replace it and add this to a list. This list will be used
# generate the replacement tuple.
pat = re.compile("%.")
param = ()
@ -317,37 +318,37 @@ class NameDisplay:
s = 'def fn(raw_data):\n'\
' return "%s" %% (%s)' % (new_fmt,",".join(param))
exec(s)
exec(s)
return fn
def _gen_cooked_func(self, format_str):
"""The job of building the name from a format string is rather
expensive and it is called lots and lots of times. So it is worth
going to some length to optimise it as much as possible.
"""The job of building the name from a format string is rather
expensive and it is called lots and lots of times. So it is worth
going to some length to optimise it as much as possible.
This method constructs a new function that is specifically written
to format a name given a particualar format string. This is worthwhile
because the format string itself rarely changes, so by caching the new
function and calling it directly when asked to format a name to the
same format string again we can be as quick as possible.
This method constructs a new function that is specifically written
to format a name given a particualar format string. This is worthwhile
because the format string itself rarely changes, so by caching the new
function and calling it directly when asked to format a name to the
same format string again we can be as quick as possible.
The new function is of the form:
The new function is of the form:
def fn(first,surname,prefix,suffix,patronymic,title,call,):
def fn(first,surname,prefix,suffix,patronymic,title,call,):
return "%s %s %s %s %s" % (first,surname,prefix,suffix,patronymic)
"""
# we need the names of each of the variables or methods that are
# called to fill in each format flag.
# we need the names of each of the variables or methods that are
# called to fill in each format flag.
d = {"%t":"title",
"%f":"first",
"%p":"prefix",
"%l":"surname",
"%s":"suffix",
"%y":"patronymic",
"%c":"call",
"%c":"call",
"%T":"title.upper()",
"%F":"first.upper()",
"%P":"prefix.upper()",
@ -360,8 +361,8 @@ class NameDisplay:
new_fmt = format_str
# replace the specific format string flags with a
# flag that works in standard python format strings.
# replace the specific format string flags with a
# flag that works in standard python format strings.
new_fmt = new_fmt.replace("%t","%s")
new_fmt = new_fmt.replace("%f","%s")
new_fmt = new_fmt.replace("%p","%s")
@ -379,11 +380,11 @@ class NameDisplay:
new_fmt = new_fmt.replace("%C","%s")
new_fmt = new_fmt.replace("%%",'%')
# find each format flag in the original format string
# for each one we find the variable name that is needed to
# replace it and add this to a list. This list will be used
# generate the replacement tuple.
pat = re.compile("%.")
# find each format flag in the original format string
# for each one we find the variable name that is needed to
# replace it and add this to a list. This list will be used
# generate the replacement tuple.
pat = re.compile('|'.join(d.keys()))
param = ()
mat = pat.search(format_str)
@ -393,7 +394,7 @@ class NameDisplay:
s = 'def fn(first,surname,prefix,suffix,patronymic,title,call,):\n'\
' return "%s" %% (%s)' % (new_fmt,",".join(param))
exec(s)
exec(s)
return fn
@ -403,19 +404,19 @@ class NameDisplay:
name.call,format_str)
def format_str_raw(self,raw_data,format_str):
"""
Format a name from the raw name list. To make this as fast as possible
this uses _gen_raw_func to generate a new method for each new format_string.
Is does not call _format_str_base because it would introduce an extra
method call and we need all the speed we can squeeze out of this.
"""
"""
Format a name from the raw name list. To make this as fast as possible
this uses _gen_raw_func to generate a new method for each new format_string.
Is does not call _format_str_base because it would introduce an extra
method call and we need all the speed we can squeeze out of this.
"""
func = self.__class__.raw_format_funcs.get(format_str)
if func == None:
func = self._gen_raw_func(format_str)
self.__class__.raw_format_funcs[format_str] = func
s = func(raw_data)
s = func(raw_data)
return ' '.join(s.split())
@ -443,10 +444,14 @@ class NameDisplay:
func = self._gen_cooked_func(format_str)
self.__class__.format_funcs[format_str] = func
s = func(first,surname,prefix,suffix,patronymic,title,call)
try:
s = func(first,surname,prefix,suffix,patronymic,title,call)
except (ValueError,TypeError,):
raise NameDisplayError, "Incomplete format string"
return ' '.join(s.split())
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
def sort_string(self,name):
return u"%-25s%-30s%s" % (name.surname,name.first_name,name.suffix)

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# Copyright (C) 2000-2007 Donald N. Allingham
#
# 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
@ -383,8 +383,6 @@ class EditFamily(EditPrimary):
EditPrimary.__init__(self, dbstate, uistate, track,
family, dbstate.db.get_family_from_handle)
self.in_save = False
# look for the scenerio of a child and no parents on a new
# family
@ -433,7 +431,7 @@ class EditFamily(EditPrimary):
def check_for_family_change(self, handles):
# check to see if the handle matches the current object
if not self.in_save and self.obj.get_handle() in handles:
if self.obj.get_handle() in handles:
self.obj = self.dbstate.db.get_family_from_handle(self.obj.get_handle())
self.reload_people()
@ -802,7 +800,6 @@ class EditFamily(EditPrimary):
def __do_save(self):
self.ok_button.set_sensitive(False)
self.in_save = True
if not self.added:
original = self.db.get_family_from_handle(self.obj.handle)
@ -834,7 +831,21 @@ class EditFamily(EditPrimary):
self.ok_button.set_sensitive(True)
return
if not original and self.object_is_empty():
QuestionDialog.ErrorDialog(
_("Cannot save family"),
_("No data exists for this family. "
"Please enter data or cancel the edit."))
self.ok_button.set_sensitive(True)
return
# We disconnect the callbacks to all signals we connected earlier.
# This prevents the signals originating in any of the following
# commits from being caught by us again.
for key in self.signal_keys:
self.db.disconnect(key)
self.signal_keys = []
if not original and not self.object_is_empty():
trans = self.db.transaction_begin()
@ -861,12 +872,6 @@ class EditFamily(EditPrimary):
self.db.add_family(self.obj,trans)
self.db.transaction_commit(trans,_("Add Family"))
elif not original and self.object_is_empty():
QuestionDialog.ErrorDialog(_("Cannot save family"),
_("No data exists for this family. Please "
"enter data or cancel the edit."))
self.ok_button.set_sensitive(True)
return
elif original and self.object_is_empty():
trans = self.db.transaction_begin()
self.db.remove_family(self.obj.handle,trans)
@ -901,7 +906,6 @@ class EditFamily(EditPrimary):
self.db.commit_family(self.obj,trans)
self.db.transaction_commit(trans,_("Edit Family"))
self.in_save = False
self.close()
def _cleanup_on_exit(self):

View File

@ -1,7 +1,7 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2003-2006 Donald N. Allingham
# Copyright (C) 2003-2007 Donald N. Allingham
#
# 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
@ -151,3 +151,14 @@ class DbError(Exception):
def __str__(self):
"Return string representation"
return self.value
class NameDisplayError(Exception):
"""
Error used to report that the name display format string is invalid.
"""
def __init__(self,value):
Exception.__init__(self)
self.value = value
def __str__(self):
return self.value

View File

@ -26,6 +26,7 @@
#
#-------------------------------------------------------------------------
from gettext import gettext as _
from xml.sax.saxutils import escape
#-------------------------------------------------------------------------
#
@ -46,6 +47,7 @@ from RelLib import Name
import ManagedWindow
from GrampsWidgets import *
import QuestionDialog
from Errors import NameDisplayError
#-------------------------------------------------------------------------
#
@ -379,12 +381,12 @@ class GrampsPreferences(ManagedWindow.ManagedWindow):
Name format editor Edit button callback
"""
num,name,fmt = self.selected_fmt[COL_NUM:COL_EXPL]
dlg = NameFormatEditDlg(name,fmt,self.examplename)
dlg = NameFormatEditDlg(name, fmt, self.examplename)
dlg.dlg.set_transient_for(self.window)
(res,name,fmt) = dlg.run()
if name != self.selected_fmt[COL_NAME] or \
fmt != self.selected_fmt[COL_FMT]:
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,
@ -586,12 +588,13 @@ class NameFormatEditDlg:
"""
"""
def __init__(self,fmt_name,fmt_str,name):
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 = gtk.glade.XML(const.gladeFile,'namefmt_edit','gramps')
self.top = gtk.glade.XML(const.gladeFile, 'namefmt_edit','gramps')
self.dlg = self.top.get_widget('namefmt_edit')
ManagedWindow.set_titles(self.dlg, None, _('Name Format Editor'))
@ -601,7 +604,7 @@ class NameFormatEditDlg:
self.nameentry.set_text(self.fmt_name)
self.formatentry = self.top.get_widget('format_entry')
self.formatentry.connect('changed',self.cb_format_changed)
self.formatentry.connect('changed', self.cb_format_changed)
self.formatentry.set_text(self.fmt_str)
def run(self):
@ -614,7 +617,15 @@ class NameFormatEditDlg:
self.fmt_str = self.formatentry.get_text()
if self.response == gtk.RESPONSE_OK:
if self.fmt_name == '' and self.fmt_str == '':
if not self.valid:
q = QuestionDialog.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 == ''):
QuestionDialog.ErrorDialog(
@ -625,11 +636,15 @@ class NameFormatEditDlg:
self.dlg.destroy()
return (self.response, self.fmt_name, self.fmt_str)
def cb_format_changed(self,obj):
def cb_format_changed(self, obj):
try:
t = (_nd.format_str(self.name,obj.get_text()))
except ValueError, msg:
t = _("Invalid format string: %s") % msg
self.examplelabel.set_text(
'<span weight="bold" style="italic">%s</span>' % t)
t = (_nd.format_str(self.name, escape(obj.get_text())))
sample = '<span weight="bold" style="italic">%s</span>' % t
self.valid = True
except NameDisplayError:
t = _("Invalid or incomplete format definition")
sample = '<span foreground="#FF0000">%s</span>' % t
self.valid = False
self.examplelabel.set_text(sample)
self.examplelabel.set_use_markup(True)