* src/PedView.py: Replaced gnome canvas by an implementation that uses gtk+ only. Still incomplete.
* src/gramps_main.py: Removed canvas specific calls of the PedView svn: r4376
This commit is contained in:
parent
7cac4ec348
commit
715cf4c956
@ -1,3 +1,8 @@
|
|||||||
|
2005-04-19 Martin Hawlisch <Martin.Hawlisch@gmx.de>
|
||||||
|
* src/PedView.py: Replaced gnome canvas by an implementation
|
||||||
|
that uses gtk+ only. Still incomplete.
|
||||||
|
* src/gramps_main.py: Removed canvas specific calls of the PedView
|
||||||
|
|
||||||
2005-04-18 Don Allingham <don@gramps-project.org>
|
2005-04-18 Don Allingham <don@gramps-project.org>
|
||||||
* src/edit_person.glade: re-add edit_person.glade
|
* src/edit_person.glade: re-add edit_person.glade
|
||||||
* src/EditPerson.py: start of new EditPerson dialog
|
* src/EditPerson.py: start of new EditPerson dialog
|
||||||
|
717
src/PedView.py
717
src/PedView.py
@ -67,125 +67,58 @@ _BURI = _('bur.')
|
|||||||
_CREM = _('crem.')
|
_CREM = _('crem.')
|
||||||
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# DispBox class
|
|
||||||
#
|
|
||||||
#-------------------------------------------------------------------------
|
|
||||||
class DispBox:
|
|
||||||
"""
|
|
||||||
This class handles the person box, including its expanded and
|
|
||||||
shrunk states, as well as the callbacks for events occurring in the box.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self,root,style,x,y,w,h,person,db,change,edit,build_menu):
|
|
||||||
shadow = _PAD
|
|
||||||
xpad = _PAD
|
|
||||||
|
|
||||||
self.db = db
|
|
||||||
self.change = change
|
|
||||||
self.edit = edit
|
|
||||||
self.build_menu = build_menu
|
|
||||||
self.x = x
|
|
||||||
self.y = y
|
|
||||||
self.w = w
|
|
||||||
self.h = h
|
|
||||||
self.person = person
|
|
||||||
self.root = root
|
|
||||||
|
|
||||||
self.name = NameDisplay.displayer.display(person)
|
|
||||||
|
|
||||||
self.exp = build_detail_string( db, person)
|
|
||||||
|
|
||||||
self.group = self.root.add(CanvasGroup,x=x,y=y)
|
|
||||||
self.shadow = self.group.add(
|
|
||||||
CanvasRect, x1=shadow, y1=shadow, x2=w+shadow, y2=h+shadow,
|
|
||||||
outline_color_gdk=style.dark[gtk.STATE_NORMAL],
|
|
||||||
fill_color_gdk=style.dark[gtk.STATE_NORMAL])
|
|
||||||
|
|
||||||
# draw the real box
|
|
||||||
self.bkgnd = self.group.add(
|
|
||||||
CanvasRect, x1=0, y1=0, x2=w, y2=h,
|
|
||||||
outline_color_gdk=style.fg[gtk.STATE_NORMAL],
|
|
||||||
fill_color_gdk=style.base[gtk.STATE_NORMAL])
|
|
||||||
|
|
||||||
font = gtk.gdk.font_from_description(style.font_desc)
|
|
||||||
self.textbox = self.group.add(
|
|
||||||
CanvasText, x=xpad, y=h/2.0, text=self.name,
|
|
||||||
fill_color_gdk=style.text[gtk.STATE_NORMAL],
|
|
||||||
font=font, anchor=gtk.ANCHOR_WEST)
|
|
||||||
self.group.connect('event',self.group_event)
|
|
||||||
self.group.set_data(_PERSON,person.get_handle())
|
|
||||||
|
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
self.shadow.destroy()
|
|
||||||
self.bkgnd.destroy()
|
|
||||||
self.textbox.destroy()
|
|
||||||
self.group.destroy()
|
|
||||||
return
|
|
||||||
|
|
||||||
def group_event(self,obj,event):
|
|
||||||
"""Handle events over a drawn box. Doubleclick would edit,
|
|
||||||
shift doubleclick would change the active person, entering
|
|
||||||
the box expands it to display more information, leaving a
|
|
||||||
box returns it to the original size and information"""
|
|
||||||
if event.type == gtk.gdk._2BUTTON_PRESS:
|
|
||||||
self.edit(self.person)
|
|
||||||
return 0
|
|
||||||
elif event.type == gtk.gdk.ENTER_NOTIFY:
|
|
||||||
self.expand()
|
|
||||||
return 0
|
|
||||||
elif event.type == gtk.gdk.LEAVE_NOTIFY:
|
|
||||||
self.shrink()
|
|
||||||
return 0
|
|
||||||
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
|
|
||||||
self.build_menu(event,self.person)
|
|
||||||
return True
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def expand(self):
|
|
||||||
"""Expand a box to include additional information"""
|
|
||||||
self.textbox.set(text=self.exp)
|
|
||||||
self.bkgnd.set(y1=-self.h,y2=self.h*2)
|
|
||||||
self.shadow.set(y1=-self.h+_PAD,y2=self.h*2+_PAD)
|
|
||||||
|
|
||||||
def shrink(self):
|
|
||||||
"""Expand a box to include additional information"""
|
|
||||||
self.textbox.set(text=self.name)
|
|
||||||
self.bkgnd.set(y1=0,y2=self.h)
|
|
||||||
self.shadow.set(y1=_PAD,y2=self.h+_PAD)
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# PedigreeView
|
# PedigreeView
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
class PedigreeView:
|
class PedigreeView:
|
||||||
def __init__(self,parent,canvas,update,status_bar,lp):
|
def __init__(self,parent,canvas,update,status_bar,edit_person):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
self.relcalc = Relationship.RelationshipCalculator(self.parent.db)
|
self.relcalc = Relationship.RelationshipCalculator(self.parent.db)
|
||||||
self.parent.connect('database-changed',self.change_db)
|
self.parent.connect('database-changed',self.change_db)
|
||||||
self.parent.connect('active-changed',self.active_changed)
|
self.parent.connect('active-changed',self.active_changed)
|
||||||
|
|
||||||
self.canvas = canvas
|
# FIXME: Hack to avoid changing the glade file
|
||||||
self.canvas_items = []
|
# Replace canvas by notebook
|
||||||
self.boxes = []
|
parent_container = canvas.get_parent()
|
||||||
self.root = self.canvas.root()
|
canvas.destroy()
|
||||||
self.active_person = None
|
self.notebook = gtk.Notebook()
|
||||||
self.x1 = 0
|
self.notebook.set_show_border(False)
|
||||||
self.x2 = 0
|
self.notebook.set_show_tabs(False)
|
||||||
self.y1 = 0
|
parent_container.add_with_viewport(self.notebook)
|
||||||
self.y2 = 0
|
# ###
|
||||||
|
|
||||||
|
self.table_2 = gtk.Table(1,1,False)
|
||||||
|
self.add_table_to_notebook( self.table_2)
|
||||||
|
|
||||||
|
self.table_3 = gtk.Table(1,1,False)
|
||||||
|
self.add_table_to_notebook( self.table_3)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
parent_container.connect("size-allocate", self.size_request_cb)
|
||||||
|
|
||||||
|
self.notebook.show_all()
|
||||||
|
|
||||||
self.update = update
|
self.update = update
|
||||||
self.sb = status_bar
|
self.sb = status_bar
|
||||||
self.load_person = lp
|
self.edit_person = edit_person
|
||||||
self.anchor = None
|
|
||||||
self.canvas.parent.connect('button-press-event',self.on_canvas_press)
|
|
||||||
self.change_db(self.parent.db)
|
self.change_db(self.parent.db)
|
||||||
self.distance = self.relcalc.get_relationship_distance
|
self.distance = self.relcalc.get_relationship_distance
|
||||||
|
|
||||||
|
def add_table_to_notebook( self, table):
|
||||||
|
frame = gtk.ScrolledWindow(None,None)
|
||||||
|
frame.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
|
||||||
|
frame.add_with_viewport(table)
|
||||||
|
self.notebook.append_page(frame,None)
|
||||||
|
|
||||||
def change_db(self,db):
|
def change_db(self,db):
|
||||||
# Reconnect signals
|
# Reconnect signals
|
||||||
self.db = db
|
self.db = db
|
||||||
@ -197,188 +130,270 @@ class PedigreeView:
|
|||||||
self.active_person = None
|
self.active_person = None
|
||||||
|
|
||||||
def person_updated_cb(self,handle_list):
|
def person_updated_cb(self,handle_list):
|
||||||
self.load_canvas(self.active_person)
|
self.rebuild_trees(self.active_person)
|
||||||
|
|
||||||
def person_rebuild(self):
|
def person_rebuild(self):
|
||||||
self.load_canvas(self.active_person)
|
self.rebuild_trees(self.active_person)
|
||||||
|
|
||||||
def active_changed(self,handle):
|
def active_changed(self,handle):
|
||||||
if handle:
|
if handle:
|
||||||
self.active_person = self.db.get_person_from_handle(handle)
|
self.active_person = self.db.get_person_from_handle(handle)
|
||||||
self.load_canvas(self.active_person)
|
self.rebuild_trees(self.active_person)
|
||||||
else:
|
else:
|
||||||
self.load_canvas(None)
|
self.rebuild_trees(None)
|
||||||
|
|
||||||
def clear(self):
|
def size_request_cb(self, widget, event, data=None):
|
||||||
for i in self.canvas_items:
|
v = widget.get_allocation()
|
||||||
i.destroy()
|
page_list = range(0,self.notebook.get_n_pages())
|
||||||
for i in self.boxes:
|
page_list.reverse()
|
||||||
i.cleanup()
|
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;
|
||||||
|
|
||||||
def load_canvas(self, person):
|
def rebuild_trees(self,person):
|
||||||
"""Redraws the pedigree view window, using the passed person
|
pos_2 =((0,1,3,(3,2,7)),
|
||||||
as the root person of the tree."""
|
(2,0,1,None),
|
||||||
|
(2,4,1,None))
|
||||||
self.clear()
|
pos_3 =((0,2,5,(3,4,5)),
|
||||||
|
(2,1,1,(5,1,1)),
|
||||||
if person is not self.active_person:
|
(2,7,1,(5,7,1)),
|
||||||
self.active_person = person
|
(4,0,1,None),
|
||||||
if person == None:
|
(4,2,1,None),
|
||||||
return
|
(4,6,1,None),
|
||||||
|
(4,8,1,None))
|
||||||
h = 0
|
pos_4 =((0, 5,5,(3, 7,5)),
|
||||||
w = 0
|
(2, 2,3,(5, 3,3)),
|
||||||
(x2,y2) = self.canvas.get_size()
|
(2,10,3,(5,11,3)),
|
||||||
|
(4, 1,1,(7,1,1)),
|
||||||
self.canvas.set_scroll_region(0,0,x2,y2)
|
(4, 5,1,(7,5,1)),
|
||||||
|
(4, 9,1,(7,9,1)),
|
||||||
style = self.canvas.get_style()
|
(4,13,1,(7,13,1)),
|
||||||
font = gtk.gdk.font_from_description(style.font_desc)
|
(6, 0,1,None),
|
||||||
|
(6, 2,1,None),
|
||||||
|
(6, 4,1,None),
|
||||||
|
(6, 6,1,None),
|
||||||
|
(6, 8,1,None),
|
||||||
|
(6,10,1,None),
|
||||||
|
(6,12,1,None),
|
||||||
|
(6,14,1,None),)
|
||||||
|
pos_5 =((0,10,11,(3,15,3)),
|
||||||
|
(2, 5,5,(5, 7,1)),
|
||||||
|
(2,21,5,(5,23,1)),
|
||||||
|
(4, 2,3,(7,3,1)),
|
||||||
|
(4,10,3,(7,11,1)),
|
||||||
|
(4,18,3,(7,19,1)),
|
||||||
|
(4,26,3,(7,27,1)),
|
||||||
|
(6, 1,1,(9,1,1)),
|
||||||
|
(6, 5,1,(9,5,1)),
|
||||||
|
(6, 9,1,(9,9,1)),
|
||||||
|
(6,13,1,(9,13,1)),
|
||||||
|
(6,17,1,(9,17,1)),
|
||||||
|
(6,21,1,(9,21,1)),
|
||||||
|
(6,25,1,(9,25,1)),
|
||||||
|
(6,29,1,(9,29,1)),
|
||||||
|
(8, 0,1,None),
|
||||||
|
(8, 2,1,None),
|
||||||
|
(8, 4,1,None),
|
||||||
|
(8, 6,1,None),
|
||||||
|
(8, 8,1,None),
|
||||||
|
(8,10,1,None),
|
||||||
|
(8,12,1,None),
|
||||||
|
(8,14,1,None),
|
||||||
|
(8,16,1,None),
|
||||||
|
(8,18,1,None),
|
||||||
|
(8,20,1,None),
|
||||||
|
(8,22,1,None),
|
||||||
|
(8,24,1,None),
|
||||||
|
(8,26,1,None),
|
||||||
|
(8,28,1,None),
|
||||||
|
(8,30,1,None),)
|
||||||
|
self.rebuild( self.table_2, pos_2, person)
|
||||||
|
self.rebuild( self.table_3, pos_3, person)
|
||||||
|
self.rebuild( self.table_4, pos_4, person)
|
||||||
|
self.rebuild( self.table_5, pos_5, person)
|
||||||
|
|
||||||
|
def rebuild( self, table_widget, positions, active_person):
|
||||||
|
# Build ancestor tree
|
||||||
lst = [None]*31
|
lst = [None]*31
|
||||||
self.find_tree(self.active_person,0,1,lst)
|
self.find_tree(self.active_person,0,1,lst)
|
||||||
|
|
||||||
# determine the largest string width and height for calcuation
|
# Purge current table content
|
||||||
# of box sizes.
|
for child in table_widget.get_children():
|
||||||
|
child.destroy()
|
||||||
a = pango.Layout(self.canvas.get_pango_context())
|
table_widget.resize(1,1)
|
||||||
|
|
||||||
for t in lst:
|
debug = False
|
||||||
if t:
|
if debug:
|
||||||
boxtext = build_detail_string(self.db,t[0]).encode("UTF-8")
|
xmax = 0
|
||||||
for line in boxtext.split("\n"):
|
ymax = 0
|
||||||
try:
|
for field in positions:
|
||||||
a.set_text(line,len(line))
|
x = field[0]+3
|
||||||
except TypeError:
|
if x > xmax:
|
||||||
a.set_text(line)
|
xmax = x
|
||||||
(w1,h1) = a.get_pixel_size()
|
y = field[1]+field[2]
|
||||||
h = max(h,h1)
|
if y > ymax:
|
||||||
w = max(w,w1)
|
ymax = y
|
||||||
cpad = 10
|
for x in range(0,xmax):
|
||||||
w = w+_PAD
|
for y in range(0,ymax):
|
||||||
|
label=gtk.Label("%d,%d"%(x,y))
|
||||||
|
frame = gtk.ScrolledWindow(None,None)
|
||||||
|
frame.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
|
||||||
|
frame.set_policy(gtk.POLICY_NEVER,gtk.POLICY_NEVER)
|
||||||
|
frame.add(label)
|
||||||
|
table_widget.attach(frame,x,x+1,y,y+1,0,0,0,0)
|
||||||
|
|
||||||
cw = x2-(2*cpad)-10-h
|
for i in range(0,31):
|
||||||
ch = y2-(2*cpad)
|
try:
|
||||||
|
# Table placement for person data
|
||||||
|
x = positions[i][0]
|
||||||
|
y = positions[i][1]
|
||||||
|
w = 3
|
||||||
|
h = positions[i][2]
|
||||||
|
|
||||||
|
# Keine Person, daher leere Box
|
||||||
|
if not lst[i]:
|
||||||
|
label = gtk.Label(" ")
|
||||||
|
frame = gtk.ScrolledWindow(None,None)
|
||||||
|
frame.set_shadow_type(gtk.SHADOW_OUT)
|
||||||
|
frame.set_policy(gtk.POLICY_NEVER,gtk.POLICY_NEVER)
|
||||||
|
frame.add_with_viewport(label)
|
||||||
|
if positions[i][2] > 1:
|
||||||
|
table_widget.attach(frame,x,x+w,y,y+h,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,0)
|
||||||
|
else:
|
||||||
|
table_widget.attach(frame,x,x+w,y,y+h,gtk.EXPAND|gtk.FILL,gtk.FILL,0,0)
|
||||||
|
continue
|
||||||
|
|
||||||
if 5*w < cw and 24*h < ch:
|
# button t change active person
|
||||||
gen = 31
|
jump_image = gtk.Image()
|
||||||
xdiv = 5.0
|
jump_image.set_from_stock(gtk.STOCK_JUMP_TO,gtk.ICON_SIZE_MENU)
|
||||||
elif 4*w < cw and 12*h < ch:
|
jump_button = gtk.Button()
|
||||||
gen = 15
|
jump_button.add(jump_image)
|
||||||
xdiv = 4.0
|
jump_button.set_data(_PERSON,lst[i][0].get_handle())
|
||||||
else:
|
jump_button.connect("clicked", self.on_childmenu_changed);
|
||||||
gen = 7
|
|
||||||
xdiv = 3.0
|
# button to edit person
|
||||||
|
edit_image = gtk.Image()
|
||||||
|
edit_image.set_from_stock(gtk.STOCK_EDIT,gtk.ICON_SIZE_MENU)
|
||||||
|
edit_button = gtk.Button()
|
||||||
|
edit_button.add(edit_image)
|
||||||
|
edit_button.set_data(_PERSON,lst[i][0].get_handle())
|
||||||
|
edit_button.connect("clicked", self.edit_person_cb);
|
||||||
|
|
||||||
|
# button to jump to children
|
||||||
|
children_button = None
|
||||||
|
if i == 0 and active_person:
|
||||||
|
for family_handle in active_person.get_family_handle_list():
|
||||||
|
family = self.db.get_family_from_handle(family_handle)
|
||||||
|
if not family:
|
||||||
|
continue
|
||||||
|
if len(family.get_child_handle_list()) > 0:
|
||||||
|
children_image = gtk.Image()
|
||||||
|
children_image.set_from_stock(gtk.STOCK_GO_BACK,gtk.ICON_SIZE_MENU)
|
||||||
|
children_button = gtk.Button()
|
||||||
|
children_button.add(children_image)
|
||||||
|
children_button.connect("clicked", self.on_show_child_menu)
|
||||||
|
break
|
||||||
|
# Navigation button
|
||||||
|
nav_image = gtk.Image()
|
||||||
|
nav_image.set_from_stock(gtk.STOCK_INDEX,gtk.ICON_SIZE_MENU)
|
||||||
|
nav_button = gtk.Button()
|
||||||
|
nav_button.add(nav_image)
|
||||||
|
nav_button.connect("button-press-event", self.build_full_nav_menu_cb)
|
||||||
|
nav_button.set_data(_PERSON,lst[i][0].get_handle())
|
||||||
|
|
||||||
xpts = self.build_x_coords(cw/xdiv,_CANVASPAD+h)
|
# Box to place buttons and text side by side
|
||||||
ypts = self.build_y_coords((ch-h)/32.0, h)
|
box1 = gtk.HBox(False,0)
|
||||||
|
box1.set_border_width(0)
|
||||||
|
|
||||||
|
if positions[i][2] > 1:
|
||||||
|
# Multiline text boxes get vertical buttons
|
||||||
|
frame = gtk.ScrolledWindow(None,None)
|
||||||
|
frame.set_shadow_type(gtk.SHADOW_OUT)
|
||||||
|
frame.set_policy(gtk.POLICY_NEVER,gtk.POLICY_NEVER)
|
||||||
|
viewport1 = gtk.Viewport(None,None)
|
||||||
|
viewport1.set_shadow_type(gtk.SHADOW_NONE)
|
||||||
|
viewport1.set_border_width(0)
|
||||||
|
frame.add(viewport1)
|
||||||
|
viewport1.add(box1)
|
||||||
|
|
||||||
|
box2 = gtk.VBox(False,0) # buttons go into a new box
|
||||||
|
box2.pack_start(edit_button,False,False,0)
|
||||||
|
box2.pack_start(jump_button,False,False,0)
|
||||||
|
box2.pack_start(nav_button,False,False,0)
|
||||||
|
if children_button:
|
||||||
|
box2.pack_start(children_button,False,False,0)
|
||||||
|
|
||||||
|
# Multiline text using TextBuffer
|
||||||
|
textbuffer = gtk.TextBuffer()
|
||||||
|
textbuffer.set_text(self.format_person(lst[i][0], positions[i][2]))
|
||||||
|
text = gtk.TextView(textbuffer)
|
||||||
|
text.set_editable(False)
|
||||||
|
text.set_cursor_visible(False)
|
||||||
|
text.set_wrap_mode(gtk.WRAP_WORD)
|
||||||
|
frame2 = gtk.ScrolledWindow(None,None)
|
||||||
|
frame2.set_shadow_type(gtk.SHADOW_NONE)
|
||||||
|
frame2.set_policy(gtk.POLICY_NEVER,gtk.POLICY_NEVER)
|
||||||
|
viewport2 = gtk.Viewport(None,None)
|
||||||
|
viewport2.set_shadow_type(gtk.SHADOW_NONE)
|
||||||
|
viewport2.set_border_width(0)
|
||||||
|
viewport2.add(text)
|
||||||
|
frame2.add(viewport2)
|
||||||
|
box1.pack_start(box2,False,False,0)
|
||||||
|
box1.pack_start(frame2,True,True,0)
|
||||||
|
table_widget.attach(frame,x,x+w,y,y+h,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,0)
|
||||||
|
else:
|
||||||
|
# buttons go into the same box as the text
|
||||||
|
box1.pack_start(edit_button,False,False,0)
|
||||||
|
box1.pack_start(jump_button,False,False,0)
|
||||||
|
box1.pack_start(nav_button,False,False,0)
|
||||||
|
if children_button:
|
||||||
|
box1.pack_start(children_button,False,False,0)
|
||||||
|
|
||||||
|
#Single line text using Entry
|
||||||
|
text = gtk.Entry()
|
||||||
|
text.set_text(self.format_person(lst[i][0], positions[i][2]))
|
||||||
|
text.set_editable(False)
|
||||||
|
text.set_has_frame(False)
|
||||||
|
frame2 = gtk.ScrolledWindow(None,None)
|
||||||
|
frame2.set_shadow_type(gtk.SHADOW_OUT)
|
||||||
|
frame2.set_policy(gtk.POLICY_NEVER,gtk.POLICY_NEVER)
|
||||||
|
viewport2 = gtk.Viewport(None,None)
|
||||||
|
viewport2.set_shadow_type(gtk.SHADOW_NONE)
|
||||||
|
viewport2.set_border_width(0)
|
||||||
|
viewport2.add(text)
|
||||||
|
frame2.add(viewport2)
|
||||||
|
box1.pack_start(frame2,True,True,0)
|
||||||
|
table_widget.attach(box1,x,x+w,y,y+h,gtk.EXPAND|gtk.FILL,gtk.FILL,0,0)
|
||||||
|
|
||||||
|
# Marriage data
|
||||||
|
if positions[i][3] and lst[i][2]:
|
||||||
|
text = self.format_relation( lst[i][2], positions[i][3][2])
|
||||||
|
label = gtk.Label(text)
|
||||||
|
label.set_justify(gtk.JUSTIFY_CENTER)
|
||||||
|
label.set_line_wrap(True)
|
||||||
|
x = positions[i][3][0]
|
||||||
|
y = positions[i][3][1]
|
||||||
|
w = 2
|
||||||
|
h = 1
|
||||||
|
if positions[i][3][2] > 1:
|
||||||
|
table_widget.attach(label,x,x+w,y,y+h,gtk.EXPAND|gtk.FILL,gtk.EXPAND|gtk.FILL,0,0)
|
||||||
|
else:
|
||||||
|
table_widget.attach(label,x,x+w,y,y+h,gtk.EXPAND|gtk.FILL,gtk.FILL,0,0)
|
||||||
|
except IndexError:
|
||||||
|
pass
|
||||||
|
table_widget.show_all()
|
||||||
|
|
||||||
self.anchor_txt = self.root.add(
|
|
||||||
CanvasText, x=0, y=y2-12, font=font, text=self.make_anchor_label(),
|
|
||||||
fill_color_gdk=style.fg[gtk.STATE_NORMAL],
|
|
||||||
anchor=gtk.ANCHOR_WEST)
|
|
||||||
self.canvas_items.append(self.anchor_txt)
|
|
||||||
|
|
||||||
for family_handle in self.active_person.get_family_handle_list():
|
def edit_person_cb(self,obj):
|
||||||
family = self.db.get_family_from_handle(family_handle)
|
person_handle = obj.get_data(_PERSON)
|
||||||
if not family:
|
person = self.db.get_person_from_handle(person_handle)
|
||||||
continue
|
if person:
|
||||||
if len(family.get_child_handle_list()) > 0:
|
self.edit_person(person)
|
||||||
button,arrow = self.make_arrow_button(gtk.ARROW_LEFT,
|
return True
|
||||||
self.on_show_child_menu)
|
return 0
|
||||||
item = self.root.add(CanvasWidget, widget=button,
|
|
||||||
x=_CANVASPAD, y=ypts[0]+(h/2.0),
|
|
||||||
height=h, width=h,
|
|
||||||
size_pixels=1, anchor=gtk.ANCHOR_WEST)
|
|
||||||
self.canvas_items.append(item)
|
|
||||||
self.canvas_items.append(button)
|
|
||||||
self.canvas_items.append(arrow)
|
|
||||||
break
|
|
||||||
|
|
||||||
if lst[1]:
|
|
||||||
p = lst[1]
|
|
||||||
self.add_parent_button(p[0],x2-_PAD,ypts[1],h)
|
|
||||||
|
|
||||||
if lst[2]:
|
|
||||||
p = lst[2]
|
|
||||||
self.add_parent_button(p[0],x2-_PAD,ypts[2],h)
|
|
||||||
|
|
||||||
gen_no = 1
|
|
||||||
if self.anchor:
|
|
||||||
(firstRel,secondRel,common) = self.distance(self.active_person,
|
|
||||||
self.anchor)
|
|
||||||
if not common or type(common) in [type(''),type(u'')]:
|
|
||||||
self.remove_anchor()
|
|
||||||
else:
|
|
||||||
gen_no = len(firstRel)-len(secondRel)
|
|
||||||
|
|
||||||
for i in range(int(xdiv)):
|
|
||||||
item = self.root.add(CanvasText, x=(cw*i/xdiv + cpad), y=h,
|
|
||||||
text=str(gen_no),
|
|
||||||
font=font,
|
|
||||||
anchor=gtk.ANCHOR_WEST)
|
|
||||||
self.canvas_items.append(item)
|
|
||||||
gen_no = gen_no + 1
|
|
||||||
|
|
||||||
for i in range(gen):
|
|
||||||
if lst[i]:
|
|
||||||
if i < int(gen/2.0):
|
|
||||||
findex = (2*i)+1
|
|
||||||
mindex = findex+1
|
|
||||||
if lst[findex]:
|
|
||||||
p = lst[findex]
|
|
||||||
self.draw_canvas_line(xpts[i], ypts[i], xpts[findex],
|
|
||||||
ypts[findex], h, w, p[0], style,
|
|
||||||
p[1])
|
|
||||||
if lst[mindex]:
|
|
||||||
p = lst[mindex]
|
|
||||||
self.draw_canvas_line(xpts[i],ypts[i], xpts[mindex],
|
|
||||||
ypts[mindex], h, w, p[0], style,
|
|
||||||
p[1])
|
|
||||||
p = lst[i]
|
|
||||||
box = DispBox(self.root,style,xpts[i],ypts[i],w,h,p[0],
|
|
||||||
self.db,
|
|
||||||
self.parent.change_active_person,
|
|
||||||
self.load_person, self.build_full_nav_menu)
|
|
||||||
self.boxes.append(box)
|
|
||||||
|
|
||||||
def make_arrow_button(self,direction,function):
|
|
||||||
"""Make a button containing an arrow with the attached callback"""
|
|
||||||
|
|
||||||
arrow = gtk.Arrow(direction,gtk.SHADOW_NONE)
|
|
||||||
button = gtk.Button()
|
|
||||||
button.add(arrow)
|
|
||||||
button.connect("clicked",function)
|
|
||||||
arrow.show()
|
|
||||||
button.show()
|
|
||||||
return (button, arrow)
|
|
||||||
|
|
||||||
def set_anchor(self):
|
|
||||||
if self.active_person:
|
|
||||||
self.anchor = self.active_person
|
|
||||||
else:
|
|
||||||
self.anchor = None
|
|
||||||
self.anchor_txt.set(text=self.make_anchor_label())
|
|
||||||
|
|
||||||
def remove_anchor(self):
|
|
||||||
self.anchor = None
|
|
||||||
self.anchor_txt.set(text=self.make_anchor_label())
|
|
||||||
|
|
||||||
def on_anchor_set(self,junk):
|
|
||||||
self.set_anchor()
|
|
||||||
self.load_canvas(self.active_person)
|
|
||||||
|
|
||||||
def on_anchor_removed(self,junk):
|
|
||||||
self.remove_anchor()
|
|
||||||
self.load_canvas(self.active_person)
|
|
||||||
|
|
||||||
def make_anchor_label(self):
|
|
||||||
"""Make a label containing the name of the anchored person"""
|
|
||||||
if self.anchor:
|
|
||||||
anchor_string = self.anchor.get_primary_name().get_regular_name()
|
|
||||||
return "%s: %s" % (_("Anchor"),anchor_string)
|
|
||||||
else:
|
|
||||||
return ""
|
|
||||||
|
|
||||||
def on_show_child_menu(self,obj):
|
def on_show_child_menu(self,obj):
|
||||||
"""User clicked button to move to child of active person"""
|
"""User clicked button to move to child of active person"""
|
||||||
@ -412,99 +427,26 @@ class PedigreeView:
|
|||||||
menuitem.connect("activate",self.on_childmenu_changed)
|
menuitem.connect("activate",self.on_childmenu_changed)
|
||||||
menuitem.show()
|
menuitem.show()
|
||||||
myMenu.popup(None,None,None,0,0)
|
myMenu.popup(None,None,None,0,0)
|
||||||
return 1
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
def on_childmenu_changed(self,obj):
|
def on_childmenu_changed(self,obj):
|
||||||
"""Callback for the pulldown menu selection, changing to the person
|
"""Callback for the pulldown menu selection, changing to the person
|
||||||
attached with menu item."""
|
attached with menu item."""
|
||||||
|
|
||||||
person_handle = obj.get_data(_PERSON)
|
person_handle = obj.get_data(_PERSON)
|
||||||
person = self.db.get_person_from_handle(person_handle)
|
if person_handle:
|
||||||
if person:
|
self.parent.emit("active-changed", (person_handle,))
|
||||||
self.parent.change_active_person(person)
|
return 1
|
||||||
return 1
|
return 0
|
||||||
|
|
||||||
def add_parent_button(self,parent,x,y,h):
|
|
||||||
"""Add a button with a right pointing button on the main group at
|
|
||||||
the specified location. Attach the passed parent and the callback
|
|
||||||
to the button."""
|
|
||||||
|
|
||||||
button,arrow = self.make_arrow_button(gtk.ARROW_RIGHT,
|
|
||||||
self.change_to_parent)
|
|
||||||
button.set_data(_PERSON,parent.get_handle())
|
|
||||||
|
|
||||||
item = self.root.add(CanvasWidget, widget=button, x=x, y=y+(h/2),
|
|
||||||
height=h, width=h, size_pixels=1,
|
|
||||||
anchor=gtk.ANCHOR_EAST)
|
|
||||||
self.canvas_items.append(arrow)
|
|
||||||
self.canvas_items.append(item)
|
|
||||||
self.canvas_items.append(button)
|
|
||||||
|
|
||||||
def change_to_parent(self,obj):
|
|
||||||
"""Callback to right pointing arrow button. Gets the person
|
|
||||||
attached to the button and change the root person to that
|
|
||||||
person, redrawing the view."""
|
|
||||||
person_handle = obj.get_data(_PERSON)
|
|
||||||
person = self.db.get_person_from_handle(person_handle)
|
|
||||||
if self.active_person:
|
|
||||||
self.active_person = person
|
|
||||||
self.parent.change_active_person(person)
|
|
||||||
|
|
||||||
def draw_canvas_line(self,x1,y1,x2,y2,h,w,data,style,ls):
|
|
||||||
"""Draw an two segment line between the x,y point pairs. Attach
|
|
||||||
a event callback and data to the line."""
|
|
||||||
|
|
||||||
startx = x1+(w/2.0)
|
|
||||||
pts = [startx,y1, startx,y2+(h/2.0), x2,y2+(h/2.0)]
|
|
||||||
item = self.root.add(CanvasLine, width_pixels=2,
|
|
||||||
points=pts, line_style=ls,
|
|
||||||
fill_color_gdk=style.fg[gtk.STATE_NORMAL])
|
|
||||||
item.set_data(_PERSON,data.get_handle())
|
|
||||||
item.connect("event",self.line_event)
|
|
||||||
self.canvas_items.append(item)
|
|
||||||
|
|
||||||
def build_x_coords(self,x,cpad):
|
|
||||||
"""Build the array of x coordinates for the possible positions
|
|
||||||
on the pedegree view."""
|
|
||||||
return [cpad] + [x+cpad]*2 + [x*2+cpad]*4 + [x*3+cpad]*8 + [x*4+cpad]*16
|
|
||||||
|
|
||||||
def build_y_coords(self, y, top_pad):
|
|
||||||
"""Build the array of y coordinates for the possible positions
|
|
||||||
on the pedegree view."""
|
|
||||||
res = [ y*16.0, y*8.0, y*24.0, y*4.0, y*12.0, y*20.0, y*28.0, y*2.0,
|
|
||||||
y*6.0, y*10.0, y*14.0, y*18.0, y*22.0, y*26.0, y*30.0, y,
|
|
||||||
y*3.0, y*5.0, y*7.0, y*9.0, y*11.0, y*13.0, y*15.0, y*17.0,
|
|
||||||
y*19.0, y*21.0, y*23.0, y*25.0, y*27.0, y*29.0, y*31.0 ]
|
|
||||||
return map(lambda coord, top_pad=top_pad: coord + top_pad, res)
|
|
||||||
|
|
||||||
def line_event(self,obj,event):
|
|
||||||
"""Catch X events over a line and respond to the ones we care about"""
|
|
||||||
|
|
||||||
person_handle = obj.get_data(_PERSON)
|
|
||||||
if not person_handle:
|
|
||||||
return
|
|
||||||
person = self.db.get_person_from_handle(person_handle)
|
|
||||||
style = self.canvas.get_style()
|
|
||||||
|
|
||||||
if event.type == gtk.gdk._2BUTTON_PRESS:
|
|
||||||
if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
|
|
||||||
self.parent.change_active_person(person)
|
|
||||||
elif event.type == gtk.gdk.ENTER_NOTIFY:
|
|
||||||
obj.set(fill_color_gdk=style.bg[gtk.STATE_SELECTED],
|
|
||||||
width_pixels=4)
|
|
||||||
name = NameDisplay.displayer.display(person)
|
|
||||||
msg = _("Double clicking will make %s the active person") % name
|
|
||||||
self.sb.set_status(msg)
|
|
||||||
elif event.type == gtk.gdk.LEAVE_NOTIFY:
|
|
||||||
obj.set(fill_color_gdk=style.fg[gtk.STATE_NORMAL], width_pixels=2)
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def find_tree(self,person,index,depth,lst,val=0):
|
def find_tree(self,person,index,depth,lst,val=0):
|
||||||
"""Recursively build a list of ancestors"""
|
"""Recursively build a list of ancestors"""
|
||||||
|
|
||||||
if depth > 5 or person == None:
|
if depth > 5 or person == None:
|
||||||
return
|
return
|
||||||
lst[index] = (person,val)
|
lst[index] = (person,val,None)
|
||||||
|
|
||||||
parent_families = person.get_parent_family_handle_list()
|
parent_families = person.get_parent_family_handle_list()
|
||||||
if parent_families:
|
if parent_families:
|
||||||
@ -517,6 +459,7 @@ class PedigreeView:
|
|||||||
|
|
||||||
family = self.db.get_family_from_handle(family_handle)
|
family = self.db.get_family_from_handle(family_handle)
|
||||||
if family != None:
|
if family != None:
|
||||||
|
lst[index] = (person,val,family)
|
||||||
father_handle = family.get_father_handle()
|
father_handle = family.get_father_handle()
|
||||||
if father_handle != None:
|
if father_handle != None:
|
||||||
father = self.db.get_person_from_handle(father_handle)
|
father = self.db.get_person_from_handle(father_handle)
|
||||||
@ -526,25 +469,6 @@ class PedigreeView:
|
|||||||
mother = self.db.get_person_from_handle(mother_handle)
|
mother = self.db.get_person_from_handle(mother_handle)
|
||||||
self.find_tree(mother,(2*index)+2,depth+1,lst,mrel)
|
self.find_tree(mother,(2*index)+2,depth+1,lst,mrel)
|
||||||
|
|
||||||
def on_canvas1_event(self,obj,event):
|
|
||||||
"""Handle resize events over the canvas, redrawing if the size changes"""
|
|
||||||
|
|
||||||
if event.type == gtk.gdk.EXPOSE:
|
|
||||||
x1,y1,x2,y2 = self.canvas.get_allocation()
|
|
||||||
if self.x1 != x1 or self.x2 != x2 or \
|
|
||||||
self.y1 != y1 or self.y2 != y2:
|
|
||||||
self.x1 = x1; self.x2 = x2
|
|
||||||
self.y1 = y1; self.y2 = y2
|
|
||||||
self.canvas.set_size(x2,y2)
|
|
||||||
self.load_canvas(self.active_person)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
def on_canvas_press(self,obj,event):
|
|
||||||
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
|
|
||||||
self.build_nav_menu(event)
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def add_nav_portion_to_menu(self,menu):
|
def add_nav_portion_to_menu(self,menu):
|
||||||
"""
|
"""
|
||||||
This function adds a common history-navigation portion
|
This function adds a common history-navigation portion
|
||||||
@ -560,8 +484,8 @@ class PedigreeView:
|
|||||||
#(gtk.STOCK_HOME,self.parent.on_home_clicked,1),
|
#(gtk.STOCK_HOME,self.parent.on_home_clicked,1),
|
||||||
(_("Home"),self.parent.on_home_clicked,1),
|
(_("Home"),self.parent.on_home_clicked,1),
|
||||||
(None,None,0),
|
(None,None,0),
|
||||||
(_("Set anchor"),self.on_anchor_set,1),
|
#(_("Set anchor"),self.on_anchor_set,1),
|
||||||
(_("Remove anchor"),self.on_anchor_removed,1),
|
#(_("Remove anchor"),self.on_anchor_removed,1),
|
||||||
]
|
]
|
||||||
|
|
||||||
for stock_id,callback,sensitivity in entries:
|
for stock_id,callback,sensitivity in entries:
|
||||||
@ -577,15 +501,8 @@ class PedigreeView:
|
|||||||
item.show()
|
item.show()
|
||||||
menu.append(item)
|
menu.append(item)
|
||||||
|
|
||||||
def build_nav_menu(self,event):
|
|
||||||
"""Builds the menu with only history-based navigation."""
|
|
||||||
|
|
||||||
menu = gtk.Menu()
|
|
||||||
menu.set_title(_('People Menu'))
|
|
||||||
self.add_nav_portion_to_menu(menu)
|
|
||||||
menu.popup(None,None,None,event.button,event.time)
|
|
||||||
|
|
||||||
def build_full_nav_menu(self,event,person):
|
def build_full_nav_menu_cb(self,obj,event):
|
||||||
"""
|
"""
|
||||||
Builds the full menu (including Siblings, Spouses, Children,
|
Builds the full menu (including Siblings, Spouses, Children,
|
||||||
and Parents) with navigation.
|
and Parents) with navigation.
|
||||||
@ -594,6 +511,11 @@ class PedigreeView:
|
|||||||
menu = gtk.Menu()
|
menu = gtk.Menu()
|
||||||
menu.set_title(_('People Menu'))
|
menu.set_title(_('People Menu'))
|
||||||
|
|
||||||
|
person_handle = obj.get_data(_PERSON)
|
||||||
|
person = self.db.get_person_from_handle(person_handle)
|
||||||
|
if not person:
|
||||||
|
return 0
|
||||||
|
|
||||||
# Go over spouses and build their menu
|
# Go over spouses and build their menu
|
||||||
item = gtk.MenuItem(_("Spouses"))
|
item = gtk.MenuItem(_("Spouses"))
|
||||||
fam_list = person.get_family_handle_list()
|
fam_list = person.get_family_handle_list()
|
||||||
@ -732,6 +654,55 @@ class PedigreeView:
|
|||||||
self.add_nav_portion_to_menu(menu)
|
self.add_nav_portion_to_menu(menu)
|
||||||
menu.popup(None,None,None,event.button,event.time)
|
menu.popup(None,None,None,event.button,event.time)
|
||||||
|
|
||||||
|
def format_relation( self, family, line_count):
|
||||||
|
text = ""
|
||||||
|
for event_handle in family.get_event_list():
|
||||||
|
event = self.db.get_event_from_handle(event_handle)
|
||||||
|
if event:
|
||||||
|
text += _(event.get_name())
|
||||||
|
text += "\n"
|
||||||
|
text += event.get_date()
|
||||||
|
text += "\n"
|
||||||
|
text += self.get_place_name(event.get_place_handle())
|
||||||
|
return text
|
||||||
|
|
||||||
|
def get_place_name( self, place_handle):
|
||||||
|
text = ""
|
||||||
|
place = self.db.get_place_from_handle(place_handle)
|
||||||
|
if place:
|
||||||
|
place_title = self.db.get_place_from_handle(place_handle).get_title()
|
||||||
|
if place_title != "":
|
||||||
|
if len(place_title) > 15:
|
||||||
|
text = place_title[:14]+"..."
|
||||||
|
else:
|
||||||
|
text = place_title
|
||||||
|
return text
|
||||||
|
|
||||||
|
def format_person( self, person, line_count):
|
||||||
|
if not person:
|
||||||
|
return ""
|
||||||
|
name = NameDisplay.displayer.display(person)
|
||||||
|
if line_count < 3:
|
||||||
|
return name
|
||||||
|
birth = self.db.get_event_from_handle( person.get_birth_handle())
|
||||||
|
bd=""
|
||||||
|
bp=""
|
||||||
|
if birth:
|
||||||
|
bd = birth.get_date()
|
||||||
|
bp = self.get_place_name(birth.get_place_handle())
|
||||||
|
death = self.db.get_event_from_handle( person.get_death_handle())
|
||||||
|
dd=""
|
||||||
|
dp=""
|
||||||
|
if death:
|
||||||
|
dd = death.get_date()
|
||||||
|
dp = self.get_place_name(death.get_place_handle())
|
||||||
|
if line_count < 5:
|
||||||
|
return "%s\n%s\n%s" % (name,bd,dd)
|
||||||
|
else:
|
||||||
|
return "%s\n%s\n %s\n%s\n %s" % (name,bd,bp,dd,dp)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# Function to return children's list of a person
|
# Function to return children's list of a person
|
||||||
|
Loading…
Reference in New Issue
Block a user