fanchart: allow reorder on the desc fam chart, improve layout, shorter print string

svn: r20410
This commit is contained in:
Benny Malengier 2012-09-18 12:04:37 +00:00
parent e60b305a0d
commit 0478af1335
7 changed files with 260 additions and 175 deletions

View File

@ -495,6 +495,7 @@ src/gui/widgets/labels.py
src/gui/widgets/monitoredwidgets.py src/gui/widgets/monitoredwidgets.py
src/gui/widgets/photo.py src/gui/widgets/photo.py
src/gui/widgets/progressdialog.py src/gui/widgets/progressdialog.py
src/gui/widgets/reorderfam.py
src/gui/widgets/styledtexteditor.py src/gui/widgets/styledtexteditor.py
src/gui/widgets/undoableentry.py src/gui/widgets/undoableentry.py
src/gui/widgets/validatedmaskedentry.py src/gui/widgets/validatedmaskedentry.py

View File

@ -22,6 +22,7 @@ pkgpython_PYTHON = \
multitreeview.py \ multitreeview.py \
photo.py \ photo.py \
progressdialog.py \ progressdialog.py \
reorderfam.py \
shortlistcomboentry.py \ shortlistcomboentry.py \
springseparator.py \ springseparator.py \
statusbar.py \ statusbar.py \

View File

@ -57,6 +57,7 @@ from gen.db import DbTxn
from gen.display.name import displayer as name_displayer from gen.display.name import displayer as name_displayer
from gen.errors import WindowActiveError from gen.errors import WindowActiveError
from gui.editors import EditPerson, EditFamily from gui.editors import EditPerson, EditFamily
from gui.widgets.reorderfam import Reorder
import gen.lib import gen.lib
import gui.utils import gui.utils
from gui.ddtargets import DdTargets from gui.ddtargets import DdTargets
@ -90,6 +91,7 @@ BORDER_EDGE_WIDTH = 10 # empty white box size at edge to indicate parents
CHILDRING_WIDTH = 12 # width of the children ring inside the person CHILDRING_WIDTH = 12 # width of the children ring inside the person
TRANSLATE_PX = 10 # size of the central circle, used to move the chart TRANSLATE_PX = 10 # size of the central circle, used to move the chart
PAD_PX = 4 # padding with edges PAD_PX = 4 # padding with edges
PAD_TEXT = 2 # padding for text in boxes
BACKGROUND_SCHEME1 = 0 BACKGROUND_SCHEME1 = 0
BACKGROUND_SCHEME2 = 1 BACKGROUND_SCHEME2 = 1
@ -578,15 +580,15 @@ class FanChartBaseWidget(Gtk.DrawingArea):
#spread rest #spread rest
degoffsetheight = (degavailheight - degneedheight) / 2 degoffsetheight = (degavailheight - degneedheight) / 2
txlen = len(text) txlen = len(text)
if w > height: if w > height - PAD_TEXT:
txlen = int(w/height * txlen) txlen = int(w/height * txlen)
cont = True cont = True
while cont: while cont:
layout = self.create_pango_layout(text[:txlen]) layout = self.create_pango_layout(text[:txlen])
layout.set_font_description(font) layout.set_font_description(font)
w, h = layout.get_size() w, h = layout.get_size()
w = w / Pango.SCALE + 5 # 5 pixel padding w = w / Pango.SCALE + 2*PAD_TEXT # padding before/after
h = h / Pango.SCALE + 4 # 4 pixel padding h = h / Pango.SCALE + 4 # padding in height text
if w > height: if w > height:
if txlen <= 1: if txlen <= 1:
cont = False cont = False
@ -604,15 +606,15 @@ class FanChartBaseWidget(Gtk.DrawingArea):
cr.rotate(pos * math.pi / 180) cr.rotate(pos * math.pi / 180)
layout.context_changed() layout.context_changed()
if (start + rotval) % 360 > 179: if (start + rotval) % 360 > 179:
cr.move_to(radius+2, 0) cr.move_to(radius + PAD_TEXT, 0)
else: else:
cr.move_to(-radius-height+6, 0) cr.move_to(-radius - height + PAD_TEXT, 0)
PangoCairo.show_layout(cr, layout) PangoCairo.show_layout(cr, layout)
cr.restore() cr.restore()
else: else:
# center text: # center text:
# 1. determine degrees of the text we can draw # 1. determine degrees of the text we can draw
degpadding = 5 / radius * (180 / math.pi) # degrees for 5 pixel padding degpadding = PAD_TEXT / radius * (180 / math.pi) # degrees for padding
degneed = degpadding degneed = degpadding
maxlen = len(text) maxlen = len(text)
hoffset = 0 hoffset = 0
@ -625,12 +627,12 @@ class FanChartBaseWidget(Gtk.DrawingArea):
if h/2 > hoffset: if h/2 > hoffset:
hoffset = h/2 hoffset = h/2
degneed += w / radius * (180 / math.pi) degneed += w / radius * (180 / math.pi)
if degneed > stop - start: if degneed > stop - start - degpadding:
#outside of the box #outside of the box
maxlen = i maxlen = i
break break
# 2. determine degrees over we can distribute before and after # 2. determine degrees over we can distribute before and after
if degneed > stop - start: if degneed > stop - start - degpadding:
degover = 0 degover = 0
else: else:
degover = stop - start - degneed - degpadding degover = stop - start - degneed - degpadding
@ -1277,7 +1279,7 @@ class FanChartWidget(FanChartBaseWidget):
if spacepolartext < PIXELS_PER_GENERATION * 1.1: if spacepolartext < PIXELS_PER_GENERATION * 1.1:
# more space to print it radial # more space to print it radial
radial = True radial = True
radstart = radius - PIXELS_PER_GENERATION + 4 radstart = radius - PIXELS_PER_GENERATION
self.draw_text(cr, name, radstart, start, stop, self.draw_text(cr, name, radstart, start, stop,
PIXELS_PER_GENERATION, radial, PIXELS_PER_GENERATION, radial,
self.fontcolor(r, g, b, a), self.fontbold(a)) self.fontcolor(r, g, b, a), self.fontbold(a))
@ -1507,12 +1509,31 @@ class FanChartGrampsGUI(object):
edit_item.show() edit_item.show()
menu.append(edit_item) menu.append(edit_item)
if family_handle: if family_handle:
family = self.dbstate.db.get_family_from_handle(family_handle)
edit_fam_item = Gtk.ImageMenuItem.new_from_stock( edit_fam_item = Gtk.ImageMenuItem.new_from_stock(
stock_id=Gtk.STOCK_EDIT, accel_group=None) stock_id=Gtk.STOCK_EDIT, accel_group=None)
edit_fam_item.set_label(_("Edit family")) edit_fam_item.set_label(_("Edit family"))
edit_fam_item.connect("activate", self.edit_fam_cb, family_handle) edit_fam_item.connect("activate", self.edit_fam_cb, family_handle)
edit_fam_item.show() edit_fam_item.show()
menu.append(edit_fam_item) menu.append(edit_fam_item)
#see if a reorder button is needed
if family.get_father_handle() == person_handle:
parth = family.get_mother_handle()
else:
parth = family.get_father_handle()
lenfams = 0
if parth:
partner = self.dbstate.db.get_person_from_handle(parth)
lenfams = len(partner.get_family_handle_list())
if lenfams in [0, 1]:
lenfams = len(partner.get_parent_family_handle_list())
reord_fam_item = Gtk.ImageMenuItem.new_from_stock(
stock_id=Gtk.STOCK_SORT_ASCENDING, accel_group=None)
reord_fam_item.set_label(_("Reorder families"))
reord_fam_item.connect("activate", self.reord_fam_cb, parth)
reord_fam_item.set_sensitive(lenfams > 1)
reord_fam_item.show()
menu.append(reord_fam_item)
clipboard_item = Gtk.ImageMenuItem.new_from_stock(stock_id=Gtk.STOCK_COPY, accel_group=None) 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, clipboard_item.connect("activate", self.copy_person_to_clipboard_cb,
@ -1760,6 +1781,13 @@ class FanChartGrampsGUI(object):
return True return True
return False return False
def reord_fam_cb(self, obj, person_handle):
try:
Reorder(self.dbstate, self.uistate, [], person_handle)
except WindowActiveError:
pass
return True
def add_person_cb(self, obj): def add_person_cb(self, obj):
""" """
Add a person Add a person

View File

@ -553,7 +553,7 @@ class FanChartDescWidget(FanChartBaseWidget):
if spacepolartext < width * 1.1: if spacepolartext < width * 1.1:
# more space to print it radial # more space to print it radial
radial = True radial = True
radstart = radius + 4 radstart = radius
self.draw_text(cr, name, radstart, start_rad/ math.pi*180, self.draw_text(cr, name, radstart, start_rad/ math.pi*180,
stop_rad/ math.pi*180, width, radial, stop_rad/ math.pi*180, width, radial,
self.fontcolor(r, g, b, a), self.fontbold(a)) self.fontcolor(r, g, b, a), self.fontbold(a))

View File

@ -0,0 +1,218 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2001-2007 Donald N. Allingham
# Copyright (C) 2009-2010 Gary Burton
#
# 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: relview.py 20294 2012-08-30 20:34:42Z bmcage $
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gen.ggettext import sgettext as _
#-------------------------------------------------------------------------
#
# Set up logging
#
#-------------------------------------------------------------------------
import logging
_LOG = logging.getLogger("gui.widgets.reorderfam")
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
#
# Gramps Modules
#
#-------------------------------------------------------------------------
from gen.db import DbTxn
from gui.listmodel import ListModel
from gui.managedwindow import ManagedWindow
from gui.glade import Glade
from gen.display.name import displayer as name_displayer
#-------------------------------------------------------------------------
#
# Reorder class
#
#-------------------------------------------------------------------------
class Reorder(ManagedWindow):
"""
Interface to reorder the families a person is parent in
"""
def __init__(self, state, uistate, track, handle):
xml = Glade('reorder.glade')
top = xml.toplevel
self.dbstate = state
ManagedWindow.__init__(self, uistate, track, self)
self.person = self.dbstate.db.get_person_from_handle(handle)
self.parent_list = self.person.get_parent_family_handle_list()
self.family_list = self.person.get_family_handle_list()
penable = len(self.parent_list) > 1
fenable = len(self.family_list) > 1
self.set_window(top, None, _("Reorder Relationships"))
self.ptree = xml.get_object('ptree')
self.pmodel = ListModel(self.ptree,
[(_('Father'), -1, 200),
(_('Mother'), -1, 200),
('', -1, 0)])
self.ftree = xml.get_object('ftree')
self.fmodel = ListModel(self.ftree,
[(_('Spouse'), -1, 200),
(_('Relationship'), -1, 200),
('', -1, 0)])
xml.get_object('ok').connect('clicked', self.ok_clicked)
xml.get_object('cancel').connect('clicked', self.cancel_clicked)
fup = xml.get_object('fup')
fup.connect('clicked', self.fup_clicked)
fup.set_sensitive(fenable)
fdown = xml.get_object('fdown')
fdown.connect('clicked', self.fdown_clicked)
fdown.set_sensitive(fenable)
pup = xml.get_object('pup')
pup.connect('clicked', self.pup_clicked)
pup.set_sensitive(penable)
pdown = xml.get_object('pdown')
pdown.connect('clicked', self.pdown_clicked)
pdown.set_sensitive(penable)
self.fill_data()
self.show()
def fill_data(self):
self.fill_parents()
self.fill_family()
def fill_parents(self):
for handle in self.parent_list:
family = self.dbstate.db.get_family_from_handle(handle)
fhandle = family.get_father_handle()
mhandle = family.get_mother_handle()
fname = ""
if fhandle:
father = self.dbstate.db.get_person_from_handle(fhandle)
if father:
fname = name_displayer.display(father)
mname = ""
if mhandle:
mother = self.dbstate.db.get_person_from_handle(mhandle)
if mother:
mname = name_displayer.display(mother)
self.pmodel.add([fname, mname, handle])
def fill_family(self):
for handle in self.family_list:
family = self.dbstate.db.get_family_from_handle(handle)
fhandle = family.get_father_handle()
mhandle = family.get_mother_handle()
name = ""
if fhandle and fhandle != self.person.handle:
spouse = self.dbstate.db.get_person_from_handle(fhandle)
if spouse:
name = name_displayer.display(spouse)
elif mhandle:
spouse = self.dbstate.db.get_person_from_handle(mhandle)
if spouse:
name = name_displayer.display(spouse)
reltype = str(family.get_relationship())
self.fmodel.add([name, reltype, handle])
def cancel_clicked(self, obj):
self.close()
def ok_clicked(self, obj):
name = name_displayer.display(self.person)
msg = _("Reorder Relationships: %s") % name
with DbTxn(msg, self.dbstate.db) as trans:
self.dbstate.db.commit_person(self.person, trans)
self.close()
def pup_clicked(self, obj):
"""Moves the current selection up one row"""
row = self.pmodel.get_selected_row()
if not row or row == -1:
return
store, the_iter = self.pmodel.get_selected()
data = self.pmodel.get_data(the_iter, xrange(3))
self.pmodel.remove(the_iter)
self.pmodel.insert(row-1, data, None, 1)
handle = self.parent_list.pop(row)
self.parent_list.insert(row-1, handle)
def pdown_clicked(self, obj):
row = self.pmodel.get_selected_row()
if row + 1 >= self.pmodel.count or row == -1:
return
store, the_iter = self.pmodel.get_selected()
data = self.pmodel.get_data(the_iter, xrange(3))
self.pmodel.remove(the_iter)
self.pmodel.insert(row+1, data, None, 1)
handle = self.parent_list.pop(row)
self.parent_list.insert(row+1, handle)
def fup_clicked(self, obj):
row = self.fmodel.get_selected_row()
if not row or row == -1:
return
store, the_iter = self.fmodel.get_selected()
data = self.fmodel.get_data(the_iter, xrange(3))
self.fmodel.remove(the_iter)
self.fmodel.insert(row-1, data, None, 1)
handle = self.family_list.pop(row)
self.family_list.insert(row-1, handle)
def fdown_clicked(self, obj):
row = self.fmodel.get_selected_row()
if row + 1 >= self.fmodel.count or row == -1:
return
store, the_iter = self.fmodel.get_selected()
data = self.fmodel.get_data(the_iter, xrange(3))
self.fmodel.remove(the_iter)
self.fmodel.insert(row+1, data, None, 1)
handle = self.family_list.pop(row)
self.family_list.insert(row+1, handle)

View File

@ -162,7 +162,7 @@ class FanChartDescView(fanchartdesc.FanChartDescGrampsGUI, NavigationView):
""" """
NavigationView.define_actions(self) NavigationView.define_actions(self)
self._add_action('PrintView', Gtk.STOCK_PRINT, _("_Print/Save View..."), self._add_action('PrintView', Gtk.STOCK_PRINT, _("_Print..."),
accel="<PRIMARY>P", accel="<PRIMARY>P",
tip=_("Print or save the Fan Chart View"), tip=_("Print or save the Fan Chart View"),
callback=self.printview) callback=self.printview)

View File

@ -68,15 +68,13 @@ import gen.datehandler
from gui.thumbnails import get_thumbnail_image from gui.thumbnails import get_thumbnail_image
from gen.config import config from gen.config import config
from gui import widgets from gui import widgets
from gui.widgets.reorderfam import Reorder
from gui.selectors import SelectorFactory from gui.selectors import SelectorFactory
from gen.errors import WindowActiveError from gen.errors import WindowActiveError
from gui.views.bookmarks import PersonBookmarks from gui.views.bookmarks import PersonBookmarks
from gen.const import CUSTOM_FILTERS from gen.const import CUSTOM_FILTERS
from gen.utils.db import (get_birth_or_fallback, get_death_or_fallback, from gen.utils.db import (get_birth_or_fallback, get_death_or_fallback,
preset_name) preset_name)
from gui.listmodel import ListModel
from gui.managedwindow import ManagedWindow
from gui.glade import Glade
_GenderCode = { _GenderCode = {
gen.lib.Person.MALE : u'\u2642', gen.lib.Person.MALE : u'\u2642',
@ -1712,167 +1710,6 @@ class RelationshipView(NavigationView):
""" """
return [self.content_panel, self.config_panel] return [self.content_panel, self.config_panel]
#-------------------------------------------------------------------------
#
# Reorder class
#
#-------------------------------------------------------------------------
class Reorder(ManagedWindow):
def __init__(self, state, uistate, track, handle):
xml = Glade('reorder.glade')
top = xml.toplevel
self.dbstate = state
ManagedWindow.__init__(self, uistate, track, self)
self.person = self.dbstate.db.get_person_from_handle(handle)
self.parent_list = self.person.get_parent_family_handle_list()
self.family_list = self.person.get_family_handle_list()
penable = len(self.parent_list) > 1
fenable = len(self.family_list) > 1
self.set_window(top, None, _("Reorder Relationships"))
self.ptree = xml.get_object('ptree')
self.pmodel = ListModel(self.ptree,
[(_('Father'), -1, 200),
(_('Mother'), -1, 200),
('', -1, 0)])
self.ftree = xml.get_object('ftree')
self.fmodel = ListModel(self.ftree,
[(_('Spouse'), -1, 200),
(_('Relationship'), -1, 200),
('', -1, 0)])
xml.get_object('ok').connect('clicked', self.ok_clicked)
xml.get_object('cancel').connect('clicked', self.cancel_clicked)
fup = xml.get_object('fup')
fup.connect('clicked', self.fup_clicked)
fup.set_sensitive(fenable)
fdown = xml.get_object('fdown')
fdown.connect('clicked', self.fdown_clicked)
fdown.set_sensitive(fenable)
pup = xml.get_object('pup')
pup.connect('clicked', self.pup_clicked)
pup.set_sensitive(penable)
pdown = xml.get_object('pdown')
pdown.connect('clicked', self.pdown_clicked)
pdown.set_sensitive(penable)
self.fill_data()
self.show()
def fill_data(self):
self.fill_parents()
self.fill_family()
def fill_parents(self):
for handle in self.parent_list:
family = self.dbstate.db.get_family_from_handle(handle)
fhandle = family.get_father_handle()
mhandle = family.get_mother_handle()
fname = ""
if fhandle:
father = self.dbstate.db.get_person_from_handle(fhandle)
if father:
fname = name_displayer.display(father)
mname = ""
if mhandle:
mother = self.dbstate.db.get_person_from_handle(mhandle)
if mother:
mname = name_displayer.display(mother)
self.pmodel.add([fname, mname, handle])
def fill_family(self):
for handle in self.family_list:
family = self.dbstate.db.get_family_from_handle(handle)
fhandle = family.get_father_handle()
mhandle = family.get_mother_handle()
name = ""
if fhandle and fhandle != self.person.handle:
spouse = self.dbstate.db.get_person_from_handle(fhandle)
if spouse:
name = name_displayer.display(spouse)
elif mhandle:
spouse = self.dbstate.db.get_person_from_handle(mhandle)
if spouse:
name = name_displayer.display(spouse)
reltype = str(family.get_relationship())
self.fmodel.add([name, reltype, handle])
def cancel_clicked(self, obj):
self.close()
def ok_clicked(self, obj):
name = name_displayer.display(self.person)
msg = _("Reorder Relationships: %s") % name
with DbTxn(msg, self.dbstate.db) as trans:
self.dbstate.db.commit_person(self.person, trans)
self.close()
def pup_clicked(self, obj):
"""Moves the current selection up one row"""
row = self.pmodel.get_selected_row()
if not row or row == -1:
return
store, the_iter = self.pmodel.get_selected()
data = self.pmodel.get_data(the_iter, xrange(3))
self.pmodel.remove(the_iter)
self.pmodel.insert(row-1, data, None, 1)
handle = self.parent_list.pop(row)
self.parent_list.insert(row-1, handle)
def pdown_clicked(self, obj):
row = self.pmodel.get_selected_row()
if row + 1 >= self.pmodel.count or row == -1:
return
store, the_iter = self.pmodel.get_selected()
data = self.pmodel.get_data(the_iter, xrange(3))
self.pmodel.remove(the_iter)
self.pmodel.insert(row+1, data, None, 1)
handle = self.parent_list.pop(row)
self.parent_list.insert(row+1, handle)
def fup_clicked(self, obj):
row = self.fmodel.get_selected_row()
if not row or row == -1:
return
store, the_iter = self.fmodel.get_selected()
data = self.fmodel.get_data(the_iter, xrange(3))
self.fmodel.remove(the_iter)
self.fmodel.insert(row-1, data, None, 1)
handle = self.family_list.pop(row)
self.family_list.insert(row-1, handle)
def fdown_clicked(self, obj):
row = self.fmodel.get_selected_row()
if row + 1 >= self.fmodel.count or row == -1:
return
store, the_iter = self.fmodel.get_selected()
data = self.fmodel.get_data(the_iter, xrange(3))
self.fmodel.remove(the_iter)
self.fmodel.insert(row+1, data, None, 1)
handle = self.family_list.pop(row)
self.family_list.insert(row+1, handle)
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# Function to return if person has children # Function to return if person has children