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/photo.py
src/gui/widgets/progressdialog.py
src/gui/widgets/reorderfam.py
src/gui/widgets/styledtexteditor.py
src/gui/widgets/undoableentry.py
src/gui/widgets/validatedmaskedentry.py

View File

@ -22,6 +22,7 @@ pkgpython_PYTHON = \
multitreeview.py \
photo.py \
progressdialog.py \
reorderfam.py \
shortlistcomboentry.py \
springseparator.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.errors import WindowActiveError
from gui.editors import EditPerson, EditFamily
from gui.widgets.reorderfam import Reorder
import gen.lib
import gui.utils
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
TRANSLATE_PX = 10 # size of the central circle, used to move the chart
PAD_PX = 4 # padding with edges
PAD_TEXT = 2 # padding for text in boxes
BACKGROUND_SCHEME1 = 0
BACKGROUND_SCHEME2 = 1
@ -578,15 +580,15 @@ class FanChartBaseWidget(Gtk.DrawingArea):
#spread rest
degoffsetheight = (degavailheight - degneedheight) / 2
txlen = len(text)
if w > height:
if w > height - PAD_TEXT:
txlen = int(w/height * txlen)
cont = True
while cont:
layout = self.create_pango_layout(text[:txlen])
layout.set_font_description(font)
w, h = layout.get_size()
w = w / Pango.SCALE + 5 # 5 pixel padding
h = h / Pango.SCALE + 4 # 4 pixel padding
w = w / Pango.SCALE + 2*PAD_TEXT # padding before/after
h = h / Pango.SCALE + 4 # padding in height text
if w > height:
if txlen <= 1:
cont = False
@ -604,15 +606,15 @@ class FanChartBaseWidget(Gtk.DrawingArea):
cr.rotate(pos * math.pi / 180)
layout.context_changed()
if (start + rotval) % 360 > 179:
cr.move_to(radius+2, 0)
cr.move_to(radius + PAD_TEXT, 0)
else:
cr.move_to(-radius-height+6, 0)
cr.move_to(-radius - height + PAD_TEXT, 0)
PangoCairo.show_layout(cr, layout)
cr.restore()
else:
# center text:
# 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
maxlen = len(text)
hoffset = 0
@ -625,12 +627,12 @@ class FanChartBaseWidget(Gtk.DrawingArea):
if h/2 > hoffset:
hoffset = h/2
degneed += w / radius * (180 / math.pi)
if degneed > stop - start:
if degneed > stop - start - degpadding:
#outside of the box
maxlen = i
break
# 2. determine degrees over we can distribute before and after
if degneed > stop - start:
if degneed > stop - start - degpadding:
degover = 0
else:
degover = stop - start - degneed - degpadding
@ -1277,7 +1279,7 @@ class FanChartWidget(FanChartBaseWidget):
if spacepolartext < PIXELS_PER_GENERATION * 1.1:
# more space to print it radial
radial = True
radstart = radius - PIXELS_PER_GENERATION + 4
radstart = radius - PIXELS_PER_GENERATION
self.draw_text(cr, name, radstart, start, stop,
PIXELS_PER_GENERATION, radial,
self.fontcolor(r, g, b, a), self.fontbold(a))
@ -1507,12 +1509,31 @@ class FanChartGrampsGUI(object):
edit_item.show()
menu.append(edit_item)
if family_handle:
family = self.dbstate.db.get_family_from_handle(family_handle)
edit_fam_item = Gtk.ImageMenuItem.new_from_stock(
stock_id=Gtk.STOCK_EDIT, accel_group=None)
edit_fam_item.set_label(_("Edit family"))
edit_fam_item.connect("activate", self.edit_fam_cb, family_handle)
edit_fam_item.show()
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.connect("activate", self.copy_person_to_clipboard_cb,
@ -1760,6 +1781,13 @@ class FanChartGrampsGUI(object):
return True
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):
"""
Add a person

View File

@ -553,7 +553,7 @@ class FanChartDescWidget(FanChartBaseWidget):
if spacepolartext < width * 1.1:
# more space to print it radial
radial = True
radstart = radius + 4
radstart = radius
self.draw_text(cr, name, radstart, start_rad/ math.pi*180,
stop_rad/ math.pi*180, width, radial,
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)
self._add_action('PrintView', Gtk.STOCK_PRINT, _("_Print/Save View..."),
self._add_action('PrintView', Gtk.STOCK_PRINT, _("_Print..."),
accel="<PRIMARY>P",
tip=_("Print or save the Fan Chart View"),
callback=self.printview)

View File

@ -68,15 +68,13 @@ import gen.datehandler
from gui.thumbnails import get_thumbnail_image
from gen.config import config
from gui import widgets
from gui.widgets.reorderfam import Reorder
from gui.selectors import SelectorFactory
from gen.errors import WindowActiveError
from gui.views.bookmarks import PersonBookmarks
from gen.const import CUSTOM_FILTERS
from gen.utils.db import (get_birth_or_fallback, get_death_or_fallback,
preset_name)
from gui.listmodel import ListModel
from gui.managedwindow import ManagedWindow
from gui.glade import Glade
_GenderCode = {
gen.lib.Person.MALE : u'\u2642',
@ -1712,167 +1710,6 @@ class RelationshipView(NavigationView):
"""
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