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:
Benny Malengier 2012-09-01 15:13:44 +00:00
parent 455d077c2c
commit c86f383122
11 changed files with 498 additions and 746 deletions

View File

@ -218,6 +218,7 @@ src/gen/utils/debug.py
src/gen/utils/file.py
src/gen/utils/id.py
src/gen/utils/image.py
src/gen/utils/libformatting.py
# gen.utils.docgen
src/gen/utils/docgen/__init__.py
@ -316,7 +317,6 @@ src/plugins/sidebar/sidebar.gpr.py
src/plugins/docgen/pdfdoc.py
# plugins/lib directory
src/plugins/lib/libformatting.py
src/plugins/lib/libgrampsxml.py
src/plugins/lib/libhtml.py
src/plugins/lib/libhtmlbackend.py

View File

@ -40,7 +40,8 @@ from cgi import escape
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
from gen.utils.db import (get_birth_or_fallback, get_death_or_fallback,
get_marriage_or_fallback)
#-------------------------------------------------------------------------
#
@ -198,3 +199,4 @@ class FormattingHelper(object):
"""
self._text_cache = {}
self._markup_cache = {}

View File

@ -1110,7 +1110,7 @@ class GrampsPreferences(ConfigureDialog):
self.add_spinner(table,
_('Date before range'),
2, 'behavior.date-before-range', (1, 80))
self.add_spinner(table,
self.add_spinner(table,
_('Maximum age probably alive'),
3, 'behavior.max-age-prob-alive', (80, 140))
self.add_spinner(table,

View File

@ -42,6 +42,7 @@ from gi.repository import Gtk
from gi.repository import PangoCairo
import math
import cPickle as pickle
from cgi import escape
#-------------------------------------------------------------------------
#
@ -53,6 +54,8 @@ import gen.lib
import gui.utils
from gui.ddtargets import DdTargets
from gen.utils.alive import probably_alive
from gen.utils.libformatting import FormattingHelper
from gen.utils.db import (find_children, find_parents, find_witnessed_people)
#-------------------------------------------------------------------------
#
@ -78,17 +81,37 @@ class FanChartWidget(Gtk.DrawingArea):
Interactive Fan Chart Widget.
"""
BORDER_EDGE_WIDTH = 10
GENCOLOR = ((229,191,252),
(191,191,252),
(191,222,252),
(183,219,197),
(206,246,209))
TRANSLATE_PX = 10
BACKGROUND_SCHEME1 = 0
BACKGROUND_SCHEME2 = 1
BACKGROUND_GENDER = 2
BACKGROUND_WHITE = 3
GENCOLOR = {
BACKGROUND_SCHEME1: ((255, 63, 0),
(255,175, 15),
(255,223, 87),
(255,255,111),
(159,255,159),
(111,215,255),
( 79,151,255),
(231, 23,255),
(231, 23,121),
(210,170,124),
(189,153,112)),
BACKGROUND_SCHEME2: ((229,191,252),
(191,191,252),
(191,222,252),
(183,219,197),
(206,246,209)),
BACKGROUND_WHITE: ((255,255,255),),
}
COLLAPSED = 0
NORMAL = 1
EXPANDED = 2
def __init__(self, generations, dbstate, context_popup_callback=None):
def __init__(self, dbstate, callback_popup=None):
"""
Fan Chart Widget. Handles visualization of data in self.data.
See main() of FanChartGramplet for example of model format.
@ -96,6 +119,7 @@ class FanChartWidget(Gtk.DrawingArea):
GObject.GObject.__init__(self)
self.dbstate = dbstate
self.translating = False
self.on_popup = callback_popup
self.last_x, self.last_y = None, None
self.connect("button_release_event", self.on_mouse_up)
self.connect("motion_notify_event", self.on_mouse_move)
@ -104,7 +128,6 @@ class FanChartWidget(Gtk.DrawingArea):
self.connect("drag_data_get", self.on_drag_data_get)
self.connect("drag_begin", self.on_drag_begin)
self.connect("drag_end", self.on_drag_end)
self.context_popup_callback = context_popup_callback
self.add_events(Gdk.EventMask.BUTTON_PRESS_MASK |
Gdk.EventMask.BUTTON_RELEASE_MASK |
Gdk.EventMask.POINTER_MOTION_MASK)
@ -122,22 +145,26 @@ class FanChartWidget(Gtk.DrawingArea):
self.pixels_per_generation = 50 # size of radius for generation
## gotten from experiments with "sans serif 8":
self.degrees_per_radius = .80
self._mouse_click = False
## Other fonts will have different settings. Can you compute that
## from the font size? I have no idea.
self.generations = generations
self._mouse_click = False
self.rotate_value = 90 # degrees, initially, 1st gen male on right half
self.center_xy = [0, 0] # distance from center (x, y)
self.set_generations(self.generations)
self.center = 50 # pixel radius of center
self.gen_color = True
#default values
self.reset(9, self.BACKGROUND_SCHEME1)
self.set_size_request(120, 120)
def reset_generations(self):
def reset(self, maxgen, background):
"""
Reset all of the data on where slices appear, and if they are expanded.
Reset all of the data on where/how slices appear, and if they are expanded.
"""
self.set_generations(self.generations)
self.background = background
if self.background == self.BACKGROUND_GENDER:
self.colors = None
else:
self.colors = self.GENCOLOR[self.background]
self.set_generations(maxgen)
def set_generations(self, generations):
"""
@ -269,19 +296,19 @@ class FanChartWidget(Gtk.DrawingArea):
x, y, w, h = alloc.x, alloc.y, alloc.width, alloc.height
start_rad = start * math.pi/180
stop_rad = stop * math.pi/180
if self.gen_color:
r,g,b = self.GENCOLOR[generation % len(self.GENCOLOR)]
if gender == gen.lib.Person.MALE:
r *= .9
g *= .9
b *= .9
else:
if self.background == self.BACKGROUND_GENDER:
try:
alive = probably_alive(person, self.dbstate.db)
except RuntimeError:
alive = False
backgr, border = gui.utils.color_graph_box(alive, person.gender)
r, g, b = gui.utils.hex_to_rgb(backgr)
else:
r,g,b = self.colors[generation % len(self.colors)]
if gender == gen.lib.Person.MALE:
r *= .9
g *= .9
b *= .9
radius = generation * self.pixels_per_generation + self.center
# If max generation, and they have parents:
if generation == self.generations - 1 and parents:
@ -572,8 +599,8 @@ class FanChartWidget(Gtk.DrawingArea):
# Do things based on state, event.get_state(), or button, event.button
if gui.utils.is_right_click(event):
text, person, parents, child = self.data[generation][selected]
if person and self.context_popup_callback:
self.context_popup_callback(widget, event, person.handle)
if person and self.on_popup:
self.on_popup(widget, event, person.handle)
return True
return False
@ -619,3 +646,358 @@ class FanChartWidget(Gtk.DrawingArea):
sel_data.set(sel_data.get_target(), 8, pickle.dumps(data))
elif ('TEXT' in tgs or 'text/plain' in tgs) and info == 0L:
sel_data.set_text(self.format_helper.format_person(person, 11), -1)
class FanChartGrampsGUI(object):
""" class for functions fanchart GUI elements will need in Gramps
"""
def __init__(self, maxgen, background, on_childmenu_changed):
"""
Common part of GUI that shows Fan Chart, needs to know what to do if
one moves via Fan Chart to a new person
on_childmenu_changed: in popup, function called on moving to a new person
"""
self.fan = None
self.on_childmenu_changed = on_childmenu_changed
self.format_helper = FormattingHelper(self.dbstate)
self.maxgen = maxgen
self.background = background
def have_parents(self, person):
"""
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 set_fan(self, fan):
"""
Set the fanchartwidget to work on
"""
self.fan = fan
self.fan.format_helper = self.format_helper
def main(self):
"""
Fill the data structures with the active data. This initializes all
data.
"""
self.fan.reset(self.maxgen, self.background)
person = self.dbstate.db.get_person_from_handle(self.get_active('Person'))
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.maxgen):
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.maxgen - 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.maxgen - 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_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 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

View File

@ -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

View File

@ -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)

View File

@ -17,7 +17,6 @@ SUBDIRS = maps
pkgpython_PYTHON = \
libcairodoc.py\
libformatting.py\
libgedcom.py\
libgrampsxml.py\
libgrdb.py\

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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