remove empty families

svn: r6293
This commit is contained in:
Don Allingham 2006-04-08 05:56:31 +00:00
parent 6ddcf8b7bc
commit ffae52385f
6 changed files with 711 additions and 600 deletions

View File

@ -1,3 +1,6 @@
2006-04-07 Don Allingham <don@gramps-project.org>
* src/Editors/_EditFamily.py: remove empty families
2006-04-07 Brian Matherly <pez4brian@users.sourceforge.net> 2006-04-07 Brian Matherly <pez4brian@users.sourceforge.net>
* src/docgen/PdfDoc.py: fix columns, error check images * src/docgen/PdfDoc.py: fix columns, error check images
* src/docgen/RTFDoc.py: error check images * src/docgen/RTFDoc.py: error check images

View File

@ -34,9 +34,9 @@ import Errors
from PluginUtils import ReportUtils from PluginUtils import ReportUtils
_GenderCode = { _GenderCode = {
RelLib.Person.MALE : u'\u2642', RelLib.Person.MALE : u'\u2642',
RelLib.Person.FEMALE : u'\u2640', RelLib.Person.FEMALE : u'\u2640',
RelLib.Person.UNKNOWN : u'\u2650', RelLib.Person.UNKNOWN : u'\u2650',
} }
_NAME_START = 0 _NAME_START = 0
@ -72,19 +72,20 @@ class AttachList:
self.max_x = 0 self.max_x = 0
self.max_y = 0 self.max_y = 0
def attach(self,widget,x0,x1,y0,y1,xoptions=gtk.EXPAND|gtk.FILL, def attach(self, widget, x0, x1, y0, y1, xoptions=gtk.EXPAND|gtk.FILL,
yoptions=gtk.EXPAND|gtk.FILL): yoptions=gtk.EXPAND|gtk.FILL):
assert(x1>x0) assert(x1>x0)
self.list.append((widget,x0,x1,y0,y1,xoptions,yoptions)) self.list.append((widget, x0, x1, y0, y1, xoptions, yoptions))
self.max_x = max(self.max_x,x1) self.max_x = max(self.max_x, x1)
self.max_y = max(self.max_y,y1) self.max_y = max(self.max_y, y1)
class FamilyView(PageView.PersonNavView): class FamilyView(PageView.PersonNavView):
def __init__(self,dbstate,uistate): def __init__(self, dbstate, uistate):
PageView.PersonNavView.__init__(self,'Relationship View',dbstate,uistate)
dbstate.connect('database-changed',self.change_db) PageView.PersonNavView.__init__(self, 'Relationship View', dbstate, uistate)
dbstate.connect('active-changed',self.change_person) dbstate.connect('database-changed', self.change_db)
dbstate.connect('active-changed', self.change_person)
self.show_siblings = Config.get_family_siblings() self.show_siblings = Config.get_family_siblings()
if self.show_siblings == None: if self.show_siblings == None:
self.show_siblings = True self.show_siblings = True
@ -95,15 +96,15 @@ class FamilyView(PageView.PersonNavView):
self.redrawing = False self.redrawing = False
self.child = None self.child = None
def connect_to_db(self,db): def connect_to_db(self, db):
db.connect('person-update', self.person_update) db.connect('person-update', self.person_update)
db.connect('person-rebuild',self.person_rebuild) db.connect('person-rebuild', self.person_rebuild)
db.connect('family-update', self.family_update) db.connect('family-update', self.family_update)
db.connect('family-add', self.family_add) db.connect('family-add', self.family_add)
db.connect('family-delete', self.family_delete) db.connect('family-delete', self.family_delete)
db.connect('family-rebuild',self.family_rebuild) db.connect('family-rebuild', self.family_rebuild)
def person_update(self,handle_list): def person_update(self, handle_list):
if self.dbstate.active: if self.dbstate.active:
while not self.change_person(self.dbstate.active.handle): while not self.change_person(self.dbstate.active.handle):
pass pass
@ -113,17 +114,17 @@ class FamilyView(PageView.PersonNavView):
while not self.change_person(self.dbstate.active.handle): while not self.change_person(self.dbstate.active.handle):
pass pass
def family_update(self,handle_list): def family_update(self, handle_list):
if self.dbstate.active: if self.dbstate.active:
while not self.change_person(self.dbstate.active.handle): while not self.change_person(self.dbstate.active.handle):
pass pass
def family_add(self,handle_list): def family_add(self, handle_list):
if self.dbstate.active: if self.dbstate.active:
while not self.change_person(self.dbstate.active.handle): while not self.change_person(self.dbstate.active.handle):
pass pass
def family_delete(self,handle_list): def family_delete(self, handle_list):
if self.dbstate.active: if self.dbstate.active:
while not self.change_person(self.dbstate.active.handle): while not self.change_person(self.dbstate.active.handle):
pass pass
@ -143,7 +144,7 @@ class FamilyView(PageView.PersonNavView):
def build_widget(self): def build_widget(self):
self.scroll = gtk.ScrolledWindow() self.scroll = gtk.ScrolledWindow()
self.scroll.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) self.scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.scroll.show() self.scroll.show()
self.vbox = gtk.VBox() self.vbox = gtk.VBox()
self.vbox.show() self.vbox.show()
@ -190,36 +191,36 @@ class FamilyView(PageView.PersonNavView):
def define_actions(self): def define_actions(self):
PageView.PersonNavView.define_actions(self) PageView.PersonNavView.define_actions(self)
self.add_toggle_action('Details', None, _('Show details'), self.add_toggle_action('Details', None, _('Show details'),
None, None, self.details_toggle, None, None, self.details_toggle,
self.show_details) self.show_details)
self.add_toggle_action('Siblings', None, _('Show siblings'), self.add_toggle_action('Siblings', None, _('Show siblings'),
None, None, self.siblings_toggle, None, None, self.siblings_toggle,
self.show_siblings) self.show_siblings)
def siblings_toggle(self,obj): def siblings_toggle(self, obj):
self.show_siblings = obj.get_active() self.show_siblings = obj.get_active()
self.change_person(self.dbstate.active.handle) self.change_person(self.dbstate.active.handle)
Config.save_family_siblings(self.show_siblings) Config.save_family_siblings(self.show_siblings)
def details_toggle(self,obj): def details_toggle(self, obj):
self.show_details = obj.get_active() self.show_details = obj.get_active()
self.change_person(self.dbstate.active.handle) self.change_person(self.dbstate.active.handle)
Config.save_family_details(self.show_details) Config.save_family_details(self.show_details)
def change_db(self,db): def change_db(self, db):
self.connect_to_db(db) self.connect_to_db(db)
if self.child: if self.child:
self.vbox.remove(self.child) self.vbox.remove(self.child)
self.child = None self.child = None
self.dbstate.db.connect('family-update',self.redraw) self.dbstate.db.connect('family-update', self.redraw)
self.dbstate.db.connect('family-add',self.redraw) self.dbstate.db.connect('family-add', self.redraw)
self.dbstate.db.connect('family-delete',self.redraw) self.dbstate.db.connect('family-delete', self.redraw)
self.dbstate.db.connect('person-update',self.redraw) self.dbstate.db.connect('person-update', self.redraw)
self.dbstate.db.connect('person-add',self.redraw) self.dbstate.db.connect('person-add', self.redraw)
self.dbstate.db.connect('person-delete',self.redraw) self.dbstate.db.connect('person-delete', self.redraw)
def get_name(self,handle,use_gender=False): def get_name(self, handle, use_gender=False):
if handle: if handle:
p = self.dbstate.db.get_person_from_handle(handle) p = self.dbstate.db.get_person_from_handle(handle)
name = NameDisplay.displayer.display(p) name = NameDisplay.displayer.display(p)
@ -227,15 +228,15 @@ class FamilyView(PageView.PersonNavView):
gender = _GenderCode[p.gender] gender = _GenderCode[p.gender]
else: else:
gender = "" gender = ""
return (name,gender) return (name, gender)
else: else:
return (_(u"Unknown"),"") return (_(u"Unknown"), "")
def redraw(self,*obj): def redraw(self, *obj):
if self.dbstate.active: if self.dbstate.active:
self.change_person(self.dbstate.active.handle) self.change_person(self.dbstate.active.handle)
def change_person(self,obj): def change_person(self, obj):
if self.redrawing: if self.redrawing:
return False return False
self.redrawing = True self.redrawing = True
@ -251,11 +252,11 @@ class FamilyView(PageView.PersonNavView):
self.row = 5 self.row = 5
family_handle_list = person.get_parent_family_handle_list() family_handle_list = person.get_parent_family_handle_list()
if family_handle_list: if family_handle_list:
for (family_handle,mrel,frel) in family_handle_list: for (family_handle, mrel, frel) in family_handle_list:
if family_handle: if family_handle:
self.write_parents(family_handle) self.write_parents(family_handle)
else: else:
self.write_label("%s:" % _('Parents'),None,True) self.write_label("%s:" % _('Parents'), None, True)
self.row += 1 self.row += 1
family_handle_list = person.get_family_handle_list() family_handle_list = person.get_family_handle_list()
@ -264,14 +265,14 @@ class FamilyView(PageView.PersonNavView):
if family_handle: if family_handle:
self.write_family(family_handle) self.write_family(family_handle)
else: else:
self.write_label("%s:" % _('Family'),None,False) self.write_label("%s:" % _('Family'), None, False)
self.row += 1 self.row += 1
self.row = 1 self.row = 1
self.write_title(person) self.write_title(person)
# Here it is necessary to beat GTK into submission. For some # Here it is necessary to beat GTK into submission. For some
# bizzare reason, if you have an empty column that is spanned, # bizzare reason, if you have an empty column that is spanned,
# you lose the appropriate FILL handling. So, we need to see if # you lose the appropriate FILL handling. So, we need to see if
# column 3 is unused (usually if there is no siblings or children. # column 3 is unused (usually if there is no siblings or children.
# If so, we need to subtract one index of each x coord > 3. # If so, we need to subtract one index of each x coord > 3.
@ -286,7 +287,7 @@ class FamilyView(PageView.PersonNavView):
else: else:
cols = self.attach.max_x-1 cols = self.attach.max_x-1
self.child = gtk.Table(self.attach.max_y,cols) self.child = gtk.Table(self.attach.max_y, cols)
self.child.set_border_width(12) self.child.set_border_width(12)
self.child.set_col_spacings(12) self.child.set_col_spacings(12)
self.child.set_row_spacings(9) self.child.set_row_spacings(9)
@ -299,31 +300,31 @@ class FamilyView(PageView.PersonNavView):
x0 -= 1 x0 -= 1
if x1 > 4: if x1 > 4:
x1 -= 1 x1 -= 1
self.child.attach(d[0],x0,x1,d[3],d[4],d[5],d[6]) self.child.attach(d[0], x0, x1, d[3], d[4], d[5], d[6])
self.child.show_all() self.child.show_all()
if old_child: if old_child:
self.vbox.remove(old_child) self.vbox.remove(old_child)
self.vbox.pack_start(self.child,False) self.vbox.pack_start(self.child, False)
self.redrawing = False self.redrawing = False
return True return True
def write_title(self,person): def write_title(self, person):
# name and edit button # name and edit button
name = NameDisplay.displayer.display(person) name = NameDisplay.displayer.display(person)
fmt = '<span size="larger" weight="bold">%s %s</span>' fmt = '<span size="larger" weight="bold">%s %s</span>'
text = fmt % (cgi.escape(name),_GenderCode[person.gender]) text = fmt % (cgi.escape(name), _GenderCode[person.gender])
label = GrampsWidgets.MarkupLabel(text) label = GrampsWidgets.MarkupLabel(text)
button = GrampsWidgets.IconButton(self.edit_button_press,person.handle) button = GrampsWidgets.IconButton(self.edit_button_press, person.handle)
hbox = GrampsWidgets.LinkBox(label,button) hbox = GrampsWidgets.LinkBox(label, button)
# GRAMPS ID # GRAMPS ID
self.row = 1 self.row = 1
self.write_person_data("%s:" % _('ID'),person.gramps_id) self.write_person_data("%s:" % _('ID'), person.gramps_id)
# birth/death events # birth/death events
@ -332,20 +333,20 @@ class FamilyView(PageView.PersonNavView):
birth = self.dbstate.db.get_event_from_handle(birth_ref.ref) birth = self.dbstate.db.get_event_from_handle(birth_ref.ref)
else: else:
birth = None birth = None
self.write_person_event("%s:" % _('Birth'),birth) self.write_person_event("%s:" % _('Birth'), birth)
death_ref = person.get_death_ref() death_ref = person.get_death_ref()
if death_ref: if death_ref:
death = self.dbstate.db.get_event_from_handle(death_ref.ref) death = self.dbstate.db.get_event_from_handle(death_ref.ref)
else: else:
death = None death = None
self.write_person_event("%s:" % _('Death'),death) self.write_person_event("%s:" % _('Death'), death)
# separator # separator
end = self.attach.max_x end = self.attach.max_x
sep = gtk.HSeparator() sep = gtk.HSeparator()
sep.show() sep.show()
self.attach.attach(hbox,_NAME_START,end,0,1,gtk.FILL|gtk.EXPAND) self.attach.attach(hbox, _NAME_START, end, 0, 1, gtk.FILL|gtk.EXPAND)
# image # image
image_list = person.get_media_list() image_list = person.get_media_list()
@ -356,10 +357,10 @@ class FamilyView(PageView.PersonNavView):
image = gtk.Image() image = gtk.Image()
image.set_from_pixbuf(pixbuf) image.set_from_pixbuf(pixbuf)
image.show() image.show()
self.attach.attach(image,end,end+1,0,4, self.attach.attach(image, end, end+1, 0, 4,
xoptions=gtk.SHRINK|gtk.FILL) xoptions=gtk.SHRINK|gtk.FILL)
self.attach.attach(sep,0,self.attach.max_x,4,5) self.attach.attach(sep, 0, self.attach.max_x, 4, 5)
def write_person_event(self, ename, event): def write_person_event(self, ename, event):
if event: if event:
@ -372,8 +373,8 @@ class FamilyView(PageView.PersonNavView):
date_str = DateHandler.displayer.display(dobj) date_str = DateHandler.displayer.display(dobj)
value = { value = {
'date' : DateHandler.displayer.display(dobj), 'date' : DateHandler.displayer.display(dobj),
'place' : pname, 'place' : pname,
} }
else: else:
pname = None pname = None
@ -381,37 +382,37 @@ class FamilyView(PageView.PersonNavView):
if dobj: if dobj:
if pname: if pname:
self.write_person_data(ename, self.write_person_data(ename,
_('%(date)s in %(place)s') % value) _('%(date)s in %(place)s') % value)
else: else:
self.write_person_data(ename,'%(date)s' % value) self.write_person_data(ename, '%(date)s' % value)
elif pname: elif pname:
self.write_person_data(ename,pname) self.write_person_data(ename, pname)
else: else:
self.write_person_data(ename,'') self.write_person_data(ename, '')
def write_person_data(self,title,data): def write_person_data(self, title, data):
self.attach.attach(GrampsWidgets.BasicLabel(title),_ALABEL_START, self.attach.attach(GrampsWidgets.BasicLabel(title), _ALABEL_START,
_ALABEL_STOP,self.row,self.row+1, _ALABEL_STOP, self.row, self.row+1,
xoptions=gtk.FILL|gtk.SHRINK) xoptions=gtk.FILL|gtk.SHRINK)
self.attach.attach(GrampsWidgets.BasicLabel(data), self.attach.attach(GrampsWidgets.BasicLabel(data),
_ADATA_START,_ADATA_STOP, _ADATA_START, _ADATA_STOP,
self.row,self.row+1) self.row, self.row+1)
self.row += 1 self.row += 1
def write_label(self,title,family,is_parent): def write_label(self, title, family, is_parent):
msg = "<i><b>%s</b></i>" % cgi.escape(title) msg = "<i><b>%s</b></i>" % cgi.escape(title)
self.attach.attach(GrampsWidgets.MarkupLabel(msg), self.attach.attach(GrampsWidgets.MarkupLabel(msg),
_LABEL_START,_LABEL_STOP, _LABEL_START, _LABEL_STOP,
self.row,self.row+1,gtk.SHRINK|gtk.FILL) self.row, self.row+1, gtk.SHRINK|gtk.FILL)
if family: if family:
value = family.gramps_id value = family.gramps_id
else: else:
value = "" value = ""
self.attach.attach(GrampsWidgets.BasicLabel(value), self.attach.attach(GrampsWidgets.BasicLabel(value),
_DATA_START,_DATA_STOP, _DATA_START, _DATA_STOP,
self.row,self.row+1,gtk.SHRINK|gtk.FILL) self.row, self.row+1, gtk.SHRINK|gtk.FILL)
hbox = gtk.HBox() hbox = gtk.HBox()
hbox.set_spacing(12) hbox.set_spacing(12)
@ -422,42 +423,42 @@ class FamilyView(PageView.PersonNavView):
call_fcn = self.add_family call_fcn = self.add_family
del_fcn = self.delete_family del_fcn = self.delete_family
add = GrampsWidgets.IconButton(call_fcn,None,gtk.STOCK_ADD) add = GrampsWidgets.IconButton(call_fcn, None, gtk.STOCK_ADD)
hbox.pack_start(add,False) hbox.pack_start(add, False)
if is_parent: if is_parent:
add = GrampsWidgets.IconButton(self.select_family,None,gtk.STOCK_INDEX) add = GrampsWidgets.IconButton(self.select_family, None, gtk.STOCK_INDEX)
hbox.pack_start(add,False) hbox.pack_start(add, False)
if family: if family:
edit = GrampsWidgets.IconButton(self.edit_family,family.handle, edit = GrampsWidgets.IconButton(self.edit_family, family.handle,
gtk.STOCK_EDIT) gtk.STOCK_EDIT)
hbox.pack_start(edit,False) hbox.pack_start(edit, False)
delete = GrampsWidgets.IconButton(del_fcn,family.handle, delete = GrampsWidgets.IconButton(del_fcn, family.handle,
gtk.STOCK_REMOVE) gtk.STOCK_REMOVE)
hbox.pack_start(delete,False) hbox.pack_start(delete, False)
self.attach.attach(hbox,_BTN_START,_BTN_STOP,self.row,self.row+1) self.attach.attach(hbox, _BTN_START, _BTN_STOP, self.row, self.row+1)
self.row += 1 self.row += 1
###################################################################### ######################################################################
def write_parents(self,family_handle): def write_parents(self, family_handle):
family = self.dbstate.db.get_family_from_handle(family_handle) family = self.dbstate.db.get_family_from_handle(family_handle)
if not family: if not family:
return return
self.write_label("%s:" % _('Parents'),family,True), self.write_label("%s:" % _('Parents'), family, True),
self.write_person(_('Father'),family.get_father_handle()) self.write_person(_('Father'), family.get_father_handle())
if self.show_details: if self.show_details:
value = self.info_string(family.get_father_handle()) value = self.info_string(family.get_father_handle())
if value: if value:
self.attach.attach(GrampsWidgets.BasicLabel(value),_PDTLS_START, self.attach.attach(GrampsWidgets.BasicLabel(value), _PDTLS_START,
_PDTLS_STOP,self.row, self.row+1) _PDTLS_STOP, self.row, self.row+1)
self.row += 1 self.row += 1
self.write_person(_('Mother'),family.get_mother_handle()) self.write_person(_('Mother'), family.get_mother_handle())
if self.show_details: if self.show_details:
value = self.info_string(family.get_mother_handle()) value = self.info_string(family.get_mother_handle())
if value: if value:
self.attach.attach(GrampsWidgets.BasicLabel(value),_PDTLS_START, self.attach.attach(GrampsWidgets.BasicLabel(value), _PDTLS_START,
_PDTLS_STOP, self.row, self.row+1) _PDTLS_STOP, self.row, self.row+1)
self.row += 1 self.row += 1
@ -469,50 +470,50 @@ class FamilyView(PageView.PersonNavView):
label = _("Siblings") label = _("Siblings")
if child_list: if child_list:
for child in child_list: for child in child_list:
self.write_child(label,child) self.write_child(label, child)
label = u"" label = u""
self.row += 1 self.row += 1
def write_person(self,title,handle): def write_person(self, title, handle):
if title: if title:
format = '<span weight="bold">%s: </span>' format = '<span weight="bold">%s: </span>'
else: else:
format = "%s" format = "%s"
label = GrampsWidgets.MarkupLabel(format % cgi.escape(title)) label = GrampsWidgets.MarkupLabel(format % cgi.escape(title))
self.attach.attach(label,_PLABEL_START,_PLABEL_STOP,self.row, self.attach.attach(label, _PLABEL_START, _PLABEL_STOP, self.row,
self.row+1, xoptions=gtk.FILL|gtk.SHRINK) self.row+1, xoptions=gtk.FILL|gtk.SHRINK)
if handle: if handle:
link_label = GrampsWidgets.LinkLabel(self.get_name(handle,True), link_label = GrampsWidgets.LinkLabel(self.get_name(handle, True),
self.button_press,handle) self.button_press, handle)
button = GrampsWidgets.IconButton(self.edit_button_press,handle) button = GrampsWidgets.IconButton(self.edit_button_press, handle)
self.attach.attach(GrampsWidgets.LinkBox(link_label,button), self.attach.attach(GrampsWidgets.LinkBox(link_label, button),
_PDATA_START,_PDATA_STOP,self.row,self.row+1) _PDATA_START, _PDATA_STOP, self.row, self.row+1)
else: else:
link_label = gtk.Label(_('Unknown')) link_label = gtk.Label(_('Unknown'))
link_label.set_alignment(0,0.5) link_label.set_alignment(0, 0.5)
link_label.show() link_label.show()
self.attach.attach(link_label, self.attach.attach(link_label,
_PDATA_START,_PDATA_STOP,self.row,self.row+1) _PDATA_START, _PDATA_STOP, self.row, self.row+1)
self.row += 1 self.row += 1
def write_child(self,title,handle): def write_child(self, title, handle):
if title: if title:
format = '<span weight="bold">%s: </span>' format = '<span weight="bold">%s: </span>'
else: else:
format = "%s" format = "%s"
label = GrampsWidgets.MarkupLabel(format % cgi.escape(title)) label = GrampsWidgets.MarkupLabel(format % cgi.escape(title))
self.attach.attach(label,_CLABEL_START,_CLABEL_STOP,self.row, self.attach.attach(label, _CLABEL_START, _CLABEL_STOP, self.row,
self.row+1,xoptions=gtk.FILL|gtk.SHRINK) self.row+1, xoptions=gtk.FILL|gtk.SHRINK)
link_label = GrampsWidgets.LinkLabel(self.get_name(handle,True), link_label = GrampsWidgets.LinkLabel(self.get_name(handle, True),
self.button_press,handle) self.button_press, handle)
button = GrampsWidgets.IconButton(self.edit_button_press,handle) button = GrampsWidgets.IconButton(self.edit_button_press, handle)
self.attach.attach(GrampsWidgets.LinkBox(link_label,button), self.attach.attach(GrampsWidgets.LinkBox(link_label, button),
_CDATA_START, _CDATA_STOP, self.row, self.row+1, _CDATA_START, _CDATA_STOP, self.row, self.row+1,
xoptions=gtk.EXPAND|gtk.FILL) xoptions=gtk.EXPAND|gtk.FILL)
self.row += 1 self.row += 1
@ -520,17 +521,17 @@ class FamilyView(PageView.PersonNavView):
if self.show_details: if self.show_details:
value = self.info_string(handle) value = self.info_string(handle)
if value: if value:
self.attach.attach(GrampsWidgets.BasicLabel(value), self.attach.attach(GrampsWidgets.BasicLabel(value),
_CDTLS_START, _CDTLS_STOP, self.row, _CDTLS_START, _CDTLS_STOP, self.row,
self.row+1) self.row+1)
self.row += 1 self.row += 1
def write_data(self,title,start_col=_SDATA_START,stop_col=_SDATA_STOP): def write_data(self, title, start_col=_SDATA_START, stop_col=_SDATA_STOP):
self.attach.attach(GrampsWidgets.BasicLabel(title),start_col,stop_col, self.attach.attach(GrampsWidgets.BasicLabel(title), start_col, stop_col,
self.row, self.row+1, xoptions=gtk.EXPAND|gtk.FILL) self.row, self.row+1, xoptions=gtk.EXPAND|gtk.FILL)
self.row += 1 self.row += 1
def info_string(self,handle): def info_string(self, handle):
child = self.dbstate.db.get_person_from_handle(handle) child = self.dbstate.db.get_person_from_handle(handle)
if not child: if not child:
return None return None
@ -538,22 +539,22 @@ class FamilyView(PageView.PersonNavView):
death_ref = child.get_death_ref() death_ref = child.get_death_ref()
value = None value = None
if birth_ref or death_ref: if birth_ref or death_ref:
info = ReportUtils.get_birth_death_strings(self.dbstate.db,child) info = ReportUtils.get_birth_death_strings(self.dbstate.db, child)
bdate = info[0] bdate = info[0]
ddate = info[4] ddate = info[4]
if bdate and ddate: if bdate and ddate:
value = _("b. %s, d. %s") % (bdate,ddate) value = _("b. %s, d. %s") % (bdate, ddate)
elif bdate: elif bdate:
value = _("b. %s") % (bdate) value = _("b. %s") % (bdate)
elif ddate: elif ddate:
value = _("d. %s") % (ddate) value = _("d. %s") % (ddate)
return value return value
def button_press(self,obj,event,handle): def button_press(self, obj, event, handle):
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1: if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
self.dbstate.change_active_handle(handle) self.dbstate.change_active_handle(handle)
def write_relationship(self,family): def write_relationship(self, family):
rtype = family.get_relationship() rtype = family.get_relationship()
if type(rtype) == tuple: if type(rtype) == tuple:
if rtype[0] == RelLib.Family.CUSTOM: if rtype[0] == RelLib.Family.CUSTOM:
@ -564,22 +565,22 @@ class FamilyView(PageView.PersonNavView):
rel_text = Utils.family_relations[rtype] rel_text = Utils.family_relations[rtype]
self.write_data(_('Relationship type: %s') % rel_text) self.write_data(_('Relationship type: %s') % rel_text)
def place_name(self,handle): def place_name(self, handle):
p = self.dbstate.db.get_place_from_handle(handle) p = self.dbstate.db.get_place_from_handle(handle)
return p.get_title() return p.get_title()
def write_marriage(self,family): def write_marriage(self, family):
value = False value = False
for event_ref in family.get_event_ref_list(): for event_ref in family.get_event_ref_list():
handle = event_ref.ref handle = event_ref.ref
event = self.dbstate.db.get_event_from_handle(handle) event = self.dbstate.db.get_event_from_handle(handle)
etype = event.get_type() etype = event.get_type()
if etype[0] == RelLib.Event.MARRIAGE: if etype[0] == RelLib.Event.MARRIAGE:
self.write_event_ref(_('Marriage'),event) self.write_event_ref(_('Marriage'), event)
value = True value = True
return value return value
def write_event_ref(self, ename, event, start_col=_SDATA_START, def write_event_ref(self, ename, event, start_col=_SDATA_START,
stop_col=_SDATA_STOP): stop_col=_SDATA_STOP):
if event: if event:
dobj = event.get_date_object() dobj = event.get_date_object()
@ -591,9 +592,9 @@ class FamilyView(PageView.PersonNavView):
date_str = DateHandler.displayer.display(dobj) date_str = DateHandler.displayer.display(dobj)
value = { value = {
'date' : DateHandler.displayer.display(dobj), 'date' : DateHandler.displayer.display(dobj),
'place' : pname, 'place' : pname,
'event_type' : ename, 'event_type' : ename,
} }
else: else:
pname = None pname = None
@ -603,18 +604,18 @@ class FamilyView(PageView.PersonNavView):
if dobj: if dobj:
if pname: if pname:
self.write_data(_('%(event_type)s: %(date)s in %(place)s') % self.write_data(_('%(event_type)s: %(date)s in %(place)s') %
value,start_col,stop_col) value, start_col, stop_col)
else: else:
self.write_data(_('%(event_type)s: %(date)s') % value, self.write_data(_('%(event_type)s: %(date)s') % value,
start_col, stop_col) start_col, stop_col)
elif pname: elif pname:
self.write_data(_('%(event_type)s: %(place)s') % value, self.write_data(_('%(event_type)s: %(place)s') % value,
start_col,stop_col) start_col, stop_col)
else: else:
self.write_data(_('%(event_type)s:') % value, self.write_data(_('%(event_type)s:') % value,
start_col, stop_col) start_col, stop_col)
def write_family(self,family_handle): def write_family(self, family_handle):
family = self.dbstate.db.get_family_from_handle(family_handle) family = self.dbstate.db.get_family_from_handle(family_handle)
father_handle = family.get_father_handle() father_handle = family.get_father_handle()
mother_handle = family.get_mother_handle() mother_handle = family.get_mother_handle()
@ -623,14 +624,14 @@ class FamilyView(PageView.PersonNavView):
else: else:
handle = father_handle handle = father_handle
self.write_label("%s:" % _('Family'),family,False) self.write_label("%s:" % _('Family'), family, False)
if handle: if handle:
self.write_person(_('Spouse'),handle) self.write_person(_('Spouse'), handle)
value = self.info_string(handle) value = self.info_string(handle)
if value: if value:
self.attach.attach(GrampsWidgets.BasicLabel(value), self.attach.attach(GrampsWidgets.BasicLabel(value),
_PDTLS_START, _PDTLS_STOP, _PDTLS_START, _PDTLS_STOP,
self.row, self.row+1) self.row, self.row+1)
self.row += 1 self.row += 1
if not self.write_marriage(family): if not self.write_marriage(family):
@ -640,7 +641,7 @@ class FamilyView(PageView.PersonNavView):
label = _("Children") label = _("Children")
if child_list: if child_list:
for child in child_list: for child in child_list:
self.write_child(label,child) self.write_child(label, child)
label = u"" label = u""
self.row += 1 self.row += 1
@ -654,7 +655,7 @@ class FamilyView(PageView.PersonNavView):
except Errors.WindowActiveError: except Errors.WindowActiveError:
pass pass
def edit_person(self,obj,handle): def edit_person(self, obj, handle):
from Editors import EditPerson from Editors import EditPerson
person = self.dbstate.db.get_person_from_handle(handle) person = self.dbstate.db.get_person_from_handle(handle)
try: try:
@ -662,16 +663,16 @@ class FamilyView(PageView.PersonNavView):
except Errors.WindowActiveError: except Errors.WindowActiveError:
pass pass
def edit_family(self,obj,event,handle): def edit_family(self, obj, event, handle):
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1: if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
from Editors import EditFamily from Editors import EditFamily
family = self.dbstate.db.get_family_from_handle(handle) family = self.dbstate.db.get_family_from_handle(handle)
try: try:
EditFamily(self.dbstate,self.uistate,[],family) EditFamily(self.dbstate, self.uistate, [], family)
except Errors.WindowActiveError: except Errors.WindowActiveError:
pass pass
def add_family(self,obj,event,handle): def add_family(self, obj, event, handle):
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1: if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
from Editors import EditFamily from Editors import EditFamily
family = RelLib.Family() family = RelLib.Family()
@ -683,7 +684,7 @@ class FamilyView(PageView.PersonNavView):
family.set_mother_handle(person.handle) family.set_mother_handle(person.handle)
try: try:
EditFamily(self.dbstate,self.uistate,[],family) EditFamily(self.dbstate, self.uistate, [], family)
except Errors.WindowActiveError: except Errors.WindowActiveError:
pass pass
@ -700,16 +701,16 @@ class FamilyView(PageView.PersonNavView):
family.add_child_handle(person.handle) family.add_child_handle(person.handle)
person.add_parent_family_handle( person.add_parent_family_handle(
family.handle, family.handle,
(RelLib.Person.CHILD_BIRTH,''), (RelLib.Person.CHILD_BIRTH, ''),
(RelLib.Person.CHILD_BIRTH,'')) (RelLib.Person.CHILD_BIRTH, ''))
trans = self.dbstate.db.transaction_begin() trans = self.dbstate.db.transaction_begin()
self.dbstate.db.commit_person(person,trans) self.dbstate.db.commit_person(person, trans)
self.dbstate.db.commit_family(family,trans) self.dbstate.db.commit_family(family, trans)
self.dbstate.db.transaction_commit(trans,_("Add Family")) self.dbstate.db.transaction_commit(trans, _("Add Family"))
def add_parent_family(self,obj,event,handle): def add_parent_family(self, obj, event, handle):
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1: if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
from Editors import EditFamily from Editors import EditFamily
family = RelLib.Family() family = RelLib.Family()
@ -718,24 +719,24 @@ class FamilyView(PageView.PersonNavView):
family.add_child_handle(person.handle) family.add_child_handle(person.handle)
try: try:
EditFamily(self.dbstate,self.uistate,[],family) EditFamily(self.dbstate, self.uistate, [], family)
except Errors.WindowActiveError: except Errors.WindowActiveError:
pass pass
def delete_family(self,obj,event,handle): def delete_family(self, obj, event, handle):
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1: if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
import GrampsDb import GrampsDb
GrampsDb.remove_parent_from_family(self.dbstate.db, GrampsDb.remove_parent_from_family(self.dbstate.db,
self.dbstate.active.handle, self.dbstate.active.handle,
handle) handle)
def delete_parent_family(self,obj,event,handle): def delete_parent_family(self, obj, event, handle):
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1: if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
import GrampsDb import GrampsDb
GrampsDb.remove_child_from_family(self.dbstate.db, GrampsDb.remove_child_from_family(self.dbstate.db,
self.dbstate.active.handle, self.dbstate.active.handle,
handle) handle)
def change_to(self,obj,handle): def change_to(self, obj, handle):
self.dbstate.change_active_handle(handle) self.dbstate.change_active_handle(handle)

View File

@ -335,7 +335,8 @@ class FastFemaleFilter:
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
class EditFamily(EditPrimary): class EditFamily(EditPrimary):
def __init__(self,dbstate,uistate,track,family): def __init__(self,dbstate, uistate, track, family):
EditPrimary.__init__(self, dbstate, uistate, track, EditPrimary.__init__(self, dbstate, uistate, track,
family, dbstate.db.get_family_from_handle) family, dbstate.db.get_family_from_handle)
@ -765,7 +766,13 @@ class EditFamily(EditPrimary):
person.family_list.append(self.obj.handle) person.family_list.append(self.obj.handle)
self.db.commit_person(person,trans) self.db.commit_person(person,trans)
def object_is_empty(self):
return self.obj.get_father_handle() == None and \
self.obj.get_mother_handle() == None and \
len(self.obj.get_child_handle_list()) == 0
def save(self,*obj): def save(self,*obj):
if not self.added: if not self.added:
original = self.db.get_family_from_handle(self.obj.handle) original = self.db.get_family_from_handle(self.obj.handle)
else: else:
@ -806,6 +813,10 @@ class EditFamily(EditPrimary):
_("No data exists for this family. Please " _("No data exists for this family. Please "
"enter data or cancel the edit.")) "enter data or cancel the edit."))
return return
elif original and self.object_is_empty():
trans = self.db.transaction_begin()
self.db.remove_family(self.obj.handle,trans)
self.db.transaction_commit(trans,_("Remove Family"))
elif cmp(original.serialize(),self.obj.serialize()): elif cmp(original.serialize(),self.obj.serialize()):
trans = self.db.transaction_begin() trans = self.db.transaction_begin()
@ -838,5 +849,6 @@ class EditFamily(EditPrimary):
else: else:
self.db.commit_family(self.obj,trans) self.db.commit_family(self.obj,trans)
self.db.transaction_commit(trans,_("Edit Family")) self.db.transaction_commit(trans,_("Edit Family"))
self.close_window() self.close_window()

View File

@ -5,21 +5,28 @@
# #
# 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
# the Free Software Foundation; either version 2 of the License,or # the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not,write to the Free Software # along with this program; if not, write to the Free Software
# Foundation,Inc.,59 Temple Place,Suite 330,Boston,MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# #
# $Id$ # $Id$
"""
TreeModel for the GRAMPS Person tree.
"""
__author__ = "Donald N. Allingham"
__revision__ = "$Revision:$"
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# Standard python modules # Standard python modules
@ -77,32 +84,38 @@ _codeset = GrampsLocale.codeset
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
_ID_COL = 1 _ID_COL = 1
_GENDER_COL= 2 _GENDER_COL = 2
_NAME_COL = 3 _NAME_COL = 3
_DEATH_COL = 6 _DEATH_COL = 6
_BIRTH_COL = 7 _BIRTH_COL = 7
_EVENT_COL = 8 _EVENT_COL = 8
_FAMILY_COL= 9 _FAMILY_COL = 9
_CHANGE_COL= 19 _CHANGE_COL = 19
_MARKER_COL= 20 _MARKER_COL = 20
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# python 2.3 has a bug in the unicode sorting using locale.strcoll. Seems # python 2.3 has a bug in the unicode sorting using locale.strcoll. Seems
# to have a buffer overrun. We can convince it to do the right thing by # to have a buffer overrun. We can convince it to do the right thing by
# forcing the string to be nul terminated,sorting,then stripping off the # forcing the string to be nul terminated, sorting, then stripping off the
# nul. # nul.
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
if sys.version_info[0:2] == (2, 3): if sys.version_info[0:2] == (2, 3):
def locale_sort(mylist): def locale_sort(mylist):
mylist = map(lambda x: x + "\x00",mylist) """
Sort version to get around a python2.3 bug with unicode strings
"""
mylist = [ value + "\x00" for value in mylist ]
mylist.sort(locale.strcoll) mylist.sort(locale.strcoll)
return map(lambda x: x[:-1],mylist) return [ value[:-1] for value in mylist ]
else: else:
def locale_sort(mylist): def locale_sort(mylist):
"""
Normal sort routine
"""
mylist.sort(locale.strcoll) mylist.sort(locale.strcoll)
return mylist return mylist
@ -112,8 +125,15 @@ else:
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
class PeopleModel(gtk.GenericTreeModel): class PeopleModel(gtk.GenericTreeModel):
"""
Basic GenericTreeModel interface to handle the Tree interface for
the PersonView
"""
def __init__(self, db, data_filter=None, invert_result=False, skip=[]): def __init__(self, db, data_filter=None, invert_result=False, skip=[]):
"""
Initialize the model building the initial data
"""
gtk.GenericTreeModel.__init__(self) gtk.GenericTreeModel.__init__(self)
self.db = db self.db = db
@ -128,10 +148,16 @@ class PeopleModel(gtk.GenericTreeModel):
self.rebuild_data(data_filter, skip) self.rebuild_data(data_filter, skip)
def rebuild_data(self, data_filter=None, skip=[]): def rebuild_data(self, data_filter=None, skip=[]):
"""
Convience function that calculates the new data and assigns it.
"""
self.calculate_data(data_filter, skip) self.calculate_data(data_filter, skip)
self.assign_data() self.assign_data()
def calculate_data(self, dfilter=None, skip=[]): def calculate_data(self, dfilter=None, skip=[]):
"""
Calculates the new path to node values for the model.
"""
if dfilter: if dfilter:
self.dfilter = dfilter self.dfilter = dfilter
self.temp_iter2path = {} self.temp_iter2path = {}
@ -194,7 +220,7 @@ class PeopleModel(gtk.GenericTreeModel):
def on_get_n_columns(self): def on_get_n_columns(self):
return len(COLUMN_DEFS) return len(COLUMN_DEFS)
def on_get_path(self,node): def on_get_path(self, node):
'''returns the tree path (a tuple of indices at the various '''returns the tree path (a tuple of indices at the various
levels) for a particular node.''' levels) for a particular node.'''
try: try:
@ -209,7 +235,7 @@ class PeopleModel(gtk.GenericTreeModel):
def on_get_column_type(self, index): def on_get_column_type(self, index):
return COLUMN_DEFS[index][COLUMN_DEF_TYPE] return COLUMN_DEFS[index][COLUMN_DEF_TYPE]
def on_get_iter(self,path): def on_get_iter(self, path):
try: try:
if len(path)==1: # Top Level if len(path)==1: # Top Level
return self.top_path2iter[path[0]] return self.top_path2iter[path[0]]
@ -223,23 +249,23 @@ class PeopleModel(gtk.GenericTreeModel):
# test for header or data row-type # test for header or data row-type
if self.sname_sub.has_key(node): if self.sname_sub.has_key(node):
# Header rows dont get the background color set # Header rows dont get the background color set
if col==self.marker_color_column: if col == self.marker_color_column:
return None return None
# test for 'header' column being empty (most are) # test for 'header' column being empty (most are)
if not COLUMN_DEFS[col][COLUMN_DEF_HEADER]: if not COLUMN_DEFS[col][COLUMN_DEF_HEADER]:
return u'' return u''
# return values for 'header' row,calling a function # return values for 'header' row, calling a function
# according to column_defs table # according to column_defs table
val = COLUMN_DEFS[col][COLUMN_DEF_HEADER](self, node) val = COLUMN_DEFS[col][COLUMN_DEF_HEADER](self, node)
return val return val
else: else:
# return values for 'data' row,calling a function # return values for 'data' row, calling a function
# according to column_defs table # according to column_defs table
try: try:
if node != self.prev_handle: if node != self.prev_handle:
self.prev_data = self.db.get_raw_person_data(str(node)) self.prev_data = self.db.get_raw_person_data(str(node))
self.prev_handle = node self.prev_handle = node
return COLUMN_DEFS[col][COLUMN_DEF_LIST](self, return COLUMN_DEFS[col][COLUMN_DEF_LIST](self,
self.prev_data, node) self.prev_data, node)
except: except:
if col == _MARKER_COL: if col == _MARKER_COL:
@ -247,7 +273,7 @@ class PeopleModel(gtk.GenericTreeModel):
else: else:
return u'error' return u'error'
def on_iter_next(self,node): def on_iter_next(self, node):
'''returns the next node at this level of the tree''' '''returns the next node at this level of the tree'''
try: try:
path = self.top_path2iter.index(node) path = self.top_path2iter.index(node)
@ -265,7 +291,7 @@ class PeopleModel(gtk.GenericTreeModel):
else: else:
return self.path2iter.get((node, 0)) return self.path2iter.get((node, 0))
def on_iter_has_child(self,node): def on_iter_has_child(self, node):
'''returns true if this node has children''' '''returns true if this node has children'''
if node == None: if node == None:
return len(self.sname_sub) return len(self.sname_sub)
@ -292,7 +318,7 @@ class PeopleModel(gtk.GenericTreeModel):
except IndexError: except IndexError:
return None return None
def on_iter_parent(self,node): def on_iter_parent(self, node):
'''returns the parent of this node''' '''returns the parent of this node'''
path = self.iter2path.get(node) path = self.iter2path.get(node)
if path: if path:
@ -309,7 +335,7 @@ class PeopleModel(gtk.GenericTreeModel):
handle = data[0] handle = data[0]
for family_handle in data[_FAMILY_COL]: for family_handle in data[_FAMILY_COL]:
family = self.db.get_family_from_handle(family_handle) family = self.db.get_family_from_handle(family_handle)
for spouse_id in [family.get_father_handle(), for spouse_id in [family.get_father_handle(),
family.get_mother_handle()]: family.get_mother_handle()]:
if not spouse_id: if not spouse_id:
continue continue
@ -317,7 +343,7 @@ class PeopleModel(gtk.GenericTreeModel):
continue continue
spouse = self.db.get_person_from_handle(spouse_id) spouse = self.db.get_person_from_handle(spouse_id)
if len(spouses_names) > 0: if len(spouses_names) > 0:
spouses_names += "," spouses_names += ", "
spouses_names += NameDisplay.displayer.display(spouse) spouses_names += NameDisplay.displayer.display(spouse)
return spouses_names return spouses_names
@ -330,15 +356,16 @@ class PeopleModel(gtk.GenericTreeModel):
return data[_ID_COL] return data[_ID_COL]
def column_change(self, data, node): def column_change(self, data, node):
return unicode(time.strftime('%x %X', time.localtime(data[_CHANGE_COL])), return unicode(
_codeset) time.strftime('%x %X', time.localtime(data[_CHANGE_COL])),
_codeset)
def column_gender(self, data, node): def column_gender(self, data, node):
return _GENDER[data[_GENDER_COL]] return _GENDER[data[_GENDER_COL]]
def column_birth_day(self, data, node): def column_birth_day(self, data, node):
if data[_BIRTH_COL]: if data[_BIRTH_COL]:
b=EventRef() b = EventRef()
b.unserialize(data[_BIRTH_COL]) b.unserialize(data[_BIRTH_COL])
birth = self.db.get_event_from_handle(b.ref) birth = self.db.get_event_from_handle(b.ref)
date_str = DateHandler.get_date(birth) date_str = DateHandler.get_date(birth)
@ -351,7 +378,7 @@ class PeopleModel(gtk.GenericTreeModel):
event = self.db.get_event_from_handle(er.ref) event = self.db.get_event_from_handle(er.ref)
etype = event.get_type()[0] etype = event.get_type()[0]
date_str = DateHandler.get_date(event) date_str = DateHandler.get_date(event)
if (etype in [Event.BAPTISM,Event.CHRISTEN] if (etype in [Event.BAPTISM, Event.CHRISTEN]
and date_str != ""): and date_str != ""):
return "<i>" + cgi.escape(date_str) + "</i>" return "<i>" + cgi.escape(date_str) + "</i>"
@ -372,7 +399,7 @@ class PeopleModel(gtk.GenericTreeModel):
event = self.db.get_event_from_handle(er.ref) event = self.db.get_event_from_handle(er.ref)
etype = event.get_type()[0] etype = event.get_type()[0]
date_str = DateHandler.get_date(event) date_str = DateHandler.get_date(event)
if (etype in [Event.BURIAL,Event.CREMATION] if (etype in [Event.BURIAL, Event.CREMATION]
and date_str != ""): and date_str != ""):
return "<i>" + cgi.escape(date_str) + "</i>" return "<i>" + cgi.escape(date_str) + "</i>"
@ -404,7 +431,7 @@ class PeopleModel(gtk.GenericTreeModel):
er.unserialize(event_ref) er.unserialize(event_ref)
event = self.db.get_event_from_handle(er.ref) event = self.db.get_event_from_handle(er.ref)
etype = event.get_type()[0] etype = event.get_type()[0]
if etype in [Event.BAPTISM,Event.CHRISTEN]: if etype in [Event.BAPTISM, Event.CHRISTEN]:
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)
@ -422,7 +449,8 @@ class PeopleModel(gtk.GenericTreeModel):
if event: if event:
place_handle = event.get_place_handle() place_handle = event.get_place_handle()
if place_handle: if place_handle:
place_title = self.db.get_place_from_handle(place_handle).get_title() place = self.db.get_place_from_handle(place_handle)
place_title = place.get_title()
if place_title != "": if place_title != "":
return cgi.escape(place_title) return cgi.escape(place_title)
@ -431,10 +459,11 @@ class PeopleModel(gtk.GenericTreeModel):
er.unserialize(event_ref) er.unserialize(event_ref)
event = self.db.get_event_from_handle(er.ref) event = self.db.get_event_from_handle(er.ref)
etype = event.get_type()[0] etype = event.get_type()[0]
if etype in [Event.BURIAL,Event.CREMATION]: if etype in [Event.BURIAL, Event.CREMATION]:
place_handle = event.get_place_handle() place_handle = event.get_place_handle()
if place_handle: if place_handle:
place_title = self.db.get_place_from_handle(place_handle).get_title() place = self.db.get_place_from_handle(place_handle)
place_title = place.get_title()
if place_title != "": if place_title != "":
return "<i>" + cgi.escape(place_title) + "</i>" return "<i>" + cgi.escape(place_title) + "</i>"
@ -466,7 +495,10 @@ class PeopleModel(gtk.GenericTreeModel):
def column_tooltip(self, data, node): def column_tooltip(self, data, node):
if const.use_tips: if const.use_tips:
return ToolTips.TipFromFunction(self.db,lambda: self.db.get_person_from_handle(data[0])) return ToolTips.TipFromFunction(
self.db,
lambda: self.db.get_person_from_handle(data[0])
)
else: else:
return u'' return u''
@ -480,32 +512,32 @@ class PeopleModel(gtk.GenericTreeModel):
def column_header_view(self, node): def column_header_view(self, node):
return True return True
_GENDER = [ _(u'female'),_(u'male'),_(u'unknown') ] _GENDER = [ _(u'female'), _(u'male'), _(u'unknown') ]
# table of column definitions # table of column definitions
# (unless this is declared after the PeopleModel class,an error is thrown) # (unless this is declared after the PeopleModel class, an error is thrown)
COLUMN_DEFS = [ COLUMN_DEFS = [
# data column (method) header column (method) column data type (PeopleModel.column_name, PeopleModel.column_header, str),
(PeopleModel.column_name, PeopleModel.column_header, str), (PeopleModel.column_id, None, str),
(PeopleModel.column_id, None, str), (PeopleModel.column_gender, None, str),
(PeopleModel.column_gender, None, str), (PeopleModel.column_birth_day, None, str),
(PeopleModel.column_birth_day, None, str), (PeopleModel.column_birth_place, None, str),
(PeopleModel.column_birth_place, None, str), (PeopleModel.column_death_day, None, str),
(PeopleModel.column_death_day, None, str), (PeopleModel.column_death_place, None, str),
(PeopleModel.column_death_place, None, str), (PeopleModel.column_spouse, None, str),
(PeopleModel.column_spouse, None, str), (PeopleModel.column_change, None, str),
(PeopleModel.column_change, None, str), (PeopleModel.column_cause_of_death, None, str),
(PeopleModel.column_cause_of_death, None, str), (PeopleModel.column_marker_text, None, str),
(PeopleModel.column_marker_text, None, str), (PeopleModel.column_marker_color, None, str),
(PeopleModel.column_marker_color, None, str),
# the order of the above columns must match PeopleView.column_names # the order of the above columns must match PeopleView.column_names
# these columns are hidden,and must always be last in the list # these columns are hidden, and must always be last in the list
(PeopleModel.column_tooltip, None, object), (PeopleModel.column_tooltip, None, object),
(PeopleModel.column_int_id, None, str), (PeopleModel.column_int_id, None, str),
] ]
# dynamic calculation of column indices,for use by various Views # dynamic calculation of column indices, for use by various Views
COLUMN_INT_ID = 13 COLUMN_INT_ID = 13
# indices into main column definition table # indices into main column definition table

View File

@ -8,7 +8,7 @@
# the Free Software Foundation; either version 2 of the License, or # the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
@ -23,7 +23,7 @@
"Support for dates" "Support for dates"
__author__ = "Donald N. Allingham" __author__ = "Donald N. Allingham"
__version__ = "$Revision$" __revision__ = "$Revision$"
from gettext import gettext as _ from gettext import gettext as _
from _CalSdn import * from _CalSdn import *
@ -35,7 +35,7 @@ from _CalSdn import *
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
class DateError(Exception): class DateError(Exception):
"""Error used to report Date errors""" """Error used to report Date errors"""
def __init__(self,value=""): def __init__(self, value=""):
Exception.__init__(self) Exception.__init__(self)
self.value = value self.value = value
@ -49,7 +49,7 @@ class DateError(Exception):
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
class Date: class Date:
""" """
The core date handling class for GRAMPs. Supports partial dates, The core date handling class for GRAMPs. Supports partial dates,
compound dates and alternate calendars. compound dates and alternate calendars.
""" """
@ -61,9 +61,9 @@ class Date:
MOD_SPAN = 5 MOD_SPAN = 5
MOD_TEXTONLY = 6 MOD_TEXTONLY = 6
QUAL_NONE = 0 QUAL_NONE = 0
QUAL_ESTIMATED = 1 QUAL_ESTIMATED = 1
QUAL_CALCULATED= 2 QUAL_CALCULATED = 2
CAL_GREGORIAN = 0 CAL_GREGORIAN = 0
CAL_JULIAN = 1 CAL_JULIAN = 1
@ -72,7 +72,7 @@ class Date:
CAL_PERSIAN = 4 CAL_PERSIAN = 4
CAL_ISLAMIC = 5 CAL_ISLAMIC = 5
EMPTY = (0,0,0,False) EMPTY = (0, 0, 0, False)
_POS_DAY = 0 _POS_DAY = 0
_POS_MON = 1 _POS_MON = 1
@ -84,39 +84,39 @@ class Date:
_POS_RSL = 7 _POS_RSL = 7
_calendar_convert = [ _calendar_convert = [
gregorian_sdn, gregorian_sdn,
julian_sdn, julian_sdn,
hebrew_sdn, hebrew_sdn,
french_sdn, french_sdn,
persian_sdn, persian_sdn,
islamic_sdn, islamic_sdn,
] ]
_calendar_change = [ _calendar_change = [
gregorian_ymd, gregorian_ymd,
julian_ymd, julian_ymd,
hebrew_ymd, hebrew_ymd,
french_ymd, french_ymd,
persian_ymd, persian_ymd,
islamic_ymd, islamic_ymd,
] ]
calendar_names = ["Gregorian", calendar_names = ["Gregorian",
"Julian", "Julian",
"Hebrew", "Hebrew",
"French Republican", "French Republican",
"Persian", "Persian",
"Islamic"] "Islamic"]
ui_calendar_names = [_("Gregorian"), ui_calendar_names = [_("Gregorian"),
_("Julian"), _("Julian"),
_("Hebrew"), _("Hebrew"),
_("French Republican"), _("French Republican"),
_("Persian"), _("Persian"),
_("Islamic")] _("Islamic")]
def __init__(self,source=None): def __init__(self, source=None):
""" """
Creates a new Date instance. Creates a new Date instance.
""" """
@ -136,15 +136,21 @@ class Date:
self.sortval = 0 self.sortval = 0
def serialize(self): def serialize(self):
return (self.calendar,self.modifier,self.quality, """
self.dateval,self.text,self.sortval) Convert to a series of tuples for data storage
"""
return (self.calendar, self.modifier, self.quality,
self.dateval, self.text, self.sortval)
def unserialize(self,data): def unserialize(self, data):
(self.calendar,self.modifier,self.quality, """
self.dateval,self.text,self.sortval) = data Load from the format created by serialize
"""
(self.calendar, self.modifier, self.quality,
self.dateval, self.text, self.sortval) = data
return self return self
def copy(self,source): def copy(self, source):
""" """
Copy all the attributes of the given Date instance Copy all the attributes of the given Date instance
to the present instance, without creating a new object. to the present instance, without creating a new object.
@ -156,17 +162,17 @@ class Date:
self.text = source.text self.text = source.text
self.sortval = source.sortval self.sortval = source.sortval
def __cmp__(self,other): def __cmp__(self, other):
""" """
Comparison function. Allows the usage of equality tests. Comparison function. Allows the usage of equality tests.
This allows you do run statements like 'date1 <= date2' This allows you do run statements like 'date1 <= date2'
""" """
if isinstance(other,Date): if isinstance(other, Date):
return cmp(self.sortval,other.sortval) return cmp(self.sortval, other.sortval)
else: else:
return -1 return -1
def is_equal(self,other): def is_equal(self, other):
""" """
Return 1 if the given Date instance is the same as the present Return 1 if the given Date instance is the same as the present
instance IN ALL REGARDS. Needed, because the __cmp__ only looks instance IN ALL REGARDS. Needed, because the __cmp__ only looks
@ -216,14 +222,14 @@ class Date:
val = self.text val = self.text
elif self.modifier == Date.MOD_RANGE or self.modifier == Date.MOD_SPAN: elif self.modifier == Date.MOD_RANGE or self.modifier == Date.MOD_SPAN:
val = "%04d-%02d-%02d - %04d-%02d-%02d" % ( val = "%04d-%02d-%02d - %04d-%02d-%02d" % (
self.dateval[Date._POS_YR],self.dateval[Date._POS_MON], self.dateval[Date._POS_YR], self.dateval[Date._POS_MON],
self.dateval[Date._POS_DAY],self.dateval[Date._POS_RYR], self.dateval[Date._POS_DAY], self.dateval[Date._POS_RYR],
self.dateval[Date._POS_RMON],self.dateval[Date._POS_RDAY]) self.dateval[Date._POS_RMON], self.dateval[Date._POS_RDAY])
else: else:
val = "%04d-%02d-%02d" % ( val = "%04d-%02d-%02d" % (
self.dateval[Date._POS_YR],self.dateval[Date._POS_MON], self.dateval[Date._POS_YR], self.dateval[Date._POS_MON],
self.dateval[Date._POS_DAY]) self.dateval[Date._POS_DAY])
return "%s%s%s%s" % (qual,pref,val,cal) return "%s%s%s%s" % (qual, pref, val, cal)
def get_sort_value(self): def get_sort_value(self):
""" """
@ -251,12 +257,12 @@ class Date:
""" """
return self.modifier return self.modifier
def set_modifier(self,val): def set_modifier(self, val):
""" """
Sets the modifier for the date. Sets the modifier for the date.
""" """
if val not in (Date.MOD_NONE,Date.MOD_BEFORE,Date.MOD_AFTER, if val not in (Date.MOD_NONE, Date.MOD_BEFORE, Date.MOD_AFTER,
Date.MOD_ABOUT,Date.MOD_RANGE,Date.MOD_SPAN, Date.MOD_ABOUT, Date.MOD_RANGE, Date.MOD_SPAN,
Date.MOD_TEXTONLY): Date.MOD_TEXTONLY):
raise DateError("Invalid modifier") raise DateError("Invalid modifier")
self.modifier = val self.modifier = val
@ -272,11 +278,11 @@ class Date:
""" """
return self.quality return self.quality
def set_quality(self,val): def set_quality(self, val):
""" """
Sets the quality selected for the date. Sets the quality selected for the date.
""" """
if val not in (Date.QUAL_NONE,Date.QUAL_ESTIMATED, if val not in (Date.QUAL_NONE, Date.QUAL_ESTIMATED,
Date.QUAL_CALCULATED): Date.QUAL_CALCULATED):
raise DateError("Invalid quality") raise DateError("Invalid quality")
self.quality = val self.quality = val
@ -295,12 +301,12 @@ class Date:
""" """
return self.calendar return self.calendar
def set_calendar(self,val): def set_calendar(self, val):
""" """
Sets the calendar selected for the date. Sets the calendar selected for the date.
""" """
if val not in (Date.CAL_GREGORIAN,Date.CAL_JULIAN,Date.CAL_HEBREW, if val not in (Date.CAL_GREGORIAN, Date.CAL_JULIAN, Date.CAL_HEBREW,
Date.CAL_FRENCH,Date.CAL_PERSIAN,Date.CAL_ISLAMIC): Date.CAL_FRENCH, Date.CAL_PERSIAN, Date.CAL_ISLAMIC):
raise DateError("Invalid calendar") raise DateError("Invalid calendar")
self.calendar = val self.calendar = val
@ -309,7 +315,7 @@ class Date:
Returns a tuple representing the start date. If the date is a Returns a tuple representing the start date. If the date is a
compound date (range or a span), it is the first part of the compound date (range or a span), it is the first part of the
compound date. If the date is a text string, a tuple of compound date. If the date is a text string, a tuple of
(0,0,0,False) is returned. Otherwise, a date of (DD,MM,YY,slash) (0, 0, 0, False) is returned. Otherwise, a date of (DD, MM, YY, slash)
is returned. If slash is True, then the date is in the form of 1530/1. is returned. If slash is True, then the date is in the form of 1530/1.
""" """
if self.modifier == Date.MOD_TEXTONLY: if self.modifier == Date.MOD_TEXTONLY:
@ -322,7 +328,7 @@ class Date:
""" """
Returns a tuple representing the second half of a compound date. Returns a tuple representing the second half of a compound date.
If the date is not a compound date, (including text strings) a tuple If the date is not a compound date, (including text strings) a tuple
of (0,0,0,False) is returned. Otherwise, a date of (DD,MM,YY,slash) of (0, 0, 0, False) is returned. Otherwise, a date of (DD, MM, YY, slash)
is returned. If slash is True, then the date is in the form of 1530/1. is returned. If slash is True, then the date is in the form of 1530/1.
""" """
if self.modifier == Date.MOD_RANGE or self.modifier == Date.MOD_SPAN: if self.modifier == Date.MOD_RANGE or self.modifier == Date.MOD_SPAN:
@ -331,21 +337,30 @@ class Date:
val = Date.EMPTY val = Date.EMPTY
return val return val
def _get_low_item(self,index): def _get_low_item(self, index):
"""
Returns the item specified
"""
if self.modifier == Date.MOD_TEXTONLY: if self.modifier == Date.MOD_TEXTONLY:
val = 0 val = 0
else: else:
val = self.dateval[index] val = self.dateval[index]
return val return val
def _get_low_item_valid(self,index): def _get_low_item_valid(self, index):
"""
Determines if the item specified is valid
"""
if self.modifier == Date.MOD_TEXTONLY: if self.modifier == Date.MOD_TEXTONLY:
val = False val = False
else: else:
val = self.dateval[index] != 0 val = self.dateval[index] != 0
return val return val
def _get_high_item(self,index): def _get_high_item(self, index):
"""
Returns the item specified
"""
if self.modifier == Date.MOD_SPAN or self.modifier == Date.MOD_RANGE: if self.modifier == Date.MOD_SPAN or self.modifier == Date.MOD_RANGE:
val = self.dateval[index] val = self.dateval[index]
else: else:
@ -360,13 +375,17 @@ class Date:
""" """
return self._get_low_item(Date._POS_YR) return self._get_low_item(Date._POS_YR)
def set_year(self,year): def set_year(self, year):
""" """
Sets the year value
""" """
self.dateval = self.dateval[0:2] + (year,) + self.dateval[3:] self.dateval = self.dateval[0:2] + (year, ) + self.dateval[3:]
self.calc_sort_value() self._calc_sort_value()
def get_year_valid(self): def get_year_valid(self):
"""
Returns true if the year is valid
"""
return self._get_low_item_valid(Date._POS_YR) return self._get_low_item_valid(Date._POS_YR)
def get_month(self): def get_month(self):
@ -378,6 +397,9 @@ class Date:
return self._get_low_item(Date._POS_MON) return self._get_low_item(Date._POS_MON)
def get_month_valid(self): def get_month_valid(self):
"""
Returns true if the month is valid
"""
return self._get_low_item_valid(Date._POS_MON) return self._get_low_item_valid(Date._POS_MON)
def get_day(self): def get_day(self):
@ -389,15 +411,15 @@ class Date:
return self._get_low_item(Date._POS_DAY) return self._get_low_item(Date._POS_DAY)
def get_day_valid(self): def get_day_valid(self):
"""
Returns true if the day is valid
"""
return self._get_low_item_valid(Date._POS_DAY) return self._get_low_item_valid(Date._POS_DAY)
def get_valid(self): def get_valid(self):
""" Returns true if any part of the date is valid""" """ Returns true if any part of the date is valid"""
return self.modifier != Date.MOD_TEXTONLY return self.modifier != Date.MOD_TEXTONLY
def get_incomplete(self):
pass
def get_stop_year(self): def get_stop_year(self):
""" """
Returns the day of the year associated with the second Returns the day of the year associated with the second
@ -441,7 +463,7 @@ class Date:
""" """
return self.text return self.text
def set(self,quality,modifier,calendar,value,text=None): def set(self, quality, modifier, calendar, value, text=None):
""" """
Sets the date to the specified value. Parameters are:: Sets the date to the specified value. Parameters are::
@ -452,76 +474,82 @@ class Date:
calendar - The calendar associated with the date (see calendar - The calendar associated with the date (see
get_calendar for more information). get_calendar for more information).
value - A tuple representing the date information. For a value - A tuple representing the date information. For a
non-compound date, the format is (DD,MM,YY,slash) non-compound date, the format is (DD, MM, YY, slash)
and for a compound date the tuple stores data as and for a compound date the tuple stores data as
(DD,MM,YY,slash1,DD,MM,YY,slash2) (DD, MM, YY, slash1, DD, MM, YY, slash2)
text - A text string holding either the verbatim user input text - A text string holding either the verbatim user input
or a comment relating to the date. or a comment relating to the date.
The sort value is recalculated. The sort value is recalculated.
""" """
if modifier in (Date.MOD_NONE,Date.MOD_BEFORE, if modifier in (Date.MOD_NONE, Date.MOD_BEFORE,
Date.MOD_AFTER,Date.MOD_ABOUT) and len(value) < 4: Date.MOD_AFTER, Date.MOD_ABOUT) and len(value) < 4:
raise DateError("Invalid value. Should be: (DD,MM,YY,slash)") raise DateError("Invalid value. Should be: (DD, MM, YY, slash)")
if modifier in (Date.MOD_RANGE,Date.MOD_SPAN) and len(value) < 8: if modifier in (Date.MOD_RANGE, Date.MOD_SPAN) and len(value) < 8:
raise DateError( raise DateError("Invalid value. Should be: (DD, MM, "
"Invalid value. Should be: (DD,MM,YY,slash1,DD,MM,YY,slash2)") "YY, slash1, DD, MM, YY, slash2)")
if modifier not in (Date.MOD_NONE,Date.MOD_BEFORE,Date.MOD_AFTER, if modifier not in (Date.MOD_NONE, Date.MOD_BEFORE, Date.MOD_AFTER,
Date.MOD_ABOUT,Date.MOD_RANGE,Date.MOD_SPAN, Date.MOD_ABOUT, Date.MOD_RANGE, Date.MOD_SPAN,
Date.MOD_TEXTONLY): Date.MOD_TEXTONLY):
raise DateError("Invalid modifier") raise DateError("Invalid modifier")
if quality not in (Date.QUAL_NONE,Date.QUAL_ESTIMATED, if quality not in (Date.QUAL_NONE, Date.QUAL_ESTIMATED,
Date.QUAL_CALCULATED): Date.QUAL_CALCULATED):
raise DateError("Invalid quality") raise DateError("Invalid quality")
if calendar not in (Date.CAL_GREGORIAN,Date.CAL_JULIAN,Date.CAL_HEBREW, if calendar not in (Date.CAL_GREGORIAN, Date.CAL_JULIAN,
Date.CAL_FRENCH,Date.CAL_PERSIAN,Date.CAL_ISLAMIC): Date.CAL_HEBREW, Date.CAL_FRENCH,
Date.CAL_PERSIAN, Date.CAL_ISLAMIC):
raise DateError("Invalid calendar") raise DateError("Invalid calendar")
self.quality = quality self.quality = quality
self.modifier = modifier self.modifier = modifier
self.calendar = calendar self.calendar = calendar
self.dateval = value self.dateval = value
year = max(value[Date._POS_YR],1) year = max(value[Date._POS_YR], 1)
month = max(value[Date._POS_MON],1) month = max(value[Date._POS_MON], 1)
day = max(value[Date._POS_DAY],1) day = max(value[Date._POS_DAY], 1)
if year == 0 and month == 0 and day == 0: if year == 0 and month == 0 and day == 0:
self.sortval = 0 self.sortval = 0
else: else:
self.sortval = Date._calendar_convert[calendar](year,month,day) func = Date._calendar_convert[calendar]
self.sortval = func(year, month, day)
if text: if text:
self.text = text self.text = text
def calc_sort_value(self): def _calc_sort_value(self):
year = max(self.dateval[Date._POS_YR],1) """
month = max(self.dateval[Date._POS_MON],1) Calculates the numerical sort value associated with the date
day = max(self.dateval[Date._POS_DAY],1) """
year = max(self.dateval[Date._POS_YR], 1)
month = max(self.dateval[Date._POS_MON], 1)
day = max(self.dateval[Date._POS_DAY], 1)
if year == 0 and month == 0 and day == 0: if year == 0 and month == 0 and day == 0:
self.sortval = 0 self.sortval = 0
else: else:
self.sortval = Date._calendar_convert[self.calendar](year,month,day) func = Date._calendar_convert[self.calendar]
self.sortval = func(year, month, day)
def convert_calendar(self,calendar): def convert_calendar(self, calendar):
""" """
Converts the date from the current calendar to the specified Converts the date from the current calendar to the specified
calendar. calendar.
""" """
if calendar == self.calendar: if calendar == self.calendar:
return return
(y,m,d) = Date._calendar_change[calendar](self.sortval) (year, month, day) = Date._calendar_change[calendar](self.sortval)
if self.is_compound(): if self.is_compound():
ry = max(self.dateval[Date._POS_RYR],1) ryear = max(self.dateval[Date._POS_RYR], 1)
rm = max(self.dateval[Date._POS_RMON],1) rmonth = max(self.dateval[Date._POS_RMON], 1)
rd = max(self.dateval[Date._POS_RDAY],1) rday = max(self.dateval[Date._POS_RDAY], 1)
sdn = Date._calendar_convert[self.calendar](ry,rm,rd) sdn = Date._calendar_convert[self.calendar](ryear, rmonth, rday)
(ny,nm,nd) = Date._calendar_change[calendar](sdn) (nyear, nmonth, nday) = Date._calendar_change[calendar](sdn)
self.dateval = (d,m,y,self.dateval[Date._POS_SL], self.dateval = (day, month, year, self.dateval[Date._POS_SL],
nd,nm,ny,self.dateval[Date._POS_RSL]) nday, nmonth, nyear, self.dateval[Date._POS_RSL])
else: else:
self.dateval = (d,m,y,self.dateval[Date._POS_SL]) self.dateval = (day, month, year, self.dateval[Date._POS_SL])
self.calendar = calendar self.calendar = calendar
def set_as_text(self,text): def set_as_text(self, text):
""" """
Sets the day to a text string, and assigns the sort value Sets the day to a text string, and assigns the sort value
to zero. to zero.
@ -530,7 +558,7 @@ class Date:
self.text = text self.text = text
self.sortval = 0 self.sortval = 0
def set_text_value(self,text): def set_text_value(self, text):
""" """
Sets the text string to a given text. Sets the text string to a given text.
""" """

File diff suppressed because it is too large Load Diff