diff --git a/src/config.py b/src/config.py index a431490fe..fa81035fc 100644 --- a/src/config.py +++ b/src/config.py @@ -204,14 +204,10 @@ register('interface.patro-title', 0) register('interface.pedview-layout', 0) register('interface.pedview-show-images', True) register('interface.pedview-show-marriage', False) -register('interface.pedview-tree-size', 0) -register('interface.pedviewext-layout', 0) -register('interface.pedviewext-show-images', True) -register('interface.pedviewext-show-marriage', False) -register('interface.pedviewext-tree-size', 5) -register('interface.pedviewext-tree-direction', 2) -register('interface.pedviewext-scroll-direction', False) -register('interface.pedviewext-show-unknown-peoples', False) +register('interface.pedview-tree-size', 5) +register('interface.pedview-tree-direction', 2) +register('interface.pedview-scroll-direction', False) +register('interface.pedview-show-unknown-people', False) register('interface.person-height', 550) register('interface.person-ref-height', 350) register('interface.person-ref-width', 600) diff --git a/src/plugins/view/Makefile.am b/src/plugins/view/Makefile.am index 471d9f28c..bed3cf7a7 100644 --- a/src/plugins/view/Makefile.am +++ b/src/plugins/view/Makefile.am @@ -17,8 +17,6 @@ pkgdata_PYTHON = \ mediaview.py \ noteview.py \ pedigreeview.py \ - pedigreeviewext.py \ - pedigreeviewext.gpr.py \ personlistview.py \ persontreeview.py \ placelistview.py \ diff --git a/src/plugins/view/pedigreeview.py b/src/plugins/view/pedigreeview.py index 10d5b1584..bafb1b14c 100644 --- a/src/plugins/view/pedigreeview.py +++ b/src/plugins/view/pedigreeview.py @@ -4,6 +4,8 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2001-2007 Donald N. Allingham, Martin Hawlisch +# Copyright (C) 2009 Yevgeny Zegzda +# Copyright (C) 2010 Nick Hall # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -52,20 +54,20 @@ except: #------------------------------------------------------------------------- import gen.lib from gui.views.navigationview import NavigationView +from gui.filtereditor import FilterEditor from gen.display.name import displayer as name_displayer from Utils import (media_path_full, probably_alive, find_children, find_parents, find_witnessed_people) from libformatting import FormattingHelper import ThumbNails import Errors -from gui.editors import EditPerson, EditFamily +from gui.editors import EditPerson, EditFamily from DdTargets import DdTargets import cPickle as pickle import config -from QuestionDialog import RunDatabaseRepair, ErrorDialog import Bookmarks import const -from gui.filtereditor import FilterEditor +from QuestionDialog import RunDatabaseRepair, ErrorDialog #------------------------------------------------------------------------- # @@ -80,73 +82,99 @@ _CHRI = _('short for chistianized|chr.') _BURI = _('short for buried|bur.') _CREM = _('short for cremated|crem.') -class PersonBoxWidget_old( gtk.Button): - def __init__(self,fh,person,maxlines,image=None): - if person: - gtk.Button.__init__(self, fh.format_person(person, maxlines)) - gender = person.get_gender() - if gender == gen.lib.Person.MALE: - self.modify_bg( gtk.STATE_NORMAL, self.get_colormap().alloc_color("#F5FFFF")) - elif gender == gen.lib.Person.FEMALE: - self.modify_bg( gtk.STATE_NORMAL, self.get_colormap().alloc_color("#FFF5FF")) - else: - self.modify_bg( gtk.STATE_NORMAL, self.get_colormap().alloc_color("#FFFFF5")) - else: - gtk.Button.__init__(self, " ") - #self.set_sensitive(False) - self.fh = fh - self.set_alignment(0.0,0.0) - white = self.get_colormap().alloc_color("white") - self.modify_bg( gtk.STATE_ACTIVE, white) - self.modify_bg( gtk.STATE_PRELIGHT, white) - self.modify_bg( gtk.STATE_SELECTED, white) - -class _PersonWidget_base: - def __init__(self, view, fh, person): +class _PersonWidgetBase: + """ + Defualt set up for person widgets. + Set up drag options and button release events. + """ + def __init__(self, view, format_helper, person): self.view = view - self.fh = fh + self.format_helper = format_helper self.person = person self.force_mouse_over = False if self.person: + self.add_events(gtk.gdk.BUTTON_PRESS_MASK) self.add_events(gtk.gdk.BUTTON_RELEASE_MASK) self.connect("button-release-event", self.on_button_release_cb) self.connect("drag_data_get", self.drag_data_get) - self.connect('drag_begin', self.drag_begin_cb) + self.connect("drag_begin", self.drag_begin_cb) + # Enable drag self.drag_source_set(gtk.gdk.BUTTON1_MASK, - [DdTargets.PERSON_LINK.target()]+ - [t.target() for t in DdTargets._all_text_types], - gtk.gdk.ACTION_COPY) + [DdTargets.PERSON_LINK.target()]+ + [t.target() for t in DdTargets._all_text_types], + gtk.gdk.ACTION_COPY) - def drag_begin_cb(self, widget, *data): + def drag_begin_cb(self, widget, data): + """Set up some inital conditions for drag. Set up icon.""" self.drag_source_set_icon_stock('gramps-person') def drag_data_get(self, widget, context, sel_data, info, time): + """ + Returned parameters after drag. + Specified for 'person-link', for others return text info about person. + """ if sel_data.target == DdTargets.PERSON_LINK.drag_type: - data = (DdTargets.PERSON_LINK.drag_type, id(self), self.person.get_handle(), 0) + data = (DdTargets.PERSON_LINK.drag_type, + id(self), self.person.get_handle(), 0) sel_data.set(sel_data.target, 8, pickle.dumps(data)) else: - sel_data.set(sel_data.target, 8, self.fh.format_person( self.person,11)) + sel_data.set(sel_data.target, 8, + self.format_helper.format_person(self.person, 11)) - def on_button_release_cb(self,widget,event): - self.view.on_childmenu_changed(None, self.person.get_handle()) + def on_button_release_cb(self, widget, event): + """ + Defualt action for release event from mouse. + Change active person to current. + """ + if event.button == 1 and event.type == gtk.gdk.BUTTON_RELEASE: + self.view.on_childmenu_changed(None, self.person.get_handle()) + return True return False + + def get_image(self, dbstate, person): + """ + Return a thumbnail image for the given person. + """ + image = False + media_list = person.get_media_list() + if media_list: + photo = media_list[0] + object_handle = photo.get_reference_handle() + obj = dbstate.db.get_object_from_handle( + object_handle) + if obj: + mtype = obj.get_mime_type() + if mtype and mtype[0:5] == "image": + image = ThumbNails.get_thumbnail_path( + media_path_full( + dbstate.db, + obj.get_path()), + rectangle=photo.get_rectangle()) + return image - -class PersonBoxWidget_cairo( gtk.DrawingArea, _PersonWidget_base): - def __init__(self,view,fh,person,alive,maxlines,image=None): +class PersonBoxWidgetCairo(gtk.DrawingArea, _PersonWidgetBase): + """Draw person box using cairo library""" + def __init__(self, view, format_helper, dbstate, person, alive, maxlines, + image=None): gtk.DrawingArea.__init__(self) - _PersonWidget_base.__init__(self,view,fh,person) - self.add_events(gtk.gdk.BUTTON_PRESS_MASK) # Required for popup menu - self.add_events(gtk.gdk.ENTER_NOTIFY_MASK) # Required for tooltip and mouse-over - self.add_events(gtk.gdk.LEAVE_NOTIFY_MASK) # Required for tooltip and mouse-over + _PersonWidgetBase.__init__(self, view, format_helper, person) + # Required for popup menu + self.add_events(gtk.gdk.BUTTON_PRESS_MASK) + self.add_events(gtk.gdk.BUTTON_RELEASE_MASK) + # Required for tooltip and mouse-over + self.add_events(gtk.gdk.ENTER_NOTIFY_MASK) + # Required for tooltip and mouse-over + self.add_events(gtk.gdk.LEAVE_NOTIFY_MASK) + self.alive = alive self.maxlines = maxlines self.hightlight = False self.connect("expose_event", self.expose) self.connect("realize", self.realize) self.text = "" if self.person: - self.text = self.fh.format_person(self.person,self.maxlines,True) + self.text = self.format_helper.format_person(self.person, + self.maxlines, True) if alive and self.person.get_gender() == gen.lib.Person.MALE: self.bgcolor = (185/256.0, 207/256.0, 231/256.0) self.bordercolor = (32/256.0, 74/256.0, 135/256.0) @@ -158,156 +186,209 @@ class PersonBoxWidget_cairo( gtk.DrawingArea, _PersonWidget_base): self.bordercolor = (143/256.0, 89/256.0, 2/256.0) elif self.person.get_gender() == gen.lib.Person.MALE: self.bgcolor = (185/256.0, 207/256.0, 231/256.0) - self.bordercolor = (0,0,0) + self.bordercolor = (0, 0, 0) elif self.person.get_gender() == gen.lib.Person.FEMALE: self.bgcolor = (255/256.0, 205/256.0, 241/256.0) - self.bordercolor = (0,0,0) + self.bordercolor = (0, 0, 0) else: self.bgcolor = (244/256.0, 220/256.0, 183/256.0) - self.bordercolor = (0,0,0) + self.bordercolor = (0, 0, 0) else: self.bgcolor = (211/256.0, 215/256.0, 207/256.0) - self.bordercolor = (0,0,0) - self.image = image - try: - self.img_surf = cairo.ImageSurface.create_from_png(image) - except: + self.bordercolor = (0, 0, 0) + if image: + self.image = self.get_image(dbstate, person) + if self.image: + self.img_surf = cairo.ImageSurface.create_from_png(self.image) + else: self.image = False - self.connect("enter-notify-event", self.on_enter_cb) # enable mouse-over + # enable mouse-over + self.connect("enter-notify-event", self.on_enter_cb) + # enable mouse-out self.connect("leave-notify-event", self.on_leave_cb) - self.set_size_request(120,25) + self.set_size_request(120, 25) + # GTK object use in realize and expose methods + self.context = None + self.textlayout = None - def on_enter_cb(self,widget,event): + def on_enter_cb(self, widget, event): + """On mouse-over highlight border""" if self.person or self.force_mouse_over: self.hightlight = True self.queue_draw() - - def on_leave_cb(self,widget,event): + + def on_leave_cb(self, widget, event): + """On mouse-out normal border""" self.hightlight = False self.queue_draw() - def realize(self,widget): + def realize(self, widget): + """ + Necessary actions when the widget is instantiated on a particular + display. Print text and resize element. + """ self.context = self.window.cairo_create() self.textlayout = self.context.create_layout() - self.textlayout.set_font_description(self.get_style().font_desc) + self.textlayout.set_font_description(self.get_style().font_desc) self.textlayout.set_markup(self.text) - s = self.textlayout.get_pixel_size() - xmin = s[0] + 12 - ymin = s[1] + 11 + size = self.textlayout.get_pixel_size() + xmin = size[0] + 12 + ymin = size[1] + 11 if self.image: xmin += self.img_surf.get_width() - ymin = max( ymin,self.img_surf.get_height()+4) - self.set_size_request(max(xmin,120),max(ymin,25)) - - def expose(self,widget,event): + ymin = max(ymin, self.img_surf.get_height()+4) + self.set_size_request(max(xmin, 120), max(ymin, 25)) + + def expose(self, widget, event): + """ + Redrawing the contents of the widget. + Creat new cairo object and draw in it all (borders, background and etc.) + witout text. + """ alloc = self.get_allocation() self.context = self.window.cairo_create() # widget area for debugging - #self.context.rectangle(0,0,alloc.width,alloc.height) - #self.context.set_source_rgb( 1,0,1) + #self.context.rectangle(0, 0, alloc.width, alloc.height) + #self.context.set_source_rgb(1, 0, 1) #self.context.fill_preserve() #self.context.stroke() - + # Create box shape and store path - self.context.move_to(0,5) - self.context.curve_to(0,2,2,0, 5,0) - self.context.line_to(alloc.width-8,0) - self.context.curve_to(alloc.width-5,0,alloc.width-3,2, alloc.width-3,5) - self.context.line_to(alloc.width-3,alloc.height-8) - self.context.curve_to(alloc.width-3,alloc.height-5, alloc.width-5,alloc.height-3, alloc.width-8,alloc.height-3) - self.context.line_to(5,alloc.height-3) - self.context.curve_to(2,alloc.height-3,0,alloc.height-5,0,alloc.height-8) + self.context.move_to(0, 5) + self.context.curve_to(0, 2, 2, 0, 5, 0) + self.context.line_to(alloc.width-8, 0) + self.context.curve_to(alloc.width-5, 0, + alloc.width-3, 2, + alloc.width-3, 5) + self.context.line_to(alloc.width-3, alloc.height-8) + self.context.curve_to(alloc.width-3, alloc.height-5, + alloc.width-5, alloc.height-3, + alloc.width-8, alloc.height-3) + self.context.line_to(5, alloc.height-3) + self.context.curve_to(2, alloc.height-3, + 0, alloc.height-5, + 0, alloc.height-8) self.context.close_path() path = self.context.copy_path() - + # shadow self.context.save() - self.context.translate(3,3) + self.context.translate(3, 3) self.context.new_path() - self.context.append_path( path) + self.context.append_path(path) self.context.set_source_rgba(*(self.bordercolor[:3] + (0.4,))) self.context.fill_preserve() self.context.set_line_width(0) self.context.stroke() self.context.restore() - + # box shape used for clipping - self.context.append_path( path) + self.context.append_path(path) self.context.clip() # background - self.context.append_path( path) + self.context.append_path(path) self.context.set_source_rgb(*self.bgcolor[:3]) self.context.fill_preserve() self.context.stroke() # image if self.image: - self.context.set_source_surface( self.img_surf,alloc.width-4-self.img_surf.get_width(),1) + self.context.set_source_surface(self.img_surf, + alloc.width-4-self.img_surf.get_width(), 1) self.context.paint() - + # text - self.context.move_to(5,4) - self.context.set_source_rgb( 0,0,0) - self.context.show_layout( self.textlayout) + self.context.move_to(5, 4) + self.context.set_source_rgb(0, 0, 0) + self.context.show_layout(self.textlayout) # text extents - #self.context.set_source_rgba( 1,0,0,0.5) + #self.context.set_source_rgba(1, 0, 0, 0.5) #s = self.textlayout.get_pixel_size() #self.context.set_line_width(1) - #self.context.rectangle(5.5,4.5,s[0]-1,s[1]-1) + #self.context.rectangle(5.5, 4.5, s[0]-1, s[1]-1) #self.context.stroke() + # Mark deceased + if self.person and not self.alive: + self.context.set_line_width(2) + self.context.move_to(0, 10) + self.context.line_to(10, 0) + self.context.stroke() + #border if self.hightlight: self.context.set_line_width(5) else: self.context.set_line_width(2) - self.context.append_path( path) + self.context.append_path(path) self.context.set_source_rgb(*self.bordercolor[:3]) self.context.stroke() - -class PersonBoxWidget( gtk.DrawingArea, _PersonWidget_base): - def __init__(self,view,fh,person,alive,maxlines,image=None): +class PersonBoxWidget(gtk.DrawingArea, _PersonWidgetBase): + """ + Draw person box using GC library. + For version PyGTK < 2.8 + """ + def __init__(self, view, format_helper, dbstate, person, alive, maxlines, + image=False): gtk.DrawingArea.__init__(self) - _PersonWidget_base.__init__(self,view,fh,person) - self.add_events(gtk.gdk.BUTTON_PRESS_MASK) # Required for popup menu - self.add_events(gtk.gdk.ENTER_NOTIFY_MASK) # Required for tooltip and mouse-over - self.add_events(gtk.gdk.LEAVE_NOTIFY_MASK) # Required for tooltip and mouse-over + _PersonWidgetBase.__init__(self, view, format_helper, person) + # Required for popup menu and right mouse button click + self.add_events(gtk.gdk.BUTTON_PRESS_MASK + | gtk.gdk.BUTTON_RELEASE_MASK + # Required for tooltip and mouse-over + | gtk.gdk.ENTER_NOTIFY_MASK + # Required for tooltip and mouse-over + | gtk.gdk.LEAVE_NOTIFY_MASK) self.maxlines = maxlines - self.alive = alive; - try: - self.image = gtk.gdk.pixbuf_new_from_file( image) - except: - self.image = None + self.alive = alive + if image: + self.image = self.get_image(dbstate, person) + if self.image: + self.image = gtk.gdk.pixbuf_new_from_file(self.image) + else: + self.image = False self.connect("expose_event", self.expose) self.connect("realize", self.realize) text = "" if self.person: - text = self.fh.format_person(self.person,self.maxlines) - self.connect("enter-notify-event", self.on_enter_cb) # enable mouse-over + text = self.format_helper.format_person(self.person, self.maxlines) + # enable mouse-over + self.connect("enter-notify-event", self.on_enter_cb) self.connect("leave-notify-event", self.on_leave_cb) self.textlayout = self.create_pango_layout(text) - s = self.textlayout.get_pixel_size() - xmin = s[0] + 12 - ymin = s[1] + 11 + size = self.textlayout.get_pixel_size() + xmin = size[0] + 12 + ymin = size[1] + 11 if self.image: xmin += self.image.get_width() - ymin = max( ymin,self.image.get_height()+4) - self.set_size_request(max(xmin,120),max(ymin,25)) + ymin = max(ymin, self.image.get_height()+4) + self.set_size_request(max(xmin, 120), max(ymin, 25)) + # GTK object use in realize and expose methods + self.bg_gc = None + self.text_gc = None + self.border_gc = None + self.shadow_gc = None - def on_enter_cb(self,widget,event): - """ On mouse-over hightlight border""" + def on_enter_cb(self, widget, event): + """On mouse-over highlight border""" self.border_gc.line_width = 3 self.queue_draw() - - def on_leave_cb(self,widget,event): + + def on_leave_cb(self, widget, event): + """On mouse-out normal border""" self.border_gc.line_width = 1 self.queue_draw() - - def realize(self,widget): + + def realize(self, widget): + """ + Necessary actions when the widget is instantiated on a particular + display. Creat all elements for person box(bg_gc, text_gc, border_gc, + shadow_gc), and setup they style. + """ self.bg_gc = self.window.new_gc() self.text_gc = self.window.new_gc() self.border_gc = self.window.new_gc() @@ -318,99 +399,303 @@ class PersonBoxWidget( gtk.DrawingArea, _PersonWidget_base): self.shadow_gc.line_width = 4 if self.person: if self.alive and self.person.get_gender() == gen.lib.Person.MALE: - self.bg_gc.set_foreground( self.get_colormap().alloc_color("#b9cfe7")) - self.border_gc.set_foreground( self.get_colormap().alloc_color("#204a87")) + self.bg_gc.set_foreground( + self.get_colormap().alloc_color("#b9cfe7")) + self.border_gc.set_foreground( + self.get_colormap().alloc_color("#204a87")) elif self.person.get_gender() == gen.lib.Person.MALE: - self.bg_gc.set_foreground( self.get_colormap().alloc_color("#b9cfe7")) - self.border_gc.set_foreground( self.get_colormap().alloc_color("#000000")) - elif self.alive and self.person.get_gender() == gen.lib.Person.FEMALE: - self.bg_gc.set_foreground( self.get_colormap().alloc_color("#ffcdf1")) - self.border_gc.set_foreground( self.get_colormap().alloc_color("#87206a")) + self.bg_gc.set_foreground( + self.get_colormap().alloc_color("#b9cfe7")) + self.border_gc.set_foreground( + self.get_colormap().alloc_color("#000000")) + elif self.alive and \ + self.person.get_gender() == gen.lib.Person.FEMALE: + self.bg_gc.set_foreground( + self.get_colormap().alloc_color("#ffcdf1")) + self.border_gc.set_foreground( + self.get_colormap().alloc_color("#87206a")) elif self.person.get_gender() == gen.lib.Person.FEMALE: - self.bg_gc.set_foreground( self.get_colormap().alloc_color("#ffcdf1")) - self.border_gc.set_foreground( self.get_colormap().alloc_color("#000000")) + self.bg_gc.set_foreground( + self.get_colormap().alloc_color("#ffcdf1")) + self.border_gc.set_foreground( + self.get_colormap().alloc_color("#000000")) elif self.alive: - self.bg_gc.set_foreground( self.get_colormap().alloc_color("#f4dcb7")) - self.border_gc.set_foreground( self.get_colormap().alloc_color("#8f5902")) + self.bg_gc.set_foreground( + self.get_colormap().alloc_color("#f4dcb7")) + self.border_gc.set_foreground( + self.get_colormap().alloc_color("#8f5902")) else: - self.bg_gc.set_foreground( self.get_colormap().alloc_color("#f4dcb7")) - self.border_gc.set_foreground( self.get_colormap().alloc_color("#000000")) + self.bg_gc.set_foreground( + self.get_colormap().alloc_color("#f4dcb7")) + self.border_gc.set_foreground( + self.get_colormap().alloc_color("#000000")) else: - self.bg_gc.set_foreground( self.get_colormap().alloc_color("#eeeeee")) - self.border_gc.set_foreground( self.get_colormap().alloc_color("#777777")) - self.shadow_gc.set_foreground( self.get_colormap().alloc_color("#999999")) + self.bg_gc.set_foreground( + self.get_colormap().alloc_color("#eeeeee")) + self.border_gc.set_foreground( + self.get_colormap().alloc_color("#777777")) + self.shadow_gc.set_foreground( + self.get_colormap().alloc_color("#999999")) - def expose(self,widget,event): + def expose(self, widget, event): + """ + Redrawing the contents of the widget. + Drawing borders and person info on exist elements. + """ alloc = self.get_allocation() # shadow - self.window.draw_line(self.shadow_gc, 3, alloc.height-1, alloc.width, alloc.height-1) - self.window.draw_line(self.shadow_gc, alloc.width-1, 3, alloc.width-1, alloc.height) + self.window.draw_line(self.shadow_gc, 3, alloc.height-1, + alloc.width, alloc.height-1) + self.window.draw_line(self.shadow_gc, alloc.width-1, 3, + alloc.width-1, alloc.height) # box background - self.window.draw_rectangle(self.bg_gc, True, 1, 1, alloc.width-5, alloc.height-5) + self.window.draw_rectangle(self.bg_gc, True, 1, 1, + alloc.width-5, alloc.height-5) # text if self.person: - self.window.draw_layout( self.text_gc, 5,4, self.textlayout) + self.window.draw_layout(self.text_gc, 5, 4, self.textlayout) # image if self.image: - self.window.draw_pixbuf( self.text_gc, self.image, 0,0, alloc.width-4-self.image.get_width(),1) + self.window.draw_pixbuf(self.text_gc, self.image, 0, 0, + alloc.width-4-self.image.get_width(), 1) # border if self.border_gc.line_width > 1: - self.window.draw_rectangle(self.border_gc, False, 1, 1, alloc.width-6, alloc.height-6) + self.window.draw_rectangle(self.border_gc, False, 1, 1, + alloc.width-6, alloc.height-6) else: - self.window.draw_rectangle(self.border_gc, False, 0, 0, alloc.width-4, alloc.height-4) + self.window.draw_rectangle(self.border_gc, False, 0, 0, + alloc.width-4, alloc.height-4) +class LineWidget(gtk.DrawingArea): + """ + Draw lines linking Person boxes - Types A and C. + """ + def __init__(self, child, father, frel, mother, mrel, direction): + gtk.DrawingArea.__init__(self) + + self.child_box = child + self.father_box = father + self.mother_box = mother + self.frel = frel + self.mrel = mrel + self.direction = direction + + self.connect("expose_event", self.expose) + self.connect("realize", self.realize) + + def realize(self, widget): + """ + Necessary actions when the widget is instantiated on a particular + display. + """ + self.set_size_request(20, 20) + self.line_gc = self.window.new_gc() + self.line_gc.set_foreground( + self.get_colormap().alloc_color("#000000")) + + def expose(self, widget, event): + """ + Redraw the contents of the widget. + """ + alloc = self.get_allocation() + child = self.child_box.get_allocation() + + if self.father_box: + father = self.father_box.get_allocation() + if self.mother_box: + mother = self.mother_box.get_allocation() + + if self.direction in [2, 3]: # horizontal + child_side = 0 + centre = alloc.width / 2 + parent_side = alloc.width + middle = child.y - alloc.y + child.height / 2 + if self.father_box: + father_side = father.height / 2 + if self.mother_box: + mother_side = alloc.height - mother.height / 2 + else: + child_side = 0 + centre = alloc.height / 2 + parent_side = alloc.height + middle = child.x - alloc.x + child.width / 2 + if self.father_box: + father_side = father.width / 2 + if self.mother_box: + mother_side = alloc.width - mother.width / 2 + + if self.direction in [1, 3]: # bottom to top or right to left + child_side = parent_side + parent_side = 0 + + self.line_gc.line_width = 3 + + if self.father_box: + self.draw_link(parent_side, middle, child_side, centre, + father_side, self.mrel) + + if self.mother_box: + self.draw_link(parent_side, middle, child_side, centre, + mother_side, self.frel) + + def draw_link(self, parent_side, middle, child_side, centre, side, rela): + """ + Draw a link between parent and child. + """ + if rela: + self.line_gc.line_style = gtk.gdk.LINE_SOLID + else: + self.line_gc.line_style = gtk.gdk.LINE_ON_OFF_DASH + + self.draw_line(centre, side, parent_side, side) + self.draw_line(centre, side, centre, middle) + self.draw_line(centre, middle, child_side, middle) + + def draw_line(self, x1, y1, x2, y2): + """ + Draw a single line in a link. + """ + if self.direction in [2, 3]: # horizontal + self.window.draw_line(self.line_gc, x1, y1, x2, y2) + else: + self.window.draw_line(self.line_gc, y1, x1, y2, x2) + +class LineWidget2(gtk.DrawingArea): + """ + Draw lines linking Person boxes - Type B. + """ + def __init__(self, male, rela, direction): + gtk.DrawingArea.__init__(self) + + self.male = male + self.rela = rela + self.direction = direction + + self.connect("expose_event", self.expose) + self.connect("realize", self.realize) + + def realize(self, widget): + """ + Necessary actions when the widget is instantiated on a particular + display. + """ + self.set_size_request(20, -1) + self.line_gc = self.window.new_gc() + self.line_gc.set_foreground( + self.get_colormap().alloc_color("#000000")) + + def expose(self, widget, event): + """ + Redraw the contents of the widget. + """ + alloc = self.get_allocation() + + if self.direction in [2, 3]: # horizontal + child_x = alloc.width / 2 + child_y = alloc.height + parent_x = alloc.width + parent_y = alloc.height / 2 + mid_x = alloc.width / 2 + mid_y = alloc.height / 2 + else: + child_y = alloc.width + child_x = alloc.height / 2 + parent_y = alloc.width / 2 + parent_x = alloc.height + mid_y = alloc.width / 2 + mid_x = alloc.height / 2 + + if not self.rela: + self.line_gc.line_style = gtk.gdk.LINE_ON_OFF_DASH + else: + self.line_gc.line_style = gtk.gdk.LINE_SOLID + + self.line_gc.line_width = 3 + + if self.direction in [1, 3]: + parent_x = 0 + + if not self.male: + child_y = 0 + + self.draw_line(child_x, child_y, mid_x, mid_y) + self.draw_line(mid_x, mid_y, parent_x, parent_y) + + def draw_line(self, x1, y1, x2, y2): + """ + Draw a single line in a link. + """ + if self.direction in [2, 3]: # horizontal + self.window.draw_line(self.line_gc, x1, y1, x2, y2) + else: + self.window.draw_line(self.line_gc, y1, x1, y2, x2) + #------------------------------------------------------------------------- # # PedigreeView # #------------------------------------------------------------------------- class PedigreeView(NavigationView): + """ + View for pedigree tree. + Displays the ancestors of a selected individual. + """ def __init__(self, dbstate, uistate, nav_group=0): NavigationView.__init__(self, _('Pedigree'), dbstate, uistate, dbstate.db.get_bookmarks(), Bookmarks.PersonBookmarks, - nav_group) + nav_group) + self.func_list = { + 'F2' : self.kb_goto_home, + 'F3' : self.kb_change_style, + 'F4' : self.kb_change_direction, + 'F6' : self.kb_plus_generation, + 'F5' : self.kb_minus_generation, 'J' : self.jump, } self.dbstate = dbstate - self.dbstate.connect('database-changed',self.change_db) - #self.dbstate.connect('active-changed',self.goto_active_person) - self.force_size = config.get('interface.pedview-tree-size') # Automatic resize - self.tree_style = config.get('interface.pedview-layout') # Nice tree - self.show_images = config.get('interface.pedview-show-images') # Show photos of persons - self.show_marriage_data = config.get('interface.pedview-show-marriage') # Hide marriage data by default + self.dbstate.connect('database-changed', self.change_db) + # Automatic resize + self.force_size = config.get('interface.pedview-tree-size') + # Nice tree + self.tree_style = config.get('interface.pedview-layout') + # Show photos of persons + self.show_images = config.get('interface.pedview-show-images') + # Hide marriage data by default + self.show_marriage_data = config.get( + 'interface.pedview-show-marriage') + # Tree draw direction + self.tree_direction = config.get('interface.pedview-tree-direction') + # Show on not unknown people. + # Default - not show, for mo fast display hight tree + self.show_unknown_people = config.get( + 'interface.pedview-show-unknown-people') + self.format_helper = FormattingHelper(self.dbstate) + + # Depth of tree. + self._depth = 1 + # Variables for drag and scroll + self._last_x = 0 + self._last_y = 0 + self._in_move = False + # Change or nor mouse whell scroll direction + self.scroll_direction = config.get( + 'interface.pedview-scroll-direction') + self.key_active_changed = None + # GTK objects + self.scrolledwindow = None + self.table = None def change_page(self): + """Called when the page changes.""" NavigationView.change_page(self) self.uistate.clear_filter_results() - def init_parent_signals_cb(self, widget, event): - # required to properly bootstrap the signal handlers. - # This handler is connected by build_widget. After the outside ViewManager - # has placed this widget we are able to access the parent container. - self.notebook.disconnect(self.bootstrap_handler) - self.notebook.parent.connect("size-allocate", self.size_request_cb) - self.size_request_cb(widget.parent,event) - - def add_table_to_notebook( self, table): - frame = gtk.ScrolledWindow(None,None) - frame.set_shadow_type(gtk.SHADOW_NONE) - frame.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC) - frame.add_with_viewport(table) - table.get_parent().set_shadow_type(gtk.SHADOW_NONE) - table.set_row_spacings(1) - table.set_col_spacings(0) - try: - self.notebook.append_page(frame,None) - except: - # for PyGtk < 2.4 - self.notebook.append_page(frame,gtk.Label("")) - def get_stock(self): """ The category stock icon @@ -426,30 +711,33 @@ class PedigreeView(NavigationView): """ Builds the interface and returns a gtk.Container type that contains the interface. This containter will be inserted into - a gtk.Notebook page. + a gtk.ScrolledWindow page. """ - - self.notebook = gtk.Notebook() - self.notebook.connect("button-press-event", self.bg_button_press_cb) - self.bootstrap_handler = self.notebook.connect("size-request", self.init_parent_signals_cb) - self.notebook.set_show_border(False) - self.notebook.set_show_tabs(False) - - self.table_2 = gtk.Table(1,1,False) - self.add_table_to_notebook( self.table_2) + self.scrolledwindow = gtk.ScrolledWindow(None, None) + self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, + gtk.POLICY_AUTOMATIC) + self.scrolledwindow.add_events(gtk.gdk.SCROLL_MASK) + self.scrolledwindow.connect("scroll-event", self.bg_scroll_event) + event_box = gtk.EventBox() + # Required for drag-scroll events and popup menu + event_box.add_events(gtk.gdk.BUTTON_PRESS_MASK + | gtk.gdk.BUTTON_RELEASE_MASK + | gtk.gdk.BUTTON1_MOTION_MASK) + # Signal begin drag-scroll + event_box.connect("button-press-event", self.bg_button_press_cb) + # Signal end drag-scroll and popup menu + event_box.connect("button-release-event", self.bg_button_release_cb) + #Signal for controll motion-notify when left mouse button pressed + event_box.connect("motion-notify-event", self.bg_motion_notify_event_cb) + self.scrolledwindow.add_with_viewport(event_box) - self.table_3 = gtk.Table(1,1,False) - self.add_table_to_notebook( self.table_3) + self.table = gtk.Table(1, 1, False) + event_box.add(self.table) + event_box.get_parent().set_shadow_type(gtk.SHADOW_NONE) + self.table.set_row_spacings(1) + self.table.set_col_spacings(0) - self.table_4 = gtk.Table(1,1,False) - self.add_table_to_notebook( self.table_4) - - self.table_5 = gtk.Table(1,1,False) - self.add_table_to_notebook( self.table_5) - - self.rebuild_trees(None) - - return self.notebook + return self.scrolledwindow def ui_definition(self): """ @@ -479,8 +767,8 @@ class PedigreeView(NavigationView): - - + + @@ -499,7 +787,6 @@ class PedigreeView(NavigationView): be able to toggle these when you are at the end of the history or at the beginning of the history. """ - NavigationView.define_actions(self) self._add_action('FilterEdit', None, _('Person Filter Editor'), @@ -519,15 +806,19 @@ class PedigreeView(NavigationView): information. """ try: - self.rebuild_trees(self.get_active()) + active = self.get_active() + if active: + self.rebuild_trees(active) + else: + self.rebuild_trees(None) except AttributeError, msg: RunDatabaseRepair(str(msg)) - def change_db(self,db): + def change_db(self, db): """ - Callback associated with DbState. Whenenver the database + Callback associated with DbState. Whenever the database changes, this task is called. In this case, we rebuild the - columns, and connect signals to the connected database. Tere + columns, and connect signals to the connected database. Tree is no need to store the database, since we will get the value from self.state.db """ @@ -536,7 +827,7 @@ class PedigreeView(NavigationView): db.connect('person-delete', self.person_rebuild) db.connect('person-rebuild', self.person_rebuild_bm) db.connect('family-update', self.person_rebuild) - db.connect('family-add', self.person_rebuild) + db.connect('family-add', self.person_rebuild) db.connect('family-delete', self.person_rebuild) db.connect('family-rebuild', self.person_rebuild) self.bookmarks.update_bookmarks(self.dbstate.db.get_bookmarks()) @@ -559,366 +850,416 @@ class PedigreeView(NavigationView): self.rebuild_trees(None) self.uistate.modify_statusbar(self.dbstate) - def person_rebuild_bm(self,dummy=None): + def person_rebuild_bm(self, dummy=None): """Large change to person database""" self.person_rebuild(dummy) if self.active: self.bookmarks.redraw() - def person_rebuild(self,dummy=None): + def person_rebuild(self, dummy=None): + """Callback function for signals of change database.""" self.format_helper.clear_cache() self.dirty = True self.rebuild_trees(self.get_active()) - def request_resize(self): - self.size_request_cb(self.notebook.parent,None,None) - - def size_request_cb(self, widget, event, data=None): - if self.force_size == 0: - v = widget.get_allocation() - page_list = range(0,self.notebook.get_n_pages()) - page_list.reverse() - for n in page_list: - p = self.notebook.get_nth_page(n).get_child().get_child().get_allocation() - if v.width >= p.width and v.height > p.height: - self.notebook.set_current_page(n) - break; - else: - self.notebook.set_current_page(self.force_size-2) - def rebuild_trees(self, person_handle): - + """ + Rebild tree with root person_handle. + Called from many fuctions, when need full redraw tree. + """ person = None if person_handle: person = self.dbstate.db.get_person_from_handle(person_handle) self.dirty = False - if self.tree_style not in (0, 1): - self.tree_style = 0 + if self.tree_style == 1 and \ + (self.force_size > 5 or self.force_size == 0): + self.force_size = 5 - if self.tree_style == 0: - pos_2 =(((0,0,1,3),(1,0,3),(2,1,1,1)), - ((2,0,1,1),None,None), - ((2,2,1,1),None,None)) - pos_3 =(((0,2,1,3),(1,1,5),(2,3,1,1)), - ((2,0,1,3),(3,0,3),(4,1,1,1)), - ((2,4,1,3),(3,4,3),(4,5,1,1)), - ((4,0,1,1),None,None), - ((4,2,1,1),None,None), - ((4,4,1,1),None,None), - ((4,6,1,1),None,None)) - pos_4 =(((0,6,1,3),(1,3,9),(2,5,1,5)), - ((2,2,1,3),(3,1,5),(4,3,1,1)), - ((2,10,1,3),(3,9,5),(4,11,1,1)), - ((4,0,1,3),(5,0,3),(6,1,1,1)), - ((4,4,1,3),(5,4,3),(6,5,1,1)), - ((4,8,1,3),(5,8,3),(6,9,1,1)), - ((4,12,1,3),(5,12,3),(6,13,1,1)), - ((6,0,1,1),None,None), - ((6,2,1,1),None,None), - ((6,4,1,1),None,None), - ((6,6,1,1),None,None), - ((6,8,1,1),None,None), - ((6,10,1,1),None,None), - ((6,12,1,1),None,None), - ((6,14,1,1),None,None)) - pos_5 =(((0,14,1,3),(1,7,17),(2,13,1,5)), - ((2,6,1,3),(3,3,9),(4,5,1,5)), - ((2,22,1,3),(3,19,9),(4,21,1,5)), - ((4,2,1,3),(5,1,5),(6,3,1,1)), - ((4,10,1,3),(5,9,5),(6,11,1,1)), - ((4,18,1,3),(5,17,5),(6,19,1,1)), - ((4,26,1,3),(5,25,5),(6,27,1,1)), - ((6,0,1,3),(7,0,3),(8,1,1,1)), - ((6,4,1,3),(7,4,3),(8,5,1,1)), - ((6,8,1,3),(7,8,3),(8,9,1,1)), - ((6,12,1,3),(7,12,3),(8,13,1,1)), - ((6,16,1,3),(7,16,3),(8,17,1,1)), - ((6,20,1,3),(7,20,3),(8,21,1,1)), - ((6,24,1,3),(7,24,3),(8,25,1,1)), - ((6,28,1,3),(7,28,3),(8,29,1,1)), - ((8,0,1,1),None,None), - ((8,2,1,1),None,None), - ((8,4,1,1),None,None), - ((8,6,1,1),None,None), - ((8,8,1,1),None,None), - ((8,10,1,1),None,None), - ((8,12,1,1),None,None), - ((8,14,1,1),None,None), - ((8,16,1,1),None,None), - ((8,18,1,1),None,None), - ((8,20,1,1),None,None), - ((8,22,1,1),None,None), - ((8,24,1,1),None,None), - ((8,26,1,1),None,None), - ((8,28,1,1),None,None), - ((8,30,1,1),None,None)) - elif self.tree_style == 1: - # format of the definition is: - # ((each box of the pedigree has a node here), - # ((person data), (connection line), (marriage data)), - # ((person box position and size),(parent relation box),(marriage data)), - # ((or for another design),((fater relation box),(mother relation box)),(marriage data))) - pos_2 =(((0,3,3,3),((1,0,3),(1,6,3)),(3,3,2,3)), - ((2,0,3,3),None,None), - ((2,6,3,3),None,None)) - pos_3 =(((0,4,3,5),((1,1,3),(1,9,3)),(3,5,2,3)), - ((2,1,3,3),((3,0,1),(3,4,1)),(5,1,2,3)), - ((2,9,3,3),((3,8,1),(3,12,1)),(5,9,2,3)), - ((4,0,3,1),None,None), - ((4,4,3,1),None,None), - ((4,8,3,1),None,None), - ((4,12,3,1),None,None)) - pos_4 =(((0, 5,3,5),((1,2,3),(1,10,3)),(3, 6,2,3)), - ((2, 2,3,3),((3,1,1),(3,5,1)),(5, 3,2,1)), - ((2,10,3,3),((3,9,1),(3,13,1)),(5,11,2,1)), - ((4, 1,3,1),((5,0,1),(5,2,1)),(7,1,2,1)), - ((4, 5,3,1),((5,4,1),(5,6,1)),(7,5,2,1)), - ((4, 9,3,1),((5,8,1),(5,10,1)),(7,9,2,1)), - ((4,13,3,1),((5,12,1),(5,14,1)),(7,13,2,1)), - ((6, 0,3,1),None,None), - ((6, 2,3,1),None,None), - ((6, 4,3,1),None,None), - ((6, 6,3,1),None,None), - ((6, 8,3,1),None,None), - ((6,10,3,1),None,None), - ((6,12,3,1),None,None), - ((6,14,3,1),None,None),) - pos_5 =(((0,10,3,11),((1,5,5),(1,21,5)),(3,13,2,5)), - ((2, 5,3,5),((3,2,3),(3,10,3)),(5, 6,2,3)), - ((2,21,3,5),((3,18,3),(3,26,3)),(5,22,2,3)), - ((4, 2,3,3),((5,1,1),(5,5,1)),(7,3,2,1)), - ((4,10,3,3),((5,9,1),(5,13,1)),(7,11,2,1)), - ((4,18,3,3),((5,17,1),(5,21,1)),(7,19,2,1)), - ((4,26,3,3),((5,25,1),(5,29,1)),(7,27,2,1)), - ((6, 1,3,1),((7,0,1),(7,2,1)),(9,1,2,1)), - ((6, 5,3,1),((7,4,1),(7,6,1)),(9,5,2,1)), - ((6, 9,3,1),((7,8,1),(7,10,1)),(9,9,2,1)), - ((6,13,3,1),((7,12,1),(7,14,1)),(9,13,2,1)), - ((6,17,3,1),((7,16,1),(7,18,1)),(9,17,2,1)), - ((6,21,3,1),((7,20,1),(7,22,1)),(9,21,2,1)), - ((6,25,3,1),((7,24,1),(7,26,1)),(9,25,2,1)), - ((6,29,3,1),((7,28,1),(7,30,1)),(9,29,2,1)), - ((8, 0,3,1),None,None), - ((8, 2,3,1),None,None), - ((8, 4,3,1),None,None), - ((8, 6,3,1),None,None), - ((8, 8,3,1),None,None), - ((8,10,3,1),None,None), - ((8,12,3,1),None,None), - ((8,14,3,1),None,None), - ((8,16,3,1),None,None), - ((8,18,3,1),None,None), - ((8,20,3,1),None,None), - ((8,22,3,1),None,None), - ((8,24,3,1),None,None), - ((8,26,3,1),None,None), - ((8,28,3,1),None,None), - ((8,30,3,1),None,None),) + # A position definition is a tuple of nodes. + # Each node consists of a tuple of: + # (person box rectangle, connection, marriage box rectangle) + # A rectangle is a tuple of the format (x, y, width, height) + # A connectcion is either a line or a tuple of two lines. + # A line is of the format (x, y, height). Lines have a width of 1. + if self.tree_style == 1: + if self.force_size == 2: + pos = (((0, 3, 3, 3), ((1, 0, 3), (1, 6, 3)), (3, 3, 2, 3)), + ((2, 0, 3, 3), None, None), + ((2, 6, 3, 3), None, None)) + elif self.force_size == 3: + pos = (((0, 4, 3, 5), ((1, 1, 3), (1, 9, 3)), (3, 5, 2, 3)), + ((2, 1, 3, 3), ((3, 0, 1), (3, 4, 1)), (5, 1, 2, 3)), + ((2, 9, 3, 3), ((3, 8, 1), (3, 12, 1)), (5, 9, 2, 3)), + ((4, 0, 3, 1), None, None), + ((4,4,3,1),None,None), + ((4,8,3,1),None,None), + ((4,12,3,1),None,None)) + elif self.force_size == 4: + pos = (((0, 5, 3, 5), ((1, 2, 3), (1, 10, 3)), (3, 6, 2, 3)), + ((2, 2, 3, 3), ((3, 1, 1), (3, 5, 1)), (5, 3, 2, 1)), + ((2, 10, 3, 3), ((3, 9, 1), (3, 13, 1)), (5, 11, 2, 1)), + ((4, 1, 3, 1), ((5, 0, 1), (5, 2, 1)), (7, 1, 2, 1)), + ((4, 5, 3, 1), ((5, 4, 1), (5, 6, 1)), (7, 5, 2, 1)), + ((4, 9, 3, 1), ((5, 8, 1), (5, 10, 1)), (7, 9, 2, 1)), + ((4, 13, 3, 1), ((5, 12, 1), (5, 14, 1)), (7, 13, 2, 1)), + ((6, 0, 3, 1), None, None), + ((6, 2, 3, 1), None, None), + ((6, 4, 3, 1), None, None), + ((6, 6, 3, 1), None, None), + ((6, 8, 3, 1), None, None), + ((6, 10, 3, 1), None, None), + ((6, 12, 3, 1), None, None), + ((6, 14, 3, 1), None, None)) + elif self.force_size == 5: + pos = (((0, 10, 3, 11), ((1, 5, 5), (1, 21, 5)), (3, 13, 2, 5)), + ((2, 5, 3, 5), ((3, 2, 3), (3, 10, 3)), (5, 6, 2, 3)), + ((2, 21, 3, 5), ((3, 18, 3), (3, 26, 3)), (5, 22, 2, 3)), + ((4, 2, 3, 3), ((5, 1, 1), (5, 5, 1)), (7, 3, 2, 1)), + ((4, 10, 3, 3), ((5, 9, 1), (5, 13, 1)), (7, 11, 2, 1)), + ((4, 18, 3, 3), ((5, 17, 1), (5, 21, 1)), (7, 19, 2, 1)), + ((4, 26, 3, 3), ((5, 25, 1), (5, 29, 1)), (7, 27, 2, 1)), + ((6, 1, 3, 1), ((7, 0, 1), (7, 2, 1)), (9, 1, 2, 1)), + ((6, 5, 3, 1), ((7, 4, 1), (7, 6, 1)), (9, 5, 2, 1)), + ((6, 9, 3, 1), ((7, 8, 1), (7, 10, 1)), (9, 9, 2, 1)), + ((6, 13, 3, 1), ((7, 12, 1), (7, 14, 1)), (9, 13, 2, 1)), + ((6, 17, 3, 1), ((7, 16, 1), (7, 18, 1)), (9, 17, 2, 1)), + ((6, 21, 3, 1), ((7, 20, 1), (7, 22, 1)), (9, 21, 2, 1)), + ((6, 25, 3, 1), ((7, 24, 1), (7, 26, 1)), (9, 25, 2, 1)), + ((6, 29, 3, 1), ((7, 28, 1), (7, 30, 1)), (9, 29, 2, 1)), + ((8, 0, 3, 1), None, None), + ((8, 2, 3, 1), None, None), + ((8, 4, 3, 1), None, None), + ((8, 6, 3, 1), None, None), + ((8, 8, 3, 1), None, None), + ((8, 10, 3, 1), None, None), + ((8, 12, 3, 1), None, None), + ((8, 14, 3, 1), None, None), + ((8, 16, 3, 1), None, None), + ((8, 18, 3, 1), None, None), + ((8, 20, 3, 1), None, None), + ((8, 22, 3, 1), None, None), + ((8, 24, 3, 1), None, None), + ((8, 26, 3, 1), None, None), + ((8, 28, 3, 1), None, None), + ((8, 30, 3, 1), None, None)) + else: + pos = None # Build ancestor tree only one for all different sizes - lst = [None]*31 - self.find_tree(person,0,1,lst) - - self.rebuild( self.table_2, pos_2, person, lst) - self.rebuild( self.table_3, pos_3, person, lst) - self.rebuild( self.table_4, pos_4, person, lst) - self.rebuild( self.table_5, pos_5, person, lst) - - def rebuild( self, table_widget, positions, active_person, lst): + self._depth = 1 + lst = [None] * (2**self.force_size) + self.find_tree(person, 0, 1, lst) + + if person: + self.rebuild(self.table, pos, lst, self.force_size) + + def rebuild(self, table_widget, positions, lst, size): + """ + Function called from rebuild_trees. + For table_widget (gtk.Table) place list of person, use positions array. + For style C position calculated, for others style use static posotins. + All display options process in this function. + """ # Purge current table content for child in table_widget.get_children(): child.destroy() - table_widget.resize(1,1) - + table_widget.resize(1, 1) + + # Calculate maximum table size xmax = 0 ymax = 0 - for i in range(0,31): - try: - # Table placement for person data - x = positions[i][0][0]+1 - y = positions[i][0][1]+1 - w = positions[i][0][2] - h = positions[i][0][3] - except IndexError: # no position for this person defined - continue - if not lst[i]: - # No person -> show empty box - if cairo_available: - pw = PersonBoxWidget_cairo( self, self.format_helper, None, False, 0, None); + if self.tree_style == 0: + xmax = 2 * size + ymax = 2 ** size + elif self.tree_style == 1: + xmax = 2 * size + 2 + ymax = [0, 8, 12, 14, 30][size - 1] + elif self.tree_style == 2: + # For style C change tree depth if they real size less then max. + if self.show_unknown_people: + self._depth += 1 + if size > self._depth: + size = self._depth + xmax = 2 * size + ymax = 2 ** size * 2 + + pbw = None + for i in range(0, 2 ** size - 1): + #################################################################### + # Table placement for person data + #################################################################### + if self.tree_style in [0, 2]: + # Dynamic position person in tree + width = _width = 1 + height = _height = 3 + level = int(math.log(i+1, 2)) + _y = i + 1 - (2**level) + + if self.tree_style == 0: + _delta = (2**size) / (2**level) else: - pw = PersonBoxWidget( self, self.format_helper, None, False, 0, None); + _delta = (2**size) / (2**level) * 2 + + x = (1 + _width) * level + 1 + y = _delta / 2 + _y * _delta - 1 + + if self.tree_style == 0 and level == size - 1: + y = _delta / 2 + _y * _delta + height = _height = 1 + else: + try: + x = positions[i][0][0]+1 + y = positions[i][0][1]+1 + width = positions[i][0][2] + height = positions[i][0][3] + except IndexError: # no position for this person defined + continue + + last_pbw = pbw + pbw = None + if not lst[i] and \ + ((self.tree_style in [0, 2] and self.show_unknown_people and + lst[((i+1)/2)-1]) or self.tree_style == 1): + # + # No person -> show empty box + # + if cairo_available: + pbw = PersonBoxWidgetCairo(self, self.format_helper, + self.dbstate, None, False, 0, None) + else: + pbw = PersonBoxWidget(self, self.format_helper, + self.dbstate, None, False, 0, None) + if i > 0 and lst[((i+1)/2)-1]: fam_h = None fam = lst[((i+1)/2)-1][2] if fam: fam_h = fam.get_handle() if not self.dbstate.db.readonly: - pw.connect("button-press-event", self.missing_parent_button_press_cb,lst[((i+1)/2)-1][0].get_handle(),fam_h) - pw.force_mouse_over = True - if positions[i][0][2] > 1: - table_widget.attach(pw,x,x+w,y,y+h,gtk.FILL,gtk.FILL,0,0) - else: - table_widget.attach(pw,x,x+w,y,y+h,gtk.FILL,gtk.FILL,0,0) - if x+w > xmax: - xmax = x+w - if y+h > ymax: - ymax = y+h - else: - # Get foto - image = None - if self.show_images and i < ((len(positions)-1)/2) and positions[i][0][3] > 1: - media_list = lst[i][0].get_media_list() - if media_list: - ph = media_list[0] - object_handle = ph.get_reference_handle() - obj = self.dbstate.db.get_object_from_handle(object_handle) - if obj: - mtype = obj.get_mime_type() - if mtype and mtype[0:5] == "image": - image = ThumbNails.get_thumbnail_path( - media_path_full( - self.dbstate.db, - obj.get_path()), - rectangle=ph.get_rectangle()) - if cairo_available: - pw = PersonBoxWidget_cairo( self, self.format_helper, lst[i][0], lst[i][3], positions[i][0][3], image); - else: - pw = PersonBoxWidget( self, self.format_helper, lst[i][0], lst[i][3], positions[i][0][3], image); - if positions[i][0][3] < 7: - pw.set_tooltip_text(self.format_helper.format_person(lst[i][0], 11)) + pbw.connect("button-press-event", + self.missing_parent_button_press_cb, + lst[((i+1)/2)-1][0].get_handle(), fam_h) + pbw.force_mouse_over = True - pw.connect("button-press-event", self.person_button_press_cb,lst[i][0].get_handle()) - if positions[i][0][2] > 1: - table_widget.attach(pw,x,x+w,y,y+h,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,0) + elif lst[i]: + # + # Person exists -> populate box + # + image = False + if self.show_images and height > 1 and \ + (i < ((2**size-1)/2) or self.tree_style == 2): + image = True + + if cairo_available: + pbw = PersonBoxWidgetCairo(self, self.format_helper, + self.dbstate, lst[i][0], lst[i][3], height, image) else: - table_widget.attach(pw,x,x+w,y,y+h,gtk.FILL,gtk.FILL,0,0) - if x+w > xmax: - xmax = x+w - if y+h > ymax: - ymax = y+h + pbw = PersonBoxWidget(self, self.format_helper, + self.dbstate, lst[i][0], lst[i][3], height, image) + lst[i][4] = pbw + if height < 7: + pbw.set_tooltip_text(self.format_helper.format_person( + lst[i][0], 11)) + + fam_h = None + if lst[i][2]: + fam_h = lst[i][2].get_handle() + pbw.connect("button-press-event", + self.person_button_press_cb, + lst[i][0].get_handle(), fam_h) + + if pbw: + self.attach_widget(table_widget, pbw, xmax, + x, x+width, y, y+height) + #################################################################### # Connection lines - if positions[i][1] and len(positions[i][1]) == 2: + #################################################################### + if self.tree_style == 1 and \ + positions[i][1] and len(positions[i][1]) == 2: # separate boxes for father and mother x = positions[i][1][0][0]+1 y = positions[i][1][0][1]+1 - w = 1 - h = positions[i][1][0][2] - line = gtk.DrawingArea() - line.set_size_request(20,-1) - line.connect("expose-event", self.line_expose_cb) + width = 1 + height = positions[i][1][0][2] + + rela = False + if lst[2*i+1]: # Father + rela = lst[2*i+1][1] + line = LineWidget2(1, rela, self.tree_direction) + if lst[i] and lst[i][2]: - line.add_events(gtk.gdk.BUTTON_PRESS_MASK) # Required for popup menu - line.connect("button-press-event", self.relation_button_press_cb,lst[i][2].get_handle()) - line.set_data("idx", i*2+1) - if lst[i*2+1]: - line.set_data("rela", lst[i*2+1][1]) - table_widget.attach(line,x,x+w,y,y+h,gtk.FILL,gtk.FILL,0,0) - if x+w > xmax: - xmax = x+w - if y+h > ymax: - ymax = y+h - + # Required for popup menu + line.add_events(gtk.gdk.BUTTON_PRESS_MASK) + line.connect("button-press-event", + self.relation_button_press_cb, + lst[i][2].get_handle()) + + self.attach_widget(table_widget, line, xmax, + x, x+width, y, y+height) + x = positions[i][1][1][0]+1 y = positions[i][1][1][1]+1 w = 1 h = positions[i][1][1][2] - line = gtk.DrawingArea() - line.set_size_request(20,-1) - line.connect("expose-event", self.line_expose_cb) + + rela = False + if lst[2*i+2]: # Mother + rela = lst[2*i+2][1] + line = LineWidget2(0, rela, self.tree_direction) + if lst[i] and lst[i][2]: - line.add_events(gtk.gdk.BUTTON_PRESS_MASK) # Required for popup menu - line.connect("button-press-event", self.relation_button_press_cb,lst[i][2].get_handle()) - line.set_data("idx", i*2+2) - if lst[i*2+2]: - line.set_data("rela", lst[i*2+2][1]) - table_widget.attach(line,x,x+w,y,y+h,gtk.FILL,gtk.FILL,0,0) - if x+w > xmax: - xmax = x+w - if y+h > ymax: - ymax = y+h - if positions[i][1] and len(positions[i][1]) == 3: + # Required for popup menu + line.add_events(gtk.gdk.BUTTON_PRESS_MASK) + line.connect("button-press-event", + self.relation_button_press_cb, + lst[i][2].get_handle()) + + self.attach_widget(table_widget, line, xmax, + x, x+width, y, y+height) + + elif self.tree_style in [0, 2] and lst[((i+1)/2)-1]: # combined for father and mother - x = positions[i][1][0]+1 - y = positions[i][1][1]+1 - w = 1 - h = positions[i][1][2] - line = gtk.DrawingArea() - line.set_size_request(20,-1) - line.connect("expose-event", self.tree_expose_cb) - if lst[i] and lst[i][2]: - line.add_events(gtk.gdk.BUTTON_PRESS_MASK) # Required for popup menu - line.connect("button-press-event", self.relation_button_press_cb,lst[i][2].get_handle()) - line.set_data("height", h) - if lst[i] and lst[i][2]: - line.add_events(gtk.gdk.ENTER_NOTIFY_MASK) # Required for tooltip and mouse-over - line.add_events(gtk.gdk.LEAVE_NOTIFY_MASK) # Required for tooltip and mouse-over - line.set_tooltip_text(self.format_helper.format_relation(lst[i][2], 11)) - if lst[i*2+1]: - line.set_data("frela", lst[i*2+1][1]) - if lst[i*2+2]: - line.set_data("mrela", lst[i*2+2][1]) - table_widget.attach(line,x,x+w,y,y+h,gtk.FILL,gtk.FILL,0,0) - if x+w > xmax: - xmax = x+w - if y+h > ymax: - ymax = y+h - + x = (1 + _width) * level + y = _y * _delta - (_delta / 2) - 1 + width = 1 + height = _delta + 3 + + if self.tree_style == 0 and level == size - 1: + height -= 2 + y += 1 + + if i > 0 and i % 2 == 0 and (pbw or last_pbw): + frela = mrela = None + if lst[i]: + frela = lst[i][1] + if lst[i - 1]: + mrela = lst[i-1][1] + + line = LineWidget(lst[((i+1)/2)-1][4], + last_pbw, mrela, + pbw, frela, + self.tree_direction) + + if lst[i] and lst[i][2]: + # Required for popup menu + line.add_events(gtk.gdk.BUTTON_PRESS_MASK) + line.connect("button-press-event", + self.relation_button_press_cb, + lst[i][2].get_handle()) + # Required for tooltip and mouse-over + line.add_events(gtk.gdk.ENTER_NOTIFY_MASK) + # Required for tooltip and mouse-over + line.add_events(gtk.gdk.LEAVE_NOTIFY_MASK) + line.set_tooltip_text( + self.format_helper.format_relation( + lst[((i+1)/2)-1][2], 11)) + + self.attach_widget(table_widget, line, xmax, + x, x+width, y, y+height) + + #################################################################### # Show marriage data - if self.show_marriage_data and positions[i][2]: + #################################################################### + if self.show_marriage_data and \ + ((self.tree_style == 1 and positions[i][2]) or + (self.tree_style in [0, 2] and (level+1) < size)): if lst[i] and lst[i][2]: - text = self.format_helper.format_relation( lst[i][2], positions[i][2][3]) + text = self.format_helper.format_relation(lst[i][2], 1) else: text = " " label = gtk.Label(text) label.set_justify(gtk.JUSTIFY_LEFT) label.set_line_wrap(True) - label.set_alignment(0.1,0.5) - x = positions[i][2][0]+1 - y = positions[i][2][1]+1 - w = positions[i][2][2] - h = positions[i][2][3] - table_widget.attach(label,x,x+w,y,y+h,gtk.FILL,gtk.FILL,0,0) - + label.set_alignment(0.1, 0.5) + if self.tree_style in [0, 2]: + x = (1 + _width) * (level + 1) + 1 + y = _delta / 2 + _y * _delta -1 + _height / 2 + width = 1 + height = 1 + if self.tree_style == 0 and level < 2: + y -= 2 + height +=4 + else: + x = positions[i][2][0]+1 + y = positions[i][2][1]+1 + width = positions[i][2][2] + height = positions[i][2][3] + + self.attach_widget(table_widget, label, xmax, + x, x+width, y, y+height) + + ######################################################################## # Add navigation arrows + ######################################################################## if lst[0]: - l=gtk.Button() - l.add(gtk.Arrow(gtk.ARROW_LEFT, gtk.SHADOW_IN)) - childlist = find_children(self.dbstate.db,lst[0][0]) + if self.tree_direction == 2: + child_arrow = gtk.ARROW_LEFT + parent_arrow = gtk.ARROW_RIGHT + elif self.tree_direction == 0: + child_arrow = gtk.ARROW_UP + parent_arrow = gtk.ARROW_DOWN + elif self.tree_direction == 1: + child_arrow = gtk.ARROW_DOWN + parent_arrow = gtk.ARROW_UP + elif self.tree_direction == 3: + child_arrow = gtk.ARROW_RIGHT + parent_arrow = gtk.ARROW_LEFT + + button = gtk.Button() + button.add(gtk.Arrow(child_arrow, gtk.SHADOW_IN)) + childlist = find_children(self.dbstate.db, lst[0][0]) if childlist: - l.connect("clicked",self.on_show_child_menu) - l.set_tooltip_text(_("Jump to child...")) + button.connect("clicked", self.on_show_child_menu) + button.set_tooltip_text(_("Jump to child...")) else: - l.set_sensitive(False) + button.set_sensitive(False) + ymid = int(math.floor(ymax/2)) - table_widget.attach(l,0,1,ymid,ymid+1,0,0,0,0) - l = gtk.Button() - l.add(gtk.Arrow(gtk.ARROW_RIGHT, gtk.SHADOW_IN)) + self.attach_widget(table_widget, button, xmax, + 0, 1, ymid, ymid +1, fill=False) + + button = gtk.Button() + button.add(gtk.Arrow(parent_arrow, gtk.SHADOW_IN)) if lst[1]: - l.connect("clicked",self.on_childmenu_changed,lst[1][0].handle) - l.set_tooltip_text(("Jump to father")) + button.connect("clicked", self.on_childmenu_changed, + lst[1][0].handle) + button.set_tooltip_text(("Jump to father")) else: - l.set_sensitive(False) + button.set_sensitive(False) + ymid = int(math.floor(ymax/4)) - table_widget.attach(l,xmax,xmax+1,ymid-1,ymid+2,0,0,0,0) - l = gtk.Button() - l.add(gtk.Arrow(gtk.ARROW_RIGHT, gtk.SHADOW_IN)) + self.attach_widget(table_widget, button, xmax, + xmax, xmax+1, ymid-1, ymid+2, fill=False) + + button = gtk.Button() + button.add(gtk.Arrow(parent_arrow, gtk.SHADOW_IN)) if lst[2]: - l.connect("clicked",self.on_childmenu_changed,lst[2][0].handle) - l.set_tooltip_text(_("Jump to mother")) + button.connect("clicked", self.on_childmenu_changed, + lst[2][0].handle) + button.set_tooltip_text(_("Jump to mother")) else: - l.set_sensitive(False) + button.set_sensitive(False) + ymid = int(math.floor(ymax/4*3)) - table_widget.attach(l,xmax,xmax+1,ymid-1,ymid+2,0,0,0,0) - - # add dummy widgets into the corners of the table to allow the pedigree to be centered - l = gtk.Label("") - table_widget.attach(l,0,1,0,1,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,0) - l = gtk.Label("") - table_widget.attach(l,xmax,xmax+1,ymax,ymax+1,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,0) + self.attach_widget(table_widget, button, xmax, + xmax, xmax+1, ymid-1, ymid+2, fill=False) + + # add dummy widgets into the corners of the table + # to allow the pedigree to be centered + label = gtk.Label("") + table_widget.attach(label, 0, 1, 0, 1, + gtk.EXPAND|gtk.FILL, gtk.EXPAND|gtk.FILL, 0, 0) + label = gtk.Label("") + if self.tree_direction in [2, 3]: + table_widget.attach(label, xmax, xmax+1, ymax, ymax+1, + gtk.EXPAND|gtk.FILL, gtk.EXPAND|gtk.FILL, 0, 0) + else: + table_widget.attach(label, ymax, ymax+1, xmax, xmax+1, + gtk.EXPAND|gtk.FILL, gtk.EXPAND|gtk.FILL, 0, 0) debug = False if debug: @@ -926,88 +1267,97 @@ class PedigreeView(NavigationView): xmax = 0 ymax = 0 # iterate table to see which cells are used. - for c in table_widget.get_children(): - l=table_widget.child_get_property(c,"left-attach") - r=table_widget.child_get_property(c,"right-attach") - t=table_widget.child_get_property(c,"top-attach") - b=table_widget.child_get_property(c,"bottom-attach") - for x in range(l,r): - for y in range(t,b): + for child in table_widget.get_children(): + left = table_widget.child_get_property(child, "left-attach") + right = table_widget.child_get_property(child, "right-attach") + top = table_widget.child_get_property(child, "top-attach") + bottom = table_widget.child_get_property(child, "bottom-attach") + for x in range(left, right): + for y in range(top, bottom): try: - used_cells[x][y] = True; + used_cells[x][y] = True except KeyError: used_cells[x] = {} - used_cells[x][y] = True; + used_cells[x][y] = True if y > ymax: ymax = y if x > xmax: xmax = x - for x in range(0,xmax+1): - for y in range(0,ymax+1): + for x in range(0, xmax+1): + for y in range(0, ymax+1): try: tmp = used_cells[x][y] except KeyError: # fill unused cells - label=gtk.Label("%d,%d"%(x,y)) - frame = gtk.ScrolledWindow(None,None) + label = gtk.Label("%d,%d"%(x, y)) + frame = gtk.ScrolledWindow(None, None) frame.set_shadow_type(gtk.SHADOW_NONE) - frame.set_policy(gtk.POLICY_NEVER,gtk.POLICY_NEVER) + frame.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER) frame.add_with_viewport(label) - table_widget.attach(frame,x,x+1,y,y+1,gtk.FILL,gtk.FILL,0,0) + table_widget.attach(frame, x, x+1, y, y+1, + gtk.FILL, gtk.FILL, 0, 0) table_widget.show_all() - def line_expose_cb(self, area, event): - gc = area.window.new_gc() - alloc = area.get_allocation() - idx = area.get_data("idx") - rela = area.get_data("rela") - if not rela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - gc.line_width = 3 - if idx %2 == 0: - area.window.draw_line(gc, alloc.width, alloc.height/2, alloc.width/2,alloc.height/2) - area.window.draw_line(gc, alloc.width/2, 0, alloc.width/2,alloc.height/2) - else: - area.window.draw_line(gc, alloc.width, alloc.height/2, alloc.width/2,alloc.height/2) - area.window.draw_line(gc, alloc.width/2, alloc.height, alloc.width/2,alloc.height/2) + # Setup scrollbars for view root person + window = table_widget.get_parent().get_parent() + hadjustment = window.get_hadjustment() + vadjustment = window.get_vadjustment() + if self.tree_direction == 2: + self.update_scrollbar_positions(hadjustment, hadjustment.lower) + self.update_scrollbar_positions(vadjustment, + (vadjustment.upper - vadjustment.page_size) / 2) + elif self.tree_direction == 0: + self.update_scrollbar_positions(hadjustment, + (hadjustment.upper - hadjustment.page_size) / 2) + self.update_scrollbar_positions(vadjustment, + vadjustment.upper - vadjustment.page_size) + elif self.tree_direction == 1: + self.update_scrollbar_positions(hadjustment, + (hadjustment.upper - hadjustment.page_size) / 2) + self.update_scrollbar_positions(vadjustment, vadjustment.lower) + elif self.tree_direction == 3: + self.update_scrollbar_positions(hadjustment, + hadjustment.upper - hadjustment.page_size) + self.update_scrollbar_positions(vadjustment, + (vadjustment.upper - vadjustment.page_size) / 2) - def tree_expose_cb(self, area, event): - gc = area.window.new_gc() - alloc = area.get_allocation() - h = area.get_data("height") - gap = alloc.height / (h*2) - frela = area.get_data("frela") - mrela = area.get_data("mrela") - if not frela and not mrela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - gc.line_width = 3 - rela = area.get_data("mrela") - area.window.draw_line(gc, 0, alloc.height/2, alloc.width/2,alloc.height/2) + # Setup mouse wheel scroll direction for style C, + # depending of tree direction + if self.tree_direction in [0, 1]: + self.change_scroll_direction_cb(None, True) + elif self.tree_direction in [2, 3]: + self.change_scroll_direction_cb(None, False) - if not frela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - area.window.draw_line(gc, alloc.width/2, alloc.height/2, alloc.width/2,gap) - area.window.draw_line(gc, alloc.width/2, gap, alloc.width,gap) - - if not mrela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - area.window.draw_line(gc, alloc.width/2, alloc.height/2, alloc.width/2,alloc.height-gap) - area.window.draw_line(gc, alloc.width/2, alloc.height-gap, alloc.width,alloc.height-gap) + def attach_widget(self, table, widget, xmax, x1, x2, y1, y2, fill=True): + """ + Attach a widget to the table. + """ + xopts = yopts = 0 + if fill: + xopts = yopts = gtk.FILL - def home(self, obj): + if self.tree_direction == 0: # Vertical (top to bottom) + table.attach(widget, y1, y2, x1, x2, xopts, yopts, 0, 0) + elif self.tree_direction == 1: # Vertical (bottom to top) + table.attach(widget, y1, y2, xmax - x2 + 1, xmax - x1 + 1, + xopts, yopts, 0, 0) + elif self.tree_direction == 2: # Horizontal (left to right) + table.attach(widget, x1, x2, y1, y2, xopts, yopts, 0, 0) + elif self.tree_direction == 3: # Horizontal (right to left) + table.attach(widget, xmax - x2 + 1, xmax - x1 + 1, y1, y2, + xopts, yopts, 0, 0) + + def home(self, menuitem): + """Change root person to default person for database.""" defperson = self.dbstate.db.get_default_person() if defperson: self.change_active(defperson.get_handle()) - def edit_person_cb(self, obj,person_handle): + def edit_person_cb(self, obj, person_handle): + """ + Open edit person window for person_handle. + Called after double click or from submenu. + """ person = self.dbstate.db.get_person_from_handle(person_handle) if person: try: @@ -1017,7 +1367,11 @@ class PedigreeView(NavigationView): return True return False - def edit_family_cb(self, obj,family_handle): + def edit_family_cb(self, obj, family_handle): + """ + Open edit person family for family_handle. + Called after double click or from submenu. + """ family = self.dbstate.db.get_family_from_handle(family_handle) if family: try: @@ -1027,7 +1381,8 @@ class PedigreeView(NavigationView): return True return False - def add_parents_cb(self, obj,person_handle, family_handle): + def add_parents_cb(self, obj, person_handle, family_handle): + """Edit not full family.""" if family_handle: # one parent already exists -> Edit current family family = self.dbstate.db.get_family_from_handle(family_handle) else: # no parents -> create new family @@ -1036,65 +1391,147 @@ class PedigreeView(NavigationView): childref.set_reference_handle(person_handle) family.add_child_ref(childref) try: - EditFamily(self.dbstate,self.uistate,[],family) + EditFamily(self.dbstate, self.uistate, [], family) except Errors.WindowActiveError: pass - def copy_person_to_clipboard_cb(self, obj,person_handle): - """Renders the person data into some lines of text and puts that into the clipboard""" + def copy_person_to_clipboard_cb(self, obj, person_handle): + """ + Renders the person data into some lines of text and + puts that into the clipboard + """ person = self.dbstate.db.get_person_from_handle(person_handle) if person: - cb = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD) - cb.set_text( self.format_helper.format_person(person,11)) + clipboard = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD) + clipboard.set_text(self.format_helper.format_person(person, 11)) return True return False - def copy_family_to_clipboard_cb(self, obj,family_handle): - """Renders the family data into some lines of text and puts that into the clipboard""" + def copy_family_to_clipboard_cb(self, obj, family_handle): + """ + Renders the family data into some lines of text and + puts that into the clipboard + """ family = self.dbstate.db.get_family_from_handle(family_handle) if family: - cb = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD) - cb.set_text( self.format_helper.format_relation(family,11)) + clipboard = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD) + clipboard.set_text(self.format_helper.format_relation(family, 11)) return True return False - def on_show_option_menu_cb(self, obj,data=None): - myMenu = gtk.Menu() - self.add_nav_portion_to_menu(myMenu) - self.add_settings_to_menu(myMenu) - myMenu.popup(None,None,None,0,0) - return(True); + def on_show_option_menu_cb(self, obj, event, data=None): + """Right click option menu.""" + menu = gtk.Menu() + self.add_nav_portion_to_menu(menu) + self.add_settings_to_menu(menu) + menu.popup(None, None, None, 0, event.time) + return True - def bg_button_press_cb(self, obj,event): - if event.button != 1: - self.on_show_option_menu_cb(obj) + def bg_button_press_cb(self, widget, event): + """ + Enter in scroll mode when mouse button pressed in background + or call option menu. + """ + if event.button == 1 and event.type == gtk.gdk.BUTTON_PRESS: + widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR)) + self._last_x = event.x + self._last_y = event.y + self._in_move = True + return True + elif event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: + self.on_show_option_menu_cb(widget, event) return True return False - - def person_button_press_cb(self, obj,event,person_handle): - if event.button==1 and event.type == gtk.gdk._2BUTTON_PRESS: - self.edit_person_cb( obj, person_handle) - elif event.button!=1: - self.build_full_nav_menu_cb(obj,event,person_handle) + + def bg_button_release_cb(self, widget, event): + """Exit from scroll mode when button release.""" + if event.button == 1 and event.type == gtk.gdk.BUTTON_RELEASE: + self.bg_motion_notify_event_cb(widget, event) + widget.window.set_cursor(None) + self._in_move = False + return True + return False + + def bg_motion_notify_event_cb(self, widget, event): + """Function for motion notify events for drag and scroll mode.""" + if self._in_move and (event.type == gtk.gdk.MOTION_NOTIFY or \ + event.type == gtk.gdk.BUTTON_RELEASE): + window = widget.get_parent() + hadjustment = window.get_hadjustment() + vadjustment = window.get_vadjustment() + self.update_scrollbar_positions(vadjustment, + vadjustment.value - (event.y - self._last_y)) + self.update_scrollbar_positions(hadjustment, + hadjustment.value - (event.x - self._last_x)) + return True + return False + + def update_scrollbar_positions(self, adjustment, value): + """Controle value then try setup in scrollbar.""" + if value > (adjustment.upper - adjustment.page_size): + adjustment.set_value(adjustment.upper - adjustment.page_size) + else: + adjustment.set_value(value) return True - def relation_button_press_cb(self, obj,event,family_handle): - if event.button==1 and event.type == gtk.gdk._2BUTTON_PRESS: - self.edit_family_cb( obj, family_handle) - elif event.button!=1: - self.build_relation_nav_menu_cb(obj,event,family_handle) + def bg_scroll_event(self, widget, event): + """ + Function change scroll direction to horizontally + if variable self.scroll_direction setup. + """ + if self.scroll_direction and event.type == gtk.gdk.SCROLL: + if event.direction == gtk.gdk.SCROLL_UP: + event.direction = gtk.gdk.SCROLL_LEFT + elif event.direction == gtk.gdk.SCROLL_DOWN: + event.direction = gtk.gdk.SCROLL_RIGHT + return False + + def person_button_press_cb(self, obj, event, person_handle, family_handle): + """ + Call edit person function for mouse left button double click on person + or submenu for person for mouse right click. + And setup plug for button press on person widget. + """ + if event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: + self.build_full_nav_menu_cb(obj, event, + person_handle, family_handle) + return True + elif event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS: + self.edit_person_cb(obj, person_handle) + return True return True - def missing_parent_button_press_cb(self, obj,event,person_handle,family_handle): - if event.button==1 and event.type == gtk.gdk._2BUTTON_PRESS: - self.add_parents_cb(obj,person_handle,family_handle) - elif event.button!=1: - self.build_missing_parent_nav_menu_cb(obj,event,person_handle,family_handle) + def relation_button_press_cb(self, obj, event, family_handle): + """ + Call edit family function for mouse left button double click + on family line or call full submenu for mouse right click. + And setup plug for button press on family line. + """ + if event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: + self.build_relation_nav_menu_cb(obj, event, family_handle) + return True + elif event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS: + self.edit_family_cb(obj, family_handle) + return True return True + def missing_parent_button_press_cb(self, obj, event, + person_handle, family_handle): + """ + Call function for not full family for mouse left button double click + on missing persons or call submenu for mouse right click. + """ + if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS: + self.add_parents_cb(obj, person_handle, family_handle) + return True + elif event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: + self.build_missing_parent_nav_menu_cb(obj, event, person_handle, + family_handle) + return True + return False + def on_show_child_menu(self, obj): """User clicked button to move to child of active person""" - person = self.dbstate.db.get_person_from_handle(self.get_active()) if person: # Build and display the menu attached to the left pointing arrow @@ -1111,137 +1548,204 @@ class PedigreeView(NavigationView): for child_handle in childlist: child = self.dbstate.db.get_person_from_handle(child_handle) cname = escape(name_displayer.display(child)) - if find_children(self.dbstate.db,child): + if find_children(self.dbstate.db, child): label = gtk.Label('%s' % cname) else: label = gtk.Label(cname) label.set_use_markup(True) label.show() - label.set_alignment(0,0) + label.set_alignment(0, 0) menuitem = gtk.ImageMenuItem(None) - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO,gtk.ICON_SIZE_MENU) + go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, + gtk.ICON_SIZE_MENU) go_image.show() menuitem.set_image(go_image) menuitem.add(label) myMenu.append(menuitem) - menuitem.connect("activate",self.on_childmenu_changed,child_handle) + menuitem.connect("activate", self.on_childmenu_changed, + child_handle) menuitem.show() - myMenu.popup(None,None,None,0,0) + myMenu.popup(None, None, None, 0, 0) return 1 return 0 - def on_childmenu_changed(self, obj,person_handle): - """Callback for the pulldown menu selection, changing to the person - attached with menu item.""" + def on_childmenu_changed(self, obj, person_handle): + """ + Callback for the pulldown menu selection, changing to the person + attached with menu item. + """ self.change_active(person_handle) return True - - def change_force_size_cb(self,event,data): - if data in [0,2,3,4,5]: - config.set('interface.pedview-tree-size',data) + + def change_force_size_cb(self, menuitem, data): + """Change force_size option.""" + if data in [2, 3, 4, 5, 6, 7, 8, 9, 10]: + config.set('interface.pedview-tree-size', data) self.force_size = data self.dirty = True - self.size_request_cb(self.notebook.parent,None) # switch to matching size + # switch to matching size + self.rebuild_trees(self.get_active()) - def change_tree_style_cb(self,event,data): - if data in [0,1]: - config.set('interface.pedview-layout',data) + def change_tree_style_cb(self, menuitem, data): + """Change tree_style option.""" + if data in [0, 1, 2]: + config.set('interface.pedview-layout', data) if self.tree_style != data: + if data == 1 and self.force_size > 5: + self.force_size = 5 self.dirty = True self.tree_style = data - self.rebuild_trees(self.get_active()) # Rebuild using new style + self.rebuild_trees(self.get_active()) - def change_show_images_cb(self,event): + def change_tree_direction_cb(self, menuitem, data): + """Change tree_direction option.""" + if data in [0, 1, 2, 3]: + config.set('interface.pedview-tree-direction', data) + if self.tree_direction != data: + self.dirty = True + self.tree_direction = data + self.rebuild_trees(self.get_active()) + + def change_show_images_cb(self, event): + """Change show_images option.""" self.show_images = not self.show_images - config.set('interface.pedview-show-images',self.show_images) + config.set('interface.pedview-show-images', self.show_images) self.dirty = True - self.rebuild_trees(self.get_active()) # Rebuild using new style + self.rebuild_trees(self.get_active()) - def change_show_marriage_cb(self,event): + def change_show_marriage_cb(self, event): + """Change show_marriage_data option.""" self.show_marriage_data = not self.show_marriage_data - config.set('interface.pedview-show-marriage', self.show_marriage_data) + config.set('interface.pedview-show-marriage', + self.show_marriage_data) self.dirty = True - self.rebuild_trees(self.get_active()) # Rebuild using new style + self.rebuild_trees(self.get_active()) - def find_tree(self,person,index,depth,lst,val=0): + def change_show_unknown_people_cb(self, event): + """Change show_unknown_people option.""" + self.show_unknown_people = not self.show_unknown_people + config.set('interface.pedview-show-unknown-people', + self.show_unknown_people) + self.dirty = True + self.rebuild_trees(self.get_active()) + + def change_scroll_direction_cb(self, menuitem, data): + """Change scroll_direction option.""" + config.set('interface.pedview-scroll-direction', + self.scroll_direction) + if data: + self.scroll_direction = True + else: + self.scroll_direction = False + + def kb_goto_home(self): + """Goto home person from keyboard.""" + self.home(None) + + def kb_plus_generation(self): + """Increment size of tree from keyboard.""" + self.change_force_size_cb(None, self.force_size + 1) + + def kb_minus_generation(self): + """Decrement size of tree from keyboard.""" + self.change_force_size_cb(None, self.force_size - 1) + + def kb_change_style(self): + """Change style of tree from keyboard.""" + next_style = self.tree_style + 1 + if next_style > 2: + next_style = 0 + self.change_tree_style_cb(None, next_style) + + def kb_change_direction(self): + """Change direction of tree from keyboard.""" + next_direction = self.tree_direction + 1 + if next_direction > 3: + next_direction = 0 + self.change_tree_direction_cb(None, next_direction) + + def find_tree(self, person, index, depth, lst, val=0): """Recursively build a list of ancestors""" - if depth > 5 or person is None: + if depth > self.force_size or not person: return + if self._depth < depth: + self._depth = depth + try: alive = probably_alive(person, self.dbstate.db) except RuntimeError: ErrorDialog(_('Relationship loop detected'), _('A person was found to be his/her own ancestor.')) alive = False - - lst[index] = (person,val,None,alive) + + lst[index] = [person, val, None, alive, None] parent_families = person.get_parent_family_handle_list() if parent_families: family_handle = parent_families[0] else: return - + mrel = True frel = True family = self.dbstate.db.get_family_from_handle(family_handle) - if family is not None: + if family: for child_ref in family.get_child_ref_list(): if child_ref.ref == person.handle: mrel = child_ref.mrel == gen.lib.ChildRefType.BIRTH frel = child_ref.frel == gen.lib.ChildRefType.BIRTH - - lst[index] = (person,val,family,alive) - father_handle = family.get_father_handle() - if father_handle is not None: - father = self.dbstate.db.get_person_from_handle(father_handle) - self.find_tree(father,(2*index)+1,depth+1,lst,frel) - mother_handle = family.get_mother_handle() - if mother_handle is not None: - mother = self.dbstate.db.get_person_from_handle(mother_handle) - self.find_tree(mother,(2*index)+2,depth+1,lst,mrel) - def add_nav_portion_to_menu(self,menu): + lst[index] = [person, val, family, alive, None] + father_handle = family.get_father_handle() + if father_handle: + father = self.dbstate.\ + db.get_person_from_handle(father_handle) + self.find_tree(father, (2*index)+1, depth+1, lst, frel) + mother_handle = family.get_mother_handle() + if mother_handle: + mother = self.dbstate.\ + db.get_person_from_handle(mother_handle) + self.find_tree(mother, (2*index)+2, depth+1, lst, mrel) + + def add_nav_portion_to_menu(self, menu): """ - This function adds a common history-navigation portion - to the context menu. Used by both build_nav_menu() and - build_full_nav_menu() methods. + This function adds a common history-navigation portion + to the context menu. Used by both build_nav_menu() and + build_full_nav_menu() methods. """ - #back_sensitivity = self.parent.hindex > 0 - #fwd_sensitivity = self.parent.hindex + 1 < len(self.parent.history) + hobj = self.uistate.get_history(self.navigation_type(), + self.navigation_group()) + home_sensitivity = True + if not self.dbstate.db.get_default_person(): + home_sensitivity = False entries = [ - #(gtk.STOCK_GO_BACK,self.parent.back_clicked,back_sensitivity), - #(gtk.STOCK_GO_FORWARD,self.parent.fwd_clicked,fwd_sensitivity), - #FIXME: revert to stock item when German gtk translation is fixed - #(gtk.STOCK_HOME,self.parent.on_home_clicked,1), - (_("Home"),self.home,1), - (None,None,0), - #(_("Set anchor"),self.on_anchor_set,1), - #(_("Remove anchor"),self.on_anchor_removed,1), + (gtk.STOCK_GO_BACK, self.back_clicked, not hobj.at_front()), + (gtk.STOCK_GO_FORWARD, self.fwd_clicked, not hobj.at_end()), + (gtk.STOCK_HOME, self.home, home_sensitivity), + (None, None, 0) ] - for stock_id,callback,sensitivity in entries: + for stock_id, callback, sensitivity in entries: item = gtk.ImageMenuItem(stock_id) - #FIXME: remove when German gtk translation is fixed - if stock_id == _("Home"): - im = gtk.image_new_from_stock(gtk.STOCK_HOME,gtk.ICON_SIZE_MENU) - im.show() - item.set_image(im) - if not self.dbstate.db.get_default_person(): - item.set_sensitive(False) - else: - item.set_sensitive(sensitivity) + item.set_sensitive(sensitivity) if callback: - item.connect("activate",callback) + item.connect("activate", callback) item.show() menu.append(item) - def add_settings_to_menu(self,menu): + def add_settings_to_menu(self, menu): + """ + Add settings to menu (Show images, Show marriage data, + Show unknown people, Mouse scroll direction, Tree style, + Tree size, Tree direction), marked selected items. + Othet menu for othet styles. + """ entry = gtk.ImageMenuItem(_("Show images")) if self.show_images: - current_show_images_image = gtk.image_new_from_stock(gtk.STOCK_APPLY,gtk.ICON_SIZE_MENU) + current_show_images_image = \ + gtk.image_new_from_stock(gtk.STOCK_APPLY, gtk.ICON_SIZE_MENU) current_show_images_image.show() entry.set_image(current_show_images_image) entry.connect("activate", self.change_show_images_cb) @@ -1250,86 +1754,181 @@ class PedigreeView(NavigationView): entry = gtk.ImageMenuItem(_("Show marriage data")) if self.show_marriage_data: - current_show_marriage_image = gtk.image_new_from_stock(gtk.STOCK_APPLY,gtk.ICON_SIZE_MENU) + current_show_marriage_image = \ + gtk.image_new_from_stock(gtk.STOCK_APPLY, gtk.ICON_SIZE_MENU) current_show_marriage_image.show() entry.set_image(current_show_marriage_image) entry.connect("activate", self.change_show_marriage_cb) entry.show() menu.append(entry) + if self.tree_style in [0, 2]: + entry = gtk.ImageMenuItem(_("Show unknown people")) + if self.show_unknown_people: + current_show_unknown_people_image = \ + gtk.image_new_from_stock(gtk.STOCK_APPLY, + gtk.ICON_SIZE_MENU) + current_show_unknown_people_image.show() + entry.set_image(current_show_unknown_people_image) + entry.connect("activate", self.change_show_unknown_people_cb) + entry.show() + menu.append(entry) + + item = gtk.MenuItem(_("Mouse scroll direction")) + item.set_submenu(gtk.Menu()) + scroll_direction_menu = item.get_submenu() + + scroll_direction_image = gtk.image_new_from_stock(gtk.STOCK_APPLY, + gtk.ICON_SIZE_MENU) + scroll_direction_image.show() + + entry = gtk.ImageMenuItem(_("Top <-> Bottom")) + entry.connect("activate", self.change_scroll_direction_cb, False) + if self.scroll_direction == False: + entry.set_image(scroll_direction_image) + entry.show() + scroll_direction_menu.append(entry) + + entry = gtk.ImageMenuItem(_("Left <-> Right")) + entry.connect("activate", self.change_scroll_direction_cb, True) + if self.scroll_direction == True: + entry.set_image(scroll_direction_image) + entry.show() + scroll_direction_menu.append(entry) + + scroll_direction_menu.show() + item.show() + menu.append(item) + item = gtk.MenuItem(_("Tree style")) item.set_submenu(gtk.Menu()) style_menu = item.get_submenu() - current_style_image = gtk.image_new_from_stock(gtk.STOCK_APPLY,gtk.ICON_SIZE_MENU) + current_style_image = gtk.image_new_from_stock(gtk.STOCK_APPLY, + gtk.ICON_SIZE_MENU) current_style_image.show() - entry = gtk.ImageMenuItem(_("Version A")) - entry.connect("activate", self.change_tree_style_cb,0) + entry = gtk.ImageMenuItem(_("Standard")) + entry.connect("activate", self.change_tree_style_cb, 0) if self.tree_style == 0: entry.set_image(current_style_image) entry.show() style_menu.append(entry) - entry = gtk.ImageMenuItem(_("Version B")) - entry.connect("activate", self.change_tree_style_cb,1) + entry = gtk.ImageMenuItem(_("Compact")) + entry.connect("activate", self.change_tree_style_cb, 1) if self.tree_style == 1: entry.set_image(current_style_image) entry.show() style_menu.append(entry) + entry = gtk.ImageMenuItem(_("Expanded")) + entry.connect("activate", self.change_tree_style_cb, 2) + if self.tree_style == 2: + entry.set_image(current_style_image) + entry.show() + style_menu.append(entry) + style_menu.show() item.show() menu.append(item) - item = gtk.MenuItem(_("Tree size")) item.set_submenu(gtk.Menu()) size_menu = item.get_submenu() - - current_size_image = gtk.image_new_from_stock(gtk.STOCK_APPLY,gtk.ICON_SIZE_MENU) + + current_size_image = gtk.image_new_from_stock(gtk.STOCK_APPLY, + gtk.ICON_SIZE_MENU) current_size_image.show() - entry = gtk.ImageMenuItem(_("Automatic")) - entry.connect("activate", self.change_force_size_cb,0) - if self.force_size == 0: - entry.set_image(current_size_image) - entry.show() - size_menu.append(entry) - - for n in range(2,6): - entry = gtk.ImageMenuItem(ngettext("%d generation", "%d generations", n) %n) - if self.force_size == n: + for num in range(2, 6): + entry = gtk.ImageMenuItem( + ngettext("%d generation", "%d generations", num) %num) + if self.force_size == num: entry.set_image(current_size_image) - entry.connect("activate", self.change_force_size_cb, n) + entry.connect("activate", self.change_force_size_cb, num) entry.show() size_menu.append(entry) - + + if self.tree_style in [0, 2]: + # Note: 10 generations can cause problems + for num in range(6, 10): + entry = gtk.ImageMenuItem( + ngettext("%d generation", "%d generations", num) %num) + if self.force_size == num: + entry.set_image(current_size_image) + entry.connect("activate", self.change_force_size_cb, num) + entry.show() + size_menu.append(entry) + + item2 = gtk.MenuItem(_("Tree direction")) + item2.set_submenu(gtk.Menu()) + direction_menu = item2.get_submenu() + + current_direction_image = gtk.image_new_from_stock(gtk.STOCK_APPLY, + gtk.ICON_SIZE_MENU) + current_direction_image.show() + + entry = gtk.ImageMenuItem(_("Vertical (top to bottom)")) + entry.connect("activate", self.change_tree_direction_cb, 0) + if self.tree_direction == 0: + entry.set_image(current_direction_image) + entry.show() + direction_menu.append(entry) + + entry = gtk.ImageMenuItem(_("Vertical (bottom to top)")) + entry.connect("activate", self.change_tree_direction_cb, 1) + if self.tree_direction == 1: + entry.set_image(current_direction_image) + entry.show() + direction_menu.append(entry) + + entry = gtk.ImageMenuItem(_("Horizontal (left to right)")) + entry.connect("activate", self.change_tree_direction_cb, 2) + if self.tree_direction == 2: + entry.set_image(current_direction_image) + entry.show() + direction_menu.append(entry) + + entry = gtk.ImageMenuItem(_("Horizontal (right to left)")) + entry.connect("activate", self.change_tree_direction_cb, 3) + if self.tree_direction == 3: + entry.set_image(current_direction_image) + entry.show() + direction_menu.append(entry) + + direction_menu.show() + item2.show() + menu.append(item2) + size_menu.show() item.show() menu.append(item) - - def build_missing_parent_nav_menu_cb(self, obj,event,person_handle,family_handle): + + def build_missing_parent_nav_menu_cb(self, obj, event, + person_handle, family_handle): + """Builds the menu for a missing parent.""" menu = gtk.Menu() menu.set_title(_('People Menu')) add_item = gtk.ImageMenuItem(gtk.STOCK_ADD) - add_item.connect("activate",self.add_parents_cb,person_handle,family_handle) + add_item.connect("activate", self.add_parents_cb, person_handle, + family_handle) add_item.show() menu.append(add_item) # Add history-based navigation self.add_nav_portion_to_menu(menu) self.add_settings_to_menu(menu) - menu.popup(None,None,None,event.button,event.time) + menu.popup(None, None, None, 0, event.time) return 1 - def build_full_nav_menu_cb(self, obj,event,person_handle): + def build_full_nav_menu_cb(self, obj, event, person_handle, family_handle): """ - Builds the full menu (including Siblings, Spouses, Children, + Builds the full menu (including Siblings, Spouses, Children, and Parents) with navigation. """ - + menu = gtk.Menu() menu.set_title(_('People Menu')) @@ -1337,27 +1936,29 @@ class PedigreeView(NavigationView): if not person: return 0 - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO,gtk.ICON_SIZE_MENU) + go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, + gtk.ICON_SIZE_MENU) go_image.show() go_item = gtk.ImageMenuItem(name_displayer.display(person)) go_item.set_image(go_image) - go_item.connect("activate",self.on_childmenu_changed,person_handle) + go_item.connect("activate", self.on_childmenu_changed, person_handle) go_item.show() menu.append(go_item) edit_item = gtk.ImageMenuItem(gtk.STOCK_EDIT) - edit_item.connect("activate",self.edit_person_cb,person_handle) + edit_item.connect("activate", self.edit_person_cb, person_handle) edit_item.show() menu.append(edit_item) clipboard_item = gtk.ImageMenuItem(gtk.STOCK_COPY) - clipboard_item.connect("activate",self.copy_person_to_clipboard_cb,person_handle) + clipboard_item.connect("activate", self.copy_person_to_clipboard_cb, + person_handle) clipboard_item.show() menu.append(clipboard_item) # collect all spouses, parents and children linked_persons = [] - + # Go over spouses and build their menu item = gtk.MenuItem(_("Spouses")) fam_list = person.get_family_handle_list() @@ -1377,12 +1978,13 @@ class PedigreeView(NavigationView): item.set_submenu(gtk.Menu()) sp_menu = item.get_submenu() - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO,gtk.ICON_SIZE_MENU) + go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, + gtk.ICON_SIZE_MENU) go_image.show() sp_item = gtk.ImageMenuItem(name_displayer.display(spouse)) sp_item.set_image(go_image) linked_persons.append(sp_id) - sp_item.connect("activate",self.on_childmenu_changed,sp_id) + sp_item.connect("activate", self.on_childmenu_changed, sp_id) sp_item.show() sp_menu.append(sp_item) @@ -1391,13 +1993,13 @@ class PedigreeView(NavigationView): item.show() menu.append(item) - + # Go over siblings and build their menu item = gtk.MenuItem(_("Siblings")) pfam_list = person.get_parent_family_handle_list() no_siblings = 1 - for f in pfam_list: - fam = self.dbstate.db.get_family_from_handle(f) + for pfam in pfam_list: + fam = self.dbstate.db.get_family_from_handle(pfam) sib_list = fam.get_child_ref_list() for sib_ref in sib_list: sib_id = sib_ref.ref @@ -1412,21 +2014,23 @@ class PedigreeView(NavigationView): item.set_submenu(gtk.Menu()) sib_menu = item.get_submenu() - if find_children(self.dbstate.db,sib): - label = gtk.Label('%s' % escape(name_displayer.display(sib))) + if find_children(self.dbstate.db, sib): + label = gtk.Label('%s' % \ + escape(name_displayer.display(sib))) else: label = gtk.Label(escape(name_displayer.display(sib))) - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO,gtk.ICON_SIZE_MENU) + go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, + gtk.ICON_SIZE_MENU) go_image.show() sib_item = gtk.ImageMenuItem(None) sib_item.set_image(go_image) label.set_use_markup(True) label.show() - label.set_alignment(0,0) + label.set_alignment(0, 0) sib_item.add(label) linked_persons.append(sib_id) - sib_item.connect("activate",self.on_childmenu_changed,sib_id) + sib_item.connect("activate", self.on_childmenu_changed, sib_id) sib_item.show() sib_menu.append(sib_item) @@ -1434,36 +2038,39 @@ class PedigreeView(NavigationView): item.set_sensitive(0) item.show() menu.append(item) - + # Go over children and build their menu item = gtk.MenuItem(_("Children")) no_children = 1 - childlist = find_children(self.dbstate.db,person) + childlist = find_children(self.dbstate.db, person) for child_handle in childlist: child = self.dbstate.db.get_person_from_handle(child_handle) if not child: continue - + if no_children: no_children = 0 item.set_submenu(gtk.Menu()) child_menu = item.get_submenu() - if find_children(self.dbstate.db,child): - label = gtk.Label('%s' % escape(name_displayer.display(child))) + if find_children(self.dbstate.db, child): + label = gtk.Label('%s' % \ + escape(name_displayer.display(child))) else: label = gtk.Label(escape(name_displayer.display(child))) - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO,gtk.ICON_SIZE_MENU) + go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, + gtk.ICON_SIZE_MENU) go_image.show() child_item = gtk.ImageMenuItem(None) child_item.set_image(go_image) label.set_use_markup(True) label.show() - label.set_alignment(0,0) + label.set_alignment(0, 0) child_item.add(label) linked_persons.append(child_handle) - child_item.connect("activate",self.on_childmenu_changed,child_handle) + child_item.connect("activate", self.on_childmenu_changed, + child_handle) child_item.show() child_menu.append(child_item) @@ -1475,7 +2082,7 @@ class PedigreeView(NavigationView): # Go over parents and build their menu item = gtk.MenuItem(_("Parents")) no_parents = 1 - par_list = find_parents(self.dbstate.db,person) + par_list = find_parents(self.dbstate.db, person) for par_id in par_list: par = self.dbstate.db.get_person_from_handle(par_id) if not par: @@ -1486,36 +2093,47 @@ class PedigreeView(NavigationView): item.set_submenu(gtk.Menu()) par_menu = item.get_submenu() - if find_parents(self.dbstate.db,par): - label = gtk.Label('%s' % escape(name_displayer.display(par))) + if find_parents(self.dbstate.db, par): + label = gtk.Label('%s' % \ + escape(name_displayer.display(par))) else: label = gtk.Label(escape(name_displayer.display(par))) - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO,gtk.ICON_SIZE_MENU) + go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, + gtk.ICON_SIZE_MENU) go_image.show() par_item = gtk.ImageMenuItem(None) par_item.set_image(go_image) label.set_use_markup(True) label.show() - label.set_alignment(0,0) + label.set_alignment(0, 0) par_item.add(label) linked_persons.append(par_id) - par_item.connect("activate",self.on_childmenu_changed,par_id) + par_item.connect("activate", self.on_childmenu_changed, par_id) par_item.show() par_menu.append(par_item) if no_parents: - item.set_sensitive(0) + if self.tree_style == 2 and not self.show_unknown_people: + item.set_submenu(gtk.Menu()) + par_menu = item.get_submenu() + par_item = gtk.ImageMenuItem(_("Add New Parents...")) + par_item.connect("activate", self.add_parents_cb, person_handle, + family_handle) + par_item.show() + par_menu.append(par_item) + else: + item.set_sensitive(0) item.show() menu.append(item) - + # Go over parents and build their menu item = gtk.MenuItem(_("Related")) no_related = 1 - for p_id in find_witnessed_people(self.dbstate.db,person): + for p_id in find_witnessed_people(self.dbstate.db, person): #if p_id in linked_persons: # continue # skip already listed family members - + per = self.dbstate.db.get_person_from_handle(p_id) if not per: continue @@ -1527,24 +2145,24 @@ class PedigreeView(NavigationView): label = gtk.Label(escape(name_displayer.display(per))) - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO,gtk.ICON_SIZE_MENU) + go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, + gtk.ICON_SIZE_MENU) go_image.show() per_item = gtk.ImageMenuItem(None) per_item.set_image(go_image) label.set_use_markup(True) label.show() - label.set_alignment(0,0) + label.set_alignment(0, 0) per_item.add(label) - per_item.connect("activate",self.on_childmenu_changed,p_id) + per_item.connect("activate", self.on_childmenu_changed, p_id) per_item.show() per_menu.append(per_item) - + if no_related: item.set_sensitive(0) item.show() menu.append(item) - - + # Add separator item = gtk.MenuItem(None) item.show() @@ -1553,13 +2171,11 @@ class PedigreeView(NavigationView): # Add history-based navigation self.add_nav_portion_to_menu(menu) self.add_settings_to_menu(menu) - menu.popup(None,None,None,event.button,event.time) + menu.popup(None, None, None, 0, event.time) return 1 - def build_relation_nav_menu_cb(self, obj,event,family_handle): - """ - Builds the menu for a parents-child relation line. - """ + def build_relation_nav_menu_cb(self, obj, event, family_handle): + """Builds the menu for a parents-child relation line.""" menu = gtk.Menu() menu.set_title(_('Family Menu')) @@ -1568,16 +2184,16 @@ class PedigreeView(NavigationView): return 0 edit_item = gtk.ImageMenuItem(gtk.STOCK_EDIT) - edit_item.connect("activate",self.edit_family_cb,family_handle) + edit_item.connect("activate", self.edit_family_cb, family_handle) edit_item.show() menu.append(edit_item) clipboard_item = gtk.ImageMenuItem(gtk.STOCK_COPY) - clipboard_item.connect("activate",self.copy_family_to_clipboard_cb,family_handle) + clipboard_item.connect("activate", self.copy_family_to_clipboard_cb, + family_handle) clipboard_item.show() menu.append(clipboard_item) - # Add separator item = gtk.MenuItem(None) item.show() @@ -1586,5 +2202,5 @@ class PedigreeView(NavigationView): # Add history-based navigation self.add_nav_portion_to_menu(menu) self.add_settings_to_menu(menu) - menu.popup(None,None,None,event.button,event.time) + menu.popup(None, None, None, 0, event.time) return 1 diff --git a/src/plugins/view/pedigreeviewext.gpr.py b/src/plugins/view/pedigreeviewext.gpr.py deleted file mode 100644 index 0bafe4f1c..000000000 --- a/src/plugins/view/pedigreeviewext.gpr.py +++ /dev/null @@ -1,43 +0,0 @@ -# encoding:utf-8 -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2009 Benny Malengier -# -# 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$ - -#------------------------------------------------------------------------ -# -# default views of Gramps -# -#------------------------------------------------------------------------ - -register(VIEW, -id = 'pedigreeviewext', -name = _("Pedigree View"), -description = _("The view showing an ancestor pedigree of the selected person"), -version = '1.0', -gramps_target_version = '3.2', -status = STABLE, -fname = 'pedigreeviewext.py', -authors = [u"The Gramps project"], -authors_email = ["http://gramps-project.org"], -category = ("Ancestry", _("Ancestry")), -viewclass = 'PedigreeViewExt', -order = START, - ) diff --git a/src/plugins/view/pedigreeviewext.py b/src/plugins/view/pedigreeviewext.py deleted file mode 100644 index 9e69e17af..000000000 --- a/src/plugins/view/pedigreeviewext.py +++ /dev/null @@ -1,2367 +0,0 @@ -# -*- python -*- -# -*- coding: utf-8 -*- -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2001-2007 Donald N. Allingham, Martin Hawlisch -# Copyright (C) 2009 Yevgeny Zegzda -# -# 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$ - -#------------------------------------------------------------------------- -# -# Python modules -# -#------------------------------------------------------------------------- -from gen.ggettext import sgettext as _ -from gen.ggettext import ngettext -from cgi import escape -import math - -#------------------------------------------------------------------------- -# -# GTK/Gnome modules -# -#------------------------------------------------------------------------- -import gtk - -try: - import cairo - cairo_available = True -except: - cairo_available = False - -#------------------------------------------------------------------------- -# -# Gramps Modules -# -#------------------------------------------------------------------------- -import gen.lib -from gui.views.navigationview import NavigationView -from gui.filtereditor import FilterEditor -from gen.display.name import displayer as name_displayer -from Utils import (media_path_full, probably_alive, find_children, - find_parents, find_witnessed_people) -from libformatting import FormattingHelper -import ThumbNails -import Errors -from gui.editors import EditPerson, EditFamily -from DdTargets import DdTargets -import cPickle as pickle -import config -import Bookmarks -import const -from QuestionDialog import RunDatabaseRepair, ErrorDialog - -#------------------------------------------------------------------------- -# -# Constants -# -#------------------------------------------------------------------------- -_PERSON = "p" -_BORN = _('short for born|b.') -_DIED = _('short for died|d.') -_BAPT = _('short for baptized|bap.') -_CHRI = _('short for chistianized|chr.') -_BURI = _('short for buried|bur.') -_CREM = _('short for cremated|crem.') - - -class _PersonBoxWidgetOld(gtk.Button): - """Old widget used before revision #5646""" - def __init__(self, format_helper, person, maxlines, image=None): - if person: - gtk.Button.__init__(self, - format_helper.format_person(person, maxlines)) - gender = person.get_gender() - if gender == gen.lib.Person.MALE: - self.modify_bg(gtk.STATE_NORMAL, - self.get_colormap().alloc_color("#F5FFFF")) - elif gender == gen.lib.Person.FEMALE: - self.modify_bg(gtk.STATE_NORMAL, - self.get_colormap().alloc_color("#FFF5FF")) - else: - self.modify_bg(gtk.STATE_NORMAL, - self.get_colormap().alloc_color("#FFFFF5")) - else: - gtk.Button.__init__(self, " ") - #self.set_sensitive(False) - self.format_helper = format_helper - self.image = image - self.set_alignment(0.0, 0.0) - white = self.get_colormap().alloc_color("white") - self.modify_bg(gtk.STATE_ACTIVE, white) - self.modify_bg(gtk.STATE_PRELIGHT, white) - self.modify_bg(gtk.STATE_SELECTED, white) - - -class _PersonWidgetBase: - """ - Defualt set up for person widgets. - Set up drag options and button release events. - """ - def __init__(self, view, format_helper, person): - self.view = view - self.format_helper = format_helper - self.person = person - self.force_mouse_over = False - if self.person: - self.add_events(gtk.gdk.BUTTON_PRESS_MASK) - self.add_events(gtk.gdk.BUTTON_RELEASE_MASK) - self.connect("button-release-event", self.on_button_release_cb) - self.connect("drag_data_get", self.drag_data_get) - self.connect("drag_begin", self.drag_begin_cb) - # Enable drag - self.drag_source_set(gtk.gdk.BUTTON1_MASK, - [DdTargets.PERSON_LINK.target()]+ - [t.target() for t in DdTargets._all_text_types], - gtk.gdk.ACTION_COPY) - - def drag_begin_cb(self, widget, data): - """Set up some inital conditions for drag. Set up icon.""" - self.drag_source_set_icon_stock('gramps-person') - - def drag_data_get(self, widget, context, sel_data, info, time): - """ - Returned parameters after drag. - Specified for 'person-link', for others return text info about person. - """ - if sel_data.target == DdTargets.PERSON_LINK.drag_type: - data = (DdTargets.PERSON_LINK.drag_type, - id(self), self.person.get_handle(), 0) - sel_data.set(sel_data.target, 8, pickle.dumps(data)) - else: - sel_data.set(sel_data.target, 8, - self.format_helper.format_person(self.person, 11)) - - def on_button_release_cb(self, widget, event): - """ - Defualt action for release event from mouse. - Change active person to current. - """ - if event.button == 1 and event.type == gtk.gdk.BUTTON_RELEASE: - self.view.on_childmenu_changed(None, self.person.get_handle()) - return True - return False - - -class PersonBoxWidgetCairo(gtk.DrawingArea, _PersonWidgetBase): - """Draw person box using cairo library""" - def __init__(self, - view, format_helper, person, alive, maxlines, image=None): - gtk.DrawingArea.__init__(self) - _PersonWidgetBase.__init__(self, view, format_helper, person) - # Required for popup menu - self.add_events(gtk.gdk.BUTTON_PRESS_MASK) - self.add_events(gtk.gdk.BUTTON_RELEASE_MASK) - # Required for tooltip and mouse-over - self.add_events(gtk.gdk.ENTER_NOTIFY_MASK) - # Required for tooltip and mouse-over - self.add_events(gtk.gdk.LEAVE_NOTIFY_MASK) - self.alive = alive - self.maxlines = maxlines - self.hightlight = False - self.connect("expose_event", self.expose) - self.connect("realize", self.realize) - self.text = "" - if self.person: - self.text = self.format_helper.format_person(self.person, - self.maxlines, True) - if alive and self.person.get_gender() == gen.lib.Person.MALE: - self.bgcolor = (185/256.0, 207/256.0, 231/256.0) - self.bordercolor = (32/256.0, 74/256.0, 135/256.0) - elif alive and self.person.get_gender() == gen.lib.Person.FEMALE: - self.bgcolor = (255/256.0, 205/256.0, 241/256.0) - self.bordercolor = (135/256.0, 32/256.0, 106/256.0) - elif alive: - self.bgcolor = (244/256.0, 220/256.0, 183/256.0) - self.bordercolor = (143/256.0, 89/256.0, 2/256.0) - elif self.person.get_gender() == gen.lib.Person.MALE: - self.bgcolor = (185/256.0, 207/256.0, 231/256.0) - self.bordercolor = (0, 0, 0) - elif self.person.get_gender() == gen.lib.Person.FEMALE: - self.bgcolor = (255/256.0, 205/256.0, 241/256.0) - self.bordercolor = (0, 0, 0) - else: - self.bgcolor = (244/256.0, 220/256.0, 183/256.0) - self.bordercolor = (0, 0, 0) - else: - self.bgcolor = (211/256.0, 215/256.0, 207/256.0) - self.bordercolor = (0, 0, 0) - self.image = image - try: - self.img_surf = cairo.ImageSurface.create_from_png(image) - except: - self.image = False - # enable mouse-over - self.connect("enter-notify-event", self.on_enter_cb) - # enable mouse-out - self.connect("leave-notify-event", self.on_leave_cb) - self.set_size_request(120, 25) - # GTK object use in realize and expose methods - self.context = None - self.textlayout = None - - def on_enter_cb(self, widget, event): - """On mouse-over highlight border""" - if self.person or self.force_mouse_over: - self.hightlight = True - self.queue_draw() - - def on_leave_cb(self, widget, event): - """On mouse-out normal border""" - self.hightlight = False - self.queue_draw() - - def realize(self, widget): - """ - Necessary actions when the widget is instantiated on a particular - display. Print text and resize element. - """ - self.context = self.window.cairo_create() - self.textlayout = self.context.create_layout() - self.textlayout.set_font_description(self.get_style().font_desc) - self.textlayout.set_markup(self.text) - size = self.textlayout.get_pixel_size() - xmin = size[0] + 12 - ymin = size[1] + 11 - if self.image: - xmin += self.img_surf.get_width() - ymin = max(ymin, self.img_surf.get_height()+4) - self.set_size_request(max(xmin, 120), max(ymin, 25)) - - def expose(self, widget, event): - """ - Redrawing the contents of the widget. - Creat new cairo object and draw in it all (borders, background and etc.) - witout text. - """ - alloc = self.get_allocation() - self.context = self.window.cairo_create() - - # widget area for debugging - #self.context.rectangle(0, 0, alloc.width, alloc.height) - #self.context.set_source_rgb(1, 0, 1) - #self.context.fill_preserve() - #self.context.stroke() - - # Create box shape and store path - self.context.move_to(0, 5) - self.context.curve_to(0, 2, 2, 0, 5, 0) - self.context.line_to(alloc.width-8, 0) - self.context.curve_to(alloc.width-5, 0, - alloc.width-3, 2, - alloc.width-3, 5) - self.context.line_to(alloc.width-3, alloc.height-8) - self.context.curve_to(alloc.width-3, alloc.height-5, - alloc.width-5, alloc.height-3, - alloc.width-8, alloc.height-3) - self.context.line_to(5, alloc.height-3) - self.context.curve_to(2, alloc.height-3, - 0, alloc.height-5, - 0, alloc.height-8) - self.context.close_path() - path = self.context.copy_path() - - # shadow - self.context.save() - self.context.translate(3, 3) - self.context.new_path() - self.context.append_path(path) - self.context.set_source_rgba(*(self.bordercolor[:3] + (0.4,))) - self.context.fill_preserve() - self.context.set_line_width(0) - self.context.stroke() - self.context.restore() - - # box shape used for clipping - self.context.append_path(path) - self.context.clip() - - # background - self.context.append_path(path) - self.context.set_source_rgb(*self.bgcolor[:3]) - self.context.fill_preserve() - self.context.stroke() - - # image - if self.image: - self.context.set_source_surface(self.img_surf, - alloc.width-4-self.img_surf.get_width(), 1) - self.context.paint() - - # text - self.context.move_to(5, 4) - self.context.set_source_rgb(0, 0, 0) - self.context.show_layout(self.textlayout) - - # text extents - #self.context.set_source_rgba(1, 0, 0, 0.5) - #s = self.textlayout.get_pixel_size() - #self.context.set_line_width(1) - #self.context.rectangle(5.5, 4.5, s[0]-1, s[1]-1) - #self.context.stroke() - - # Mark deceased - if self.person and not self.alive: - self.context.set_line_width(2) - self.context.move_to(0, 10) - self.context.line_to(10, 0) - self.context.stroke() - - #border - if self.hightlight: - self.context.set_line_width(5) - else: - self.context.set_line_width(2) - self.context.append_path(path) - self.context.set_source_rgb(*self.bordercolor[:3]) - self.context.stroke() - -class PersonBoxWidget(gtk.DrawingArea, _PersonWidgetBase): - """ - Draw person box using GC library. - For version PyGTK < 2.8 - """ - def __init__(self, - view, format_helper, person, alive, maxlines, image=None): - gtk.DrawingArea.__init__(self) - _PersonWidgetBase.__init__(self, view, format_helper, person) - # Required for popup menu and other right mouse button click - self.add_events(gtk.gdk.BUTTON_PRESS_MASK - | gtk.gdk.BUTTON_RELEASE_MASK - # Required for tooltip and mouse-over - | gtk.gdk.ENTER_NOTIFY_MASK - # Required for tooltip and mouse-over - | gtk.gdk.LEAVE_NOTIFY_MASK) - self.maxlines = maxlines - self.alive = alive - try: - self.image = gtk.gdk.pixbuf_new_from_file(image) - except: - self.image = None - self.connect("expose_event", self.expose) - self.connect("realize", self.realize) - text = "" - if self.person: - text = self.format_helper.format_person(self.person, self.maxlines) - # enable mouse-over - self.connect("enter-notify-event", self.on_enter_cb) - self.connect("leave-notify-event", self.on_leave_cb) - self.textlayout = self.create_pango_layout(text) - size = self.textlayout.get_pixel_size() - xmin = size[0] + 12 - ymin = size[1] + 11 - if self.image: - xmin += self.image.get_width() - ymin = max(ymin, self.image.get_height()+4) - self.set_size_request(max(xmin, 120), max(ymin, 25)) - # GTK object use in realize and expose methods - self.bg_gc = None - self.text_gc = None - self.border_gc = None - self.shadow_gc = None - - def on_enter_cb(self, widget, event): - """On mouse-over highlight border""" - self.border_gc.line_width = 3 - self.queue_draw() - - def on_leave_cb(self, widget, event): - """On mouse-out normal border""" - self.border_gc.line_width = 1 - self.queue_draw() - - def realize(self, widget): - """ - Necessary actions when the widget is instantiated on a particular - display. Creat all elements for person box(bg_gc, text_gc, border_gc, - shadow_gc), and setup they style. - """ - self.bg_gc = self.window.new_gc() - self.text_gc = self.window.new_gc() - self.border_gc = self.window.new_gc() - self.border_gc.line_style = gtk.gdk.LINE_SOLID - self.border_gc.line_width = 1 - self.shadow_gc = self.window.new_gc() - self.shadow_gc.line_style = gtk.gdk.LINE_SOLID - self.shadow_gc.line_width = 4 - if self.person: - if self.alive and self.person.get_gender() == gen.lib.Person.MALE: - self.bg_gc.set_foreground( - self.get_colormap().alloc_color("#b9cfe7")) - self.border_gc.set_foreground( - self.get_colormap().alloc_color("#204a87")) - elif self.person.get_gender() == gen.lib.Person.MALE: - self.bg_gc.set_foreground( - self.get_colormap().alloc_color("#b9cfe7")) - self.border_gc.set_foreground( - self.get_colormap().alloc_color("#000000")) - elif self.alive and \ - self.person.get_gender() == gen.lib.Person.FEMALE: - self.bg_gc.set_foreground( - self.get_colormap().alloc_color("#ffcdf1")) - self.border_gc.set_foreground( - self.get_colormap().alloc_color("#87206a")) - elif self.person.get_gender() == gen.lib.Person.FEMALE: - self.bg_gc.set_foreground( - self.get_colormap().alloc_color("#ffcdf1")) - self.border_gc.set_foreground( - self.get_colormap().alloc_color("#000000")) - elif self.alive: - self.bg_gc.set_foreground( - self.get_colormap().alloc_color("#f4dcb7")) - self.border_gc.set_foreground( - self.get_colormap().alloc_color("#8f5902")) - else: - self.bg_gc.set_foreground( - self.get_colormap().alloc_color("#f4dcb7")) - self.border_gc.set_foreground( - self.get_colormap().alloc_color("#000000")) - else: - self.bg_gc.set_foreground( - self.get_colormap().alloc_color("#eeeeee")) - self.border_gc.set_foreground( - self.get_colormap().alloc_color("#777777")) - self.shadow_gc.set_foreground( - self.get_colormap().alloc_color("#999999")) - - - def expose(self, widget, event): - """ - Redrawing the contents of the widget. - Drawing borders and person info on exist elements. - """ - alloc = self.get_allocation() - # shadow - self.window.draw_line(self.shadow_gc, 3, alloc.height-1, - alloc.width, alloc.height-1) - self.window.draw_line(self.shadow_gc, alloc.width-1, 3, - alloc.width-1, alloc.height) - # box background - self.window.draw_rectangle(self.bg_gc, True, 1, 1, - alloc.width-5, alloc.height-5) - # text - if self.person: - self.window.draw_layout(self.text_gc, 5, 4, self.textlayout) - # image - if self.image: - self.window.draw_pixbuf(self.text_gc, self.image, 0, 0, - alloc.width-4-self.image.get_width(), 1) - # border - if self.border_gc.line_width > 1: - self.window.draw_rectangle(self.border_gc, False, 1, 1, - alloc.width-6, alloc.height-6) - else: - self.window.draw_rectangle(self.border_gc, False, 0, 0, - alloc.width-4, alloc.height-4) - -#------------------------------------------------------------------------- -# -# PedigreeView -# -#------------------------------------------------------------------------- -class PedigreeViewExt(NavigationView): - """ - View for pedigree tree. - Displays the ancestors of a selected individual. - """ - - def __init__(self, dbstate, uistate, nav_group=0): - NavigationView.__init__(self, _('Pedigree'), dbstate, uistate, - dbstate.db.get_bookmarks(), - Bookmarks.PersonBookmarks, - nav_group) - - self.func_list = { - 'F2' : self.kb_goto_home, - 'F3' : self.kb_change_style, - 'F4' : self.kb_change_direction, - 'F6' : self.kb_plus_generation, - 'F5' : self.kb_minus_generation, - 'J' : self.jump, - } - - self.dbstate = dbstate - self.dbstate.connect('database-changed', self.change_db) - # Automatic resize - self.force_size = config.get('interface.pedviewext-tree-size') - # Nice tree - self.tree_style = config.get('interface.pedviewext-layout') - # Show photos of persons - self.show_images = config.get('interface.pedviewext-show-images') - # Hide marriage data by default - self.show_marriage_data = config.get( - 'interface.pedviewext-show-marriage') - # Tree draw direction - self.tree_direction = config.get('interface.pedviewext-tree-direction') - # Show on not unknown peoples. - # Default - not show, for mo fast display hight tree - self.show_unknown_peoples = config.get( - 'interface.pedviewext-show-unknown-peoples') - - self.format_helper = FormattingHelper(self.dbstate) - - # Depth of tree. - self._depth = 1 - # Variables for drag and scroll - self._last_x = 0 - self._last_y = 0 - self._in_move = False - # Change or nor mouse whell scroll direction - self.scroll_direction = config.get( - 'interface.pedviewext-scroll-direction') - self.key_active_changed = None - # GTK objects - self.scrolledwindow = None - self.table = None - - def change_page(self): - """Called when the page changes.""" - NavigationView.change_page(self) - self.uistate.clear_filter_results() - - def get_stock(self): - """ - The category stock icon - """ - return 'gramps-pedigree' - - def get_viewtype_stock(self): - """Type of view in category - """ - return 'gramps-pedigree' - - def build_widget(self): - """ - Builds the interface and returns a gtk.Container type that - contains the interface. This containter will be inserted into - a gtk.ScrolledWindow page. - """ - self.scrolledwindow = gtk.ScrolledWindow(None, None) - self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, - gtk.POLICY_AUTOMATIC) - self.scrolledwindow.add_events(gtk.gdk.SCROLL_MASK) - self.scrolledwindow.connect("scroll-event", self.bg_scroll_event) - event_box = gtk.EventBox() - # Required for drag-scroll events and popup menu - event_box.add_events(gtk.gdk.BUTTON_PRESS_MASK - | gtk.gdk.BUTTON_RELEASE_MASK - | gtk.gdk.BUTTON1_MOTION_MASK) - # Signal begin drag-scroll - event_box.connect("button-press-event", self.bg_button_press_cb) - # Signal end drag-scroll and popup menu - event_box.connect("button-release-event", self.bg_button_release_cb) - #Signal for controll motion-notify when left mouse button pressed - event_box.connect("motion-notify-event", self.bg_motion_notify_event_cb) - self.scrolledwindow.add_with_viewport(event_box) - - self.table = gtk.Table(1, 1, False) - event_box.add(self.table) - event_box.get_parent().set_shadow_type(gtk.SHADOW_NONE) - self.table.set_row_spacings(1) - self.table.set_col_spacings(0) - - return self.scrolledwindow - - def ui_definition(self): - """ - Specifies the UIManager XML code that defines the menus and buttons - associated with the interface. - """ - return ''' - - - - - - - - - - - - - - - - - - - - - - - - - - - - ''' - - def define_actions(self): - """ - Required define_actions function for PageView. Builds the action - group information required. We extend beyond the normal here, - since we want to have more than one action group for the PersonView. - Most PageViews really won't care about this. - - Special action groups for Forward and Back are created to allow the - handling of navigation buttons. Forward and Back allow the user to - advance or retreat throughout the history, and we want to have these - be able to toggle these when you are at the end of the history or - at the beginning of the history. - """ - NavigationView.define_actions(self) - - self._add_action('FilterEdit', None, _('Person Filter Editor'), - callback=self.filter_editor) - - def filter_editor(self, obj): - try: - FilterEditor('Person', const.CUSTOM_FILTERS, - self.dbstate, self.uistate) - except Errors.WindowActiveError: - return - - def build_tree(self): - """ - This is called by the parent class when the view becomes visible. Since - all handling of visibility is now in rebuild_trees, see that for more - information. - """ - try: - active = self.get_active() - if active: - self.rebuild_trees(active) - else: - self.rebuild_trees(None) - except AttributeError, msg: - RunDatabaseRepair(str(msg)) - - def change_db(self, db): - """ - Callback associated with DbState. Whenever the database - changes, this task is called. In this case, we rebuild the - columns, and connect signals to the connected database. Tree - is no need to store the database, since we will get the value - from self.state.db - """ - db.connect('person-add', self.person_rebuild) - db.connect('person-update', self.person_rebuild) - db.connect('person-delete', self.person_rebuild) - db.connect('person-rebuild', self.person_rebuild_bm) - db.connect('family-update', self.person_rebuild) - db.connect('family-add', self.person_rebuild) - db.connect('family-delete', self.person_rebuild) - db.connect('family-rebuild', self.person_rebuild) - self.bookmarks.update_bookmarks(self.dbstate.db.get_bookmarks()) - if self.active: - self.bookmarks.redraw() - self.build_tree() - - def navigation_type(self): - return 'Person' - - def goto_handle(self, handle=None): - self.dirty = True - if handle: - person = self.dbstate.db.get_person_from_handle(handle) - if person: - self.rebuild_trees(handle) - else: - self.rebuild_trees(None) - else: - self.rebuild_trees(None) - self.uistate.modify_statusbar(self.dbstate) - - def person_rebuild_bm(self, dummy=None): - """Large change to person database""" - self.person_rebuild(dummy) - if self.active: - self.bookmarks.redraw() - - def person_rebuild(self, dummy=None): - """Callback function for signals of change database.""" - self.format_helper.clear_cache() - self.dirty = True - self.rebuild_trees(self.get_active()) - - def rebuild_trees(self, person_handle): - """ - Rebild tree with root person_handle. - Called from many fuctions, when need full redraw tree. - """ - person = None - if person_handle: - person = self.dbstate.db.get_person_from_handle(person_handle) - - self.dirty = False - - if self.tree_style != 2 and \ - (self.force_size > 5 or self.force_size == 0): - self.force_size = 5 - - # format of the definition is: - # ((each box of the pedigree has a node here), - # ((person data), (connection line), (marriage data)), - # ((person box position and size),(parent relation box), - # (marriage data)), - # ((or for another design),((fater relation box), - # (mother relation box)),(marriage data))) - if self.tree_style == 1: - if self.force_size == 2: - pos = (((0, 3, 3, 3), ((1, 0, 3), (1, 6, 3)), (3, 3, 2, 3)), - ((2, 0, 3, 3), None, None), - ((2, 6, 3, 3), None, None)) - elif self.force_size == 3: - pos = (((0, 4, 3, 5), ((1, 1, 3), (1, 9, 3)), (3, 5, 2, 3)), - ((2, 1, 3, 3), ((3, 0, 1), (3, 4, 1)), (5, 1, 2, 3)), - ((2, 9, 3, 3), ((3, 8, 1), (3, 12, 1)), (5, 9, 2, 3)), - ((4, 0, 3, 1), None, None), - ((4,4,3,1),None,None), - ((4,8,3,1),None,None), - ((4,12,3,1),None,None)) - elif self.force_size == 4: - pos = (((0, 5, 3, 5), ((1, 2, 3), (1, 10, 3)), (3, 6, 2, 3)), - ((2, 2, 3, 3), ((3, 1, 1), (3, 5, 1)), (5, 3, 2, 1)), - ((2, 10, 3, 3), ((3, 9, 1), (3, 13, 1)), (5, 11, 2, 1)), - ((4, 1, 3, 1), ((5, 0, 1), (5, 2, 1)), (7, 1, 2, 1)), - ((4, 5, 3, 1), ((5, 4, 1), (5, 6, 1)), (7, 5, 2, 1)), - ((4, 9, 3, 1), ((5, 8, 1), (5, 10, 1)), (7, 9, 2, 1)), - ((4, 13, 3, 1), ((5, 12, 1), (5, 14, 1)), (7, 13, 2, 1)), - ((6, 0, 3, 1), None, None), - ((6, 2, 3, 1), None, None), - ((6, 4, 3, 1), None, None), - ((6, 6, 3, 1), None, None), - ((6, 8, 3, 1), None, None), - ((6, 10, 3, 1), None, None), - ((6, 12, 3, 1), None, None), - ((6, 14, 3, 1), None, None)) - elif self.force_size == 5: - pos = (((0, 10, 3, 11), ((1, 5, 5), (1, 21, 5)), (3, 13, 2, 5)), - ((2, 5, 3, 5), ((3, 2, 3), (3, 10, 3)), (5, 6, 2, 3)), - ((2, 21, 3, 5), ((3, 18, 3), (3, 26, 3)), (5, 22, 2, 3)), - ((4, 2, 3, 3), ((5, 1, 1), (5, 5, 1)), (7, 3, 2, 1)), - ((4, 10, 3, 3), ((5, 9, 1), (5, 13, 1)), (7, 11, 2, 1)), - ((4, 18, 3, 3), ((5, 17, 1), (5, 21, 1)), (7, 19, 2, 1)), - ((4, 26, 3, 3), ((5, 25, 1), (5, 29, 1)), (7, 27, 2, 1)), - ((6, 1, 3, 1), ((7, 0, 1), (7, 2, 1)), (9, 1, 2, 1)), - ((6, 5, 3, 1), ((7, 4, 1), (7, 6, 1)), (9, 5, 2, 1)), - ((6, 9, 3, 1), ((7, 8, 1), (7, 10, 1)), (9, 9, 2, 1)), - ((6, 13, 3, 1), ((7, 12, 1), (7, 14, 1)), (9, 13, 2, 1)), - ((6, 17, 3, 1), ((7, 16, 1), (7, 18, 1)), (9, 17, 2, 1)), - ((6, 21, 3, 1), ((7, 20, 1), (7, 22, 1)), (9, 21, 2, 1)), - ((6, 25, 3, 1), ((7, 24, 1), (7, 26, 1)), (9, 25, 2, 1)), - ((6, 29, 3, 1), ((7, 28, 1), (7, 30, 1)), (9, 29, 2, 1)), - ((8, 0, 3, 1), None, None), - ((8, 2, 3, 1), None, None), - ((8, 4, 3, 1), None, None), - ((8, 6, 3, 1), None, None), - ((8, 8, 3, 1), None, None), - ((8, 10, 3, 1), None, None), - ((8, 12, 3, 1), None, None), - ((8, 14, 3, 1), None, None), - ((8, 16, 3, 1), None, None), - ((8, 18, 3, 1), None, None), - ((8, 20, 3, 1), None, None), - ((8, 22, 3, 1), None, None), - ((8, 24, 3, 1), None, None), - ((8, 26, 3, 1), None, None), - ((8, 28, 3, 1), None, None), - ((8, 30, 3, 1), None, None)) - elif self.tree_style == 0: - if self.force_size == 2: - pos = (((0, 0, 1, 3), (1, 0, 3), (2, 1, 1, 1)), - ((2, 0, 1, 1), None, None), - ((2, 2, 1, 1), None, None)) - elif self.force_size == 3: - pos = (((0, 2, 1, 3), (1, 1, 5), (2, 3, 1, 1)), - ((2, 0, 1, 3), (3, 0, 3), (4, 1, 1, 1)), - ((2, 4, 1, 3), (3, 4, 3), (4, 5, 1, 1)), - ((4, 0, 1, 1), None, None), - ((4, 2, 1, 1), None, None), - ((4, 4, 1, 1), None, None), - ((4, 6, 1, 1), None, None)) - elif self.force_size == 4: - pos = (((0, 6, 1, 3), (1, 3, 9), (2, 5, 1, 5)), - ((2, 2, 1, 3), (3, 1, 5), (4, 3, 1, 1)), - ((2, 10, 1, 3), (3, 9, 5), (4, 11, 1, 1)), - ((4, 0, 1, 3), (5, 0, 3), (6, 1, 1, 1)), - ((4, 4, 1, 3), (5, 4, 3), (6, 5, 1, 1)), - ((4, 8, 1, 3), (5, 8, 3), (6, 9, 1, 1)), - ((4, 12, 1, 3), (5, 12, 3), (6, 13, 1, 1)), - ((6, 0, 1, 1), None, None), - ((6, 2, 1, 1), None, None), - ((6, 4, 1, 1), None, None), - ((6, 6, 1, 1), None, None), - ((6, 8, 1, 1), None, None), - ((6, 10, 1, 1), None, None), - ((6, 12, 1, 1), None, None), - ((6, 14, 1, 1), None, None)) - elif self.force_size == 5: - pos = (((0, 14, 1, 3), (1, 7, 17), (2, 13, 1, 5)), - ((2, 6, 1, 3), (3, 3, 9), (4, 5, 1, 5)), - ((2, 22, 1, 3), (3, 19, 9), (4, 21, 1, 5)), - ((4, 2, 1, 3), (5, 1, 5), (6, 3, 1, 1)), - ((4, 10, 1, 3), (5, 9, 5), (6, 11, 1, 1)), - ((4, 18, 1, 3), (5, 17, 5), (6, 19, 1, 1)), - ((4, 26, 1, 3), (5, 25, 5), (6, 27, 1, 1)), - ((6, 0, 1, 3), (7, 0, 3), (8, 1, 1, 1)), - ((6, 4, 1, 3), (7, 4, 3), (8, 5, 1, 1)), - ((6, 8, 1, 3), (7, 8, 3), (8, 9, 1, 1)), - ((6, 12, 1, 3), (7, 12, 3), (8, 13, 1, 1)), - ((6, 16, 1, 3), (7, 16, 3), (8, 17, 1, 1)), - ((6, 20, 1, 3), (7, 20, 3), (8, 21, 1, 1)), - ((6, 24, 1, 3), (7, 24, 3), (8, 25, 1, 1)), - ((6, 28, 1, 3), (7, 28, 3), (8, 29, 1, 1)), - ((8, 0, 1, 1), None, None), - ((8, 2, 1, 1), None, None), - ((8, 4, 1, 1), None, None), - ((8, 6, 1, 1), None, None), - ((8, 8, 1, 1), None, None), - ((8, 10, 1, 1), None, None), - ((8, 12, 1, 1), None, None), - ((8, 14, 1, 1), None, None), - ((8, 16, 1, 1), None, None), - ((8, 18, 1, 1), None, None), - ((8, 20, 1, 1), None, None), - ((8, 22, 1, 1), None, None), - ((8, 24, 1, 1), None, None), - ((8, 26, 1, 1), None, None), - ((8, 28, 1, 1), None, None), - ((8, 30, 1, 1), None, None)) - elif self.tree_style == 2: - pos = None - - # Build ancestor tree only one for all different sizes - self._depth = 1 - lst = [None] * (1 << self.force_size) # [None] * (2**self.force_size) - self.find_tree(person, 0, 1, lst) - - self.rebuild(self.table, pos, person, lst, self.force_size) - - def rebuild(self, table_widget, positions, active_person, lst, size): - """ - Function called from rebuild_trees. - For table_widget (gtk.Table) place list of person, use positions array. - For style C position calculated, for others style use static posotins. - All display options process in this function. - """ - - if not active_person: - return - - # Purge current table content - for child in table_widget.get_children(): - child.destroy() - table_widget.resize(1, 1) - - xmax = 0 - ymax = 0 - if self.tree_style == 2: - # For style C change tree depth if they real size less then max. - if self.show_unknown_peoples: - self._depth += 1 - if size > self._depth: - size = self._depth - # Calculate max X and Y for style C - if self.tree_direction == 0 or self.tree_direction == 1: - xmax = 1 << size # xmax = (1 + 1)**size - ymax = (size << 2) + 1 # ymax = (3 + 1) * size + 1 - else: - xmax = size << 1 # xmax = 2 * size - ymax = 1 << (size + 1) # ymax = 2**size * 2 - #for i in range(0, 2**size - 1): - for i in range(0, (1<> 1) + _y * _delta - 1 - if self.tree_direction == 3: - x = x - 1 - elif self.tree_direction == 0 or self.tree_direction == 1: - y += 1 - else: - try: - x = positions[i][0][0]+1 - y = positions[i][0][1]+1 - width = positions[i][0][2] - height = positions[i][0][3] - except IndexError: # no position for this person defined - continue - if not lst[i] and \ - ((self.tree_style == 2 and self.show_unknown_peoples and - lst[((i+1)>>1)-1]) or self.tree_style != 2): - # No person -> show empty box - if cairo_available: - pbw = PersonBoxWidgetCairo( - self, self.format_helper, None, False, 0, None) - else: - pbw = PersonBoxWidget( - self, self.format_helper, None, False, 0, None) - if i > 0 and lst[((i+1)>>1)-1]: # ((i+1)/2 - fam_h = None - fam = lst[((i+1)>>1)-1][2] - if fam: - fam_h = fam.get_handle() - if not self.dbstate.db.readonly: - pbw.connect("button-press-event", - self.missing_parent_button_press_cb, - lst[((i+1)>>1)-1][0].get_handle(), fam_h) - pbw.force_mouse_over = True - if self.tree_style != 2 or self.tree_direction == 2: - if width > 1: - table_widget.attach(pbw, x, x+width, y, y+height, - gtk.FILL, gtk.FILL, 0, 0) - else: - table_widget.attach(pbw, x, x+width, y, y+height, - gtk.FILL, gtk.FILL, 0, 0) - if x+width > xmax: - xmax = x+width - if y+height > ymax: - ymax = y+height - elif self.tree_direction == 0: - if width > 1: - table_widget.attach(pbw, y, y+width, x, x+height, - gtk.FILL, gtk.FILL, 0, 0) - else: - table_widget.attach(pbw, y, y+width, x, x+height, - gtk.FILL, gtk.FILL, 0, 0) - # Rotate tree for others tree directions - elif self.tree_direction == 1: - if width > 1: - table_widget.attach(pbw, y, y+width, ymax-(x+height), - ymax-x, gtk.FILL, gtk.FILL, 0, 0) - else: - table_widget.attach(pbw, y, y+width, ymax-(x+height), - ymax-x, gtk.FILL, gtk.FILL, 0, 0) - elif self.tree_direction == 3: - if width > 1: - table_widget.attach(pbw, xmax-(x+width), xmax-x, y, - y+height, gtk.FILL, gtk.FILL, 0, 0) - else: - table_widget.attach(pbw, xmax-(x+width), xmax-x, y, - y+height, gtk.FILL, gtk.FILL, 0, 0) - elif lst[i]: - # Get foto - image = None - #if self.show_images and i < ((2**size-1)/2) and height > 1: - if self.show_images and height > 1 and \ - (i < (((1<>1) or self.tree_style == 2): - media_list = lst[i][0].get_media_list() - if media_list: - photo = media_list[0] - object_handle = photo.get_reference_handle() - obj = self.dbstate.db.get_object_from_handle( - object_handle) - if obj: - mtype = obj.get_mime_type() - if mtype and mtype[0:5] == "image": - image = ThumbNails.get_thumbnail_path( - media_path_full( - self.dbstate.db, - obj.get_path()), - rectangle=photo.get_rectangle()) - if cairo_available: - pbw = PersonBoxWidgetCairo(self, self.format_helper, - lst[i][0], lst[i][3], height, image) - else: - pbw = PersonBoxWidget(self, self.format_helper, - lst[i][0], lst[i][3], height, image) - if height < 7: - pbw.set_tooltip_text(self.format_helper.format_person( - lst[i][0], 11)) - - fam_h = None - if lst[i][2]: - fam_h = lst[i][2].get_handle() - pbw.connect("button-press-event", - self.person_button_press_cb, - lst[i][0].get_handle(), fam_h) - if self.tree_style != 2 or self.tree_direction == 2: - if width > 1: - table_widget.attach(pbw, x, x+width, y, y+height, - gtk.EXPAND|gtk.FILL, gtk.EXPAND|gtk.FILL, 0, 0) - else: - table_widget.attach(pbw, x, x+width, y, y+height, - gtk.FILL, gtk.FILL, 0, 0) - if x+width > xmax: - xmax = x+width - if y+height > ymax: - ymax = y+height - elif self.tree_direction == 0: - if width > 1: - table_widget.attach(pbw, y, y+width, x, x+height, - gtk.EXPAND|gtk.FILL, gtk.EXPAND|gtk.FILL, 0, 0) - else: - table_widget.attach(pbw, y, y+width, x, x+height, - gtk.FILL, gtk.FILL, 0, 0) - # Rotate tree for others tree directions - elif self.tree_direction == 1: - if width > 1: - table_widget.attach(pbw, - y, y+width, ymax-(x+height), ymax-x, - gtk.EXPAND|gtk.FILL, gtk.EXPAND|gtk.FILL, 0, 0) - else: - table_widget.attach(pbw, - y, y+width, ymax-(x+height), ymax-x, - gtk.FILL, gtk.FILL, 0, 0) - elif self.tree_direction == 3: - if width > 1: - table_widget.attach(pbw, - xmax-(x+width), xmax-x, y, y+height, - gtk.EXPAND|gtk.FILL, gtk.EXPAND|gtk.FILL, 0, 0) - else: - table_widget.attach(pbw, - xmax-(x+width), xmax-x, y, y+height, - gtk.FILL, gtk.FILL, 0, 0) - - # Connection lines - if self.tree_style != 2 and \ - positions[i][1] and len(positions[i][1]) == 2: - # separate boxes for father and mother - x = positions[i][1][0][0]+1 - y = positions[i][1][0][1]+1 - width = 1 - height = positions[i][1][0][2] - line = gtk.DrawingArea() - line.set_size_request(20, -1) - line.connect("expose-event", self.line_expose_cb) - if lst[i] and lst[i][2]: - # Required for popup menu - line.add_events(gtk.gdk.BUTTON_PRESS_MASK) - line.connect("button-press-event", - self.relation_button_press_cb, - lst[i][2].get_handle()) - line.set_data("idx", (i<<1)+1) # i*2+1 - if lst[(i<<1)+1]: - line.set_data("rela", lst[(i<<1)+1][1]) - table_widget.attach(line, x, x+width, y, y+height, - gtk.FILL, gtk.FILL, 0, 0) - if x+width > xmax: - xmax = x+width - if y+height > ymax: - ymax = y+height - - x = positions[i][1][1][0]+1 - y = positions[i][1][1][1]+1 - w = 1 - h = positions[i][1][1][2] - line = gtk.DrawingArea() - line.set_size_request(20, -1) - line.connect("expose-event", self.line_expose_cb) - if lst[i] and lst[i][2]: - # Required for popup menu - line.add_events(gtk.gdk.BUTTON_PRESS_MASK) - line.connect("button-press-event", - self.relation_button_press_cb, - lst[i][2].get_handle()) - line.set_data("idx", (i+1)<<1) # i*2+2 - if lst[(i+1)<<1]: - line.set_data("rela", lst[(i+1)<<1][1]) - table_widget.attach(line, x, x+width, y, y+height, - gtk.FILL, gtk.FILL, 0, 0) - if x+width > xmax: - xmax = x+width - if y+height > ymax: - ymax = y+height - elif (self.tree_style != 2 and - positions[i][1] and len(positions[i][1]) == 3) or \ - (self.tree_style == 2 and (_x+1) < size and lst[i]): - # combined for father and mother - if self.tree_style == 2: - x = (1 + _width) * (_x + 1) - # y = _delta/4 + _y*_delta-1+_height/2 - y = (_delta >> 2) + _y*_delta-1 + (_height >> 1) - width = 1 - height = (_delta >> 1)+1 # _delta/2+1 - if self.tree_direction == 3: - x = x - 1 - elif self.tree_direction == 0 or self.tree_direction == 1: - y = y + 1 - else: - x = positions[i][1][0]+1 - y = positions[i][1][1]+1 - width = 1 - height = positions[i][1][2] - line = gtk.DrawingArea() - line.set_size_request(20, 20) - line.connect("expose-event", self.tree_expose_cb) - if lst[i] and lst[i][2]: - # Required for popup menu - line.add_events(gtk.gdk.BUTTON_PRESS_MASK) - line.connect("button-press-event", - self.relation_button_press_cb, - lst[i][2].get_handle()) - line.set_data("height", height) - if lst[i] and lst[i][2]: - # Required for tooltip and mouse-over - line.add_events(gtk.gdk.ENTER_NOTIFY_MASK) - # Required for tooltip and mouse-over - line.add_events(gtk.gdk.LEAVE_NOTIFY_MASK) - line.set_tooltip_text( - self.format_helper.format_relation(lst[i][2], 11)) - if lst[(i<<1)+1]: # i*2+1 - line.set_data("frela", lst[(i<<1)+1][1]) - if lst[(i+1)<<1]: # i*2+2 - line.set_data("mrela", lst[(i+1)<<1][1]) - if self.tree_style != 2 or self.tree_direction == 2: - table_widget.attach(line, x, x+width, y, y+height, - gtk.FILL, gtk.FILL, 0, 0) - if x+width > xmax: - xmax = x+width - if y+height > ymax: - ymax = y+height - # Rotate tree for others tree directions - elif self.tree_direction == 0: - table_widget.attach(line, y, y+height, x, x+width, - gtk.FILL, gtk.FILL, 0, 0) - elif self.tree_direction == 1: - table_widget.attach(line, y, y+height, ymax-(x+width), - ymax-x, gtk.FILL, gtk.FILL, 0, 0) - elif self.tree_direction == 3: - table_widget.attach(line, xmax-(x+width), xmax-x, y, - y+height, gtk.FILL, gtk.FILL, 0, 0) - - # Show marriage data - if self.show_marriage_data and \ - ((self.tree_style != 2 and positions[i][2]) or - (self.tree_style == 2 and (_x+1) < size)): - if lst[i] and lst[i][2]: - text = self.format_helper.format_relation(lst[i][2], 1) - else: - text = " " - label = gtk.Label(text) - label.set_justify(gtk.JUSTIFY_LEFT) - label.set_line_wrap(True) - label.set_alignment(0.1, 0.5) - if self.tree_style == 2: - x = (1 + _width) * (_x + 1) + 1 - # y = _delta / 2 + _y * _delta -1 + _height / 2 - y = (_delta >> 1) + _y * _delta - 1 + (_height >> 1) - width = 1 - height = 1 - if self.tree_direction == 3: - x = x - 1 - elif self.tree_direction == 0 or self.tree_direction == 1: - y = y + 1 - else: - x = positions[i][2][0]+1 - y = positions[i][2][1]+1 - width = positions[i][2][2] - height = positions[i][2][3] - if self.tree_style != 2 or self.tree_direction == 2: - table_widget.attach(label, x, x+width, y, y+height, - gtk.FILL, gtk.FILL, 0, 0) - # Rotate tree for others tree directions - elif self.tree_direction == 0: - table_widget.attach(label, y, y+width, x, x+height, - gtk.FILL, gtk.FILL, 0, 0) - elif self.tree_direction == 1: - table_widget.attach(label, y, y+width, ymax-(x+height), - ymax-x, gtk.FILL, gtk.FILL, 0, 0) - elif self.tree_direction == 3: - table_widget.attach(label, xmax-(x+width), xmax-x, y, - y+height, gtk.FILL, gtk.FILL, 0, 0) - - # Add navigation arrows - if lst[0]: - if self.tree_style != 2 or self.tree_direction == 2: - arrow_top = gtk.ARROW_LEFT - arrow_buttom = gtk.ARROW_RIGHT - elif self.tree_direction == 0: - arrow_top = gtk.ARROW_UP - arrow_buttom = gtk.ARROW_DOWN - elif self.tree_direction == 1: - arrow_top = gtk.ARROW_DOWN - arrow_buttom = gtk.ARROW_UP - elif self.tree_direction == 3: - arrow_top = gtk.ARROW_RIGHT - arrow_buttom = gtk.ARROW_LEFT - - button = gtk.Button() - button.add(gtk.Arrow(arrow_top, gtk.SHADOW_IN)) - childlist = find_children(self.dbstate.db, lst[0][0]) - if childlist: - button.connect("clicked", self.on_show_child_menu) - button.set_tooltip_text(_("Jump to child...")) - else: - button.set_sensitive(False) - if self.tree_style != 2 or self.tree_direction == 2: - ymid = int(math.floor(ymax/2)) - table_widget.attach(button, 0, 1, ymid, ymid+1, 0, 0, 0, 0) - elif self.tree_direction == 0: - xmid = int(math.floor(xmax/2)) - table_widget.attach(button, xmid, xmid+1, 0, 1, 0, 0, 0, 0) - elif self.tree_direction == 1: - xmid = int(math.floor(xmax/2)) - table_widget.attach(button, xmid, xmid+1, ymax, ymax+1, - 0, 0, 0, 0) - elif self.tree_direction == 3: - ymid = int(math.floor(ymax/2)) - table_widget.attach(button, xmax, xmax+1, ymid, ymid+1, - 0, 0, 0, 0) - - button = gtk.Button() - button.add(gtk.Arrow(arrow_buttom, gtk.SHADOW_IN)) - if lst[1]: - button.connect("clicked", self.on_childmenu_changed, - lst[1][0].handle) - button.set_tooltip_text(("Jump to father")) - else: - button.set_sensitive(False) - if self.tree_style != 2 or self.tree_direction == 2: - ymid = int(math.floor(ymax/4)) - table_widget.attach(button, xmax, xmax+1, ymid-1, ymid+2, - 0, 0, 0, 0) - elif self.tree_direction == 0: - xmid = int(math.floor(xmax/4)) - table_widget.attach(button, xmid-1, xmid+2, ymax, ymax+1, - 0, 0, 0, 0) - elif self.tree_direction == 1: - xmid = int(math.floor(xmax/4)) - table_widget.attach(button, xmid-1, xmid+2, 0, 1, 0, 0, 0, 0) - elif self.tree_direction == 3: - ymid = int(math.floor(ymax/4)) - table_widget.attach(button, 0, 1, ymid-1, ymid+2, 0, 0, 0, 0) - - button = gtk.Button() - button.add(gtk.Arrow(arrow_buttom, gtk.SHADOW_IN)) - if lst[2]: - button.connect("clicked", self.on_childmenu_changed, - lst[2][0].handle) - button.set_tooltip_text(_("Jump to mother")) - else: - button.set_sensitive(False) - if self.tree_style != 2 or self.tree_direction == 2: - ymid = int(math.floor(ymax/4*3)) - table_widget.attach(button, xmax, xmax+1, ymid-1, ymid+2, - 0, 0, 0, 0) - elif self.tree_direction == 0: - xmid = int(math.floor(xmax/4*3)) - table_widget.attach(button, xmid-1, xmid+2, ymax, ymax+1, - 0, 0, 0, 0) - elif self.tree_direction == 1: - xmid = int(math.floor(xmax/4*3)) - table_widget.attach(button, xmid-1, xmid+2, 0, 1, 0, 0, 0, 0) - elif self.tree_direction == 3: - ymid = int(math.floor(ymax/4*3)) - table_widget.attach(button, 0, 1, ymid-1, ymid+2, 0, 0, 0, 0) - - # add dummy widgets into the corners of the table - # to allow the pedigree to be centered - label = gtk.Label("") - table_widget.attach(label, 0, 1, 0, 1, - gtk.EXPAND|gtk.FILL, gtk.EXPAND|gtk.FILL, 0, 0) - label = gtk.Label("") - table_widget.attach(label, xmax, xmax+1, ymax, ymax+1, - gtk.EXPAND|gtk.FILL, gtk.EXPAND|gtk.FILL, 0, 0) - - debug = False - if debug: - used_cells = {} - xmax = 0 - ymax = 0 - # iterate table to see which cells are used. - for child in table_widget.get_children(): - left = table_widget.child_get_property(child, "left-attach") - right = table_widget.child_get_property(child, "right-attach") - top = table_widget.child_get_property(child, "top-attach") - bottom = table_widget.child_get_property(child, "bottom-attach") - for x in range(left, right): - for y in range(top, bottom): - try: - used_cells[x][y] = True - except KeyError: - used_cells[x] = {} - used_cells[x][y] = True - if y > ymax: - ymax = y - if x > xmax: - xmax = x - for x in range(0, xmax+1): - for y in range(0, ymax+1): - try: - tmp = used_cells[x][y] - except KeyError: - # fill unused cells - label = gtk.Label("%d,%d"%(x, y)) - frame = gtk.ScrolledWindow(None, None) - frame.set_shadow_type(gtk.SHADOW_NONE) - frame.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER) - frame.add_with_viewport(label) - table_widget.attach(frame, x, x+1, y, y+1, - gtk.FILL, gtk.FILL, 0, 0) - table_widget.show_all() - - # Setup scrollbars for view root person - window = table_widget.get_parent().get_parent() - hadjustment = window.get_hadjustment() - vadjustment = window.get_vadjustment() - if self.tree_style != 2 or self.tree_direction == 2: - self.update_scrollbar_positions(hadjustment, hadjustment.lower) - self.update_scrollbar_positions(vadjustment, - (vadjustment.upper - vadjustment.page_size) / 2) - elif self.tree_direction == 0: - self.update_scrollbar_positions(hadjustment, - (hadjustment.upper - hadjustment.page_size) / 2) - self.update_scrollbar_positions(vadjustment, - vadjustment.upper - vadjustment.page_size) - elif self.tree_direction == 1: - self.update_scrollbar_positions(hadjustment, - (hadjustment.upper - hadjustment.page_size) / 2) - self.update_scrollbar_positions(vadjustment, vadjustment.lower) - elif self.tree_direction == 3: - self.update_scrollbar_positions(hadjustment, - hadjustment.upper - hadjustment.page_size) - self.update_scrollbar_positions(vadjustment, - (vadjustment.upper - vadjustment.page_size) / 2) - - # Setup mouse whell scroll direction for styce C, - # depending of tree direction - if self.tree_style == 2: - if self.tree_direction in [0, 1]: - self.change_scroll_direction_cb(None, True) - elif self.tree_direction in [2, 3]: - self.change_scroll_direction_cb(None, False) - - def line_expose_cb(self, area, event): - """Expose tree lines for style B.""" - gc = area.window.new_gc() - alloc = area.get_allocation() - idx = area.get_data("idx") - rela = area.get_data("rela") - if not rela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - gc.line_width = 3 - if idx % 2 == 0: - area.window.draw_line(gc, alloc.width, alloc.height>>1, - alloc.width>>1, alloc.height>>1) - area.window.draw_line(gc, alloc.width>>1, 0, - alloc.width>>1, alloc.height>>1) - else: - area.window.draw_line(gc, alloc.width, alloc.height>>1, - alloc.width>>1, alloc.height>>1) - area.window.draw_line(gc, alloc.width>>1, alloc.height, - alloc.width>>1, alloc.height>>1) - - def tree_expose_cb(self, area, event): - """ - Expose tree lines for style A and C. - For style C check options show unknown peoples and tree direction. - """ - gc = area.window.new_gc() - alloc = area.get_allocation() - height = area.get_data("height") - frela = area.get_data("frela") - mrela = area.get_data("mrela") - if not frela and not mrela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - gc.line_width = 3 - rela = area.get_data("mrela") - if self.tree_style != 2 or self.tree_direction == 2: - gap = alloc.height / (height<<1) - if self.tree_style == 2 and \ - (self.show_unknown_peoples or - (not self.show_unknown_peoples and (frela or mrela))) or \ - self.tree_style != 2: - area.window.draw_line(gc, 0, alloc.height>>1, - alloc.width>>1, alloc.height>>1) - - if self.tree_style == 2 and \ - (self.show_unknown_peoples or - (not self.show_unknown_peoples and frela)) or \ - self.tree_style != 2: - if not frela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - area.window.draw_line(gc, alloc.width>>1, alloc.height>>1, - alloc.width>>1, gap) - area.window.draw_line(gc, alloc.width>>1, gap, - alloc.width, gap) - - if self.tree_style == 2 and \ - (self.show_unknown_peoples or - (not self.show_unknown_peoples and mrela)) or \ - self.tree_style != 2: - if not mrela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - area.window.draw_line(gc, alloc.width>>1, alloc.height>>1, - alloc.width>>1, alloc.height-gap) - area.window.draw_line(gc, alloc.width>>1, alloc.height-gap, - alloc.width, alloc.height-gap) - elif self.tree_direction == 0: - gap = alloc.width / (height<<1) - if self.show_unknown_peoples or \ - (not self.show_unknown_peoples and (frela or mrela)): - area.window.draw_line(gc, alloc.width>>1, 0, - alloc.width>>1, alloc.height>>1) - - if self.show_unknown_peoples or \ - (not self.show_unknown_peoples and frela): - if not frela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - area.window.draw_line(gc, alloc.width>>1, alloc.height>>1, - gap, alloc.height>>1) - area.window.draw_line(gc, gap, alloc.height>>1, - gap, alloc.height) - - if self.show_unknown_peoples or \ - (not self.show_unknown_peoples and mrela): - if not mrela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - area.window.draw_line(gc, alloc.width>>1, alloc.height>>1, - alloc.width-gap, alloc.height>>1) - area.window.draw_line(gc, alloc.width-gap, alloc.height>>1, - alloc.width-gap, alloc.height) - elif self.tree_direction == 1: - gap = alloc.width / (height<<1) - if self.show_unknown_peoples or \ - (not self.show_unknown_peoples and (frela or mrela)): - area.window.draw_line(gc, alloc.width>>1, alloc.height>>1, - alloc.width>>1, alloc.height) - - if self.show_unknown_peoples or \ - (not self.show_unknown_peoples and frela): - if not frela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - area.window.draw_line(gc, alloc.width>>1, alloc.height>>1, - gap, alloc.height>>1) - area.window.draw_line(gc, gap, 0, gap, alloc.height>>1) - - if self.show_unknown_peoples or \ - (not self.show_unknown_peoples and mrela): - if not mrela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - area.window.draw_line(gc, alloc.width>>1, alloc.height>>1, - alloc.width-gap, alloc.height>>1) - area.window.draw_line(gc, alloc.width-gap, 0, - alloc.width-gap, alloc.height>>1) - elif self.tree_direction == 3: - gap = alloc.height / (height<<1) - if self.show_unknown_peoples or \ - (not self.show_unknown_peoples and (frela or mrela)): - area.window.draw_line(gc, alloc.width>>1, alloc.height>>1, - alloc.width, alloc.height>>1) - - if self.show_unknown_peoples or \ - (not self.show_unknown_peoples and frela): - if not frela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - area.window.draw_line(gc, alloc.width>>1, alloc.height>>1, - alloc.width>>1, gap) - area.window.draw_line(gc, alloc.width>>1, gap, 0, gap) - - if self.show_unknown_peoples or \ - (not self.show_unknown_peoples and mrela): - if not mrela: - gc.line_style = gtk.gdk.LINE_ON_OFF_DASH - else: - gc.line_style = gtk.gdk.LINE_SOLID - area.window.draw_line(gc, alloc.width>>1, alloc.height>>1, - alloc.width>>1, alloc.height-gap) - area.window.draw_line(gc, alloc.width>>1, alloc.height-gap, - 0, alloc.height-gap) - - def home(self, menuitem): - """Change root person to default person for database.""" - defperson = self.dbstate.db.get_default_person() - if defperson: - self.change_active(defperson.get_handle()) - - def edit_person_cb(self, obj, person_handle): - """ - Open edit person window for person_handle. - Called after double click or from submenu. - """ - person = self.dbstate.db.get_person_from_handle(person_handle) - if person: - try: - EditPerson(self.dbstate, self.uistate, [], person) - except Errors.WindowActiveError: - pass - return True - return False - - def edit_family_cb(self, obj, family_handle): - """ - Open edit person family for family_handle. - Called after double click or from submenu. - """ - family = self.dbstate.db.get_family_from_handle(family_handle) - if family: - try: - EditFamily(self.dbstate, self.uistate, [], family) - except Errors.WindowActiveError: - pass - return True - return False - - def add_parents_cb(self, obj, person_handle, family_handle): - """Edit not full family.""" - if family_handle: # one parent already exists -> Edit current family - family = self.dbstate.db.get_family_from_handle(family_handle) - else: # no parents -> create new family - family = gen.lib.Family() - childref = gen.lib.ChildRef() - childref.set_reference_handle(person_handle) - family.add_child_ref(childref) - try: - EditFamily(self.dbstate, self.uistate, [], family) - except Errors.WindowActiveError: - pass - - def copy_person_to_clipboard_cb(self, obj, person_handle): - """ - Renders the person data into some lines of text and - puts that into the clipboard - """ - person = self.dbstate.db.get_person_from_handle(person_handle) - if person: - clipboard = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD) - clipboard.set_text(self.format_helper.format_person(person, 11)) - return True - return False - - def copy_family_to_clipboard_cb(self, obj, family_handle): - """ - Renders the family data into some lines of text and - puts that into the clipboard - """ - family = self.dbstate.db.get_family_from_handle(family_handle) - if family: - clipboard = gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD) - clipboard.set_text(self.format_helper.format_relation(family, 11)) - return True - return False - - def on_show_option_menu_cb(self, obj, event, data=None): - """Right click option menu.""" - menu = gtk.Menu() - self.add_nav_portion_to_menu(menu) - self.add_settings_to_menu(menu) - menu.popup(None, None, None, 0, event.time) - return True - - def bg_button_press_cb(self, widget, event): - """ - Enter in scroll mode when mouse button pressed in background - or call option menu. - """ - if event.button == 1 and event.type == gtk.gdk.BUTTON_PRESS: - widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.FLEUR)) - self._last_x = event.x - self._last_y = event.y - self._in_move = True - return True - elif event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: - self.on_show_option_menu_cb(widget, event) - return True - return False - - def bg_button_release_cb(self, widget, event): - """Exit from scroll mode when button release.""" - if event.button == 1 and event.type == gtk.gdk.BUTTON_RELEASE: - self.bg_motion_notify_event_cb(widget, event) - widget.window.set_cursor(None) - self._in_move = False - return True - return False - - def bg_motion_notify_event_cb(self, widget, event): - """Function for motion notify events for drag and scroll mode.""" - if self._in_move and (event.type == gtk.gdk.MOTION_NOTIFY or \ - event.type == gtk.gdk.BUTTON_RELEASE): - window = widget.get_parent() - hadjustment = window.get_hadjustment() - vadjustment = window.get_vadjustment() - self.update_scrollbar_positions(vadjustment, - vadjustment.value - (event.y - self._last_y)) - self.update_scrollbar_positions(hadjustment, - hadjustment.value - (event.x - self._last_x)) - return True - return False - - def update_scrollbar_positions(self, adjustment, value): - """Controle value then try setup in scrollbar.""" - if value > (adjustment.upper - adjustment.page_size): - adjustment.set_value(adjustment.upper - adjustment.page_size) - else: - adjustment.set_value(value) - return True - - def bg_scroll_event(self, widget, event): - """ - Function change scroll direction to horizontally - if variable self.scroll_direction setup. - """ - if self.scroll_direction and event.type == gtk.gdk.SCROLL: - if event.direction == gtk.gdk.SCROLL_UP: - event.direction = gtk.gdk.SCROLL_LEFT - elif event.direction == gtk.gdk.SCROLL_DOWN: - event.direction = gtk.gdk.SCROLL_RIGHT - return False - - def person_button_press_cb(self, obj, event, person_handle, family_handle): - """ - Call edit person function for mouse left button double click on person - or submenu for person for mouse right click. - And setup plug for button press on person widget. - """ - if event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: - self.build_full_nav_menu_cb(obj, event, - person_handle, family_handle) - return True - elif event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS: - self.edit_person_cb(obj, person_handle) - return True - return True - - def relation_button_press_cb(self, obj, event, family_handle): - """ - Call edit family function for mouse left button double click - on family line or call full submenu for mouse right click. - And setup plug for button press on family line. - """ - if event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: - self.build_relation_nav_menu_cb(obj, event, family_handle) - return True - elif event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS: - self.edit_family_cb(obj, family_handle) - return True - return True - - def missing_parent_button_press_cb(self, obj, event, - person_handle, family_handle): - """ - Call function for not full family for mouse left button double click - on missing persons or call submenu for mouse right click. - """ - if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS: - self.add_parents_cb(obj, person_handle, family_handle) - return True - elif event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: - self.build_missing_parent_nav_menu_cb(obj, event, person_handle, - family_handle) - return True - return False - - def on_show_child_menu(self, obj): - """User clicked button to move to child of active person""" - person = self.dbstate.db.get_person_from_handle(self.get_active()) - if person: - # Build and display the menu attached to the left pointing arrow - # button. The menu consists of the children of the current root - # person of the tree. Attach a child to each menu item. - - childlist = find_children(self.dbstate.db, person) - if len(childlist) == 1: - child = self.dbstate.db.get_person_from_handle(childlist[0]) - if child: - self.change_active(childlist[0]) - elif len(childlist) > 1: - myMenu = gtk.Menu() - for child_handle in childlist: - child = self.dbstate.db.get_person_from_handle(child_handle) - cname = escape(name_displayer.display(child)) - if find_children(self.dbstate.db, child): - label = gtk.Label('%s' % cname) - else: - label = gtk.Label(cname) - label.set_use_markup(True) - label.show() - label.set_alignment(0, 0) - menuitem = gtk.ImageMenuItem(None) - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, - gtk.ICON_SIZE_MENU) - go_image.show() - menuitem.set_image(go_image) - menuitem.add(label) - myMenu.append(menuitem) - menuitem.connect("activate", self.on_childmenu_changed, - child_handle) - menuitem.show() - myMenu.popup(None, None, None, 0, 0) - return 1 - return 0 - - def on_childmenu_changed(self, obj, person_handle): - """ - Callback for the pulldown menu selection, changing to the person - attached with menu item. - """ - self.change_active(person_handle) - return True - - def change_force_size_cb(self, menuitem, data): - """Change force_size option.""" - if data in [2, 3, 4, 5, 6, 7, 8, 9, 10]: - config.set('interface.pedview-tree-size', data) - self.force_size = data - self.dirty = True - # switch to matching size - self.rebuild_trees(self.get_active()) - - def change_tree_style_cb(self, menuitem, data): - """Change tree_style option.""" - if data in [0, 1, 2]: - config.set('interface.pedviewext-layout', data) - if self.tree_style != data: - if self.tree_style == 2 and self.force_size > 5: - self.force_size = 5 - self.dirty = True - self.tree_style = data - self.rebuild_trees(self.get_active()) - - def change_tree_direction_cb(self, menuitem, data): - """Change tree_direction option.""" - if data in [0, 1, 2, 3]: - config.set('interface.pedviewext-tree-direction', data) - if self.tree_direction != data: - self.dirty = True - self.tree_direction = data - self.rebuild_trees(self.get_active()) - - def change_show_images_cb(self, event): - """Change show_images option.""" - self.show_images = not self.show_images - config.set('interface.pedviewext-show-images', self.show_images) - self.dirty = True - self.rebuild_trees(self.get_active()) - - def change_show_marriage_cb(self, event): - """Change show_marriage_data option.""" - self.show_marriage_data = not self.show_marriage_data - config.set('interface.pedviewext-show-marriage', - self.show_marriage_data) - self.dirty = True - self.rebuild_trees(self.get_active()) - - def change_show_unknown_peoples_cb(self, event): - """Change show_unknown_peoples option.""" - self.show_unknown_peoples = not self.show_unknown_peoples - config.set('interface.pedviewext-show-unknown-peoples', - self.show_unknown_peoples) - self.dirty = True - self.rebuild_trees(self.get_active()) - - def change_scroll_direction_cb(self, menuitem, data): - """Change scroll_direction option.""" - config.set('interface.pedviewext-scroll-direction', - self.scroll_direction) - if data: - self.scroll_direction = True - else: - self.scroll_direction = False - - def kb_goto_home(self): - """Goto home person from keyboard.""" - self.home(None) - - def kb_plus_generation(self): - """Increment size of tree from keyboard.""" - self.change_force_size_cb(None, self.force_size + 1) - - def kb_minus_generation(self): - """Decrement size of tree from keyboard.""" - self.change_force_size_cb(None, self.force_size - 1) - - def kb_change_style(self): - """Change style of tree from keyboard.""" - next_style = self.tree_style + 1 - if next_style > 2: - next_style = 0 - self.change_tree_style_cb(None, next_style) - - def kb_change_direction(self): - """Change direction of tree from keyboard.""" - next_direction = self.tree_direction + 1 - if next_direction > 3: - next_direction = 0 - self.change_tree_direction_cb(None, next_direction) - - def find_tree(self, person, index, depth, lst, val=0): - """Recursively build a list of ancestors""" - - if depth > self.force_size or not person: - return - - if self._depth < depth: - self._depth = depth - - try: - alive = probably_alive(person, self.dbstate.db) - except RuntimeError: - ErrorDialog(_('Relationship loop detected'), - _('A person was found to be his/her own ancestor.')) - alive = False - - lst[index] = (person, val, None, alive) - - parent_families = person.get_parent_family_handle_list() - if parent_families: - family_handle = parent_families[0] - else: - return - - mrel = True - frel = True - family = self.dbstate.db.get_family_from_handle(family_handle) - if family: - for child_ref in family.get_child_ref_list(): - if child_ref.ref == person.handle: - mrel = child_ref.mrel == gen.lib.ChildRefType.BIRTH - frel = child_ref.frel == gen.lib.ChildRefType.BIRTH - - lst[index] = (person, val, family, alive) - father_handle = family.get_father_handle() - if father_handle: - father = self.dbstate.\ - db.get_person_from_handle(father_handle) - self.find_tree(father, (2*index)+1, depth+1, lst, frel) - mother_handle = family.get_mother_handle() - if mother_handle: - mother = self.dbstate.\ - db.get_person_from_handle(mother_handle) - self.find_tree(mother, (2*index)+2, depth+1, lst, mrel) - - def add_nav_portion_to_menu(self, menu): - """ - This function adds a common history-navigation portion - to the context menu. Used by both build_nav_menu() and - build_full_nav_menu() methods. - """ - hobj = self.uistate.get_history(self.navigation_type(), - self.navigation_group()) - home_sensitivity = True - if not self.dbstate.db.get_default_person(): - home_sensitivity = False - entries = [ - (gtk.STOCK_GO_BACK, self.back_clicked, not hobj.at_front()), - (gtk.STOCK_GO_FORWARD, self.fwd_clicked, not hobj.at_end()), - (gtk.STOCK_HOME, self.home, home_sensitivity), - (None, None, 0) - ] - - for stock_id, callback, sensitivity in entries: - item = gtk.ImageMenuItem(stock_id) - item.set_sensitive(sensitivity) - if callback: - item.connect("activate", callback) - item.show() - menu.append(item) - - def add_settings_to_menu(self, menu): - """ - Add settings to menu (Show images, Show marriage data, - Show unknown peoples, Mouse scroll direction, Tree style, - Tree size, Tree direction), marked selected items. - Othet menu for othet styles. - """ - entry = gtk.ImageMenuItem(_("Show images")) - if self.show_images: - current_show_images_image = \ - gtk.image_new_from_stock(gtk.STOCK_APPLY, gtk.ICON_SIZE_MENU) - current_show_images_image.show() - entry.set_image(current_show_images_image) - entry.connect("activate", self.change_show_images_cb) - entry.show() - menu.append(entry) - - entry = gtk.ImageMenuItem(_("Show marriage data")) - if self.show_marriage_data: - current_show_marriage_image = \ - gtk.image_new_from_stock(gtk.STOCK_APPLY, gtk.ICON_SIZE_MENU) - current_show_marriage_image.show() - entry.set_image(current_show_marriage_image) - entry.connect("activate", self.change_show_marriage_cb) - entry.show() - menu.append(entry) - - if self.tree_style == 2: - entry = gtk.ImageMenuItem(_("Show unknown peoples")) - if self.show_unknown_peoples: - current_show_unknown_peoples_image = \ - gtk.image_new_from_stock(gtk.STOCK_APPLY, - gtk.ICON_SIZE_MENU) - current_show_unknown_peoples_image.show() - entry.set_image(current_show_unknown_peoples_image) - entry.connect("activate", self.change_show_unknown_peoples_cb) - entry.show() - menu.append(entry) - - item = gtk.MenuItem(_("Mouse scroll direction")) - item.set_submenu(gtk.Menu()) - scroll_direction_menu = item.get_submenu() - - scroll_direction_image = gtk.image_new_from_stock(gtk.STOCK_APPLY, - gtk.ICON_SIZE_MENU) - scroll_direction_image.show() - - entry = gtk.ImageMenuItem(_("Top <-> Bottom")) - entry.connect("activate", self.change_scroll_direction_cb, False) - if self.scroll_direction == False: - entry.set_image(scroll_direction_image) - entry.show() - scroll_direction_menu.append(entry) - - entry = gtk.ImageMenuItem(_("Left <-> Right")) - entry.connect("activate", self.change_scroll_direction_cb, True) - if self.scroll_direction == True: - entry.set_image(scroll_direction_image) - entry.show() - scroll_direction_menu.append(entry) - - scroll_direction_menu.show() - item.show() - menu.append(item) - - item = gtk.MenuItem(_("Tree style")) - item.set_submenu(gtk.Menu()) - style_menu = item.get_submenu() - - current_style_image = gtk.image_new_from_stock(gtk.STOCK_APPLY, - gtk.ICON_SIZE_MENU) - current_style_image.show() - - entry = gtk.ImageMenuItem(_("Version A")) - entry.connect("activate", self.change_tree_style_cb, 0) - if self.tree_style == 0: - entry.set_image(current_style_image) - entry.show() - style_menu.append(entry) - - entry = gtk.ImageMenuItem(_("Version B")) - entry.connect("activate", self.change_tree_style_cb, 1) - if self.tree_style == 1: - entry.set_image(current_style_image) - entry.show() - style_menu.append(entry) - - entry = gtk.ImageMenuItem(_("Version C")) - entry.connect("activate", self.change_tree_style_cb, 2) - if self.tree_style == 2: - entry.set_image(current_style_image) - entry.show() - style_menu.append(entry) - - style_menu.show() - item.show() - menu.append(item) - - item = gtk.MenuItem(_("Tree size")) - item.set_submenu(gtk.Menu()) - size_menu = item.get_submenu() - - current_size_image = gtk.image_new_from_stock(gtk.STOCK_APPLY, - gtk.ICON_SIZE_MENU) - current_size_image.show() - - for num in range(2, 6): - entry = gtk.ImageMenuItem( - ngettext("%d generation", "%d generations", num) %num) - if self.force_size == num: - entry.set_image(current_size_image) - entry.connect("activate", self.change_force_size_cb, num) - entry.show() - size_menu.append(entry) - - if self.tree_style == 2: - - for num in range(6, 11): - entry = gtk.ImageMenuItem( - ngettext("%d generation", "%d generations", num) %num) - if self.force_size == num: - entry.set_image(current_size_image) - entry.connect("activate", self.change_force_size_cb, num) - entry.show() - size_menu.append(entry) - - item2 = gtk.MenuItem(_("Tree direction")) - item2.set_submenu(gtk.Menu()) - direction_menu = item2.get_submenu() - - current_direction_image = gtk.image_new_from_stock(gtk.STOCK_APPLY, - gtk.ICON_SIZE_MENU) - current_direction_image.show() - - entry = gtk.ImageMenuItem(_("Vertical (top to bottom)")) - entry.connect("activate", self.change_tree_direction_cb, 0) - if self.tree_direction == 0: - entry.set_image(current_direction_image) - entry.show() - direction_menu.append(entry) - - entry = gtk.ImageMenuItem(_("Vertical (bottom to top)")) - entry.connect("activate", self.change_tree_direction_cb, 1) - if self.tree_direction == 1: - entry.set_image(current_direction_image) - entry.show() - direction_menu.append(entry) - - entry = gtk.ImageMenuItem(_("Horizontal (left to right)")) - entry.connect("activate", self.change_tree_direction_cb, 2) - if self.tree_direction == 2: - entry.set_image(current_direction_image) - entry.show() - direction_menu.append(entry) - - entry = gtk.ImageMenuItem(_("Horizontal (right to left)")) - entry.connect("activate", self.change_tree_direction_cb, 3) - if self.tree_direction == 3: - entry.set_image(current_direction_image) - entry.show() - direction_menu.append(entry) - - direction_menu.show() - item2.show() - menu.append(item2) - - size_menu.show() - item.show() - menu.append(item) - - def build_missing_parent_nav_menu_cb(self, obj, event, - person_handle, family_handle): - """Builds the menu for a missing parent.""" - menu = gtk.Menu() - menu.set_title(_('People Menu')) - - add_item = gtk.ImageMenuItem(gtk.STOCK_ADD) - add_item.connect("activate", self.add_parents_cb, person_handle, - family_handle) - add_item.show() - menu.append(add_item) - - # Add history-based navigation - self.add_nav_portion_to_menu(menu) - self.add_settings_to_menu(menu) - menu.popup(None, None, None, 0, event.time) - return 1 - - def build_full_nav_menu_cb(self, obj, event, person_handle, family_handle): - """ - Builds the full menu (including Siblings, Spouses, Children, - and Parents) with navigation. - """ - - menu = gtk.Menu() - menu.set_title(_('People Menu')) - - person = self.dbstate.db.get_person_from_handle(person_handle) - if not person: - return 0 - - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, - gtk.ICON_SIZE_MENU) - go_image.show() - go_item = gtk.ImageMenuItem(name_displayer.display(person)) - go_item.set_image(go_image) - go_item.connect("activate", self.on_childmenu_changed, person_handle) - go_item.show() - menu.append(go_item) - - edit_item = gtk.ImageMenuItem(gtk.STOCK_EDIT) - edit_item.connect("activate", self.edit_person_cb, person_handle) - edit_item.show() - menu.append(edit_item) - - clipboard_item = gtk.ImageMenuItem(gtk.STOCK_COPY) - clipboard_item.connect("activate", self.copy_person_to_clipboard_cb, - person_handle) - clipboard_item.show() - menu.append(clipboard_item) - - # collect all spouses, parents and children - linked_persons = [] - - # Go over spouses and build their menu - item = gtk.MenuItem(_("Spouses")) - fam_list = person.get_family_handle_list() - no_spouses = 1 - for fam_id in fam_list: - family = self.dbstate.db.get_family_from_handle(fam_id) - if family.get_father_handle() == person.get_handle(): - sp_id = family.get_mother_handle() - else: - sp_id = family.get_father_handle() - spouse = self.dbstate.db.get_person_from_handle(sp_id) - if not spouse: - continue - - if no_spouses: - no_spouses = 0 - item.set_submenu(gtk.Menu()) - sp_menu = item.get_submenu() - - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, - gtk.ICON_SIZE_MENU) - go_image.show() - sp_item = gtk.ImageMenuItem(name_displayer.display(spouse)) - sp_item.set_image(go_image) - linked_persons.append(sp_id) - sp_item.connect("activate", self.on_childmenu_changed, sp_id) - sp_item.show() - sp_menu.append(sp_item) - - if no_spouses: - item.set_sensitive(0) - - item.show() - menu.append(item) - - # Go over siblings and build their menu - item = gtk.MenuItem(_("Siblings")) - pfam_list = person.get_parent_family_handle_list() - no_siblings = 1 - for pfam in pfam_list: - fam = self.dbstate.db.get_family_from_handle(pfam) - sib_list = fam.get_child_ref_list() - for sib_ref in sib_list: - sib_id = sib_ref.ref - if sib_id == person.get_handle(): - continue - sib = self.dbstate.db.get_person_from_handle(sib_id) - if not sib: - continue - - if no_siblings: - no_siblings = 0 - item.set_submenu(gtk.Menu()) - sib_menu = item.get_submenu() - - if find_children(self.dbstate.db, sib): - label = gtk.Label('%s' % \ - escape(name_displayer.display(sib))) - else: - label = gtk.Label(escape(name_displayer.display(sib))) - - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, - gtk.ICON_SIZE_MENU) - go_image.show() - sib_item = gtk.ImageMenuItem(None) - sib_item.set_image(go_image) - label.set_use_markup(True) - label.show() - label.set_alignment(0, 0) - sib_item.add(label) - linked_persons.append(sib_id) - sib_item.connect("activate", self.on_childmenu_changed, sib_id) - sib_item.show() - sib_menu.append(sib_item) - - if no_siblings: - item.set_sensitive(0) - item.show() - menu.append(item) - - # Go over children and build their menu - item = gtk.MenuItem(_("Children")) - no_children = 1 - childlist = find_children(self.dbstate.db, person) - for child_handle in childlist: - child = self.dbstate.db.get_person_from_handle(child_handle) - if not child: - continue - - if no_children: - no_children = 0 - item.set_submenu(gtk.Menu()) - child_menu = item.get_submenu() - - if find_children(self.dbstate.db, child): - label = gtk.Label('%s' % \ - escape(name_displayer.display(child))) - else: - label = gtk.Label(escape(name_displayer.display(child))) - - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, - gtk.ICON_SIZE_MENU) - go_image.show() - child_item = gtk.ImageMenuItem(None) - child_item.set_image(go_image) - label.set_use_markup(True) - label.show() - label.set_alignment(0, 0) - child_item.add(label) - linked_persons.append(child_handle) - child_item.connect("activate", self.on_childmenu_changed, - child_handle) - child_item.show() - child_menu.append(child_item) - - if no_children: - item.set_sensitive(0) - item.show() - menu.append(item) - - # Go over parents and build their menu - item = gtk.MenuItem(_("Parents")) - no_parents = 1 - par_list = find_parents(self.dbstate.db, person) - for par_id in par_list: - par = self.dbstate.db.get_person_from_handle(par_id) - if not par: - continue - - if no_parents: - no_parents = 0 - item.set_submenu(gtk.Menu()) - par_menu = item.get_submenu() - - if find_parents(self.dbstate.db, par): - label = gtk.Label('%s' % \ - escape(name_displayer.display(par))) - else: - label = gtk.Label(escape(name_displayer.display(par))) - - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, - gtk.ICON_SIZE_MENU) - go_image.show() - par_item = gtk.ImageMenuItem(None) - par_item.set_image(go_image) - label.set_use_markup(True) - label.show() - label.set_alignment(0, 0) - par_item.add(label) - linked_persons.append(par_id) - par_item.connect("activate", self.on_childmenu_changed, par_id) - par_item.show() - par_menu.append(par_item) - - if no_parents: - if self.tree_style == 2 and not self.show_unknown_peoples: - item.set_submenu(gtk.Menu()) - par_menu = item.get_submenu() - par_item = gtk.ImageMenuItem(_("Add New Parents...")) - par_item.connect("activate", self.add_parents_cb, person_handle, - family_handle) - par_item.show() - par_menu.append(par_item) - else: - item.set_sensitive(0) - item.show() - menu.append(item) - - # Go over parents and build their menu - item = gtk.MenuItem(_("Related")) - no_related = 1 - for p_id in find_witnessed_people(self.dbstate.db, person): - #if p_id in linked_persons: - # continue # skip already listed family members - - per = self.dbstate.db.get_person_from_handle(p_id) - if not per: - continue - - if no_related: - no_related = 0 - item.set_submenu(gtk.Menu()) - per_menu = item.get_submenu() - - label = gtk.Label(escape(name_displayer.display(per))) - - go_image = gtk.image_new_from_stock(gtk.STOCK_JUMP_TO, - gtk.ICON_SIZE_MENU) - go_image.show() - per_item = gtk.ImageMenuItem(None) - per_item.set_image(go_image) - label.set_use_markup(True) - label.show() - label.set_alignment(0, 0) - per_item.add(label) - per_item.connect("activate", self.on_childmenu_changed, p_id) - per_item.show() - per_menu.append(per_item) - - if no_related: - item.set_sensitive(0) - item.show() - menu.append(item) - - # Add separator - item = gtk.MenuItem(None) - item.show() - menu.append(item) - - # Add history-based navigation - self.add_nav_portion_to_menu(menu) - self.add_settings_to_menu(menu) - menu.popup(None, None, None, 0, event.time) - return 1 - - def build_relation_nav_menu_cb(self, obj, event, family_handle): - """Builds the menu for a parents-child relation line.""" - menu = gtk.Menu() - menu.set_title(_('Family Menu')) - - family = self.dbstate.db.get_family_from_handle(family_handle) - if not family: - return 0 - - edit_item = gtk.ImageMenuItem(gtk.STOCK_EDIT) - edit_item.connect("activate", self.edit_family_cb, family_handle) - edit_item.show() - menu.append(edit_item) - - clipboard_item = gtk.ImageMenuItem(gtk.STOCK_COPY) - clipboard_item.connect("activate", self.copy_family_to_clipboard_cb, - family_handle) - clipboard_item.show() - menu.append(clipboard_item) - - # Add separator - item = gtk.MenuItem(None) - item.show() - menu.append(item) - - # Add history-based navigation - self.add_nav_portion_to_menu(menu) - self.add_settings_to_menu(menu) - menu.popup(None, None, None, 0, event.time) - return 1