Refractor so common base fan chart gramplet and view are shared
Fan chart view allows now configuration: max generation to set, 4 color schemes svn: r20307
This commit is contained in:
@@ -38,7 +38,6 @@ from gi.repository import Pango
|
||||
from gi.repository import Gtk
|
||||
import math
|
||||
from gi.repository import Gdk
|
||||
from cgi import escape
|
||||
try:
|
||||
import cairo
|
||||
except ImportError:
|
||||
@@ -49,33 +48,31 @@ except ImportError:
|
||||
# GRAMPS modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gen.display.name import displayer as name_displayer
|
||||
from gen.ggettext import gettext as _
|
||||
from gen.plug import Gramplet
|
||||
from gen.utils.db import (find_children, find_parents, find_witnessed_people)
|
||||
from libformatting import FormattingHelper
|
||||
import gen.lib
|
||||
from gen.errors import WindowActiveError
|
||||
from gui.editors import EditPerson
|
||||
import gui.utils
|
||||
from gui.widgets.fanchart import FanChartWidget
|
||||
from gui.widgets.fanchart import FanChartWidget, FanChartGrampsGUI
|
||||
|
||||
class FanChartGramplet(Gramplet):
|
||||
class FanChartGramplet(FanChartGrampsGUI, Gramplet):
|
||||
"""
|
||||
The Gramplet code that realizes the FanChartWidget.
|
||||
"""
|
||||
def init(self):
|
||||
self.set_tooltip(_("Click to expand/contract person\nRight-click for options\nClick and drag in open area to rotate"))
|
||||
self.generations = 6
|
||||
self.format_helper = FormattingHelper(self.dbstate)
|
||||
self.gui.fan = FanChartWidget(self.generations, self.dbstate,
|
||||
context_popup_callback=self.on_popup)
|
||||
self.gui.fan.format_helper = self.format_helper
|
||||
|
||||
def __init__(self, gui, nav_group=0):
|
||||
Gramplet.__init__(self, gui, nav_group)
|
||||
FanChartGrampsGUI.__init__(self, 6, 0, self.on_childmenu_changed)
|
||||
self.set_fan(FanChartWidget(self.dbstate, self.on_popup))
|
||||
# Replace the standard textview with the fan chart widget:
|
||||
self.gui.get_container_widget().remove(self.gui.textview)
|
||||
self.gui.get_container_widget().add_with_viewport(self.gui.fan)
|
||||
self.gui.get_container_widget().add_with_viewport(self.fan)
|
||||
# Make sure it is visible:
|
||||
self.gui.fan.show()
|
||||
self.fan.show()
|
||||
|
||||
def init(self):
|
||||
self.set_tooltip(_("Click to expand/contract person\nRight-click for options\nClick and drag in open area to rotate"))
|
||||
|
||||
def active_changed(self, handle):
|
||||
"""
|
||||
@@ -84,340 +81,8 @@ class FanChartGramplet(Gramplet):
|
||||
# Reset everything but rotation angle (leave it as is)
|
||||
self.update()
|
||||
|
||||
def have_parents(self, person):
|
||||
"""
|
||||
Returns True if a person has parents.
|
||||
"""
|
||||
if person:
|
||||
m = self.get_parent(person, "female")
|
||||
f = self.get_parent(person, "male")
|
||||
return not m is f is None
|
||||
return False
|
||||
|
||||
def have_children(self, person):
|
||||
"""
|
||||
Returns True if a person has children.
|
||||
"""
|
||||
if person:
|
||||
for family_handle in person.get_family_handle_list():
|
||||
family = self.dbstate.db.get_family_from_handle(family_handle)
|
||||
if family and len(family.get_child_ref_list()) > 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_parent(self, person, gender):
|
||||
"""
|
||||
Get the father if gender == "male", or get mother otherwise.
|
||||
"""
|
||||
if person:
|
||||
parent_handle_list = person.get_parent_family_handle_list()
|
||||
if parent_handle_list:
|
||||
family_id = parent_handle_list[0]
|
||||
family = self.dbstate.db.get_family_from_handle(family_id)
|
||||
if family:
|
||||
if gender == "male":
|
||||
person_handle = gen.lib.Family.get_father_handle(family)
|
||||
else:
|
||||
person_handle = gen.lib.Family.get_mother_handle(family)
|
||||
if person_handle:
|
||||
return self.dbstate.db.get_person_from_handle(person_handle)
|
||||
return None
|
||||
|
||||
def main(self):
|
||||
"""
|
||||
Fill the data structures with the active data. This initializes all
|
||||
data.
|
||||
"""
|
||||
self.gui.fan.reset_generations()
|
||||
active_handle = self.get_active('Person')
|
||||
person = self.dbstate.db.get_person_from_handle(active_handle)
|
||||
if not person:
|
||||
name = None
|
||||
else:
|
||||
name = name_displayer.display(person)
|
||||
parents = self.have_parents(person)
|
||||
child = self.have_children(person)
|
||||
self.gui.fan.data[0][0] = (name, person, parents, child)
|
||||
for current in range(1, self.generations):
|
||||
parent = 0
|
||||
# name, person, parents, children
|
||||
for (n,p,q,c) in self.gui.fan.data[current - 1]:
|
||||
# Get father's details:
|
||||
person = self.get_parent(p, "male")
|
||||
if person:
|
||||
name = name_displayer.display(person)
|
||||
else:
|
||||
name = None
|
||||
if current == self.generations - 1:
|
||||
parents = self.have_parents(person)
|
||||
else:
|
||||
parents = None
|
||||
self.gui.fan.data[current][parent] = (name, person, parents, None)
|
||||
if person is None:
|
||||
# start,stop,male/right,state
|
||||
self.gui.fan.angle[current][parent][3] = self.gui.fan.COLLAPSED
|
||||
parent += 1
|
||||
# Get mother's details:
|
||||
person = self.get_parent(p, "female")
|
||||
if person:
|
||||
name = name_displayer.display(person)
|
||||
else:
|
||||
name = None
|
||||
if current == self.generations - 1:
|
||||
parents = self.have_parents(person)
|
||||
else:
|
||||
parents = None
|
||||
self.gui.fan.data[current][parent] = (name, person, parents, None)
|
||||
if person is None:
|
||||
# start,stop,male/right,state
|
||||
self.gui.fan.angle[current][parent][3] = self.gui.fan.COLLAPSED
|
||||
parent += 1
|
||||
self.gui.fan.queue_draw()
|
||||
|
||||
def on_childmenu_changed(self, obj, person_handle):
|
||||
"""Callback for the pulldown menu selection, changing to the person
|
||||
attached with menu item."""
|
||||
self.set_active('Person', person_handle)
|
||||
return True
|
||||
|
||||
def edit_person_cb(self, obj,person_handle):
|
||||
person = self.dbstate.db.get_person_from_handle(person_handle)
|
||||
if person:
|
||||
try:
|
||||
EditPerson(self.dbstate, self.uistate, [], person)
|
||||
except WindowActiveError:
|
||||
pass
|
||||
return True
|
||||
return False
|
||||
|
||||
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_for_display(Gdk.Display.get_default(),
|
||||
Gdk.SELECTION_CLIPBOARD)
|
||||
cb.set_text( self.format_helper.format_person(person,11))
|
||||
return True
|
||||
return False
|
||||
|
||||
def on_popup(self, obj, event, person_handle):
|
||||
"""
|
||||
Builds the full menu (including Siblings, Spouses, Children,
|
||||
and Parents) with navigation. Copied from PedigreeView.
|
||||
"""
|
||||
|
||||
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.IconSize.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(label=_("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.IconSize.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(label=_("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)
|
||||
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(label='<b><i>%s</i></b>' % escape(name_displayer.display(sib)))
|
||||
else:
|
||||
label = Gtk.Label(label=escape(name_displayer.display(sib)))
|
||||
|
||||
go_image = Gtk.Image.new_from_stock(Gtk.STOCK_JUMP_TO,Gtk.IconSize.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(label=_("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(label='<b><i>%s</i></b>' % escape(name_displayer.display(child)))
|
||||
else:
|
||||
label = Gtk.Label(label=escape(name_displayer.display(child)))
|
||||
|
||||
go_image = Gtk.Image.new_from_stock(Gtk.STOCK_JUMP_TO,Gtk.IconSize.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(label=_("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(label='<b><i>%s</i></b>' % escape(name_displayer.display(par)))
|
||||
else:
|
||||
label = Gtk.Label(label=escape(name_displayer.display(par)))
|
||||
|
||||
go_image = Gtk.Image.new_from_stock(Gtk.STOCK_JUMP_TO,Gtk.IconSize.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:
|
||||
item.set_sensitive(0)
|
||||
item.show()
|
||||
menu.append(item)
|
||||
|
||||
# Go over parents and build their menu
|
||||
item = Gtk.MenuItem(label=_("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(label=escape(name_displayer.display(per)))
|
||||
|
||||
go_image = Gtk.Image.new_from_stock(Gtk.STOCK_JUMP_TO,Gtk.IconSize.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)
|
||||
menu.popup(None, None, None, None, event.button, event.time)
|
||||
return 1
|
||||
|
||||
@@ -146,4 +146,3 @@ class QuickViewGramplet(Gramplet):
|
||||
qv_list = get_quick_report_list(code_map[qv_option.get_value()])
|
||||
for pdata in qv_list:
|
||||
list_option.add_item(pdata.id, pdata.name)
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ SUBDIRS = maps
|
||||
|
||||
pkgpython_PYTHON = \
|
||||
libcairodoc.py\
|
||||
libformatting.py\
|
||||
libgedcom.py\
|
||||
libgrampsxml.py\
|
||||
libgrdb.py\
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
# -*- python -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Gramps - a GTK+/GNOME based genealogy program
|
||||
#
|
||||
# Copyright (C) 2001-2007 Donald N. Allingham, Martin Hawlisch
|
||||
#
|
||||
# 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$
|
||||
|
||||
"""Format of commonly used expressions, making use of a cache to not
|
||||
recompute
|
||||
"""
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from cgi import escape
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Gramps modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import gen.lib
|
||||
import gen.datehandler
|
||||
from gen.display.name import displayer as name_displayer
|
||||
from gen.utils.db import get_birth_or_fallback, get_death_or_fallback, get_marriage_or_fallback
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# FormattingHelper class
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class FormattingHelper(object):
|
||||
"""Format of commonly used expressions, making use of a cache to not
|
||||
recompute
|
||||
"""
|
||||
def __init__(self, dbstate):
|
||||
self.dbstate = dbstate
|
||||
self._text_cache = {}
|
||||
self._markup_cache = {}
|
||||
|
||||
def format_relation(self, family, line_count, use_markup=False):
|
||||
""" Format a relation between parents of a family
|
||||
"""
|
||||
if not family:
|
||||
return ""
|
||||
if use_markup:
|
||||
if family.handle in self._markup_cache:
|
||||
if line_count in self._markup_cache[family.handle]:
|
||||
return self._markup_cache[family.handle][line_count]
|
||||
else:
|
||||
if family.handle in self._text_cache:
|
||||
if line_count in self._text_cache[family.handle]:
|
||||
return self._text_cache[family.handle][line_count]
|
||||
|
||||
text = ""
|
||||
marriage = get_marriage_or_fallback(self.dbstate.db, family)
|
||||
if marriage and use_markup and marriage.get_type() != gen.lib.EventType.MARRIAGE:
|
||||
mdate = "<i>%s %s</i>" % (marriage.get_type().get_abbreviation(),
|
||||
escape(gen.datehandler.get_date(marriage)))
|
||||
mplace = "<i>%s</i>" % escape(self.get_place_name(marriage.get_place_handle()))
|
||||
name = "<i>%s</i>" % str(marriage.get_type())
|
||||
elif marriage and use_markup:
|
||||
mdate = "%s %s" % (marriage.get_type().get_abbreviation(),
|
||||
escape(gen.datehandler.get_date(marriage)))
|
||||
mplace = escape(self.get_place_name(marriage.get_place_handle()))
|
||||
name = str(marriage.get_type())
|
||||
elif marriage:
|
||||
mdate = "%s %s" % (marriage.get_type().get_abbreviation(),
|
||||
gen.datehandler.get_date(marriage))
|
||||
mplace = self.get_place_name(marriage.get_place_handle())
|
||||
name = str(marriage.get_type())
|
||||
else:
|
||||
mdate = ""
|
||||
mplace = ""
|
||||
name = ""
|
||||
|
||||
if line_count >= 1:
|
||||
text += mdate
|
||||
text += "\n"
|
||||
if line_count >= 2:
|
||||
text += name
|
||||
text += "\n"
|
||||
if line_count >= 3:
|
||||
text += mplace
|
||||
text += "\n"
|
||||
|
||||
if not text:
|
||||
text = str(family.get_relationship())
|
||||
|
||||
if use_markup:
|
||||
if not family.handle in self._markup_cache:
|
||||
self._markup_cache[family.handle] = {}
|
||||
self._markup_cache[family.handle][line_count] = text
|
||||
else:
|
||||
if not family.handle in self._text_cache:
|
||||
self._text_cache[family.handle] = {}
|
||||
self._text_cache[family.handle][line_count] = text
|
||||
|
||||
return text
|
||||
|
||||
def get_place_name(self, place_handle):
|
||||
""" Obtain a place name
|
||||
"""
|
||||
text = ""
|
||||
place = self.dbstate.db.get_place_from_handle(place_handle)
|
||||
if place:
|
||||
place_title = place.get_title()
|
||||
if place_title != "":
|
||||
if len(place_title) > 25:
|
||||
text = place_title[:24]+"..."
|
||||
else:
|
||||
text = place_title
|
||||
return text
|
||||
|
||||
def format_person( self, person, line_count, use_markup=False):
|
||||
"""fromat how info about a person should be presented
|
||||
"""
|
||||
if not person:
|
||||
return ""
|
||||
if use_markup:
|
||||
if person.handle in self._markup_cache:
|
||||
if line_count in self._markup_cache[person.handle]:
|
||||
return self._markup_cache[person.handle][line_count]
|
||||
name = escape(name_displayer.display(person))
|
||||
else:
|
||||
if person.handle in self._text_cache:
|
||||
if line_count in self._text_cache[person.handle]:
|
||||
return self._text_cache[person.handle][line_count]
|
||||
name = name_displayer.display(person)
|
||||
text = name
|
||||
if line_count >= 3:
|
||||
birth = get_birth_or_fallback(self.dbstate.db, person)
|
||||
if birth and use_markup and birth.get_type() != \
|
||||
gen.lib.EventType.BIRTH:
|
||||
bdate = "<i>%s</i>" % escape(gen.datehandler.get_date(birth))
|
||||
bplace = "<i>%s</i>" % escape(self.get_place_name(
|
||||
birth.get_place_handle()))
|
||||
elif birth and use_markup:
|
||||
bdate = escape(gen.datehandler.get_date(birth))
|
||||
bplace = escape(self.get_place_name(birth.get_place_handle()))
|
||||
elif birth:
|
||||
bdate = gen.datehandler.get_date(birth)
|
||||
bplace = self.get_place_name(birth.get_place_handle())
|
||||
else:
|
||||
bdate = ""
|
||||
bplace = ""
|
||||
death = get_death_or_fallback(self.dbstate.db, person)
|
||||
if death and use_markup and death.get_type() != \
|
||||
gen.lib.EventType.DEATH:
|
||||
ddate = "<i>%s</i>" % escape(gen.datehandler.get_date(death))
|
||||
dplace = "<i>%s</i>" % escape(self.get_place_name(
|
||||
death.get_place_handle()))
|
||||
elif death and use_markup:
|
||||
ddate = escape(gen.datehandler.get_date(death))
|
||||
dplace = escape(self.get_place_name(death.get_place_handle()))
|
||||
elif death:
|
||||
ddate = gen.datehandler.get_date(death)
|
||||
dplace = self.get_place_name(death.get_place_handle())
|
||||
else:
|
||||
ddate = ""
|
||||
dplace = ""
|
||||
|
||||
if line_count < 5:
|
||||
text = "%s\n* %s\n+ %s" % (name, bdate, ddate)
|
||||
else:
|
||||
text = "%s\n* %s\n %s\n+ %s\n %s" % (name, bdate, bplace,
|
||||
ddate, dplace)
|
||||
if use_markup:
|
||||
if not person.handle in self._markup_cache:
|
||||
self._markup_cache[person.handle] = {}
|
||||
self._markup_cache[person.handle][line_count] = text
|
||||
else:
|
||||
if not person.handle in self._text_cache:
|
||||
self._text_cache[person.handle] = {}
|
||||
self._text_cache[person.handle][line_count] = text
|
||||
return text
|
||||
|
||||
def clear_cache( self):
|
||||
"""clear the cache of kept format strings
|
||||
"""
|
||||
self._text_cache = {}
|
||||
self._markup_cache = {}
|
||||
@@ -40,24 +40,6 @@ authors_email = ["http://gramps-project.org"],
|
||||
#load_on_reg = True
|
||||
)
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# libformatting
|
||||
#
|
||||
#------------------------------------------------------------------------
|
||||
register(GENERAL,
|
||||
id = 'libformatting',
|
||||
name = "FormattingHelper lib",
|
||||
description = _("Provides a FormattingHelper class for common strings"),
|
||||
version = '1.0',
|
||||
gramps_target_version = '4.0',
|
||||
status = STABLE,
|
||||
fname = 'libformatting.py',
|
||||
authors = ["The Gramps project"],
|
||||
authors_email = ["http://gramps-project.org"],
|
||||
#load_on_reg = True
|
||||
)
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# libgedcom
|
||||
|
||||
@@ -50,7 +50,7 @@ from gi.repository import GdkPixbuf
|
||||
import gen.lib
|
||||
from gen.display.name import displayer as _nd
|
||||
from gui.views.navigationview import NavigationView
|
||||
from libformatting import FormattingHelper
|
||||
from gen.utils.libformatting import FormattingHelper
|
||||
from gen.errors import WindowActiveError
|
||||
from gen.const import HOME_DIR, ROOT_DIR
|
||||
from gui.managedwindow import ManagedWindow
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import Gtk
|
||||
import cairo
|
||||
from cgi import escape
|
||||
from gen.ggettext import gettext as _
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
@@ -43,37 +42,40 @@ from gen.ggettext import gettext as _
|
||||
# GRAMPS modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
from gen.display.name import displayer as name_displayer
|
||||
from gen.utils.db import (find_children, find_parents, find_witnessed_people)
|
||||
from libformatting import FormattingHelper
|
||||
import gen.lib
|
||||
from gui.widgets.fanchart import FanChartWidget
|
||||
from gui.widgets.fanchart import FanChartWidget, FanChartGrampsGUI
|
||||
from gui.views.navigationview import NavigationView
|
||||
from gen.errors import WindowActiveError
|
||||
from gui.views.bookmarks import PersonBookmarks
|
||||
from gui.editors import EditPerson
|
||||
|
||||
|
||||
# the print settings to remember between print sessions
|
||||
PRINT_SETTINGS = None
|
||||
|
||||
class FanChartView(NavigationView):
|
||||
class FanChartView(FanChartGrampsGUI, NavigationView):
|
||||
"""
|
||||
The Gramplet code that realizes the FanChartWidget.
|
||||
"""
|
||||
#settings in the config file
|
||||
CONFIGSETTINGS = (
|
||||
('interface.fanview-maxgen', 9),
|
||||
('interface.fanview-background', 0),
|
||||
)
|
||||
def __init__(self, pdata, dbstate, uistate, nav_group=0):
|
||||
self.dbstate = dbstate
|
||||
self.uistate = uistate
|
||||
NavigationView.__init__(self, _('Fan Chart'),
|
||||
pdata, dbstate, uistate,
|
||||
dbstate.db.get_bookmarks(),
|
||||
PersonBookmarks,
|
||||
nav_group)
|
||||
nav_group)
|
||||
FanChartGrampsGUI.__init__(self,
|
||||
self._config.get('interface.fanview-maxgen'),
|
||||
self._config.get('interface.fanview-background'),
|
||||
self.on_childmenu_changed)
|
||||
|
||||
dbstate.connect('active-changed', self.active_changed)
|
||||
dbstate.connect('database-changed', self.change_db)
|
||||
self.dbstate = dbstate
|
||||
self.uistate = uistate
|
||||
self.generations = 9
|
||||
self.format_helper = FormattingHelper(self.dbstate)
|
||||
|
||||
self.additional_uis.append(self.additional_ui())
|
||||
|
||||
@@ -81,9 +83,7 @@ class FanChartView(NavigationView):
|
||||
return 'Person'
|
||||
|
||||
def build_widget(self):
|
||||
self.fan = FanChartWidget(self.generations, self.dbstate,
|
||||
context_popup_callback=self.on_popup)
|
||||
self.fan.format_helper = self.format_helper
|
||||
self.set_fan(FanChartWidget(self.dbstate, self.on_popup))
|
||||
self.scrolledwindow = Gtk.ScrolledWindow(None, None)
|
||||
self.scrolledwindow.set_policy(Gtk.PolicyType.AUTOMATIC,
|
||||
Gtk.PolicyType.AUTOMATIC)
|
||||
@@ -188,110 +188,10 @@ class FanChartView(NavigationView):
|
||||
self.change_active(handle)
|
||||
self.main()
|
||||
|
||||
def have_parents(self, person):
|
||||
def get_active(self, object):
|
||||
"""overrule get_active, to support call as in Gramplets
|
||||
"""
|
||||
Returns True if a person has parents.
|
||||
"""
|
||||
if person:
|
||||
m = self.get_parent(person, False)
|
||||
f = self.get_parent(person, True)
|
||||
return not m is f is None
|
||||
return False
|
||||
|
||||
def have_children(self, person):
|
||||
"""
|
||||
Returns True if a person has children.
|
||||
"""
|
||||
if person:
|
||||
for family_handle in person.get_family_handle_list():
|
||||
family = self.dbstate.db.get_family_from_handle(family_handle)
|
||||
if family and len(family.get_child_ref_list()) > 0:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_parent(self, person, father):
|
||||
"""
|
||||
Get the father of the family if father == True, otherwise mother
|
||||
"""
|
||||
if person:
|
||||
parent_handle_list = person.get_parent_family_handle_list()
|
||||
if parent_handle_list:
|
||||
family_id = parent_handle_list[0]
|
||||
family = self.dbstate.db.get_family_from_handle(family_id)
|
||||
if family:
|
||||
if father:
|
||||
person_handle = gen.lib.Family.get_father_handle(family)
|
||||
else:
|
||||
person_handle = gen.lib.Family.get_mother_handle(family)
|
||||
if person_handle:
|
||||
return self.dbstate.db.get_person_from_handle(person_handle)
|
||||
return None
|
||||
|
||||
def main(self):
|
||||
"""
|
||||
Fill the data structures with the active data. This initializes all
|
||||
data.
|
||||
"""
|
||||
self.fan.reset_generations()
|
||||
person = self.dbstate.db.get_person_from_handle(self.get_active())
|
||||
if not person:
|
||||
name = None
|
||||
else:
|
||||
name = name_displayer.display(person)
|
||||
parents = self.have_parents(person)
|
||||
child = self.have_children(person)
|
||||
self.fan.data[0][0] = (name, person, parents, child)
|
||||
for current in range(1, self.generations):
|
||||
parent = 0
|
||||
# name, person, parents, children
|
||||
for (n,p,q,c) in self.fan.data[current - 1]:
|
||||
# Get father's details:
|
||||
person = self.get_parent(p, True)
|
||||
if person:
|
||||
name = name_displayer.display(person)
|
||||
else:
|
||||
name = None
|
||||
if current == self.generations - 1:
|
||||
parents = self.have_parents(person)
|
||||
else:
|
||||
parents = None
|
||||
self.fan.data[current][parent] = (name, person, parents, None)
|
||||
if person is None:
|
||||
# start,stop,male/right,state
|
||||
self.fan.angle[current][parent][3] = self.fan.COLLAPSED
|
||||
parent += 1
|
||||
# Get mother's details:
|
||||
person = self.get_parent(p, False)
|
||||
if person:
|
||||
name = name_displayer.display(person)
|
||||
else:
|
||||
name = None
|
||||
if current == self.generations - 1:
|
||||
parents = self.have_parents(person)
|
||||
else:
|
||||
parents = None
|
||||
self.fan.data[current][parent] = (name, person, parents, None)
|
||||
if person is None:
|
||||
# start,stop,male/right,state
|
||||
self.fan.angle[current][parent][3] = self.fan.COLLAPSED
|
||||
parent += 1
|
||||
self.fan.queue_draw()
|
||||
|
||||
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 edit_person_cb(self, obj,person_handle):
|
||||
person = self.dbstate.db.get_person_from_handle(person_handle)
|
||||
if person:
|
||||
try:
|
||||
EditPerson(self.dbstate, self.uistate, [], person)
|
||||
except WindowActiveError:
|
||||
pass
|
||||
return True
|
||||
return False
|
||||
return NavigationView.get_active(self)
|
||||
|
||||
def person_rebuild(self, *args):
|
||||
self.update()
|
||||
@@ -301,239 +201,6 @@ class FanChartView(NavigationView):
|
||||
self.person_rebuild()
|
||||
if self.active:
|
||||
self.bookmarks.redraw()
|
||||
|
||||
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_for_display(Gdk.Display.get_default(),
|
||||
Gdk.SELECTION_CLIPBOARD)
|
||||
cb.set_text( self.format_helper.format_person(person,11), -1)
|
||||
return True
|
||||
return False
|
||||
|
||||
def on_popup(self, obj, event, person_handle):
|
||||
"""
|
||||
Builds the full menu (including Siblings, Spouses, Children,
|
||||
and Parents) with navigation. Copied from PedigreeView.
|
||||
"""
|
||||
#store menu for GTK3 to avoid it being destroyed before showing
|
||||
self.menu = Gtk.Menu()
|
||||
menu = self.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.IconSize.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.new_from_stock(stock_id=Gtk.STOCK_EDIT, accel_group=None)
|
||||
edit_item.connect("activate", self.edit_person_cb, person_handle)
|
||||
edit_item.show()
|
||||
menu.append(edit_item)
|
||||
|
||||
clipboard_item = Gtk.ImageMenuItem.new_from_stock(stock_id=Gtk.STOCK_COPY, accel_group=None)
|
||||
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(label=_("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.IconSize.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(label=_("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)
|
||||
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(label='<b><i>%s</i></b>' % escape(name_displayer.display(sib)))
|
||||
else:
|
||||
label = Gtk.Label(label=escape(name_displayer.display(sib)))
|
||||
|
||||
go_image = Gtk.Image.new_from_stock(Gtk.STOCK_JUMP_TO, Gtk.IconSize.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(label=_("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(label='<b><i>%s</i></b>' % escape(name_displayer.display(child)))
|
||||
else:
|
||||
label = Gtk.Label(label=escape(name_displayer.display(child)))
|
||||
|
||||
go_image = Gtk.Image.new_from_stock(Gtk.STOCK_JUMP_TO, Gtk.IconSize.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(label=_("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(label='<b><i>%s</i></b>' % escape(name_displayer.display(par)))
|
||||
else:
|
||||
label = Gtk.Label(label=escape(name_displayer.display(par)))
|
||||
|
||||
go_image = Gtk.Image.new_from_stock(Gtk.STOCK_JUMP_TO, Gtk.IconSize.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:
|
||||
item.set_sensitive(0)
|
||||
item.show()
|
||||
menu.append(item)
|
||||
|
||||
# Go over parents and build their menu
|
||||
item = Gtk.MenuItem(label=_("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(label=escape(name_displayer.display(per)))
|
||||
|
||||
go_image = Gtk.Image.new_from_stock(Gtk.STOCK_JUMP_TO, Gtk.IconSize.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)
|
||||
menu.popup(None, None, None, None, event.button, event.time)
|
||||
return 1
|
||||
|
||||
def printview(self, obj):
|
||||
"""
|
||||
@@ -544,6 +211,62 @@ class FanChartView(NavigationView):
|
||||
prt = CairoPrintSave(widthpx, self.fan.on_draw, self.uistate.window)
|
||||
prt.run()
|
||||
|
||||
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 can_configure(self):
|
||||
"""
|
||||
See :class:`~gui.views.pageview.PageView
|
||||
:return: bool
|
||||
"""
|
||||
return True
|
||||
|
||||
def _get_configure_page_funcs(self):
|
||||
"""
|
||||
Return a list of functions that create gtk elements to use in the
|
||||
notebook pages of the Configure dialog
|
||||
|
||||
:return: list of functions
|
||||
"""
|
||||
return [self.config_panel]
|
||||
|
||||
def config_panel(self, configdialog):
|
||||
"""
|
||||
Function that builds the widget in the configuration dialog
|
||||
"""
|
||||
table = Gtk.Table(3, 2)
|
||||
table.set_border_width(12)
|
||||
table.set_col_spacings(6)
|
||||
table.set_row_spacings(6)
|
||||
|
||||
configdialog.add_spinner(table, _("Max generations"), 0,
|
||||
'interface.fanview-maxgen', (1, 11),
|
||||
callback=self.cb_update_maxgen)
|
||||
configdialog.add_combo(table,
|
||||
_('Background'),
|
||||
4, 'interface.fanview-background',
|
||||
((0, _('Color Scheme 1')),
|
||||
(1, _('Color Scheme 2')),
|
||||
(2, _('Gender Colors')),
|
||||
(3, _('White'))),
|
||||
callback=self.cb_update_background)
|
||||
|
||||
return _('Layout'), table
|
||||
|
||||
def cb_update_maxgen(self, spinbtn, constant):
|
||||
self.maxgen = spinbtn.get_value_as_int()
|
||||
self._config.set(constant, self.maxgen)
|
||||
self.update()
|
||||
|
||||
def cb_update_background(self, obj, constant):
|
||||
entry = obj.get_active()
|
||||
self._config.set(constant, entry)
|
||||
self.background = int(entry)
|
||||
self.update()
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#
|
||||
# CairoPrintSave class
|
||||
|
||||
@@ -60,7 +60,7 @@ from gen.display.name import displayer as name_displayer
|
||||
from gen.utils.alive import probably_alive
|
||||
from gen.utils.file import media_path_full
|
||||
from gen.utils.db import find_children, find_parents, find_witnessed_people
|
||||
from libformatting import FormattingHelper
|
||||
from gen.utils.libformatting import FormattingHelper
|
||||
from gui.thumbnails import get_thumbnail_path
|
||||
from gen.errors import WindowActiveError
|
||||
from gui.editors import EditPerson, EditFamily
|
||||
|
||||
Reference in New Issue
Block a user