diff --git a/po/POTFILES.in b/po/POTFILES.in index 6b4645b74..775146e1d 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -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 diff --git a/src/gui/widgets/Makefile.am b/src/gui/widgets/Makefile.am index f5e93256a..569000819 100644 --- a/src/gui/widgets/Makefile.am +++ b/src/gui/widgets/Makefile.am @@ -22,6 +22,7 @@ pkgpython_PYTHON = \ multitreeview.py \ photo.py \ progressdialog.py \ + reorderfam.py \ shortlistcomboentry.py \ springseparator.py \ statusbar.py \ diff --git a/src/gui/widgets/fanchart.py b/src/gui/widgets/fanchart.py index b419ab26e..f055c1a56 100644 --- a/src/gui/widgets/fanchart.py +++ b/src/gui/widgets/fanchart.py @@ -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 diff --git a/src/gui/widgets/fanchartdesc.py b/src/gui/widgets/fanchartdesc.py index 655fc318b..7b35f4fee 100644 --- a/src/gui/widgets/fanchartdesc.py +++ b/src/gui/widgets/fanchartdesc.py @@ -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)) diff --git a/src/gui/widgets/reorderfam.py b/src/gui/widgets/reorderfam.py new file mode 100644 index 000000000..8cf7ff919 --- /dev/null +++ b/src/gui/widgets/reorderfam.py @@ -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) diff --git a/src/plugins/view/fanchartdescview.py b/src/plugins/view/fanchartdescview.py index ea27e7447..7654a33dc 100644 --- a/src/plugins/view/fanchartdescview.py +++ b/src/plugins/view/fanchartdescview.py @@ -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="P", tip=_("Print or save the Fan Chart View"), callback=self.printview) diff --git a/src/plugins/view/relview.py b/src/plugins/view/relview.py index 7bb3aa988..87c85b558 100644 --- a/src/plugins/view/relview.py +++ b/src/plugins/view/relview.py @@ -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