move src/Editors/* to src/gui/editors as part of GEP008

svn: r13807
This commit is contained in:
Brian Matherly
2009-12-15 05:56:12 +00:00
parent baa13df670
commit bbe2b6da0c
71 changed files with 194 additions and 280 deletions

View File

@@ -4,6 +4,7 @@
# If not using GNU make, then list all .py files individually
SUBDIRS = \
editors \
selectors \
views \
widgets

View File

@@ -26,4 +26,4 @@ Package init for the gui package.
# DO NOT IMPORT METHODS/CLASSES FROM src/gui HERE ! Only __all__
__all__ = [ "views", "widgets" ]
__all__ = [ "editors", "selectors", "views", "widgets" ]

View File

@@ -0,0 +1,46 @@
# This is the src/Editors level Makefile for Gramps
# We could use GNU make's ':=' syntax for nice wildcard use,
# but that is not necessarily portable.
# If not using GNU make, then list all .py files individually
pkgdatadir = $(datadir)/@PACKAGE@/gui/editors
pkgdata_PYTHON = \
addmedia.py\
__init__.py\
editaddress.py \
editattribute.py \
editchildRef.py \
editevent.py \
editeventRef.py \
editfamily.py \
editldsOrd.py \
editlocation.py \
editmedia.py \
editmediaRef.py \
editname.py \
editnote.py \
editperson.py \
editpersonRef.py \
editplace.py \
editprimary.py \
editreference.py \
editrepository.py \
editrepoRef.py \
editsecondary.py \
editsource.py \
editsourceRef.py \
editurl.py \
objectentries.py
pkgpyexecdir = @pkgpyexecdir@/src/editors
pkgpythondir = @pkgpythondir@/src/editors
# Clean up all the byte-compiled files
MOSTLYCLEANFILES = *pyc *pyo
GRAMPS_PY_MODPATH = "../../"
pycheck:
(export PYTHONPATH=$(GRAMPS_PY_MODPATH); \
pychecker $(pkgdata_PYTHON));

View File

@@ -0,0 +1,40 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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
#
from editaddress import EditAddress
from editattribute import EditAttribute, EditFamilyAttribute
from editchildref import EditChildRef
from editevent import EditEvent, DeleteEventQuery
from editeventref import EditEventRef
from editfamily import EditFamily
from editldsord import EditLdsOrd, EditFamilyLdsOrd
from editlocation import EditLocation
from editmedia import EditMedia, DeleteMediaQuery
from editmediaref import EditMediaRef
from editname import EditName
from editnote import EditNote, DeleteNoteQuery
from editperson import EditPerson
from editpersonref import EditPersonRef
from editplace import EditPlace, DeletePlaceQuery
from editrepository import EditRepository, DeleteRepositoryQuery
from editreporef import EditRepoRef
from editsource import EditSource, DeleteSrcQuery
from editsourceref import EditSourceRef
from editurl import EditUrl

236
src/gui/editors/addmedia.py Normal file
View File

@@ -0,0 +1,236 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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$
"""
Provide the interface to allow a person to add a media object to the database.
"""
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import os
#-------------------------------------------------------------------------
#
# internationalization
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import const
import config
import Utils
import Mime
import GrampsDisplay
import ManagedWindow
from QuestionDialog import ErrorDialog, WarningDialog
from glade import Glade
#-------------------------------------------------------------------------
#
# AddMediaObject
#
#-------------------------------------------------------------------------
class AddMediaObject(ManagedWindow.ManagedWindow):
"""
Displays the Add Media Dialog window, allowing the user to select
a file from the file system, while providing a description.
"""
def __init__(self, dbstate, uistate, track, mediaobj, callback=None):
"""
Create and displays the dialog box
db - the database in which the new object is to be stored
The mediaobject is updated with the information, and on save, the
callback function is called
"""
ManagedWindow.ManagedWindow.__init__(self, uistate, track, self)
self.dbase = dbstate.db
self.obj = mediaobj
self.callback = callback
self.last_directory = config.get('behavior.addmedia-image-dir')
self.relative_path = config.get('behavior.addmedia-relative-path')
self.glade = Glade()
self.set_window(
self.glade.toplevel,
self.glade.get_object('title'),
_('Select a media object'))
self.description = self.glade.get_object("photoDescription")
self.image = self.glade.get_object("image")
self.file_text = self.glade.get_object("fname")
if not(self.last_directory and os.path.isdir(self.last_directory)):
self.last_directory = const.USER_HOME
#if existing path, use dir of path
if not self.obj.get_path() == "":
fullname = Utils.media_path_full(self.dbase, self.obj.get_path())
dir = os.path.dirname(fullname)
if os.path.isdir(dir):
self.last_directory = dir
self.file_text.select_filename(fullname)
else:
self.file_text.set_current_folder(self.last_directory)
else:
self.file_text.set_current_folder(self.last_directory)
if not self.obj.get_description() == "":
self.description.set_text(self.obj.get_description())
self.relpath = self.glade.get_object('relpath')
self.relpath.set_active(self.relative_path)
self.temp_name = ""
self.object = None
self.glade.get_object('fname').connect('update_preview',
self.on_name_changed)
self.ok_button = self.glade.get_object('button79')
self.help_button = self.glade.get_object('button103')
self.cancel_button = self.glade.get_object('button81')
self.ok_button.connect('clicked', self.save)
self.ok_button.set_sensitive(not self.dbase.readonly)
self.help_button.connect('clicked', lambda x: GrampsDisplay.help())
self.cancel_button.connect('clicked', self.close)
self.show()
self.modal_call()
def build_menu_names(self, obj):
"""
Build the menu name for the window manager.
"""
return(_('Select media object'), None)
def save(self, *obj):
"""
Callback function called when the save button is pressed.
The media object is updated, and callback called.
"""
description = unicode(self.description.get_text())
if self.file_text.get_filename() is None:
msgstr = _("Import failed")
msgstr2 = _("The filename supplied could not be found.")
ErrorDialog(msgstr, msgstr2)
return
filename = Utils.get_unicode_path(self.file_text.get_filename())
full_file = filename
if self.relpath.get_active():
pname = unicode(Utils.media_path(self.dbase))
if not os.path.exists(pname):
msgstr = _("Cannot import %s")
msgstr2 = _("Directory specified in preferences: Base path for relative media paths: %s does not exist. Change preferences or do not use relative path when importing")
ErrorDialog(msgstr % filename, msgstr2 % pname)
return
filename = Utils.relative_path(filename, pname)
mtype = Mime.get_type(full_file)
description = description or os.path.basename(filename)
self.obj.set_description(description)
self.obj.set_mime_type(mtype)
name = filename
self.obj.set_path(name)
self.last_directory = os.path.dirname(full_file)
self.relative_path = self.relpath.get_active()
self._cleanup_on_exit()
if self.callback:
self.callback(self.obj)
def on_name_changed(self, *obj):
"""
Called anytime the filename text window changes. Checks to
see if the file exists. If it does, the image is loaded into
the preview window.
"""
fname = self.file_text.get_filename()
if not fname:
return
filename = Utils.get_unicode_path(fname)
basename = os.path.basename(filename)
(root, ext) = os.path.splitext(basename)
old_title = unicode(self.description.get_text())
if old_title == '' or old_title == self.temp_name:
self.description.set_text(root)
self.temp_name = root
filename = Utils.find_file( filename)
if filename:
mtype = Mime.get_type(filename)
if mtype and mtype.startswith("image"):
image = scale_image(filename, const.THUMBSCALE)
else:
image = Mime.find_mime_type_pixbuf(mtype)
self.image.set_from_pixbuf(image)
def _cleanup_on_exit(self):
config.set('behavior.addmedia-image-dir', self.last_directory)
config.set('behavior.addmedia-relative-path', self.relative_path)
config.save()
#-------------------------------------------------------------------------
#
# scale_image
#
#-------------------------------------------------------------------------
def scale_image(path, size):
"""
Scales the image to the specified size
"""
title_msg = _("Cannot display %s") % path
detail_msg = _('Gramps is not able to display the image file. '
'This may be caused by a corrupt file.')
try:
image1 = gtk.gdk.pixbuf_new_from_file(path)
width = image1.get_width()
height = image1.get_height()
scale = size / float(max(width, height))
return image1.scale_simple(int(scale*width), int(scale*height),
gtk.gdk.INTERP_BILINEAR)
except:
WarningDialog(title_msg, detail_msg)
return gtk.gdk.pixbuf_new_from_file(const.ICON)

View File

@@ -0,0 +1,156 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# 2009 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$
"""
The EditAddress module provides the EditAddress class. This provides a
mechanism for the user to edit address information.
"""
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from editsecondary import EditSecondary
from gen.lib import NoteType
from glade import Glade
from DisplayTabs import SourceEmbedList, NoteTab
from gui.widgets import MonitoredDate, MonitoredEntry, PrivacyButton
#-------------------------------------------------------------------------
#
# EditAddress class
#
#-------------------------------------------------------------------------
class EditAddress(EditSecondary):
"""
Displays a dialog that allows the user to edit an address.
"""
def __init__(self, dbstate, uistate, track, addr, callback):
"""
Displays the dialog box.
parent - The class that called the Address editor.
addr - The address that is to be edited
"""
EditSecondary.__init__(self, dbstate, uistate, track, addr, callback)
def _local_init(self):
self.width_key = 'interface.address-width'
self.height_key = 'interface.address-height'
self.top = Glade()
self.set_window(self.top.toplevel,
self.top.get_object("title"),
_('Address Editor'))
def _setup_fields(self):
self.addr_start = MonitoredDate(
self.top.get_object("date_entry"),
self.top.get_object("date_stat"),
self.obj.get_date_object(),
self.uistate,
self.track,
self.db.readonly)
self.street = MonitoredEntry(
self.top.get_object("street"), self.obj.set_street,
self.obj.get_street, self.db.readonly)
self.city = MonitoredEntry(
self.top.get_object("city"), self.obj.set_city,
self.obj.get_city, self.db.readonly)
self.state = MonitoredEntry(
self.top.get_object("state"), self.obj.set_state,
self.obj.get_state, self.db.readonly)
self.country = MonitoredEntry(
self.top.get_object("country"), self.obj.set_country,
self.obj.get_country, self.db.readonly)
self.postal = MonitoredEntry(
self.top.get_object("postal"), self.obj.set_postal_code,
self.obj.get_postal_code, self.db.readonly)
self.phone = MonitoredEntry(
self.top.get_object("phone"), self.obj.set_phone,
self.obj.get_phone, self.db.readonly)
self.priv = PrivacyButton(self.top.get_object("private"),
self.obj, self.db.readonly)
def _connect_signals(self):
self.define_help_button(self.top.get_object('help'))
self.define_cancel_button(self.top.get_object('cancel'))
self.define_ok_button(self.top.get_object('ok'),self.save)
def _create_tabbed_pages(self):
"""
Create the notebook tabs and inserts them into the main
window.
"""
notebook = gtk.Notebook()
self.srcref_list = self._add_tab(
notebook,
SourceEmbedList(self.dbstate,self.uistate,self.track,self.obj))
self.note_tab = self._add_tab(
notebook,
NoteTab(self.dbstate, self.uistate, self.track,
self.obj.get_note_list(),
notetype=NoteType.ADDRESS))
self._setup_notebook_tabs( notebook)
notebook.show_all()
self.top.get_object('vbox').pack_start(notebook,True)
def build_menu_names(self, obj):
return (_('Address'),_('Address Editor'))
def save(self,*obj):
"""
Called when the OK button is pressed. Gets data from the
form and updates the Address data structure.
"""
if self.callback:
self.callback(self.obj)
self.close()

View File

@@ -0,0 +1,170 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# 2009 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$
"""
The EditAttribute module provides the AttributeEditor class. This provides a
mechanism for the user to edit attribute information.
"""
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from editsecondary import EditSecondary
from gen.lib import NoteType
from glade import Glade
from DisplayTabs import SourceEmbedList, NoteTab
from gui.widgets import MonitoredEntry, PrivacyButton, MonitoredDataType
#-------------------------------------------------------------------------
#
# EditAttribute class
#
#-------------------------------------------------------------------------
class EditAttribute(EditSecondary):
"""
Displays a dialog that allows the user to edit an attribute.
"""
def __init__(self, state, uistate, track, attrib, title, data_list, callback):
"""
Displays the dialog box.
parent - The class that called the Address editor.
attrib - The attribute that is to be edited
title - The title of the dialog box
list - list of options for the pop down menu
"""
self.alist = data_list
EditSecondary.__init__(self, state, uistate, track, attrib, callback)
def _local_init(self):
self.width_key = 'interface.attribute-width'
self.height_key = 'interface.attribute-height'
self.top = Glade()
self.set_window(self.top.toplevel,
self.top.get_object('title'),
_('Attribute Editor'))
def _connect_signals(self):
self.define_cancel_button(self.top.get_object('cancel'))
self.define_help_button(self.top.get_object('help'))
self.define_ok_button(self.top.get_object('ok'),self.save)
def _setup_fields(self):
self.value_field = MonitoredEntry(
self.top.get_object("attr_value"),
self.obj.set_value, self.obj.get_value,
self.db.readonly)
self.priv = PrivacyButton(
self.top.get_object("private"),
self.obj, self.db.readonly)
self.type_selector = MonitoredDataType(
self.top.get_object("attr_menu"),
self.obj.set_type,
self.obj.get_type,
self.db.readonly,
custom_values=self.alist
)
def _create_tabbed_pages(self):
notebook = gtk.Notebook()
self.srcref_list = self._add_tab(
notebook,
SourceEmbedList(self.dbstate,self.uistate,self.track,self.obj))
self.note_tab = self._add_tab(
notebook,
NoteTab(self.dbstate, self.uistate, self.track,
self.obj.get_note_list(),
notetype = NoteType.ATTRIBUTE))
self._setup_notebook_tabs( notebook)
notebook.show_all()
self.top.get_object('vbox').pack_start(notebook,True)
def build_menu_names(self, attrib):
if not attrib:
label = _("New Attribute")
else:
label = str(attrib.get_type())
if not label.strip():
label = _("New Attribute")
label = "%s: %s" % (_('Attribute'),label)
return (label, _('Attribute Editor'))
def save(self,*obj):
"""
Called when the OK button is pressed. Gets data from the
form and updates the Attribute data structure.
"""
t = self.obj.get_type()
if t.is_custom() and str(t) == '':
from QuestionDialog import ErrorDialog
ErrorDialog(
_("Cannot save attribute"),
_("The attribute type cannot be empty"))
return
if self.callback:
self.callback(self.obj)
self.close()
#-------------------------------------------------------------------------
#
# EditAttribute class
#
#-------------------------------------------------------------------------
class EditFamilyAttribute(EditAttribute):
"""
Displays a dialog that allows the user to edit an attribute.
"""
def __init__(self, state, uistate, track, attrib, title, data_list, callback):
"""
Displays the dialog box.
parent - The class that called the Address editor.
attrib - The attribute that is to be edited
title - The title of the dialog box
list - list of options for the pop down menu
"""
EditAttribute.__init__(self, state, uistate, track, attrib, title,
data_list, callback)

View File

@@ -0,0 +1,211 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# 2009 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$
"""
The EditChildRef module provides the EditChildRef class. This provides a
mechanism for the user to edit address information.
"""
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from editsecondary import EditSecondary
from gen.lib import NoteType
import Errors
from glade import Glade
from DisplayTabs import SourceEmbedList, NoteTab
from gui.widgets import MonitoredDataType, PrivacyButton
from BasicUtils import name_displayer
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
_RETURN = gtk.gdk.keyval_from_name("Return")
_KP_ENTER = gtk.gdk.keyval_from_name("KP_Enter")
_LEFT_BUTTON = 1
_RIGHT_BUTTON = 3
#-------------------------------------------------------------------------
#
# EditChildRef class
#
#-------------------------------------------------------------------------
class EditChildRef(EditSecondary):
"""
Displays a dialog that allows the user to edit an address.
"""
def __init__(self, name, dbstate, uistate, track, childref, callback):
"""
Displays the dialog box.
parent - The class that called the ChildRef editor.
addr - The address that is to be edited
"""
self.name = name
EditSecondary.__init__(self, dbstate, uistate, track,
childref, callback)
def _local_init(self):
self.width_key = 'interface.child-ref-width'
self.height_key = 'interface.child-ref-height'
self.top = Glade()
self.set_window(self.top.toplevel,
self.top.get_object("title"),
self.name,
_('Child Reference Editor'))
self.ok_button = self.top.get_object('ok')
self.edit_button = self.top.get_object('edit')
self.name_label = self.top.get_object('name')
self.name_label.set_text(self.name)
def _setup_fields(self):
self.frel = MonitoredDataType(
self.top.get_object('frel'),
self.obj.set_father_relation,
self.obj.get_father_relation,
self.db.readonly,
self.db.get_child_reference_types()
)
self.mrel = MonitoredDataType(
self.top.get_object('mrel'),
self.obj.set_mother_relation,
self.obj.get_mother_relation,
self.db.readonly,
self.db.get_child_reference_types()
)
self.priv = PrivacyButton(
self.top.get_object("private"),
self.obj,
self.db.readonly)
def _connect_signals(self):
self.define_help_button(self.top.get_object('help'))
self.define_cancel_button(self.top.get_object('cancel'))
self.define_ok_button(self.ok_button, self.save)
self.edit_button.connect('button-press-event', self.edit_child)
self.edit_button.connect('key-press-event', self.edit_child)
def _connect_db_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self._add_db_signal('person-update', self.person_change)
self._add_db_signal('person-rebuild', self.close)
self._add_db_signal('person-delete', self.check_for_close)
def _create_tabbed_pages(self):
"""
Create the notebook tabs and inserts them into the main
window.
"""
notebook = gtk.Notebook()
self.srcref_list = self._add_tab(
notebook,
SourceEmbedList(self.dbstate,self.uistate,self.track,self.obj))
self.note_tab = self._add_tab(
notebook,
NoteTab(self.dbstate, self.uistate, self.track,
self.obj.get_note_list(),
notetype=NoteType.CHILDREF))
self._setup_notebook_tabs( notebook)
notebook.show_all()
self.top.get_object('vbox').pack_start(notebook,True)
def _post_init(self):
self.ok_button.grab_focus()
def build_menu_names(self, obj):
return (_('Child Reference'),_('Child Reference Editor'))
def edit_child(self, obj,event):
if button_activated(event, _LEFT_BUTTON):
from _EditPerson import EditPerson
handle = self.obj.ref
try:
person = self.db.get_person_from_handle(handle)
EditPerson(self.dbstate, self.uistate,
self.track, person)
except Errors.WindowActiveError:
pass
def person_change(self, handles):
# check to see if the handle matches the current object
if self.obj.ref in handles:
p = self.dbstate.db.get_person_from_handle(self.obj.ref)
self.name = name_displayer.display(p)
self.name_label.set_text(self.name)
def save(self,*obj):
"""
Called when the OK button is pressed. Gets data from the
form and updates the ChildRef data structure.
"""
if self.callback:
self.callback(self.obj)
self.close()
def check_for_close(self, handles):
"""
Callback method for delete signals.
If there is a delete signal of the primary object we are editing, the
editor (and all child windows spawned) should be closed
"""
if self.obj.ref in handles:
self.close()
def button_activated(event, mouse_button):
if (event.type == gtk.gdk.BUTTON_PRESS and \
event.button == mouse_button) or \
(event.type == gtk.gdk.KEY_PRESS and \
event.keyval in (_RETURN, _KP_ENTER)):
return True
else:
return False

View File

@@ -0,0 +1,345 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2009 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$
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from TransUtils import sgettext as _
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import const
import gen.lib
import GrampsDisplay
from editprimary import EditPrimary
from objectentries import PlaceEntry
from glade import Glade
from QuestionDialog import ErrorDialog
from DisplayTabs import (SourceEmbedList, NoteTab, GalleryTab,
EventBackRefList, AttrEmbedList)
from gui.widgets import (MonitoredEntry, PrivacyButton,
MonitoredDataType, MonitoredDate)
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
WIKI_HELP_PAGE = '%s_-_Entering_and_Editing_Data:_Detailed_-_part_2' % const.URL_MANUAL_PAGE
WIKI_HELP_SEC = _('manual|Editing_Information_About_Events')
#-------------------------------------------------------------------------
#
# EditEvent class
#
#-------------------------------------------------------------------------
class EditEvent(EditPrimary):
def __init__(self, dbstate, uistate, track, event, callback=None):
EditPrimary.__init__(self, dbstate, uistate, track,
event, dbstate.db.get_event_from_handle,
dbstate.db.get_event_from_gramps_id)
self._init_event()
def _init_event(self):
self.commit_event = self.db.commit_event
def empty_object(self):
return gen.lib.Event()
def get_menu_title(self):
if self.obj.get_handle():
event_name = self.obj.get_description()
if not event_name:
event_name = str(self.obj.get_type())
dialog_title = _('Event: %s') % event_name
else:
dialog_title = _('New Event')
return dialog_title
def get_custom_events(self):
return self.dbstate.db.get_person_event_types() + \
self.dbstate.db.get_family_event_types()
def _local_init(self):
self.width_key = 'interface.event-width'
self.height_key = 'interface.event-height'
self.top = Glade()
self.set_window(self.top.toplevel, None,
self.get_menu_title())
self.place = self.top.get_object('place')
self.share_btn = self.top.get_object('select_place')
self.add_del_btn = self.top.get_object('add_del_place')
def _connect_signals(self):
self.top.get_object('button111').connect('clicked', self.close)
self.top.get_object('button126').connect('clicked', self.help_clicked)
self.ok_button = self.top.get_object('ok')
self.ok_button.set_sensitive(not self.db.readonly)
self.ok_button.connect('clicked', self.save)
def _connect_db_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self._add_db_signal('event-rebuild', self._do_close)
self._add_db_signal('event-delete', self.check_for_close)
def _setup_fields(self):
# place, select_place, add_del_place
self.place_field = PlaceEntry(self.dbstate, self.uistate, self.track,
self.top.get_object("place"),
self.obj.set_place_handle,
self.obj.get_place_handle,
self.add_del_btn, self.share_btn)
self.descr_field = MonitoredEntry(self.top.get_object("event_description"),
self.obj.set_description,
self.obj.get_description,
self.db.readonly)
self.gid = MonitoredEntry(self.top.get_object("gid"),
self.obj.set_gramps_id,
self.obj.get_gramps_id, self.db.readonly)
self.priv = PrivacyButton( self.top.get_object("private"),
self.obj, self.db.readonly)
self.event_menu = MonitoredDataType(self.top.get_object("personal_events"),
self.obj.set_type,
self.obj.get_type,
custom_values=self.get_custom_events())
self.date_field = MonitoredDate(self.top.get_object("date_entry"),
self.top.get_object("date_stat"),
self.obj.get_date_object(),
self.uistate, self.track,
self.db.readonly)
def _create_tabbed_pages(self):
"""
Create the notebook tabs and inserts them into the main
window.
"""
notebook = gtk.Notebook()
self.source_list = SourceEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj)
self._add_tab(notebook, self.source_list)
self.note_list = NoteTab(self.dbstate,
self.uistate,
self.track,
self.obj.get_note_list(),
notetype=gen.lib.NoteType.EVENT)
self._add_tab(notebook, self.note_list)
self.gallery_list = GalleryTab(self.dbstate,
self.uistate,
self.track,
self.obj.get_media_list())
self._add_tab(notebook, self.gallery_list)
self.attr_list = AttrEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj.get_attribute_list())
self._add_tab(notebook, self.attr_list)
handle_list = self.dbstate.db.find_backlink_handles(self.obj.handle)
self.backref_list = EventBackRefList(self.dbstate,
self.uistate,
self.track,
handle_list)
self._add_tab(notebook, self.backref_list)
self._setup_notebook_tabs(notebook)
notebook.show_all()
self.top.get_object('vbox').pack_start(notebook, True)
self.track_ref_for_deletion("source_list")
self.track_ref_for_deletion("note_list")
self.track_ref_for_deletion("gallery_list")
self.track_ref_for_deletion("attr_list")
self.track_ref_for_deletion("backref_list")
def _cleanup_on_exit(self):
self.backref_list.close()
def build_menu_names(self, event):
return (_('Edit Event'), self.get_menu_title())
def help_clicked(self, obj):
"""Display the relevant portion of GRAMPS manual"""
GrampsDisplay.help(webpage=WIKI_HELP_PAGE, section=WIKI_HELP_SEC)
def save(self, *obj):
self.ok_button.set_sensitive(False)
if self.object_is_empty():
ErrorDialog(_("Cannot save event"),
_("No data exists for this event. Please "
"enter data or cancel the edit."))
self.ok_button.set_sensitive(True)
return
(uses_dupe_id, id) = self._uses_duplicate_id()
if uses_dupe_id:
prim_object = self.get_from_gramps_id(id)
name = prim_object.get_description()
msg1 = _("Cannot save event. ID already exists.")
msg2 = _("You have attempted to use the existing Gramps ID with "
"value %(id)s. This value is already used by '"
"%(prim_object)s'. Please enter a different ID or leave "
"blank to get the next available ID value.") % {
'id' : id, 'prim_object' : name }
ErrorDialog(msg1, msg2)
self.ok_button.set_sensitive(True)
return
t = self.obj.get_type()
if t.is_custom() and str(t) == '':
ErrorDialog(
_("Cannot save event"),
_("The event type cannot be empty"))
self.ok_button.set_sensitive(True)
return
if not self.obj.handle:
trans = self.db.transaction_begin()
self.db.add_event(self.obj, trans)
self.db.transaction_commit(trans, _("Add Event"))
else:
orig = self.get_from_handle(self.obj.handle)
if cmp(self.obj.serialize(), orig.serialize()):
trans = self.db.transaction_begin()
if not self.obj.get_gramps_id():
self.obj.set_gramps_id(self.db.find_next_event_gramps_id())
self.commit_event(self.obj, trans)
self.db.transaction_commit(trans, _("Edit Event"))
if self.callback:
self.callback(self.obj)
self.close()
def data_has_changed(self):
"""
A date comparison can fail incorrectly because we have made the
decision to store entered text in the date. However, there is no
entered date when importing from a XML file, so we can get an
incorrect fail.
"""
if self.db.readonly:
return False
elif self.obj.handle:
orig = self.get_from_handle(self.obj.handle)
if orig:
cmp_obj = orig
else:
cmp_obj = self.empty_object()
return cmp(cmp_obj.serialize(True)[1:],
self.obj.serialize(True)[1:]) != 0
else:
cmp_obj = self.empty_object()
return cmp(cmp_obj.serialize(True)[1:],
self.obj.serialize()[1:]) != 0
class EditPersonEvent(EditEvent):
def __init__(self, dbstate, uistate, track, event, callback=None):
EditEvent.__init__(self, dbstate, uistate, track, event, callback)
def _init_event(self):
self.commit_event = self.db.commit_personal_event
def get_custom_events(self):
return self.dbstate.db.get_person_event_types()
class EditFamilyEvent(EditEvent):
def __init__(self, dbstate, uistate, track, event, callback=None):
EditEvent.__init__(self, dbstate, uistate, track, event, callback)
def _init_event(self):
self.commit_event = self.db.commit_family_event
def get_custom_events(self):
return self.dbstate.db.get_family_event_types()
#-------------------------------------------------------------------------
#
# Delete Query class
#
#-------------------------------------------------------------------------
class DeleteEventQuery(object):
def __init__(self, dbstate, uistate, event, person_list, family_list):
self.event = event
self.db = dbstate.db
self.uistate = uistate
self.person_list = person_list
self.family_list = family_list
def query_response(self):
trans = self.db.transaction_begin()
self.db.disable_signals()
ev_handle_list = [self.event.get_handle()]
for handle in self.person_list:
person = self.db.get_person_from_handle(handle)
person.remove_handle_references('Event', ev_handle_list)
self.db.commit_person(person, trans)
for handle in self.family_list:
family = self.db.get_family_from_handle(handle)
family.remove_handle_references('Event', ev_handle_list)
self.db.commit_family(family, trans)
self.db.enable_signals()
self.db.remove_event(self.event.get_handle(), trans)
self.db.transaction_commit(
trans,_("Delete Event (%s)") % self.event.get_gramps_id())

View File

@@ -0,0 +1,266 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# 2009 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$
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import gen.lib
from glade import Glade
from DisplayTabs import (SourceEmbedList, NoteTab, GalleryTab,
EventBackRefList, AttrEmbedList)
from gui.widgets import (PrivacyButton, MonitoredEntry,
MonitoredDate, MonitoredDataType)
from editreference import RefTab, EditReference
from objectentries import PlaceEntry
#-------------------------------------------------------------------------
#
# EditEventRef class
#
#-------------------------------------------------------------------------
class EditEventRef(EditReference):
def __init__(self, state, uistate, track, event, event_ref, update):
EditReference.__init__(self, state, uistate, track, event, event_ref,
update)
self._init_event()
def _local_init(self):
self.width_key = 'interface.event-ref-width'
self.height_key = 'interface.event-ref-height'
self.top = Glade()
self.set_window(self.top.toplevel,
self.top.get_object('eer_title'),
_('Event Reference Editor'))
self.define_warn_box(self.top.get_object("eer_warning"))
self.define_expander(self.top.get_object("eer_expander"))
self.share_btn = self.top.get_object('share_place')
self.add_del_btn = self.top.get_object('add_del_place')
tblref = self.top.get_object('table64')
notebook = self.top.get_object('notebook_ref')
#recreate start page as GrampsTab
notebook.remove_page(0)
self.reftab = RefTab(self.dbstate, self.uistate, self.track,
_('General'), tblref)
tblref = self.top.get_object('table62')
notebook = self.top.get_object('notebook')
#recreate start page as GrampsTab
notebook.remove_page(0)
self.primtab = RefTab(self.dbstate, self.uistate, self.track,
_('_General'), tblref)
def _init_event(self):
self.commit_event = self.db.commit_personal_event
self.add_event = self.db.add_person_event
def get_custom_events(self):
return self.db.get_person_event_types()
def _connect_signals(self):
self.define_ok_button(self.top.get_object('ok'),self.ok_clicked)
self.define_cancel_button(self.top.get_object('cancel'))
# FIXME: activate when help page is available
#self.define_help_button(self.top.get_object('help'))
def _connect_db_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self._add_db_signal('event-rebuild', self.close)
self._add_db_signal('event-delete', self.check_for_close)
def _setup_fields(self):
self.ref_privacy = PrivacyButton(
self.top.get_object('eer_ref_priv'),
self.source_ref, self.db.readonly)
self.descr_field = MonitoredEntry(
self.top.get_object("eer_description"),
self.source.set_description,
self.source.get_description,
self.db.readonly)
self.gid = MonitoredEntry(
self.top.get_object("gid"),
self.source.set_gramps_id,
self.source.get_gramps_id,
self.db.readonly)
self.place_field = PlaceEntry(
self.dbstate,
self.uistate,
self.track,
self.top.get_object("eer_place"),
self.source.set_place_handle,
self.source.get_place_handle,
self.share_btn,
self.add_del_btn)
self.ev_privacy = PrivacyButton(
self.top.get_object("eer_ev_priv"),
self.source, self.db.readonly)
self.role_selector = MonitoredDataType(
self.top.get_object('eer_role_combo'),
self.source_ref.set_role,
self.source_ref.get_role,
self.db.readonly,
self.db.get_event_roles()
)
self.event_menu = MonitoredDataType(
self.top.get_object("eer_type_combo"),
self.source.set_type,
self.source.get_type,
self.db.readonly,
custom_values=self.get_custom_events())
self.date_check = MonitoredDate(
self.top.get_object("eer_date_entry"),
self.top.get_object("eer_date_stat"),
self.source.get_date_object(),
self.uistate,
self.track,
self.db.readonly)
def _create_tabbed_pages(self):
"""
Create the notebook tabs and inserts them into the main
window.
"""
notebook = self.top.get_object('notebook')
notebook_ref = self.top.get_object('notebook_ref')
self._add_tab(notebook, self.primtab)
self._add_tab(notebook_ref, self.reftab)
self.track_ref_for_deletion("primtab")
self.track_ref_for_deletion("reftab")
self.srcref_list = SourceEmbedList(self.dbstate,
self.uistate,
self.track,
self.source)
self._add_tab(notebook, self.srcref_list)
self.track_ref_for_deletion("srcref_list")
self.attr_list = AttrEmbedList(self.dbstate,
self.uistate,
self.track,
self.source.get_attribute_list())
self._add_tab(notebook, self.attr_list)
self.track_ref_for_deletion("attr_list")
self.note_tab = NoteTab(self.dbstate,
self.uistate,
self.track,
self.source.get_note_list(),
notetype=gen.lib.NoteType.EVENT)
self._add_tab(notebook, self.note_tab)
self.track_ref_for_deletion("note_tab")
self.note_ref_tab = NoteTab(self.dbstate,
self.uistate,
self.track,
self.source_ref.get_note_list(),
notetype=gen.lib.NoteType.EVENTREF)
self._add_tab(notebook_ref, self.note_ref_tab)
self.track_ref_for_deletion("note_ref_tab")
self.gallery_tab = GalleryTab(self.dbstate,
self.uistate,
self.track,
self.source.get_media_list())
self._add_tab(notebook, self.gallery_tab)
self.track_ref_for_deletion("gallery_tab")
self.backref_tab = EventBackRefList(self.dbstate,
self.uistate,
self.track,
self.db.find_backlink_handles(self.source.handle),
self.enable_warnbox)
self._add_tab(notebook, self.backref_tab)
self.track_ref_for_deletion("backref_tab")
self.attr_ref_list = AttrEmbedList(self.dbstate,
self.uistate,
self.track,
self.source_ref.get_attribute_list())
self._add_tab(notebook_ref, self.attr_ref_list)
self.track_ref_for_deletion("attr_ref_list")
self._setup_notebook_tabs( notebook)
self._setup_notebook_tabs( notebook_ref)
def build_menu_names(self,eventref):
if self.source:
event_name = str(self.source.get_type())
submenu_label = _('Event: %s') % event_name
else:
submenu_label = _('New Event')
return (_('Event Reference Editor'),submenu_label)
def ok_clicked(self, obj):
trans = self.db.transaction_begin()
if self.source.handle:
self.commit_event(self.source,trans)
self.db.transaction_commit(trans,_("Modify Event"))
else:
self.add_event(self.source,trans)
self.db.transaction_commit(trans,_("Add Event"))
self.source_ref.ref = self.source.handle
if self.update:
self.update(self.source_ref,self.source)
self.close()
class EditFamilyEventRef(EditEventRef):
def __init__(self, state, uistate, track, event, event_ref, update):
EditEventRef.__init__(self, state, uistate, track, event,
event_ref, update)
def _init_event(self):
self.commit_event = self.db.commit_family_event
self.add_event = self.db.add_family_event
def get_custom_events(self):
return [ gen.lib.EventType((gen.lib.EventType.CUSTOM,val)) \
for val in self.dbstate.db.get_family_event_types()]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,423 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# 2009 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$
"""
The EditLdsOrd module provides the EditLdsOrd class. This provides a
mechanism for the user to edit personal LDS information.
"""
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import gen.lib
from BasicUtils import name_displayer
import LdsUtils
from glade import Glade
from editsecondary import EditSecondary
from objectentries import PlaceEntry
from DisplayTabs import SourceEmbedList,NoteTab
from gui.widgets import (PrivacyButton, MonitoredDate,
MonitoredMenu, MonitoredStrMenu)
from gui.selectors import SelectorFactory
_DATA_MAP = {
gen.lib.LdsOrd.BAPTISM : [
gen.lib.LdsOrd.STATUS_NONE,
gen.lib.LdsOrd.STATUS_CHILD,
gen.lib.LdsOrd.STATUS_CLEARED,
gen.lib.LdsOrd.STATUS_COMPLETED,
gen.lib.LdsOrd.STATUS_INFANT,
gen.lib.LdsOrd.STATUS_PRE_1970,
gen.lib.LdsOrd.STATUS_QUALIFIED,
gen.lib.LdsOrd.STATUS_STILLBORN,
gen.lib.LdsOrd.STATUS_SUBMITTED,
gen.lib.LdsOrd.STATUS_UNCLEARED,
],
gen.lib.LdsOrd.CONFIRMATION : [
gen.lib.LdsOrd.STATUS_NONE,
gen.lib.LdsOrd.STATUS_CHILD,
gen.lib.LdsOrd.STATUS_CLEARED,
gen.lib.LdsOrd.STATUS_COMPLETED,
gen.lib.LdsOrd.STATUS_INFANT,
gen.lib.LdsOrd.STATUS_PRE_1970,
gen.lib.LdsOrd.STATUS_QUALIFIED,
gen.lib.LdsOrd.STATUS_STILLBORN,
gen.lib.LdsOrd.STATUS_SUBMITTED,
gen.lib.LdsOrd.STATUS_UNCLEARED,
],
gen.lib.LdsOrd.ENDOWMENT: [
gen.lib.LdsOrd.STATUS_NONE,
gen.lib.LdsOrd.STATUS_CHILD,
gen.lib.LdsOrd.STATUS_CLEARED,
gen.lib.LdsOrd.STATUS_COMPLETED,
gen.lib.LdsOrd.STATUS_INFANT,
gen.lib.LdsOrd.STATUS_PRE_1970,
gen.lib.LdsOrd.STATUS_QUALIFIED,
gen.lib.LdsOrd.STATUS_STILLBORN,
gen.lib.LdsOrd.STATUS_SUBMITTED,
gen.lib.LdsOrd.STATUS_UNCLEARED,
],
gen.lib.LdsOrd.SEAL_TO_PARENTS:[
gen.lib.LdsOrd.STATUS_NONE,
gen.lib.LdsOrd.STATUS_BIC,
gen.lib.LdsOrd.STATUS_CLEARED,
gen.lib.LdsOrd.STATUS_COMPLETED,
gen.lib.LdsOrd.STATUS_DNS,
gen.lib.LdsOrd.STATUS_PRE_1970,
gen.lib.LdsOrd.STATUS_QUALIFIED,
gen.lib.LdsOrd.STATUS_STILLBORN,
gen.lib.LdsOrd.STATUS_SUBMITTED,
gen.lib.LdsOrd.STATUS_UNCLEARED,
],
gen.lib.LdsOrd.SEAL_TO_SPOUSE :[
gen.lib.LdsOrd.STATUS_NONE,
gen.lib.LdsOrd.STATUS_CANCELED,
gen.lib.LdsOrd.STATUS_CLEARED,
gen.lib.LdsOrd.STATUS_COMPLETED,
gen.lib.LdsOrd.STATUS_DNS,
gen.lib.LdsOrd.STATUS_PRE_1970,
gen.lib.LdsOrd.STATUS_QUALIFIED,
gen.lib.LdsOrd.STATUS_DNS_CAN,
gen.lib.LdsOrd.STATUS_SUBMITTED,
gen.lib.LdsOrd.STATUS_UNCLEARED,
],
}
#-------------------------------------------------------------------------
#
# EditLdsOrd class
#
#-------------------------------------------------------------------------
class EditLdsOrd(EditSecondary):
"""
Displays a dialog that allows the user to edit an attribute.
"""
def __init__(self, state, uistate, track, attrib, callback):
"""
Displays the dialog box.
parent - The class that called the Address editor.
attrib - The attribute that is to be edited
title - The title of the dialog box
list - list of options for the pop down menu
"""
EditSecondary.__init__(self, state, uistate, track, attrib, callback)
def _local_init(self):
self.width_key = 'interface.lds-width'
self.height_key = 'interface.lds-height'
self.top = Glade()
self.set_window(self.top.toplevel,
self.top.get_object('title'),
_('LDS Ordinance Editor'))
self.share_btn = self.top.get_object('share_place')
self.add_del_btn = self.top.get_object('add_del_place')
def _connect_signals(self):
self.parents_select.connect('clicked',self.select_parents_clicked)
self.define_cancel_button(self.top.get_object('cancel'))
self.define_help_button(self.top.get_object('help'))
self.define_ok_button(self.top.get_object('ok'),self.save)
def _get_types(self):
return (gen.lib.LdsOrd.BAPTISM,
gen.lib.LdsOrd.ENDOWMENT,
gen.lib.LdsOrd.CONFIRMATION,
gen.lib.LdsOrd.SEAL_TO_PARENTS)
def _setup_fields(self):
self.parents_label = self.top.get_object('parents_label')
self.parents = self.top.get_object('parents')
self.parents_select = self.top.get_object('parents_select')
self.priv = PrivacyButton(
self.top.get_object("private"),
self.obj, self.db.readonly)
self.date_field = MonitoredDate(
self.top.get_object("date_entry"),
self.top.get_object("date_stat"),
self.obj.get_date_object(),
self.uistate,
self.track,
self.db.readonly)
self.place_field = PlaceEntry(
self.dbstate,
self.uistate,
self.track,
self.top.get_object("place"),
self.obj.set_place_handle,
self.obj.get_place_handle,
self.add_del_btn,
self.share_btn)
self.type_menu = MonitoredMenu(
self.top.get_object('type'),
self.obj.set_type,
self.obj.get_type,
[(item[1],item[0]) for item in gen.lib.LdsOrd._TYPE_MAP
if item[0] in self._get_types()],
self.db.readonly,
changed=self.ord_type_changed)
self.temple_menu = MonitoredStrMenu(
self.top.get_object('temple'),
self.obj.set_temple,
self.obj.get_temple,
LdsUtils.TEMPLES.name_code_data(),
self.db.readonly)
self.status_menu = MonitoredMenu(
self.top.get_object('status'),
self.obj.set_status,
self.obj.get_status,
[(item[1],item[0]) for item in gen.lib.LdsOrd._STATUS_MAP
if item[0] in _DATA_MAP[self.obj.get_type()] ],
self.db.readonly)
self.ord_type_changed()
self.update_parent_label()
def ord_type_changed(self):
if self.obj.get_type() == gen.lib.LdsOrd.BAPTISM:
self.parents.hide()
self.parents_label.hide()
self.parents_select.hide()
elif self.obj.get_type() == gen.lib.LdsOrd.ENDOWMENT:
self.parents.hide()
self.parents_label.hide()
self.parents_select.hide()
elif self.obj.get_type() == gen.lib.LdsOrd.SEAL_TO_PARENTS:
self.parents.show()
self.parents_label.show()
self.parents_select.show()
new_data = [(item[1],item[0]) for item in gen.lib.LdsOrd._STATUS_MAP
if item[0] in _DATA_MAP[self.obj.get_type()] ]
self.status_menu.change_menu(new_data)
def _create_tabbed_pages(self):
notebook = gtk.Notebook()
self.srcref_list = self._add_tab(
notebook,
SourceEmbedList(self.dbstate,self.uistate, self.track,self.obj))
self.note_tab = self._add_tab(
notebook,
NoteTab(self.dbstate, self.uistate, self.track,
self.obj.get_note_list(),
notetype=gen.lib.NoteType.LDS))
self._setup_notebook_tabs( notebook)
notebook.show_all()
self.top.get_object('vbox').pack_start(notebook,True)
def select_parents_clicked(self, obj):
SelectFamily = SelectorFactory('Family')
dialog = SelectFamily(self.dbstate,self.uistate,self.track)
family = dialog.run()
if family:
self.obj.set_family_handle(family.handle)
self.update_parent_label()
def update_parent_label(self):
handle = self.obj.get_family_handle()
if handle:
family = self.dbstate.db.get_family_from_handle(handle)
f = self.dbstate.db.get_person_from_handle(
family.get_father_handle())
m = self.dbstate.db.get_person_from_handle(
family.get_mother_handle())
if f and m:
label = _("%(father)s and %(mother)s [%(gramps_id)s]") % {
'father' : name_displayer.display(f),
'mother' : name_displayer.display(m),
'gramps_id' : family.gramps_id,
}
elif f:
label = _("%(father)s [%(gramps_id)s]") % {
'father' : name_displayer.display(f),
'gramps_id' : family.gramps_id,
}
elif m:
label = _("%(mother)s [%(gramps_id)s]") % {
'mother' : name_displayer.display(m),
'gramps_id' : family.gramps_id,
}
else:
# No translation for bare gramps_id
label = "[%(gramps_id)s]" % {
'gramps_id' : family.gramps_id,
}
else:
label = ""
self.parents.set_text(label)
def build_menu_names(self, attrib):
label = _("LDS Ordinance")
return (label, _('LDS Ordinance Editor'))
def save(self,*obj):
"""
Called when the OK button is pressed. Gets data from the
form and updates the LdsOrd data structure.
"""
if self.callback:
self.callback(self.obj)
self.close()
#-------------------------------------------------------------------------
#
# EditFamilyLdsOrd
#
#-------------------------------------------------------------------------
class EditFamilyLdsOrd(EditSecondary):
"""
Displays a dialog that allows the user to edit an attribute.
"""
def __init__(self, state, uistate, track, attrib, callback):
"""
Displays the dialog box.
parent - The class that called the Address editor.
attrib - The attribute that is to be edited
title - The title of the dialog box
list - list of options for the pop down menu
"""
EditSecondary.__init__(self, state, uistate, track, attrib, callback)
def _local_init(self):
self.top = Glade()
self.set_window(self.top.toplevel,
self.top.get_object('title'),
_('LDS Ordinance Editor'))
self.share_btn = self.top.get_object('share_place')
self.add_del_btn = self.top.get_object('add_del_place')
def _connect_signals(self):
self.define_cancel_button(self.top.get_object('cancel'))
self.define_help_button(self.top.get_object('help'))
self.define_ok_button(self.top.get_object('ok'),self.save)
def _get_types(self):
return (gen.lib.LdsOrd.SEAL_TO_SPOUSE,)
def _setup_fields(self):
self.parents_label = self.top.get_object('parents_label')
self.parents = self.top.get_object('parents')
self.parents_select = self.top.get_object('parents_select')
self.priv = PrivacyButton(
self.top.get_object("private"),
self.obj, self.db.readonly)
self.date_field = MonitoredDate(
self.top.get_object("date_entry"),
self.top.get_object("date_stat"),
self.obj.get_date_object(),
self.uistate,
self.track,
self.db.readonly)
self.place_field = PlaceEntry(
self.dbstate,
self.uistate,
self.track,
self.top.get_object("place"),
self.obj.set_place_handle,
self.obj.get_place_handle,
self.add_del_btn,
self.share_btn)
self.type_menu = MonitoredMenu(
self.top.get_object('type'),
self.obj.set_type,
self.obj.get_type,
[(item[1],item[0]) for item in gen.lib.LdsOrd._TYPE_MAP
if item[0] in self._get_types()],
self.db.readonly)
self.temple_menu = MonitoredStrMenu(
self.top.get_object('temple'),
self.obj.set_temple,
self.obj.get_temple,
LdsUtils.TEMPLES.name_code_data(),
self.db.readonly)
self.status_menu = MonitoredMenu(
self.top.get_object('status'),
self.obj.set_status,
self.obj.get_status,
[(item[1],item[0]) for item in gen.lib.LdsOrd._STATUS_MAP
if item[0] in _DATA_MAP[self.obj.get_type()]],
self.db.readonly)
def _create_tabbed_pages(self):
notebook = gtk.Notebook()
self.srcref_list = self._add_tab(
notebook,
SourceEmbedList(self.dbstate,self.uistate, self.track,self.obj))
self.note_tab = self._add_tab(
notebook,
NoteTab(self.dbstate, self.uistate, self.track,
self.obj.get_note_list(),
notetype=gen.lib.NoteType.LDS))
notebook.show_all()
self.top.get_object('vbox').pack_start(notebook,True)
def build_menu_names(self, attrib):
label = _("LDS Ordinance")
return (label, _('LDS Ordinance Editor'))
def save(self,*obj):
"""
Called when the OK button is pressed. Gets data from the
form and updates the LdsOrd data structure.
"""
if self.callback:
self.callback(self.obj)
self.close()

View File

@@ -0,0 +1,111 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# 2009 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$
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from editsecondary import EditSecondary
from glade import Glade
from gui.widgets import MonitoredEntry
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# LocationEditor class
#
#-------------------------------------------------------------------------
class EditLocation(EditSecondary):
def __init__(self,dbstate,uistate,track,location,callback):
EditSecondary.__init__(self, dbstate, uistate, track,
location, callback)
def _local_init(self):
self.width_key = 'interface.location-width'
self.height_key = 'interface.location-height'
self.top = Glade()
self.set_window(self.top.toplevel, None,
_('Location Editor'))
def _setup_fields(self):
self.street = MonitoredEntry(
self.top.get_object("street"),
self.obj.set_street,
self.obj.get_street,
self.db.readonly)
self.city = MonitoredEntry(
self.top.get_object("city"),
self.obj.set_city,
self.obj.get_city,
self.db.readonly)
self.state = MonitoredEntry(
self.top.get_object("state"),
self.obj.set_state,
self.obj.get_state,
self.db.readonly)
self.postal = MonitoredEntry(
self.top.get_object("postal"),
self.obj.set_postal_code,
self.obj.get_postal_code,
self.db.readonly)
self.phone = MonitoredEntry(
self.top.get_object("phone"),
self.obj.set_phone,
self.obj.get_phone,
self.db.readonly)
self.parish = MonitoredEntry(
self.top.get_object("parish"),
self.obj.set_parish,
self.obj.get_parish,
self.db.readonly)
self.county = MonitoredEntry(
self.top.get_object("county"),
self.obj.set_county,
self.obj.get_county,
self.db.readonly)
self.country = MonitoredEntry(
self.top.get_object("country"),
self.obj.set_country,
self.obj.get_country,
self.db.readonly)
def _connect_signals(self):
self.define_cancel_button(self.top.get_object('button119'))
self.define_ok_button(self.top.get_object('button118'),self.save)
self.define_help_button(self.top.get_object('button128'))
def save(self,*obj):
if self.callback:
self.callback(self.obj)
self.close()

View File

@@ -0,0 +1,374 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# Copyright (C) 2009 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$
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from gui.utils import open_file_with_default_application
import gen.lib
import Mime
import ThumbNails
import Utils
from editprimary import EditPrimary
from gui.widgets import MonitoredDate, MonitoredEntry, PrivacyButton
from DisplayTabs import (SourceEmbedList, AttrEmbedList, NoteTab,
MediaBackRefList)
from addmedia import AddMediaObject
from QuestionDialog import ErrorDialog
from glade import Glade
#-------------------------------------------------------------------------
#
# EditMedia
#
#-------------------------------------------------------------------------
class EditMedia(EditPrimary):
def __init__(self, dbstate, uistate, track, obj, callback=None):
EditPrimary.__init__(self, dbstate, uistate, track, obj,
dbstate.db.get_object_from_handle,
dbstate.db.get_object_from_gramps_id, callback)
if not self.obj.get_handle():
#show the addmedia dialog immediately, with track of parent.
AddMediaObject(dbstate, self.uistate, self.track, self.obj,
self._update_addmedia)
def empty_object(self):
return gen.lib.MediaObject()
def get_menu_title(self):
if self.obj.get_handle():
name = self.obj.get_description()
if not name:
name = self.obj.get_path()
if not name:
name = self.obj.get_mime_type()
if not name:
name = _('Note')
dialog_title = _('Media: %s') % name
else:
dialog_title = _('New Media')
return dialog_title
def _local_init(self):
assert(self.obj)
self.width_key = 'interface.media-width'
self.height_key = 'interface.media-height'
self.glade = Glade()
self.set_window(self.glade.toplevel,
None, self.get_menu_title())
def _connect_signals(self):
self.define_cancel_button(self.glade.get_object('button91'))
self.define_ok_button(self.glade.get_object('ok'), self.save)
self.define_help_button(self.glade.get_object('button102'))
def _connect_db_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self._add_db_signal('media-rebuild', self._do_close)
self._add_db_signal('media-delete', self.check_for_close)
def _setup_fields(self):
self.date_field = MonitoredDate(self.glade.get_object("date_entry"),
self.glade.get_object("date_edit"),
self.obj.get_date_object(),
self.uistate, self.track,
self.db.readonly)
self.descr_window = MonitoredEntry(self.glade.get_object("description"),
self.obj.set_description,
self.obj.get_description,
self.db.readonly)
self.gid = MonitoredEntry(self.glade.get_object("gid"),
self.obj.set_gramps_id,
self.obj.get_gramps_id, self.db.readonly)
self.privacy = PrivacyButton(self.glade.get_object("private"),
self.obj, self.db.readonly)
self.pixmap = self.glade.get_object("pixmap")
ebox = self.glade.get_object('eventbox')
ebox.connect('button-press-event', self.button_press_event)
self.mimetext = self.glade.get_object("type")
self.setup_filepath()
self.determine_mime()
self.draw_preview()
def determine_mime(self):
descr = Mime.get_description(self.obj.get_mime_type())
if descr:
self.mimetext.set_text(descr)
path = self.file_path.get_text()
path_full = Utils.media_path_full(self.db, path)
if path != self.obj.get_path() and path_full != self.obj.get_path():
#redetermine mime
mime = Mime.get_type(Utils.find_file(path_full))
self.obj.set_mime_type(mime)
descr = Mime.get_description(mime)
if descr:
self.mimetext.set_text(descr)
else:
self.mimetext.set_text(_('Unknown'))
#if mime type not set, is note
if not self.obj.get_mime_type():
self.mimetext.set_text(_('Note'))
def draw_preview(self):
mtype = self.obj.get_mime_type()
if mtype:
pb = ThumbNails.get_thumbnail_image(
Utils.media_path_full(self.db, self.obj.get_path()),
mtype)
self.pixmap.set_from_pixbuf(pb)
else:
pb = Mime.find_mime_type_pixbuf('text/plain')
self.pixmap.set_from_pixbuf(pb)
def setup_filepath(self):
self.select = self.glade.get_object('file_select')
self.file_path = self.glade.get_object("path")
fname = self.obj.get_path()
self.file_path.set_text(fname)
self.select.connect('clicked', self.select_file)
def _create_tabbed_pages(self):
notebook = gtk.Notebook()
self.src_tab = SourceEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj)
self._add_tab(notebook, self.src_tab)
self.track_ref_for_deletion("src_tab")
self.attr_tab = AttrEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj.get_attribute_list())
self._add_tab(notebook, self.attr_tab)
self.track_ref_for_deletion("attr_tab")
self.note_tab = NoteTab(self.dbstate,
self.uistate,
self.track,
self.obj.get_note_list(),
notetype=gen.lib.NoteType.MEDIA)
self._add_tab(notebook, self.note_tab)
self.track_ref_for_deletion("note_tab")
self.backref_tab = MediaBackRefList(self.dbstate,
self.uistate,
self.track,
self.db.find_backlink_handles(self.obj.handle))
self.backref_list = self._add_tab(notebook, self.backref_tab)
self.track_ref_for_deletion("backref_tab")
self.track_ref_for_deletion("backref_list")
self._setup_notebook_tabs( notebook)
notebook.show_all()
self.glade.get_object('vbox').pack_start(notebook, True)
def build_menu_names(self, person):
return (_('Edit Media Object'), self.get_menu_title())
def button_press_event(self, obj, event):
if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
self.view_media(obj)
def view_media(self, obj):
ref_obj = self.dbstate.db.get_object_from_handle(self.obj.handle)
if ref_obj:
media_path = Utils.media_path_full(self.dbstate.db,
ref_obj.get_path())
open_file_with_default_application(media_path)
def select_file(self, val):
self.determine_mime()
path = self.file_path.get_text()
self.obj.set_path(Utils.get_unicode_path(path))
AddMediaObject(self.dbstate, self.uistate, self.track, self.obj,
self._update_addmedia)
def _update_addmedia(self, obj):
"""
Called when the add media dialog has been called.
This allows us to update the main form in response to
any changes: Redraw relevant fields: description, mimetype and path
"""
for obj in (self.descr_window, ):
obj.update()
fname = self.obj.get_path()
self.file_path.set_text(fname)
self.determine_mime()
self.draw_preview()
def save(self, *obj):
self.ok_button.set_sensitive(False)
if self.object_is_empty():
ErrorDialog(_("Cannot save media object"),
_("No data exists for this media object. Please "
"enter data or cancel the edit."))
self.ok_button.set_sensitive(True)
return
(uses_dupe_id, id) = self._uses_duplicate_id()
if uses_dupe_id:
prim_object = self.get_from_gramps_id(id)
name = prim_object.get_description()
msg1 = _("Cannot save media object. ID already exists.")
msg2 = _("You have attempted to use the existing Gramps ID with "
"value %(id)s. This value is already used by '"
"%(prim_object)s'. Please enter a different ID or leave "
"blank to get the next available ID value.") % {
'id' : id, 'prim_object' : name }
ErrorDialog(msg1, msg2)
self.ok_button.set_sensitive(True)
return
path = self.file_path.get_text()
self.determine_mime()
self.obj.set_path(Utils.get_unicode_path(path))
trans = self.db.transaction_begin()
if not self.obj.get_handle():
self.db.add_object(self.obj, trans)
msg = _("Add Media Object (%s)") % self.obj.get_description()
else:
if not self.obj.get_gramps_id():
self.obj.set_gramps_id(self.db.find_next_object_gramps_id())
self.db.commit_media_object(self.obj, trans)
msg = _("Edit Media Object (%s)") % self.obj.get_description()
self.db.transaction_commit(trans, msg)
if self.callback:
self.callback(self.obj)
self.close()
def _cleanup_on_exit(self):
self.backref_list.close()
def data_has_changed(self):
"""
A date comparison can fail incorrectly because we have made the
decision to store entered text in the date. However, there is no
entered date when importing from a XML file, so we can get an
incorrect fail.
"""
if self.db.readonly:
return False
elif self.obj.handle:
orig = self.get_from_handle(self.obj.handle)
if orig:
cmp_obj = orig
else:
cmp_obj = self.empty_object()
return cmp(cmp_obj.serialize(True)[1:],
self.obj.serialize(True)[1:]) != 0
else:
cmp_obj = self.empty_object()
return cmp(cmp_obj.serialize(True)[1:],
self.obj.serialize()[1:]) != 0
class DeleteMediaQuery(object):
def __init__(self, dbstate, uistate, media_handle, the_lists):
self.db = dbstate.db
self.uistate = uistate
self.media_handle = media_handle
self.the_lists = the_lists
def query_response(self):
trans = self.db.transaction_begin()
self.db.disable_signals()
(person_list, family_list, event_list,
place_list,source_list) = self.the_lists
for handle in person_list:
person = self.db.get_person_from_handle(handle)
new_list = [ photo for photo in person.get_media_list() \
if photo.get_reference_handle() != self.media_handle ]
person.set_media_list(new_list)
self.db.commit_person(person, trans)
for handle in family_list:
family = self.db.get_family_from_handle(handle)
new_list = [ photo for photo in family.get_media_list() \
if photo.get_reference_handle() != self.media_handle ]
family.set_media_list(new_list)
self.db.commit_family(family, trans)
for handle in event_list:
event = self.db.get_event_from_handle(handle)
new_list = [ photo for photo in event.get_media_list() \
if photo.get_reference_handle() != self.media_handle ]
event.set_media_list(new_list)
self.db.commit_event(event, trans)
for handle in place_list:
place = self.db.get_place_from_handle(handle)
new_list = [ photo for photo in place.get_media_list() \
if photo.get_reference_handle() != self.media_handle ]
place.set_media_list(new_list)
self.db.commit_place(place, trans)
for handle in source_list:
source = self.db.get_source_from_handle(handle)
new_list = [ photo for photo in source.get_media_list() \
if photo.get_reference_handle() != self.media_handle ]
source.set_media_list(new_list)
self.db.commit_source(source, trans)
self.db.enable_signals()
self.db.remove_object(self.media_handle, trans)
self.db.transaction_commit(trans, _("Remove Media Object"))

View File

@@ -0,0 +1,573 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# 2008-2009 Stephane Charette <stephanecharette@gmail.com>
# 2009 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$
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
from TransUtils import sgettext as _
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from gui.utils import open_file_with_default_application
import const
import Mime
import ThumbNails
import Utils
from gen.lib import NoteType
from glade import Glade
from DisplayTabs import (SourceEmbedList, AttrEmbedList, MediaBackRefList,
NoteTab)
from gui.widgets import MonitoredSpinButton, MonitoredEntry, PrivacyButton
from editreference import RefTab, EditReference
from addmedia import AddMediaObject
#-------------------------------------------------------------------------
#
# EditMediaRef
#
#-------------------------------------------------------------------------
class EditMediaRef(EditReference):
def __init__(self, state, uistate, track, media, media_ref, update):
EditReference.__init__(self, state, uistate, track, media,
media_ref, update)
if not self.source.get_handle():
#show the addmedia dialog immediately, with track of parent.
AddMediaObject(state, self.uistate, self.track, self.source,
self._update_addmedia)
def _local_init(self):
self.width_key = 'interface.media-ref-width'
self.height_key = 'interface.media-ref-height'
self.top = Glade()
self.set_window(self.top.toplevel,
self.top.get_object('title'),
_('Media Reference Editor'))
self.define_warn_box(self.top.get_object("warn_box"))
self.top.get_object("label427").set_text(_("Y coordinate|Y"))
self.top.get_object("label428").set_text(_("Y coordinate|Y"))
tblref = self.top.get_object('table50')
notebook = self.top.get_object('notebook_ref')
#recreate start page as GrampsTab
notebook.remove_page(0)
self.reftab = RefTab(self.dbstate, self.uistate, self.track,
_('General'), tblref)
tblref = self.top.get_object('table2')
notebook = self.top.get_object('notebook_shared')
#recreate start page as GrampsTab
notebook.remove_page(0)
self.primtab = RefTab(self.dbstate, self.uistate, self.track,
_('_General'), tblref)
def draw_preview(self):
"""
Draw the two preview images. This method can be called on eg change of
the path.
"""
self.mtype = self.source.get_mime_type()
fullpath = Utils.media_path_full(self.db, self.source.get_path())
self.pix = ThumbNails.get_thumbnail_image(fullpath,
self.mtype)
self.pixmap.set_from_pixbuf(self.pix)
self.subpix = ThumbNails.get_thumbnail_image(fullpath,
self.mtype,
self.rectangle)
self.subpixmap.set_from_pixbuf(self.subpix)
mt = Mime.get_description(self.mtype)
self.top.get_object("type").set_text(mt if mt else "")
def _setup_fields(self):
ebox_shared = self.top.get_object('eventbox')
ebox_shared.connect('button-press-event', self.button_press_event)
if not self.dbstate.db.readonly:
self.button_press_coords = (0, 0)
ebox_ref = self.top.get_object('eventbox1')
ebox_ref.connect('button-press-event', self.button_press_event_ref)
ebox_ref.connect('button-release-event',
self.button_release_event_ref)
ebox_ref.add_events(gtk.gdk.BUTTON_PRESS_MASK)
ebox_ref.add_events(gtk.gdk.BUTTON_RELEASE_MASK)
self.pixmap = self.top.get_object("pixmap")
coord = self.source_ref.get_rectangle()
#upgrade path: set invalid (from eg old db) to none
if coord is not None and coord in (
(None,)*4,
(0, 0, 100, 100),
(coord[0], coord[1])*2
):
coord = None
self.rectangle = coord
self.subpixmap = self.top.get_object("subpixmap")
self.draw_preview()
corners = ["corner1_x", "corner1_y", "corner2_x", "corner2_y"]
if coord and isinstance(coord, tuple):
for index, corner in enumerate(corners):
self.top.get_object(corner).set_value(coord[index])
else:
for corner, value in zip(corners, [0, 0, 100, 100]):
self.top.get_object(corner).set_value(value)
if self.dbstate.db.readonly:
for corner in corners:
self.top.get_object(corner).set_sensitive(False)
self.corner1_x_spinbutton = MonitoredSpinButton(
self.top.get_object("corner1_x"),
self.set_corner1_x,
self.get_corner1_x,
self.db.readonly)
self.corner1_y_spinbutton = MonitoredSpinButton(
self.top.get_object("corner1_y"),
self.set_corner1_y,
self.get_corner1_y,
self.db.readonly)
self.corner2_x_spinbutton = MonitoredSpinButton(
self.top.get_object("corner2_x"),
self.set_corner2_x,
self.get_corner2_x,
self.db.readonly)
self.corner2_y_spinbutton = MonitoredSpinButton(
self.top.get_object("corner2_y"),
self.set_corner2_y,
self.get_corner2_y,
self.db.readonly)
self.descr_window = MonitoredEntry(
self.top.get_object("description"),
self.source.set_description,
self.source.get_description,
self.db.readonly)
self.ref_privacy = PrivacyButton(
self.top.get_object("private"),
self.source_ref,
self.db.readonly)
self.gid = MonitoredEntry(
self.top.get_object("gid"),
self.source.set_gramps_id,
self.source.get_gramps_id,
self.db.readonly)
self.privacy = PrivacyButton(
self.top.get_object("privacy"),
self.source,
self.db.readonly)
self.path_obj = MonitoredEntry(
self.top.get_object("path"),
self.source.set_path,
self.source.get_path,
self.db.readonly)
def set_corner1_x(self, value):
"""
Callback for the signal handling of the spinbutton for the first
corner x coordinate of the subsection.
Updates the subsection thumbnail using the given value
@param value: the first corner x coordinate of the subsection in int
"""
if self.rectangle is None:
self.rectangle = (0,0,100,100)
self.rectangle = (value,) + self.rectangle[1:]
self.update_subpixmap()
def set_corner1_y(self, value):
"""
Callback for the signal handling of the spinbutton for the first
corner y coordinate of the subsection.
Updates the subsection thumbnail using the given value
@param value: the first corner y coordinate of the subsection in int
"""
if self.rectangle is None:
self.rectangle = (0,0,100,100)
self.rectangle = self.rectangle[:1] + (value,) + self.rectangle[2:]
self.update_subpixmap()
def set_corner2_x(self, value):
"""
Callback for the signal handling of the spinbutton for the second
corner x coordinate of the subsection.
Updates the subsection thumbnail using the given value
@param value: the second corner x coordinate of the subsection in int
"""
if self.rectangle is None:
self.rectangle = (0,0,100,100)
self.rectangle = self.rectangle[:2] + (value,) + self.rectangle[3:]
self.update_subpixmap()
def set_corner2_y(self, value):
"""
Callback for the signal handling of the spinbutton for the second
corner y coordinate of the subsection.
Updates the subsection thumbnail using the given value
@param value: the second corner y coordinate of the subsection in int
"""
if self.rectangle is None:
self.rectangle = (0,0,100,100)
self.rectangle = self.rectangle[:3] + (value,)
self.update_subpixmap()
def get_corner1_x(self):
"""
Callback for the signal handling of the spinbutton for the first corner
x coordinate of the subsection.
@returns: the first corner x coordinate of the subsection or 0 if
there is no selection
"""
if self.rectangle is not None:
return self.rectangle[0]
else:
return 0
def get_corner1_y(self):
"""
Callback for the signal handling of the spinbutton for the first corner
y coordinate of the subsection.
@returns: the first corner y coordinate of the subsection or 0 if
there is no selection
"""
if self.rectangle is not None:
return self.rectangle[1]
else:
return 0
def get_corner2_x(self):
"""
Callback for the signal handling of the spinbutton for the second
corner x coordinate of the subsection.
@returns: the second corner x coordinate of the subsection or 100 if
there is no selection
"""
if self.rectangle is not None:
return self.rectangle[2]
else:
return 100
def get_corner2_y(self):
"""
Callback for the signal handling of the spinbutton for the second
corner x coordinate of the subsection.
@returns: the second corner x coordinate of the subsection or 100 if
there is no selection
"""
if self.rectangle is not None:
return self.rectangle[3]
else:
return 100
def update_subpixmap(self):
"""
Updates the thumbnail of the specified subsection
"""
path = self.source.get_path()
if path is None:
self.subpixmap.hide()
else:
try:
fullpath = Utils.media_path_full(self.db, path)
pixbuf = gtk.gdk.pixbuf_new_from_file(fullpath)
width = pixbuf.get_width()
height = pixbuf.get_height()
upper_x = min(self.rectangle[0], self.rectangle[2])/100.
lower_x = max(self.rectangle[0], self.rectangle[2])/100.
upper_y = min(self.rectangle[1], self.rectangle[3])/100.
lower_y = max(self.rectangle[1], self.rectangle[3])/100.
sub_x = int(upper_x * width)
sub_y = int(upper_y * height)
sub_width = int((lower_x - upper_x) * width)
sub_height = int((lower_y - upper_y) * height)
if sub_width > 0 and sub_height > 0:
pixbuf = pixbuf.subpixbuf(sub_x, sub_y, sub_width, sub_height)
width = sub_width
height = sub_height
ratio = float(max(height, width))
scale = const.THUMBSCALE / ratio
x = int(scale * width)
y = int(scale * height)
pixbuf = pixbuf.scale_simple(x, y, gtk.gdk.INTERP_BILINEAR)
self.subpixmap.set_from_pixbuf(pixbuf)
self.subpixmap.show()
except:
self.subpixmap.hide()
def build_menu_names(self, person):
"""
Provide the information needed by the base class to define the
window management menu entries.
"""
if self.source:
submenu_label = _('Media: %s') % self.source.get_gramps_id()
else:
submenu_label = _('New Media')
return (_('Media Reference Editor'),submenu_label)
def button_press_event(self, obj, event):
if event.button==1 and event.type == gtk.gdk._2BUTTON_PRESS:
photo_path = Utils.media_path_full(self.db, self.source.get_path())
open_file_with_default_application(photo_path)
def button_press_event_ref(self, widget, event):
"""
Handle the button-press-event generated by the eventbox
parent of the subpixmap. Remember these coordinates
so we can crop the picture when button-release-event
is received.
"""
self.button_press_coords = (event.x, event.y)
def button_release_event_ref(self, widget, event):
"""
Handle the button-release-event generated by the eventbox
parent of the subpixmap. Crop the picture accordingly.
"""
# reset the crop on double-click or click+CTRL
if (event.button==1 and event.type == gtk.gdk._2BUTTON_PRESS) or \
(event.button==1 and (event.state & gtk.gdk.CONTROL_MASK) ):
self.corner1_x_spinbutton.set_value(0)
self.corner1_y_spinbutton.set_value(0)
self.corner2_x_spinbutton.set_value(100)
self.corner2_y_spinbutton.set_value(100)
else:
# ensure the clicks happened at least 5 pixels away from each other
new_x1 = min(self.button_press_coords[0], event.x)
new_y1 = min(self.button_press_coords[1], event.y)
new_x2 = max(self.button_press_coords[0], event.x)
new_y2 = max(self.button_press_coords[1], event.y)
if new_x2 - new_x1 >= 5 and new_y2 - new_y1 >= 5:
# get the image size and calculate the X and Y offsets
# (image is centered when smaller than const.THUMBSCALE)
pixbuf = self.subpixmap.get_pixbuf();
w = pixbuf.get_width()
h = pixbuf.get_height()
x = (const.THUMBSCALE - w) / 2
y = (const.THUMBSCALE - h) / 2
# if the click was outside of the image,
# bring it within the boundaries
if new_x1 < x:
new_x1 = x
if new_y1 < y:
new_y1 = y
if new_x2 >= x + w:
new_x2 = x + w - 1
if new_y2 >= y + h:
new_y2 = y + h - 1
# get the old spinbutton % values
old_x1 = self.corner1_x_spinbutton.get_value()
old_y1 = self.corner1_y_spinbutton.get_value()
old_x2 = self.corner2_x_spinbutton.get_value()
old_y2 = self.corner2_y_spinbutton.get_value()
delta_x = old_x2 - old_x1 # horizontal scale
delta_y = old_y2 - old_y1 # vertical scale
# Took a while to figure out the math here.
#
# 1) figure out the current crop % values
# by doing the following:
#
# xp = click_location_x / width * 100
# yp = click_location_y / height * 100
#
# but remember that click_location_x and _y
# might not be zero-based for non-rectangular
# images, so subtract the pixbuf "x" and "y"
# to bring the values back to zero-based
#
# 2) the minimum value cannot be less than the
# existing crop value, so add the current
# minimum to the new values
new_x1 = old_x1 + delta_x * (new_x1 - x) / w
new_y1 = old_y1 + delta_y * (new_y1 - y) / h
new_x2 = old_x1 + delta_x * (new_x2 - x) / w
new_y2 = old_y1 + delta_y * (new_y2 - y) / h
# set the new values
self.corner1_x_spinbutton.set_value(new_x1)
self.corner1_y_spinbutton.set_value(new_y1)
self.corner2_x_spinbutton.set_value(new_x2)
self.corner2_y_spinbutton.set_value(new_y2)
def _update_addmedia(self, obj):
"""
Called when the add media dialog has been called.
This allows us to update the main form in response to
any changes: Redraw relevant fields: description, mimetype and path
"""
for obj in (self.descr_window, self.path_obj):
obj.update()
self.draw_preview()
def _connect_signals(self):
self.define_cancel_button(self.top.get_object('button84'))
self.define_ok_button(self.top.get_object('button82'),self.save)
def _connect_db_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self._add_db_signal('media-rebuild', self.close)
self._add_db_signal('media-delete', self.check_for_close)
def _create_tabbed_pages(self):
"""
Create the notebook tabs and inserts them into the main
window.
"""
notebook_ref = self.top.get_object('notebook_ref')
notebook_src = self.top.get_object('notebook_shared')
self._add_tab(notebook_src, self.primtab)
self._add_tab(notebook_ref, self.reftab)
self.srcref_list = self._add_tab(
notebook_ref,
SourceEmbedList(self.dbstate,self.uistate,self.track,
self.source_ref))
self.attr_list = self._add_tab(
notebook_ref,
AttrEmbedList(self.dbstate,self.uistate,self.track,
self.source_ref.get_attribute_list()))
self.backref_list = self._add_tab(
notebook_src,
MediaBackRefList(self.dbstate,self.uistate,self.track,
self.db.find_backlink_handles(self.source.handle),
self.enable_warnbox
))
self.note_ref_tab = self._add_tab(
notebook_ref,
NoteTab(self.dbstate, self.uistate, self.track,
self.source_ref.get_note_list(),
notetype=NoteType.MEDIAREF))
self.src_srcref_list = self._add_tab(
notebook_src,
SourceEmbedList(self.dbstate,self.uistate,self.track,
self.source))
self.src_attr_list = self._add_tab(
notebook_src,
AttrEmbedList(self.dbstate,self.uistate,self.track,
self.source.get_attribute_list()))
self.src_note_ref_tab = self._add_tab(
notebook_src,
NoteTab(self.dbstate, self.uistate, self.track,
self.source.get_note_list(),
notetype=NoteType.MEDIA))
self._setup_notebook_tabs(notebook_src)
self._setup_notebook_tabs(notebook_ref)
def save(self,*obj):
#first save primary object
trans = self.db.transaction_begin()
if self.source.handle:
self.db.commit_media_object(self.source, trans)
self.db.transaction_commit(trans, _("Edit Media Object (%s)"
) % self.source.get_description())
else:
self.db.add_object(self.source, trans)
self.db.transaction_commit(trans,_("Add Media Object (%s)"
) % self.source.get_description())
#save reference object in memory
coord = (
self.top.get_object("corner1_x").get_value_as_int(),
self.top.get_object("corner1_y").get_value_as_int(),
self.top.get_object("corner2_x").get_value_as_int(),
self.top.get_object("corner2_y").get_value_as_int(),
)
#do not set unset or invalid coord
if coord is not None and coord in (
(None,)*4,
(0, 0, 100, 100),
(coord[0], coord[1])*2
):
coord = None
self.source_ref.set_rectangle(coord)
#call callback if given
if self.update:
self.update(self.source_ref,self.source)
self.close()

417
src/gui/editors/editname.py Normal file
View File

@@ -0,0 +1,417 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# 2008-2009 Benny Malengier
# 2009 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$
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from BasicUtils import name_displayer
from editsecondary import EditSecondary
from gen.lib import NoteType
from DisplayTabs import GrampsTab,SourceEmbedList,NoteTab
from gui.widgets import (MonitoredEntry, MonitoredMenu, MonitoredDate,
MonitoredDataType, PrivacyButton)
from glade import Glade
#-------------------------------------------------------------------------
#
# Classes
#
#-------------------------------------------------------------------------
class GeneralNameTab(GrampsTab):
"""
This class provides the tabpage of the general name tab
"""
def __init__(self, dbstate, uistate, track, name, widget):
"""
@param dbstate: The database state. Contains a reference to
the database, along with other state information. The GrampsTab
uses this to access the database and to pass to and created
child windows (such as edit dialogs).
@type dbstate: DbState
@param uistate: The UI state. Used primarily to pass to any created
subwindows.
@type uistate: DisplayState
@param track: The window tracking mechanism used to manage windows.
This is only used to pass to generted child windows.
@type track: list
@param name: Notebook label name
@type name: str/unicode
@param widget: widget to be shown in the tab
@type widge: gtk widget
"""
GrampsTab.__init__(self, dbstate, uistate, track, name)
eventbox = gtk.EventBox()
eventbox.add(widget)
self.pack_start(eventbox)
self._set_label(show_image=False)
widget.connect('key_press_event', self.key_pressed)
self.show_all()
def is_empty(self):
"""
Override base class
"""
return False
#-------------------------------------------------------------------------
#
# EditName class
#
#-------------------------------------------------------------------------
class EditName(EditSecondary):
def __init__(self, dbstate, uistate, track, name, callback):
EditSecondary.__init__(self, dbstate, uistate,
track, name, callback)
def _local_init(self):
self.width_key = 'interface.name-width'
self.height_key = 'interface.name-height'
self.top = Glade()
self.set_window(self.top.toplevel,
self.top.get_object("title"),
_("Name Editor"))
tblgnam = self.top.get_object('table23')
notebook = self.top.get_object('notebook')
#recreate start page as GrampsTab
notebook.remove_page(0)
self.gennam = GeneralNameTab(self.dbstate, self.uistate, self.track,
_('_General'), tblgnam)
self.original_group_as = self.obj.get_group_as()
self.original_group_set = not (self.original_group_as == '')
srn = self.obj.get_surname()
self._get_global_grouping(srn)
self.group_over = self.top.get_object('group_over')
self.group_over.connect('toggled',self.on_group_over_toggled)
self.group_over.set_sensitive(not self.db.readonly)
self.toggle_dirty = False
def _post_init(self):
"""if there is override, set the override toggle active
"""
if self.original_group_set or self.global_group_set :
self.group_over.set_active(True)
def _connect_signals(self):
self.define_cancel_button(self.top.get_object('button119'))
self.define_help_button(self.top.get_object('button131'))
self.define_ok_button(self.top.get_object('button118'),self.save)
def _setup_fields(self):
self.group_as = MonitoredEntry(
self.top.get_object("group_as"),
self.obj.set_group_as,
self.obj.get_group_as,
self.db.readonly)
if not self.original_group_set:
if self.global_group_set :
self.group_as.force_value(self.global_group_as)
else :
self.group_as.force_value(self.obj.get_surname())
format_list = [(name, number) for (number, name,fmt_str,act)
in name_displayer.get_name_format(also_default=True)]
self.sort_as = MonitoredMenu(
self.top.get_object('sort_as'),
self.obj.set_sort_as,
self.obj.get_sort_as,
format_list,
self.db.readonly)
self.display_as = MonitoredMenu(
self.top.get_object('display_as'),
self.obj.set_display_as,
self.obj.get_display_as,
format_list,
self.db.readonly)
self.given_field = MonitoredEntry(
self.top.get_object("alt_given"),
self.obj.set_first_name,
self.obj.get_first_name,
self.db.readonly)
self.call_field = MonitoredEntry(
self.top.get_object("call"),
self.obj.set_call_name,
self.obj.get_call_name,
self.db.readonly)
self.title_field = MonitoredEntry(
self.top.get_object("alt_title"),
self.obj.set_title,
self.obj.get_title,
self.db.readonly)
self.suffix_field = MonitoredEntry(
self.top.get_object("alt_suffix"),
self.obj.set_suffix,
self.obj.get_suffix,
self.db.readonly)
self.patronymic_field = MonitoredEntry(
self.top.get_object("patronymic"),
self.obj.set_patronymic,
self.obj.get_patronymic,
self.db.readonly)
self.surname_field = MonitoredEntry(
self.top.get_object("alt_surname"),
self.obj.set_surname,
self.obj.get_surname,
self.db.readonly,
autolist=self.db.get_surname_list(),
changed=self.update_group_as)
self.prefix_field = MonitoredEntry(
self.top.get_object("alt_prefix"),
self.obj.set_surname_prefix,
self.obj.get_surname_prefix,
self.db.readonly)
self.date = MonitoredDate(
self.top.get_object("date_entry"),
self.top.get_object("date_stat"),
self.obj.get_date_object(),
self.uistate,
self.track,
self.db.readonly)
self.obj_combo = MonitoredDataType(
self.top.get_object("name_type"),
self.obj.set_type,
self.obj.get_type,
self.db.readonly,
self.db.get_name_types(),
)
self.privacy = PrivacyButton(
self.top.get_object("priv"), self.obj,
self.db.readonly)
def _create_tabbed_pages(self):
notebook = self.top.get_object("notebook")
self._add_tab(notebook, self.gennam)
self.srcref_list = self._add_tab(
notebook,
SourceEmbedList(self.dbstate,self.uistate,self.track,self.obj))
self.note_tab = self._add_tab(
notebook,
NoteTab(self.dbstate, self.uistate, self.track,
self.obj.get_note_list(),
notetype=NoteType.PERSONNAME))
self._setup_notebook_tabs( notebook)
def _get_global_grouping(self, srn):
""" we need info on the global grouping of the surname on init,
and on change of surname
"""
self.global_group_as = self.db.get_name_group_mapping(srn)
if srn == self.global_group_as:
self.global_group_as = None
self.global_group_set = False
else:
self.global_group_set = True
def build_menu_names(self, name):
if name:
ntext = name_displayer.display_name(name)
submenu_label = '%s: %s' % (_('Name'), ntext)
else:
submenu_label = _('New Name')
menu_label = _('Name Editor')
return (menu_label,submenu_label)
def update_group_as(self, obj):
"""Callback if surname changes on GUI
If overwrite is not set, we change the group name too
"""
name = self.obj.get_surname()
if not self.group_over.get_active():
self.group_as.force_value(name)
#new surname, so perhaps now a different grouping?
self._get_global_grouping(name)
if not self.group_over.get_active() and self.global_group_set :
self.group_over.set_active(True)
self.group_as.enable(True)
self.toggle_dirty = True
self.group_as.force_value(self.global_group_as)
elif self.group_over.get_active() and self.toggle_dirty:
#changing surname caused active group_over in past, change
# group_over as we type
if self.global_group_set :
self.group_as.force_value(self.global_group_as)
else:
self.toggle_dirty = False
self.group_as.force_value(name)
self.group_over.set_active(False)
self.group_as.enable(False)
def on_group_over_toggled(self, obj):
""" group over changes, if activated, enable edit,
if unactivated, go back to surname.
"""
self.toggle_dirty = False
#enable group as box
self.group_as.enable(obj.get_active())
if not obj.get_active():
surname = self.obj.get_surname()
self.group_as.set_text(surname)
def save(self,*obj):
"""Save the name setting. All is ok, except grouping. We need to
consider:
1/ global set, not local set --> unset (ask if global unset)
2/ global set, local set --> unset (only local unset!)
3/ not global set, local set
or not global set, not local set --> unset
4/ not local set, not global set
or not local set, global set --> set val (ask global or local)
5/ local set, not global set --> set (change local)
6/ local set, global set --> set (set to global if possible)
"""
closeit = True
surname = self.obj.get_surname()
group_as= self.obj.get_group_as()
grouping_active = self.group_over.get_active()
if not grouping_active :
#user wants to group with surname
if self.global_group_set and not self.original_group_set :
#warn that group will revert to surname
from QuestionDialog import QuestionDialog2
q = QuestionDialog2(
_("Break global name grouping?"),
_("All people with the name of %(surname)s will no longer "
"be grouped with the name of %(group_name)s."
) % { 'surname' : surname,
'group_name':group_as},
_("Continue"),
_("Return to Name Editor"))
val = q.run()
if val:
#delete the grouping link on database
self.db.set_name_group_mapping(surname, None)
self.obj.set_group_as("")
else :
closeit = False
elif self.global_group_set and self.original_group_set:
#we change it only back to surname locally, so store group_as
# Note: if all surnames are locally changed to surname, we
# should actually unsed the global group here ....
pass
else :
#global group not set, don't set local group too:
self.obj.set_group_as("")
else:
#user wants to override surname, see what he wants
if not self.original_group_set :
#if changed, ask if this has to happen for the entire group,
#this might be creation of group link, or change of group link
if self.global_group_as != group_as:
from QuestionDialog import QuestionDialog2
q = QuestionDialog2(
_("Group all people with the same name?"),
_("You have the choice of grouping all people with the "
"name of %(surname)s with the name of %(group_name)s, or "
"just mapping this particular name."
) % { 'surname' : surname,
'group_name':group_as},
_("Group all"),
_("Group this name only"))
val = q.run()
if val:
if group_as == surname :
self.db.set_name_group_mapping(surname, None)
else:
self.db.set_name_group_mapping(surname, group_as)
self.obj.set_group_as("")
else:
if self.global_group_set :
#allow smith to Dummy, but one person still Smith
self.obj.set_group_as(group_as)
elif group_as == surname :
self.obj.set_group_as("")
else:
self.obj.set_group_as(group_as)
else:
#keep original value, no original group
self.obj.set_group_as("")
elif not self.global_group_set :
#don't ask user, group was set locally before,
#change it locally only
if group_as == surname :
#remove grouping
self.obj.set_group_as("")
else:
pass
else:
#locally set group and global group set
if group_as == self.global_group_as :
#unset local group, go with global one
self.obj.set_group_as("")
else :
#local set is different from global, keep it like that
pass
if closeit:
if self.callback:
self.callback(self.obj)
self.close()

387
src/gui/editors/editnote.py Normal file
View File

@@ -0,0 +1,387 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# 2009 Gary Burton
# 2009 Benny Malengier
#
# 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$
#-------------------------------------------------------------------------
#
# Python classes
#
#-------------------------------------------------------------------------
from gettext import gettext as _
import logging
_LOG = logging.getLogger(".gui.editors.EditNote")
#-------------------------------------------------------------------------
#
# GTK libraries
#
#-------------------------------------------------------------------------
import gtk
import gobject
import pango
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import config
import const
from gui.widgets import StyledTextEditor
from editprimary import EditPrimary
from DisplayTabs import GrampsTab, NoteBackRefList
from gui.widgets import (MonitoredDataType, MonitoredCheckbox,
MonitoredEntry, PrivacyButton)
from gen.lib import Note
from QuestionDialog import ErrorDialog
from glade import Glade
#-------------------------------------------------------------------------
#
# NoteTab
#
#-------------------------------------------------------------------------
class NoteTab(GrampsTab):
"""
This class provides the tabpage of the note
"""
def __init__(self, dbstate, uistate, track, name, widget):
"""
@param dbstate: The database state. Contains a reference to
the database, along with other state information. The GrampsTab
uses this to access the database and to pass to and created
child windows (such as edit dialogs).
@type dbstate: L{DbState.DbState}
@param uistate: The UI state. Used primarily to pass to any created
subwindows.
@type uistate: L{DisplayState.DisplayState}
@param track: The window tracking mechanism used to manage windows.
This is only used to pass to generted child windows.
@type track: list
@param name: Notebook label name
@type name: str/unicode
@param widget: widget to be shown in the tab
@type widget: gtk widget
"""
GrampsTab.__init__(self, dbstate, uistate, track, name)
eventbox = gtk.EventBox()
eventbox.add(widget)
self.pack_start(eventbox)
self._set_label(show_image=False)
eventbox.connect('key_press_event', self.key_pressed)
self.show_all()
def is_empty(self):
"""
Override base class
"""
return False
#-------------------------------------------------------------------------
#
# EditNote
#
#-------------------------------------------------------------------------
class EditNote(EditPrimary):
def __init__(self, dbstate, uistate, track, note, callback=None,
callertitle = None, extratype = None):
"""Create an EditNote window. Associate a note with the window.
@param callertitle: Text passed by calling object to add to title
@type callertitle: str
@param extratype: Extra L{NoteType} values to add to the default types.
They are removed from the ignorelist of L{NoteType}.
@type extratype: list of int
"""
self.callertitle = callertitle
self.extratype = extratype
EditPrimary.__init__(self, dbstate, uistate, track, note,
dbstate.db.get_note_from_handle,
dbstate.db.get_note_from_gramps_id, callback)
def empty_object(self):
"""Return an empty Note object for comparison for changes.
It is used by the base class L{EditPrimary}.
"""
empty_note = Note();
if self.extratype:
empty_note.set_type(self.extratype[0])
return empty_note
def get_menu_title(self):
if self.obj.get_handle():
if self.callertitle :
title = _('Note: %(id)s - %(context)s') % {
'id' : self.obj.get_gramps_id(),
'context' : self.callertitle
}
else :
title = _('Note: %s') % self.obj.get_gramps_id()
else:
if self.callertitle :
title = _('New Note - %(context)s') % {
'context' : self.callertitle
}
else :
title = _('New Note')
return title
def get_custom_notetypes(self):
return self.dbstate.db.get_note_types()
def _local_init(self):
"""Local initialization function.
Perform basic initialization, including setting up widgets
and the glade interface. It is called by the base class L{EditPrimary},
and overridden here.
"""
self.width_key = 'interface.note-width'
self.height_key = 'interface.note-height'
self.top = Glade()
win = self.top.toplevel
self.set_window(win, None, self.get_menu_title())
vboxnote = self.top.get_object('vbox131')
notebook = self.top.get_object('note_notebook')
#recreate start page as GrampsTab
notebook.remove_page(0)
self.ntab = NoteTab(self.dbstate, self.uistate, self.track,
_('_Note'), vboxnote)
self.track_ref_for_deletion("ntab")
self.build_interface()
def _setup_fields(self):
"""Get control widgets and attach them to Note's attributes."""
self.type_selector = MonitoredDataType(
self.top.get_object('type'),
self.obj.set_type,
self.obj.get_type,
self.db.readonly,
custom_values=self.get_custom_notetypes(),
ignore_values=self.obj.get_type().get_ignore_list(self.extratype))
self.check = MonitoredCheckbox(
self.obj,
self.top.get_object('format'),
self.obj.set_format,
self.obj.get_format,
readonly = self.db.readonly)
self.gid = MonitoredEntry(
self.top.get_object('id'),
self.obj.set_gramps_id,
self.obj.get_gramps_id,
self.db.readonly)
self.marker = MonitoredDataType(
self.top.get_object('marker'),
self.obj.set_marker,
self.obj.get_marker,
self.db.readonly,
self.db.get_marker_types())
self.priv = PrivacyButton(
self.top.get_object("private"),
self.obj, self.db.readonly)
def _connect_signals(self):
"""Connects any signals that need to be connected.
Called by the init routine of the base class L{EditPrimary}.
"""
self.define_ok_button(self.top.get_object('ok'), self.save)
self.define_cancel_button(self.top.get_object('cancel'))
self.define_help_button(self.top.get_object('help'))
def _connect_db_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self._add_db_signal('note-rebuild', self._do_close)
self._add_db_signal('note-delete', self.check_for_close)
def _create_tabbed_pages(self):
"""Create the notebook tabs and inserts them into the main window."""
notebook = self.top.get_object("note_notebook")
self._add_tab(notebook, self.ntab)
handles = self.dbstate.db.find_backlink_handles(self.obj.handle)
self.rlist = NoteBackRefList(self.dbstate,
self.uistate,
self.track,
handles)
self.backref_tab = self._add_tab(notebook, self.rlist)
self.track_ref_for_deletion("rlist")
self.track_ref_for_deletion("backref_tab")
self._setup_notebook_tabs(notebook)
def build_interface(self):
self.texteditor = self.top.get_object('texteditor')
self.texteditor.set_editable(not self.dbstate.db.readonly)
self.texteditor.set_wrap_mode(gtk.WRAP_WORD)
# create a formatting toolbar
if not self.dbstate.db.readonly:
vbox = self.top.get_object('container')
vbox.pack_start(self.texteditor.get_toolbar(),
expand=False, fill=False)
# setup initial values for textview and textbuffer
if self.obj:
self.empty = False
self.texteditor.set_text(self.obj.get_styledtext())
_LOG.debug("Initial Note: %s" % str(self.texteditor.get_text()))
else:
self.empty = True
def build_menu_names(self, person):
"""
Provide the information needed by the base class to define the
window management menu entries.
"""
return (_('Edit Note'), self.get_menu_title())
def _post_init(self):
self.texteditor.grab_focus()
def update_note(self):
"""Update the Note object with current value."""
if self.obj:
text = self.texteditor.get_text()
self.obj.set_styledtext(text)
_LOG.debug(str(text))
def save(self, *obj):
"""Save the data."""
self.ok_button.set_sensitive(False)
self.update_note()
if self.object_is_empty():
ErrorDialog(_("Cannot save note"),
_("No data exists for this note. Please "
"enter data or cancel the edit."))
self.ok_button.set_sensitive(True)
return
(uses_dupe_id, id) = self._uses_duplicate_id()
if uses_dupe_id:
msg1 = _("Cannot save note. ID already exists.")
msg2 = _("You have attempted to use the existing Gramps ID with "
"value %(id)s. This value is already used. Please "
"enter a different ID or leave "
"blank to get the next available ID value.") % {
'id' : id }
ErrorDialog(msg1, msg2)
self.ok_button.set_sensitive(True)
return
trans = self.db.transaction_begin()
if not self.obj.get_handle():
self.db.add_note(self.obj, trans)
msg = _("Add Note")
else:
if not self.obj.get_gramps_id():
self.obj.set_gramps_id(self.db.find_next_note_gramps_id())
self.db.commit_note(self.obj, trans)
msg = _("Edit Note")
self.db.transaction_commit(trans, msg)
if self.callback:
self.callback(self.obj.get_handle())
self.close()
class DeleteNoteQuery(object):
def __init__(self, dbstate, uistate, note, the_lists):
self.note = note
self.db = dbstate.db
self.uistate = uistate
self.the_lists = the_lists
def query_response(self):
trans = self.db.transaction_begin()
self.db.disable_signals()
(person_list, family_list, event_list, place_list, source_list,
media_list, repo_list) = self.the_lists
note_handle = self.note.get_handle()
for handle in person_list:
person = self.db.get_person_from_handle(handle)
person.remove_note(note_handle)
self.db.commit_person(person, trans)
for handle in family_list:
family = self.db.get_family_from_handle(handle)
family.remove_note(note_handle)
self.db.commit_family(family, trans)
for handle in event_list:
event = self.db.get_event_from_handle(handle)
event.remove_note(note_handle)
self.db.commit_event(event, trans)
for handle in place_list:
place = self.db.get_place_from_handle(handle)
place.remove_note(note_handle)
self.db.commit_place(place, trans)
for handle in source_list:
source = self.db.get_source_from_handle(handle)
source.remove_note(note_handle)
self.db.commit_source(source, trans)
for handle in media_list:
media = self.db.get_object_from_handle(handle)
media.remove_note(note_handle)
self.db.commit_media_object(media, trans)
for handle in repo_list:
repo = self.db.get_repository_from_handle(handle)
repo.remove_note(note_handle)
self.db.commit_repository(repo, trans)
self.db.enable_signals()
self.db.remove_note(note_handle, trans)
self.db.transaction_commit(
trans,_("Delete Note (%s)") % self.note.get_gramps_id())

View File

@@ -0,0 +1,915 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# Copyright (C) 2009 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$
"""
EditPerson Dialog. Provide the interface to allow the GRAMPS program
to edit information about a particular Person.
"""
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
import locale
from TransUtils import sgettext as _
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import const
import Utils
from gui.utils import add_menuitem, open_file_with_default_application
import Mime
import gen.lib
from gui import widgets
from BasicUtils import name_displayer
import Errors
from glade import Glade
from gen.utils import set_birth_death_index
from editprimary import EditPrimary
from editmediaref import EditMediaRef
from editname import EditName
import config
from QuestionDialog import ErrorDialog, ICON
from DisplayTabs import (PersonEventEmbedList, NameEmbedList, SourceEmbedList,
AttrEmbedList, AddrEmbedList, NoteTab, GalleryTab,
WebEmbedList, PersonRefEmbedList, LdsEmbedList,
PersonBackRefList)
from gen.plug import CATEGORY_QR_PERSON
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
_select_gender = ((True, False, False),
(False, True, False),
(False, False, True))
class EditPerson(EditPrimary):
"""
The EditPerson dialog is derived from the EditPrimary class.
It allows for the editing of the primary object type of Person.
"""
QR_CATEGORY = CATEGORY_QR_PERSON
def __init__(self, dbstate, uistate, track, person, callback=None):
"""
Create an EditPerson window.
Associate a person with the window.
"""
EditPrimary.__init__(self, dbstate, uistate, track, person,
dbstate.db.get_person_from_handle,
dbstate.db.get_person_from_gramps_id, callback)
def empty_object(self):
"""
Return an empty Person object for comparison for changes.
This is used by the base class (EditPrimary).
"""
return gen.lib.Person()
def get_menu_title(self):
if self.obj.get_handle():
name = name_displayer.display(self.obj)
title = _('Person: %(name)s') % {'name': name}
else:
name = name_displayer.display(self.obj)
if name:
title = _('New Person: %(name)s') % {'name': name}
else:
title = _('New Person')
return title
def _local_init(self):
"""
Performs basic initialization, including setting up widgets and the
glade interface.
Local initialization function.
This is called by the base class of EditPrimary, and overridden here.
"""
self.width_key = 'interface.person-width'
self.height_key = 'interface.person-height'
self.pname = self.obj.get_primary_name()
self.should_guess_gender = (not self.obj.get_gramps_id() and
self.obj.get_gender () ==
gen.lib.Person.UNKNOWN)
self.load_obj = None
self.load_rect = None
self.top = Glade()
self.set_window(self.top.toplevel, None,
self.get_menu_title())
self.obj_photo = self.top.get_object("personPix")
self.eventbox = self.top.get_object("eventbox1")
self.set_contexteventbox(self.top.get_object("eventboxtop"))
def _post_init(self):
"""
Handle any initialization that needs to be done after the interface is
brought up.
Post initalization function.
This is called by _EditPrimary's init routine, and overridden in the
derived class (this class).
"""
self.load_person_image()
if self.pname.get_surname() and not self.pname.get_first_name():
self.given.grab_focus()
else:
self.surname_field.grab_focus()
def _connect_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self.define_cancel_button(self.top.get_object("button15"))
self.define_ok_button(self.top.get_object("ok"), self.save)
self.define_help_button(self.top.get_object("button134"))
self.given.connect("focus_out_event", self._given_focus_out_event)
self.top.get_object("button177").connect("clicked",
self._edit_name_clicked)
self.eventbox.connect('button-press-event',
self._image_button_press)
def _connect_db_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self._add_db_signal('person-rebuild', self._do_close)
self._add_db_signal('person-delete', self.check_for_close)
self._add_db_signal('family-rebuild', self.family_change)
self._add_db_signal('family-delete', self.family_change)
self._add_db_signal('family-update', self.family_change)
self._add_db_signal('family-add', self.family_change)
self._add_db_signal('event-update', self.event_updated)
self._add_db_signal('event-rebuild', self.event_updated)
self._add_db_signal('event-delete', self.event_updated)
def family_change(self, handle_list=[]):
"""
Callback for family change signals.
This should rebuild the
backreferences to family in person when:
1)a family the person is parent of changes. Person could have
been removed
2)a family the person is child in changes. Child could have been
removed
3)a family is changed. The person could be added as child or
parent
"""
#As this would be an extensive check, we choose the easy path and
# rebuild family backreferences on all family changes
self._update_families()
def _update_families(self):
phandle = self.obj.get_handle()
if phandle:
#new person has no handle yet and cannot be in a family.
person = self.dbstate.db.get_person_from_handle(phandle)
self.obj.set_family_handle_list(person.get_family_handle_list())
self.obj.set_parent_family_handle_list(
person.get_parent_family_handle_list())
#a family groupname in event_list might need to be changed
# we just rebuild the view always
self.event_list.rebuild_callback()
def event_updated(self, obj):
#place in event might have changed, or person event shown in the list
# we just rebuild the view always
self.event_list.rebuild_callback()
def _setup_fields(self):
"""
Connect the GrampsWidget objects to field in the interface.
This allows the widgets to keep the data in the attached Person object
up to date at all times, eliminating a lot of need in 'save' routine.
"""
self.private = widgets.PrivacyButton(
self.top.get_object('private'),
self.obj,
self.db.readonly)
self.gender = widgets.MonitoredMenu(
self.top.get_object('gender'),
self.obj.set_gender,
self.obj.get_gender,
(
(_('female'), gen.lib.Person.FEMALE),
(_('male'), gen.lib.Person.MALE),
(_('unknown'), gen.lib.Person.UNKNOWN)
),
self.db.readonly)
self.marker = widgets.MonitoredDataType(
self.top.get_object('marker'),
self.obj.set_marker,
self.obj.get_marker,
self.db.readonly,
self.db.get_marker_types(),
)
self.ntype_field = widgets.MonitoredDataType(
self.top.get_object("ntype"),
self.pname.set_type,
self.pname.get_type,
self.db.readonly,
self.db.get_name_types())
self.prefix_suffix = widgets.MonitoredComboSelectedEntry(
self.top.get_object("prefixcmb"),
self.top.get_object("prefixentry"),
[_('Prefix'), _('Suffix')],
[self.pname.set_surname_prefix, self.pname.set_suffix],
[self.pname.get_surname_prefix, self.pname.get_suffix],
default = config.get('interface.prefix-suffix'),
read_only = self.db.readonly)
self.patro_title = widgets.MonitoredComboSelectedEntry(
self.top.get_object("patrocmb"),
self.top.get_object("patroentry"),
[_('Patronymic'), _('Person|Title')],
[self.pname.set_patronymic, self.pname.set_title],
[self.pname.get_patronymic, self.pname.get_title],
default = config.get('interface.patro-title'),
read_only = self.db.readonly)
self.call = widgets.MonitoredEntry(
self.top.get_object("call"),
self.pname.set_call_name,
self.pname.get_call_name,
self.db.readonly)
self.given = widgets.MonitoredEntry(
self.top.get_object("given_name"),
self.pname.set_first_name,
self.pname.get_first_name,
self.db.readonly)
self.surname_field = widgets.MonitoredEntry(
self.top.get_object("surname"),
self.pname.set_surname,
self.pname.get_surname,
self.db.readonly,
autolist=self.db.get_surname_list())
self.gid = widgets.MonitoredEntry(
self.top.get_object("gid"),
self.obj.set_gramps_id,
self.obj.get_gramps_id,
self.db.readonly)
#make sure title updates automatically
for obj in [self.top.get_object("surname"),
self.top.get_object("given_name"),
self.top.get_object("patroentry"),
self.top.get_object("call"),
self.top.get_object("prefixentry"),
]:
obj.connect('changed', self._changed_name)
def _create_tabbed_pages(self):
"""
Create the notebook tabs and insert them into the main window.
"""
notebook = gtk.Notebook()
notebook.set_scrollable(True)
self.event_list = PersonEventEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj)
self._add_tab(notebook, self.event_list)
self.track_ref_for_deletion("event_list")
self.name_list = NameEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj.get_alternate_names(),
self.obj,
self.name_callback)
self._add_tab(notebook, self.name_list)
self.track_ref_for_deletion("name_list")
self.srcref_list = SourceEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj)
self._add_tab(notebook, self.srcref_list)
self.track_ref_for_deletion("srcref_list")
self.attr_list = AttrEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj.get_attribute_list())
self._add_tab(notebook, self.attr_list)
self.track_ref_for_deletion("attr_list")
self.addr_list = AddrEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj.get_address_list())
self._add_tab(notebook, self.addr_list)
self.track_ref_for_deletion("addr_list")
self.note_tab = NoteTab(self.dbstate,
self.uistate,
self.track,
self.obj.get_note_list(),
self.get_menu_title(),
notetype=gen.lib.NoteType.PERSON)
self._add_tab(notebook, self.note_tab)
self.track_ref_for_deletion("note_tab")
self.gallery_tab = GalleryTab(self.dbstate,
self.uistate,
self.track,
self.obj.get_media_list(),
self.load_person_image)
self._add_tab(notebook, self.gallery_tab)
self.track_ref_for_deletion("gallery_tab")
self.web_list = WebEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj.get_url_list())
self._add_tab(notebook, self.web_list)
self.track_ref_for_deletion("web_list")
self.person_ref_list = PersonRefEmbedList(self.dbstate, self.uistate,
self.track,
self.obj.get_person_ref_list())
self._add_tab(notebook, self.person_ref_list)
self.track_ref_for_deletion("person_ref_list")
self.lds_list = LdsEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj.get_lds_ord_list())
self._add_tab(notebook, self.lds_list)
self.track_ref_for_deletion("lds_list")
self.backref_tab = PersonBackRefList(self.dbstate,
self.uistate,
self.track,
self.db.find_backlink_handles(self.obj.handle))
self._add_tab(notebook, self.backref_tab)
self.track_ref_for_deletion("backref_tab")
self._setup_notebook_tabs(notebook)
notebook.show_all()
self.top.get_object('vbox').pack_start(notebook, True)
def _changed_name(self, obj):
"""
callback to changes typed by user to the person name.
Update the window title, and default name in name tab
"""
self.update_title(self.get_menu_title())
self.name_list.update_defname()
def name_callback(self):
"""
Callback if changes happen in the name tab that impact the preferred
name.
"""
self.pname = self.obj.get_primary_name()
self.ntype_field.reinit(self.pname.set_type, self.pname.get_type)
self.prefix_suffix.reinit(
[self.pname.set_surname_prefix, self.pname.set_suffix],
[self.pname.get_surname_prefix, self.pname.get_suffix])
self.call.reinit(
self.pname.set_call_name,
self.pname.get_call_name)
self.given.reinit(
self.pname.set_first_name,
self.pname.get_first_name)
self.patro_title.reinit(
[self.pname.set_patronymic, self.pname.set_title],
[self.pname.get_patronymic, self.pname.get_title])
self.surname_field.reinit(
self.pname.set_surname,
self.pname.get_surname)
def build_menu_names(self, person):
"""
Provide the information needed by the base class to define the
window management menu entries.
"""
return (_('Edit Person'), self.get_menu_title())
def _image_callback(self, ref, obj):
"""
Called when a media reference had been edited.
This allows for the updating image on the main form which has just
been modified.
"""
self.load_photo(Utils.media_path_full(self.dbstate.db, obj.get_path()),
ref.get_rectangle())
def _image_button_press(self, obj, event):
"""
Button press event that is caught when a button has been pressed while
on the image on the main form.
This does not apply to the images in galleries, just the image on the
main form.
"""
if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
media_list = self.obj.get_media_list()
if media_list:
media_ref = media_list[0]
object_handle = media_ref.get_reference_handle()
media_obj = self.db.get_object_from_handle(object_handle)
try:
EditMediaRef(self.dbstate, self.uistate, self.track,
media_obj, media_ref, self._image_callback)
except Errors.WindowActiveError:
pass
elif event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
media_list = self.obj.get_media_list()
if media_list:
photo = media_list[0]
self._show_popup(photo, event)
#do not propagate further:
return True
def _show_popup(self, photo, event):
"""
Look for right-clicks on a picture and create a popup menu of the
available actions.
"""
menu = gtk.Menu()
menu.set_title(_("Media Object"))
obj = self.db.get_object_from_handle(photo.get_reference_handle())
if obj:
add_menuitem(menu, _("View"), photo, self._popup_view_photo)
add_menuitem(menu, _("Edit Object Properties"), photo,
self._popup_change_description)
menu.popup(None, None, None, event.button, event.time)
def _popup_view_photo(self, obj):
"""
Open this picture in the default picture viewer.
"""
media_list = self.obj.get_media_list()
if media_list:
photo = media_list[0]
object_handle = photo.get_reference_handle()
ref_obj = self.db.get_object_from_handle(object_handle)
photo_path = Utils.media_path_full(self.db, ref_obj.get_path())
open_file_with_default_application(photo_path)
def _popup_change_description(self, obj):
"""
Bring up the EditMediaRef dialog for the image on the main form.
"""
media_list = self.obj.get_media_list()
if media_list:
media_ref = media_list[0]
object_handle = media_ref.get_reference_handle()
media_obj = self.db.get_object_from_handle(object_handle)
EditMediaRef(self.dbstate, self.uistate, self.track,
media_obj, media_ref, self._image_callback)
def _top_contextmenu(self):
"""
Override from base class, the menuitems and actiongroups for the top
of context menu.
"""
self.all_action = gtk.ActionGroup("/PersonAll")
self.home_action = gtk.ActionGroup("/PersonHome")
self.track_ref_for_deletion("all_action")
self.track_ref_for_deletion("home_action")
self.all_action.add_actions([
('ActivePerson', gtk.STOCK_APPLY, _("Make Active Person"),
None, None, self._make_active),
])
self.home_action.add_actions([
('HomePerson', gtk.STOCK_HOME, _("Make Home Person"),
None, None, self._make_home_person),
])
self.all_action.set_visible(True)
self.home_action.set_visible(True)
ui_top_cm = '''
<menuitem action="ActivePerson"/>
<menuitem action="HomePerson"/>'''
return ui_top_cm, [self.all_action, self.home_action]
def _post_build_popup_ui(self):
"""
Override base class, make inactive home action if not needed.
"""
if self.dbstate.db.get_default_person() and \
self.obj.get_handle() == \
self.dbstate.db.get_default_person().get_handle():
self.home_action.set_sensitive(False)
else :
self.home_action.set_sensitive(True)
def _make_active(self, obj):
self.dbstate.change_active_person(self.obj)
def _make_home_person(self, obj):
handle = self.obj.get_handle()
if handle:
self.dbstate.db.set_default_person_handle(handle)
def _given_focus_out_event (self, entry, event):
"""
Callback that occurs when the user leaves the given name field,
allowing us to attempt to guess the gender of the person if
so requested.
"""
if not self.should_guess_gender:
return False
try:
gender_type = self.db.genderStats.guess_gender(
unicode(entry.get_text()))
self.gender.force(gender_type)
except:
return False
return False
def load_photo(self, path, rectangle=None):
"""
Load, scale and display the person's main photo from the path.
"""
self.load_obj = path
self.load_rect = rectangle
if path is None:
self.obj_photo.hide()
else:
try:
i = gtk.gdk.pixbuf_new_from_file(path)
width = i.get_width()
height = i.get_height()
if rectangle is not None:
upper_x = min(rectangle[0], rectangle[2])/100.
lower_x = max(rectangle[0], rectangle[2])/100.
upper_y = min(rectangle[1], rectangle[3])/100.
lower_y = max(rectangle[1], rectangle[3])/100.
sub_x = int(upper_x * width)
sub_y = int(upper_y * height)
sub_width = int((lower_x - upper_x) * width)
sub_height = int((lower_y - upper_y) * height)
if sub_width > 0 and sub_height > 0:
i = i.subpixbuf(sub_x, sub_y, sub_width, sub_height)
ratio = float(max(i.get_height(), i.get_width()))
scale = float(100.0)/ratio
x = int(scale*(i.get_width()))
y = int(scale*(i.get_height()))
i = i.scale_simple(x, y, gtk.gdk.INTERP_BILINEAR)
self.obj_photo.set_from_pixbuf(i)
self.obj_photo.show()
except:
self.obj_photo.hide()
def _check_for_unknown_gender(self):
if self.obj.get_gender() == gen.lib.Person.UNKNOWN:
d = GenderDialog(self.window)
gender = d.run()
d.destroy()
if gender >= 0:
self.obj.set_gender(gender)
def _update_family_ids(self):
# Update each of the families child lists to reflect any
# change in ordering due to the new birth date
family = self.obj.get_main_parents_family_handle()
if (family):
f = self.db.get_family_from_handle(family)
new_order = self.reorder_child_ref_list(self.obj,
f.get_child_ref_list())
f.set_child_ref_list(new_order)
for family in self.obj.get_parent_family_handle_list():
f = self.db.get_family_from_handle(family)
new_order = self.reorder_child_ref_list(self.obj,
f.get_child_ref_list())
f.set_child_ref_list(new_order)
error = False
original = self.db.get_person_from_handle(self.obj.handle)
if original:
(female, male, unknown) = _select_gender[self.obj.get_gender()]
if male and original.get_gender() != gen.lib.Person.MALE:
for tmp_handle in self.obj.get_family_handle_list():
temp_family = self.db.get_family_from_handle(tmp_handle)
if self.obj == temp_family.get_mother_handle():
if temp_family.get_father_handle() is not None:
error = True
else:
temp_family.set_mother_handle(None)
temp_family.set_father_handle(self.obj)
elif female and original != gen.lib.Person.FEMALE:
for tmp_handle in self.obj.get_family_handle_list():
temp_family = self.db.get_family_from_handle(tmp_handle)
if self.obj == temp_family.get_father_handle():
if temp_family.get_mother_handle() is not None:
error = True
else:
temp_family.set_father_handle(None)
temp_family.set_mother_handle(self.obj)
elif unknown and original.get_gender() != gen.lib.Person.UNKNOWN:
for tmp_handle in self.obj.get_family_handle_list():
temp_family = self.db.get_family_from_handle(tmp_handle)
if self.obj == temp_family.get_father_handle():
if temp_family.get_mother_handle() is not None:
error = True
else:
temp_family.set_father_handle(None)
temp_family.set_mother_handle(self.obj)
if self.obj == temp_family.get_mother_handle():
if temp_family.get_father_handle() is not None:
error = True
else:
temp_family.set_mother_handle(None)
temp_family.set_father_handle(self.obj)
if error:
msg2 = _("Problem changing the gender")
msg = _("Changing the gender caused problems "
"with marriage information.\nPlease check "
"the person's marriages.")
ErrorDialog(msg2, msg)
def save(self, *obj):
"""
Save the data.
"""
self.ok_button.set_sensitive(False)
if self.object_is_empty():
ErrorDialog(_("Cannot save person"),
_("No data exists for this person. Please "
"enter data or cancel the edit."))
self.ok_button.set_sensitive(True)
return
(uses_dupe_id, id) = self._uses_duplicate_id()
if uses_dupe_id:
prim_object = self.get_from_gramps_id(id)
name = self.name_displayer.display(prim_object)
msg1 = _("Cannot save person. ID already exists.")
msg2 = _("You have attempted to use the existing Gramps ID with "
"value %(id)s. This value is already used by '"
"%(prim_object)s'. Please enter a different ID or leave "
"blank to get the next available ID value.") % {
'id' : id, 'prim_object' : name }
ErrorDialog(msg1, msg2)
self.ok_button.set_sensitive(True)
return
self._check_for_unknown_gender()
set_birth_death_index(self.db, self.obj)
trans = self.db.transaction_begin()
self._update_family_ids()
if not self.obj.get_handle():
self.db.add_person(self.obj, trans)
msg = _("Add Person (%s)") % self.name_displayer.display(self.obj)
else:
if not self.obj.get_gramps_id():
self.obj.set_gramps_id(self.db.find_next_person_gramps_id())
self.db.commit_person(self.obj, trans)
msg = _("Edit Person (%s)") % self.name_displayer.display(self.obj)
self.db.transaction_commit(trans, msg)
self.close()
if self.callback:
self.callback(self.obj)
def _edit_name_clicked(self, obj):
"""
Bring up the EditName dialog for this name.
Called when the edit name button is clicked for the primary name
on the main form (not in the names tab).
"""
EditName(self.dbstate, self.uistate, self.track,
self.pname, self._update_name)
def _update_name(self, name):
"""
Called when the primary name has been changed by the EditName
dialog.
This allows us to update the main form in response to any changes.
"""
for obj in (self.prefix_suffix, self.patro_title, self.given,
self.ntype_field, self.surname_field, self.call):
obj.update()
def load_person_image(self):
"""
Load the primary image into the main form if it exists.
Used as callback on Gallery Tab too.
"""
media_list = self.obj.get_media_list()
if media_list:
photo = media_list[0]
object_handle = photo.get_reference_handle()
obj = self.db.get_object_from_handle(object_handle)
full_path = Utils.media_path_full(self.dbstate.db, obj.get_path())
#reload if different media, or different rectangle
if self.load_obj != full_path or \
self.load_rect != photo.get_rectangle():
mime_type = obj.get_mime_type()
if mime_type and mime_type.startswith("image"):
self.load_photo(full_path, photo.get_rectangle())
else:
self.load_photo(None)
else:
self.load_photo(None)
def birth_dates_in_order(self, child_ref_list):
"""
Check any *valid* birthdates in the list to insure that they are in
numerically increasing order.
"""
inorder = True
prev_date = 0
handle_list = [ref.ref for ref in child_ref_list]
for i in range(len(handle_list)):
child_handle = handle_list[i]
child = self.db.get_person_from_handle(child_handle)
if child.get_birth_ref():
event_handle = child.get_birth_ref().ref
event = self.db.get_event_from_handle(event_handle)
child_date = event.get_date_object().get_sort_value()
else:
continue
if (prev_date <= child_date): # <= allows for twins
prev_date = child_date
else:
inorder = False
return inorder
def reorder_child_ref_list(self, person, child_ref_list):
"""
Reorder the child list to put the specified person in his/her
correct birth order.
Only check *valid* birthdates. Move the person as short a distance as
possible.
"""
if self.birth_dates_in_order(child_ref_list):
return(child_ref_list)
# Build the person's date string once
event_ref = person.get_birth_ref()
if event_ref:
event = self.db.get_event_from_handle(event_ref.ref)
person_bday = event.get_date_object().get_sort_value()
else:
person_bday = 0
# First, see if the person needs to be moved forward in the list
handle_list = [ref.ref for ref in child_ref_list]
index = handle_list.index(person.get_handle())
target = index
for i in range(index-1, -1, -1):
other = self.db.get_person_from_handle(handle_list[i])
event_ref = other.get_birth_ref()
if event_ref:
event = self.db.get_event_from_handle(event_ref.ref)
other_bday = event.get_date_object().get_sort_value()
if other_bday == 0:
continue
if person_bday < other_bday:
target = i
else:
continue
# Now try moving to a later position in the list
if (target == index):
for i in range(index, len(handle_list)):
other = self.db.get_person_from_handle(handle_list[i])
event_ref = other.get_birth_ref()
if event_ref:
event = self.db.get_event_from_handle(event_ref.ref)
other_bday = event.get_date_object().get_sort_value()
if other_bday == "99999999":
continue
if person_bday > other_bday:
target = i
else:
continue
# Actually need to move? Do it now.
if (target != index):
ref = child_ref_list.pop(index)
child_ref_list.insert(target, ref)
return child_ref_list
def _cleanup_on_exit(self):
config.set('interface.prefix-suffix', self.prefix_suffix.active_key)
config.set('interface.patro-title', self.patro_title.active_key)
config.save()
class GenderDialog(gtk.MessageDialog):
def __init__(self, parent=None):
gtk.MessageDialog.__init__(self,
parent,
flags=gtk.DIALOG_MODAL,
type=gtk.MESSAGE_QUESTION,
)
self.set_icon(ICON)
self.set_title('')
self.set_markup('<span size="larger" weight="bold">%s</span>' %
_('Unknown gender specified'))
self.format_secondary_text(
_("The gender of the person is currently unknown. "
"Usually, this is a mistake. Please specify the gender."))
self.add_button(_('_Male'), gen.lib.Person.MALE)
self.add_button(_('_Female'), gen.lib.Person.FEMALE)
self.add_button(_('_Unknown'), gen.lib.Person.UNKNOWN)

View File

@@ -0,0 +1,177 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# 2009 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$
"""
The EditPersonRef module provides the EditPersonRef class. This provides a
mechanism for the user to edit address information.
"""
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from BasicUtils import name_displayer
from editsecondary import EditSecondary
from gen.lib import NoteType
from gui.widgets import MonitoredEntry, PrivacyButton
from gui.selectors import SelectorFactory
from DisplayTabs import SourceEmbedList, NoteTab
from glade import Glade
#-------------------------------------------------------------------------
#
# EditPersonRef class
#
#-------------------------------------------------------------------------
class EditPersonRef(EditSecondary):
"""
Displays a dialog that allows the user to edit an address.
"""
def __init__(self, dbstate, uistate, track, addr, callback):
"""
Displays the dialog box.
parent - The class that called the PersonRef editor.
addr - The address that is to be edited
"""
EditSecondary.__init__(self, dbstate, uistate, track, addr, callback)
def _local_init(self):
self.width_key = 'interface.person-ref-width'
self.height_key = 'interface.person-ref-height'
self.top = Glade()
self.set_window(self.top.toplevel,
self.top.get_object("title"),
_('Person Reference Editor'))
self.person_label = self.top.get_object('person')
def _setup_fields(self):
if self.obj.ref:
p = self.dbstate.db.get_person_from_handle(self.obj.ref)
self.person_label.set_text(name_displayer.display(p))
self.street = MonitoredEntry(
self.top.get_object("relationship"),
self.obj.set_relation,
self.obj.get_relation,
self.db.readonly)
self.priv = PrivacyButton(
self.top.get_object("private"),
self.obj,
self.db.readonly)
def _connect_signals(self):
#self.define_help_button(self.top.get_object('help'))
self.define_cancel_button(self.top.get_object('cancel'))
self.define_ok_button(self.top.get_object('ok'),self.save)
self.top.get_object('select').connect('clicked',self._select_person)
def _connect_db_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self._add_db_signal('person-rebuild', self.close)
self._add_db_signal('person-delete', self.check_for_close)
def check_for_close(self, handles):
"""
Callback method for delete signals.
If there is a delete signal of the primary object we are editing, the
editor (and all child windows spawned) should be closed
"""
if self.obj.ref in handles:
self.close()
def _select_person(self, obj):
SelectPerson = SelectorFactory('Person')
sel = SelectPerson(self.dbstate, self.uistate, self.track)
person = sel.run()
if person:
self.obj.ref = person.get_handle()
self.person_label.set_text(name_displayer.display(person))
def _create_tabbed_pages(self):
"""
Create the notebook tabs and inserts them into the main
window.
"""
notebook = gtk.Notebook()
self.srcref_list = self._add_tab(
notebook,
SourceEmbedList(self.dbstate,self.uistate,self.track,self.obj))
self.note_tab = self._add_tab(
notebook,
NoteTab(self.dbstate, self.uistate, self.track,
self.obj.get_note_list(),
notetype=NoteType.ASSOCIATION))
self._setup_notebook_tabs( notebook)
notebook.show_all()
self.top.get_object('vbox').pack_start(notebook,True)
def build_menu_names(self, obj):
return (_('Person Reference'),_('Person Reference Editor'))
def save(self,*obj):
"""
Called when the OK button is pressed. Gets data from the
form and updates the Address data structure.
"""
if self.obj.ref:
if self.callback:
self.callback(self.obj)
self.close()
else:
from QuestionDialog import ErrorDialog
ErrorDialog(
_('No person selected'),
_('You must either select a person or Cancel '
'the edit'))

View File

@@ -0,0 +1,362 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# Copyright (C) 2009 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$
#-------------------------------------------------------------------------
#
# python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
import logging
log = logging.getLogger(".")
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import gen.lib
from editprimary import EditPrimary
from DisplayTabs import (GrampsTab, LocationEmbedList, SourceEmbedList,
GalleryTab, NoteTab, WebEmbedList, PlaceBackRefList)
from gui.widgets import MonitoredEntry, PrivacyButton
from Errors import ValidationError
from PlaceUtils import conv_lat_lon
from QuestionDialog import ErrorDialog
from glade import Glade
#-------------------------------------------------------------------------
#
# Classes
#
#-------------------------------------------------------------------------
class MainLocTab(GrampsTab):
"""
This class provides the tabpage of the main location tab
"""
def __init__(self, dbstate, uistate, track, name, widget):
"""
@param dbstate: The database state. Contains a reference to
the database, along with other state information. The GrampsTab
uses this to access the database and to pass to and created
child windows (such as edit dialogs).
@type dbstate: DbState
@param uistate: The UI state. Used primarily to pass to any created
subwindows.
@type uistate: DisplayState
@param track: The window tracking mechanism used to manage windows.
This is only used to pass to generted child windows.
@type track: list
@param name: Notebook label name
@type name: str/unicode
@param widget: widget to be shown in the tab
@type widge: gtk widget
"""
GrampsTab.__init__(self, dbstate, uistate, track, name)
eventbox = gtk.EventBox()
eventbox.add(widget)
self.pack_start(eventbox)
self._set_label(show_image=False)
eventbox.connect('key_press_event', self.key_pressed)
self.show_all()
def is_empty(self):
"""
Override base class
"""
return False
#-------------------------------------------------------------------------
#
# EditPlace
#
#-------------------------------------------------------------------------
class EditPlace(EditPrimary):
def __init__(self, dbstate, uistate, track, place, callback=None):
EditPrimary.__init__(self, dbstate, uistate, track, place,
dbstate.db.get_place_from_handle,
dbstate.db.get_place_from_gramps_id, callback)
def empty_object(self):
return gen.lib.Place()
def _local_init(self):
self.width_key = 'interface.place-width'
self.height_key = 'interface.place-height'
self.top = Glade()
self.set_window(self.top.toplevel, None,
self.get_menu_title())
tblmloc = self.top.get_object('table19')
notebook = self.top.get_object('notebook3')
#recreate start page as GrampsTab
notebook.remove_page(0)
self.mloc = MainLocTab(self.dbstate, self.uistate, self.track,
_('_Location'), tblmloc)
self.track_ref_for_deletion("mloc")
def get_menu_title(self):
if self.obj and self.obj.get_handle():
title = self.obj.get_title()
dialog_title = _('Place: %s') % title
else:
dialog_title = _('New Place')
return dialog_title
def _connect_signals(self):
self.define_ok_button(self.top.get_object('ok'), self.save)
self.define_cancel_button(self.top.get_object('cancel'))
self.define_help_button(self.top.get_object('help'))
def _connect_db_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self._add_db_signal('place-rebuild', self._do_close)
self._add_db_signal('place-delete', self.check_for_close)
def _setup_fields(self):
mloc = self.obj.get_main_location()
self.title = MonitoredEntry(self.top.get_object("place_title"),
self.obj.set_title, self.obj.get_title,
self.db.readonly)
self.street = MonitoredEntry(self.top.get_object("street"),
mloc.set_street, mloc.get_street,
self.db.readonly)
self.city = MonitoredEntry(self.top.get_object("city"),
mloc.set_city, mloc.get_city,
self.db.readonly)
self.gid = MonitoredEntry(self.top.get_object("gid"),
self.obj.set_gramps_id,
self.obj.get_gramps_id, self.db.readonly)
self.privacy = PrivacyButton(self.top.get_object("private"), self.obj,
self.db.readonly)
self.parish = MonitoredEntry(self.top.get_object("parish"),
mloc.set_parish, mloc.get_parish,
self.db.readonly)
self.county = MonitoredEntry(self.top.get_object("county"),
mloc.set_county, mloc.get_county,
self.db.readonly)
self.state = MonitoredEntry(self.top.get_object("state"),
mloc.set_state, mloc.get_state,
self.db.readonly)
self.phone = MonitoredEntry(self.top.get_object("phone"),
mloc.set_phone, mloc.get_phone,
self.db.readonly)
self.postal = MonitoredEntry(self.top.get_object("postal"),
mloc.set_postal_code,
mloc.get_postal_code, self.db.readonly)
self.country = MonitoredEntry(self.top.get_object("country"),
mloc.set_country, mloc.get_country,
self.db.readonly)
self.longitude = MonitoredEntry(
self.top.get_object("lon_entry"),
self.obj.set_longitude, self.obj.get_longitude,
self.db.readonly)
self.longitude.connect("validate", self._validate_coordinate, "lon")
#force validation now with initial entry
self.top.get_object("lon_entry").validate(force=True)
self.latitude = MonitoredEntry(
self.top.get_object("lat_entry"),
self.obj.set_latitude, self.obj.get_latitude,
self.db.readonly)
self.latitude.connect("validate", self._validate_coordinate, "lat")
#force validation now with initial entry
self.top.get_object("lat_entry").validate(force=True)
def _validate_coordinate(self, widget, text, typedeg):
if (typedeg == 'lat') and not conv_lat_lon(text, "0", "ISO-D"):
return ValidationError(_(u"Invalid latitude (syntax: 18\u00b09'") +
_('48.21"S, -18.2412 or -18:9:48.21)'))
elif (typedeg == 'lon') and not conv_lat_lon("0", text, "ISO-D"):
return ValidationError(_(u"Invalid longitude (syntax: 18\u00b09'") +
_('48.21"E, -18.2412 or -18:9:48.21)'))
def build_menu_names(self, place):
return (_('Edit Place'), self.get_menu_title())
def _create_tabbed_pages(self):
"""
Create the notebook tabs and inserts them into the main
window.
"""
notebook = self.top.get_object('notebook3')
self._add_tab(notebook, self.mloc)
self.loc_list = LocationEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj.alt_loc)
self._add_tab(notebook, self.loc_list)
self.track_ref_for_deletion("loc_list")
self.srcref_list = SourceEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj)
self._add_tab(notebook, self.srcref_list)
self.track_ref_for_deletion("srcref_list")
self.note_tab = NoteTab(self.dbstate,
self.uistate,
self.track,
self.obj.get_note_list(),
self.get_menu_title(),
notetype=gen.lib.NoteType.PLACE)
self._add_tab(notebook, self.note_tab)
self.track_ref_for_deletion("note_tab")
self.gallery_tab = GalleryTab(self.dbstate,
self.uistate,
self.track,
self.obj.get_media_list())
self._add_tab(notebook, self.gallery_tab)
self.track_ref_for_deletion("gallery_tab")
self.web_list = WebEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj.get_url_list())
self._add_tab(notebook, self.web_list)
self.track_ref_for_deletion("web_list")
self.backref_list = PlaceBackRefList(self.dbstate,
self.uistate,
self.track,
self.db.find_backlink_handles(self.obj.handle))
self.backref_tab = self._add_tab(notebook, self.backref_list)
self.track_ref_for_deletion("backref_list")
self.track_ref_for_deletion("backref_tab")
self._setup_notebook_tabs(notebook)
def _cleanup_on_exit(self):
self.backref_tab.close()
def save(self, *obj):
self.ok_button.set_sensitive(False)
if self.object_is_empty():
ErrorDialog(_("Cannot save place"),
_("No data exists for this place. Please "
"enter data or cancel the edit."))
self.ok_button.set_sensitive(True)
return
(uses_dupe_id, id) = self._uses_duplicate_id()
if uses_dupe_id:
prim_object = self.get_from_gramps_id(id)
name = prim_object.get_title()
msg1 = _("Cannot save place. ID already exists.")
msg2 = _("You have attempted to use the existing Gramps ID with "
"value %(id)s. This value is already used by '"
"%(prim_object)s'. Please enter a different ID or leave "
"blank to get the next available ID value.") % {
'id' : id, 'prim_object' : name }
ErrorDialog(msg1, msg2)
self.ok_button.set_sensitive(True)
return
trans = self.db.transaction_begin()
if not self.obj.get_handle():
self.db.add_place(self.obj, trans)
msg = _("Add Place (%s)") % self.obj.get_title()
else:
if not self.obj.get_gramps_id():
self.obj.set_gramps_id(self.db.find_next_place_gramps_id())
self.db.commit_place(self.obj, trans)
msg = _("Edit Place (%s)") % self.obj.get_title()
self.db.transaction_commit(trans, msg)
if self.callback:
self.callback(self.obj)
self.close()
#-------------------------------------------------------------------------
#
# DeletePlaceQuery
#
#-------------------------------------------------------------------------
class DeletePlaceQuery(object):
def __init__(self, dbstate, uistate, place, person_list, family_list,
event_list):
self.db = dbstate.db
self.uistate = uistate
self.obj = place
self.person_list = person_list
self.family_list = family_list
self.event_list = event_list
def query_response(self):
trans = self.db.transaction_begin()
self.db.disable_signals()
place_handle = self.obj.get_handle()
for handle in self.person_list:
person = self.db.get_person_from_handle(handle)
person.remove_handle_references('Place', place_handle)
self.db.commit_person(person, trans)
for handle in self.family_list:
family = self.db.get_family_from_handle(handle)
family.remove_handle_references('Place', place_handle)
self.db.commit_family(family, trans)
for handle in self.event_list:
event = self.db.get_event_from_handle(handle)
event.remove_handle_references('Place', place_handle)
self.db.commit_event(event, trans)
self.db.enable_signals()
self.db.remove_place(place_handle, trans)
self.db.transaction_commit(
trans,_("Delete Place (%s)") % self.obj.get_title())

View File

@@ -0,0 +1,327 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2007 Donald N. Allingham
# 2009 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$
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# GTK modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import ManagedWindow
import DateHandler
from BasicUtils import name_displayer
import config
import GrampsDisplay
from QuestionDialog import SaveDialog
import gen.lib
from gui.dbguielement import DbGUIElement
class EditPrimary(ManagedWindow.ManagedWindow, DbGUIElement):
QR_CATEGORY = -1
def __init__(self, state, uistate, track, obj, get_from_handle,
get_from_gramps_id, callback=None):
"""
Create an edit window.
Associate a person with the window.
"""
self.dp = DateHandler.parser
self.dd = DateHandler.displayer
self.name_displayer = name_displayer
self.obj = obj
self.dbstate = state
self.uistate = uistate
self.db = state.db
self.callback = callback
self.ok_button = None
self.get_from_handle = get_from_handle
self.get_from_gramps_id = get_from_gramps_id
self.contexteventbox = None
self.__tabs = []
ManagedWindow.ManagedWindow.__init__(self, uistate, track, obj)
DbGUIElement.__init__(self, self.db)
self._local_init()
self._set_size()
self._create_tabbed_pages()
self._setup_fields()
self._connect_signals()
#if the database is changed, all info shown is invalid and the window
# should close
self.dbstate.connect('database-changed', self._do_close)
self.show()
self._post_init()
def _local_init(self):
"""
Derived class should do any pre-window initalization in this task.
"""
pass
def _post_init(self):
"""
Derived class should do any post-window initalization in this task.
"""
pass
def _setup_fields(self):
pass
def _create_tabbed_pages(self):
pass
def _connect_signals(self):
pass
def build_window_key(self, obj):
if obj and obj.get_handle():
return obj.get_handle()
else:
return id(self)
def _setup_notebook_tabs(self, notebook):
for child in notebook.get_children():
label = notebook.get_tab_label(child)
page_no = notebook.page_num(child)
label.drag_dest_set(0, [], 0)
label.connect('drag_motion',
self._switch_page_on_dnd,
notebook,
page_no)
child.set_parent_notebook(notebook)
notebook.connect('key-press-event', self.key_pressed, notebook)
def key_pressed(self, obj, event, notebook):
"""
Handles the key being pressed on the notebook, pass to key press of
current page.
"""
pag = notebook.get_current_page()
if not pag == -1:
notebook.get_nth_page(pag).key_pressed(obj, event)
def _switch_page_on_dnd(self, widget, context, x, y, time, notebook,
page_no):
if notebook.get_current_page() != page_no:
notebook.set_current_page(page_no)
def _add_tab(self, notebook, page):
self.__tabs.append(page)
notebook.insert_page(page, page.get_tab_widget())
page.label.set_use_underline(True)
return page
def _cleanup_on_exit(self):
pass
def object_is_empty(self):
return cmp(self.obj.serialize()[1:],
self.empty_object().serialize()[1:]) == 0
def define_ok_button(self, button, function):
self.ok_button = button
button.connect('clicked', function)
button.set_sensitive(not self.db.readonly)
def define_cancel_button(self, button):
button.connect('clicked', self.close)
def define_help_button(self, button, webpage='', section=''):
button.connect('clicked', lambda x: GrampsDisplay.help(webpage,
section))
def _do_close(self, *obj):
self._cleanup_db_connects()
self._cleanup_on_exit()
ManagedWindow.ManagedWindow.close(self)
def _cleanup_db_connects(self):
"""
All connects that happened to signals of the db must be removed on
closed. This implies two things:
1. The connects on the main view must be disconnected
2. Connects done in subelements must be disconnected
"""
#cleanup callbackmanager of this editor
self._cleanup_callbacks()
for tab in [tab for tab in self.__tabs if hasattr(tab, 'callman')]:
tab._cleanup_callbacks()
def check_for_close(self, handles):
"""
Callback method for delete signals.
If there is a delete signal of the primary object we are editing, the
editor (and all child windows spawned) should be closed
"""
if self.obj.get_handle() in handles:
self._do_close()
def close(self, *obj):
"""If the data has changed, give the user a chance to cancel
the close window"""
if not config.get('interface.dont-ask') and self.data_has_changed():
SaveDialog(
_('Save Changes?'),
_('If you close without saving, the changes you '
'have made will be lost'),
self._do_close,
self.save)
return True
else:
self._do_close()
return False
def empty_object(self):
#empty_object should be overridden in base class and will throw an
#exception if it is not because self.empty_object().serialize() is
#called and PrimaryObject does not implement serialize(). See
#BaseObject.serialize()
return gen.lib.PrimaryObject
def data_has_changed(self):
if self.db.readonly:
return False
elif self.obj.handle:
orig = self.get_from_handle(self.obj.handle)
if orig:
cmp_obj = orig
else:
cmp_obj = self.empty_object()
return cmp(cmp_obj.serialize()[1:],
self.obj.serialize()[1:]) != 0
else:
cmp_obj = self.empty_object()
return cmp(cmp_obj.serialize()[1:],
self.obj.serialize()[1:]) != 0
def save(self, *obj):
pass
def set_contexteventbox(self, eventbox):
"""Set the contextbox that grabs button presses if not grabbed
by overlying widgets.
"""
self.contexteventbox = eventbox
self.contexteventbox.connect('button-press-event',
self._contextmenu_button_press)
def _contextmenu_button_press(self, obj, event) :
"""
Button press event that is caught when a mousebutton has been
pressed while on contexteventbox
It opens a context menu with possible actions
"""
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3 :
if self.obj.get_handle() == 0 :
return False
#build the possible popup menu
self._build_popup_ui()
#set or unset sensitivity in popup
self._post_build_popup_ui()
menu = self.popupmanager.get_widget('/Popup')
if menu:
menu.popup(None, None, None, event.button, event.time)
return True
return False
def _build_popup_ui(self):
"""
Create actions and ui of context menu
"""
from QuickReports import create_quickreport_menu
self.popupmanager = gtk.UIManager()
#add custom actions
(ui_top, action_groups) = self._top_contextmenu()
for action in action_groups :
self.popupmanager.insert_action_group(action, -1)
#see which quick reports are available now:
ui_qr = ''
if self.QR_CATEGORY > -1 :
(ui_qr, reportactions) = create_quickreport_menu(self.QR_CATEGORY,
self.dbstate, self.uistate,
self.obj.get_handle())
self.report_action = gtk.ActionGroup("/PersonReport")
self.report_action.add_actions(reportactions)
self.report_action.set_visible(True)
self.popupmanager.insert_action_group(self.report_action, -1)
popupui = '''
<ui>
<popup name="Popup">''' + ui_top + '''
<separator/>''' + ui_qr + '''
</popup>
</ui>'''
self.popupmanager.add_ui_from_string(popupui)
def _top_contextmenu(self):
"""
Derived class can create a ui with menuitems and corresponding list of
actiongroups
"""
return "", []
def _post_build_popup_ui(self):
"""
Derived class should do extra actions here on the menu
"""
pass
def _uses_duplicate_id(self):
"""
Check whether a changed or added GRAMPS ID already exists in the DB.
Return True if a duplicate GRAMPS ID has been detected.
"""
original = self.get_from_handle(self.obj.get_handle())
if original and original.get_gramps_id() == self.obj.get_gramps_id():
return (False, 0)
else:
idval = self.obj.get_gramps_id()
if self.get_from_gramps_id(idval):
return (True, idval)
return (False, 0)

View File

@@ -0,0 +1,224 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# 2009 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$
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import ManagedWindow
from DisplayTabs import GrampsTab
import config
from gui.dbguielement import DbGUIElement
#-------------------------------------------------------------------------
#
# Classes
#
#-------------------------------------------------------------------------
class RefTab(GrampsTab):
"""
This class provides a simple tabpage for use on EditReference
"""
def __init__(self, dbstate, uistate, track, name, widget):
"""
@param dbstate: The database state. Contains a reference to
the database, along with other state information. The GrampsTab
uses this to access the database and to pass to and created
child windows (such as edit dialogs).
@type dbstate: DbState
@param uistate: The UI state. Used primarily to pass to any created
subwindows.
@type uistate: DisplayState
@param track: The window tracking mechanism used to manage windows.
This is only used to pass to generted child windows.
@type track: list
@param name: Notebook label name
@type name: str/unicode
@param widget: widget to be shown in the tab
@type widge: gtk widget
"""
GrampsTab.__init__(self, dbstate, uistate, track, name)
eventbox = gtk.EventBox()
eventbox.add(widget)
self.pack_start(eventbox)
self._set_label(show_image=False)
widget.connect('key_press_event', self.key_pressed)
self.show_all()
def is_empty(self):
"""
Override base class
"""
return False
#-------------------------------------------------------------------------
#
# EditReference class
#
#-------------------------------------------------------------------------
class EditReference(ManagedWindow.ManagedWindow, DbGUIElement):
def __init__(self, state, uistate, track, source, source_ref, update):
self.db = state.db
self.dbstate = state
self.uistate = uistate
self.source_ref = source_ref
self.source = source
self.source_added = False
self.update = update
self.warn_box = None
self.__tabs = []
ManagedWindow.ManagedWindow.__init__(self, uistate, track, source_ref)
DbGUIElement.__init__(self, self.db)
self._local_init()
self._set_size()
self._create_tabbed_pages()
self._setup_fields()
self._connect_signals()
self.show()
self._post_init()
def _local_init(self):
"""
Derived class should do any pre-window initalization in this task.
"""
pass
def define_warn_box(self,box):
self.warn_box = box
def enable_warnbox(self):
self.warn_box.show()
def define_expander(self,expander):
expander.set_expanded(True)
def _post_init(self):
"""
Derived class should do any post-window initalization in this task.
"""
pass
def _setup_notebook_tabs(self, notebook):
for child in notebook.get_children():
label = notebook.get_tab_label(child)
page_no = notebook.page_num(child)
label.drag_dest_set(0, [], 0)
label.connect('drag_motion',
self._switch_page_on_dnd,
notebook,
page_no)
child.set_parent_notebook(notebook)
notebook.connect('key-press-event', self.key_pressed, notebook)
def key_pressed(self, obj, event, notebook):
"""
Handles the key being pressed on the notebook, pass to key press of
current page.
"""
pag = notebook.get_current_page()
if not pag == -1:
notebook.get_nth_page(pag).key_pressed(obj, event)
def _switch_page_on_dnd(self, widget, context, x, y, time, notebook, page_no):
if notebook.get_current_page() != page_no:
notebook.set_current_page(page_no)
def _add_tab(self, notebook,page):
self.__tabs.append(page)
notebook.insert_page(page, page.get_tab_widget())
page.label.set_use_underline(True)
return page
def _connect_signals(self):
pass
def _setup_fields(self):
pass
def _create_tabbed_pages(self):
pass
def build_window_key(self,sourceref):
#the window key for managedwindow identification. No need to return None
if self.source and self.source.get_handle():
return self.source.get_handle()
else:
return id(self)
def define_ok_button(self, button, function):
button.connect('clicked',function)
button.set_sensitive(not self.db.readonly)
def define_cancel_button(self, button):
button.connect('clicked',self.close_and_cancel)
def close_and_cancel(self, obj):
self._cleanup_on_exit()
self.close(obj)
def check_for_close(self, handles):
"""
Callback method for delete signals.
If there is a delete signal of the primary object we are editing, the
editor (and all child windows spawned) should be closed
"""
if self.source.get_handle() in handles:
self.close()
def define_help_button(self, button, webpage='', section=''):
import GrampsDisplay
button.connect('clicked', lambda x: GrampsDisplay.help(webpage,
section))
button.set_sensitive(True)
def _cleanup_on_exit(self):
pass
def close(self,*obj):
self._cleanup_db_connects()
ManagedWindow.ManagedWindow.close(self)
def _cleanup_db_connects(self):
"""
All connects that happened to signals of the db must be removed on
closed. This implies two things:
1. The connects on the main view must be disconnected
2. Connects done in subelements must be disconnected
"""
#cleanup callbackmanager of this editor
self._cleanup_callbacks()
for tab in [tab for tab in self.__tabs if hasattr(tab, 'callman')]:
tab._cleanup_callbacks()

View File

@@ -0,0 +1,202 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# 2009 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$
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from gen.lib import NoteType
from DisplayTabs import NoteTab,AddrEmbedList,WebEmbedList,SourceBackRefList
from gui.widgets import MonitoredEntry, PrivacyButton, MonitoredDataType
from editreference import RefTab, EditReference
from glade import Glade
#-------------------------------------------------------------------------
#
# EditRepoRef class
#
#-------------------------------------------------------------------------
class EditRepoRef(EditReference):
def __init__(self, state, uistate, track, source, source_ref, update):
EditReference.__init__(self, state, uistate, track, source,
source_ref, update)
def _local_init(self):
self.width_key = 'interface.repo-ref-width'
self.height_key = 'interface.repo-ref-height'
self.top = Glade()
self.set_window(self.top.toplevel,
self.top.get_object('repo_title'),
_('Repository Reference Editor'))
self.define_warn_box(self.top.get_object("warn_box"))
self.define_expander(self.top.get_object("src_expander"))
tblref = self.top.get_object('table70')
notebook = self.top.get_object('notebook_ref')
#recreate start page as GrampsTab
notebook.remove_page(0)
self.reftab = RefTab(self.dbstate, self.uistate, self.track,
_('General'), tblref)
tblref = self.top.get_object('table69')
notebook = self.top.get_object('notebook_src')
#recreate start page as GrampsTab
notebook.remove_page(0)
self.primtab = RefTab(self.dbstate, self.uistate, self.track,
_('_General'), tblref)
def _connect_signals(self):
self.define_ok_button(self.top.get_object('ok'),self.ok_clicked)
self.define_cancel_button(self.top.get_object('cancel'))
def _connect_db_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self._add_db_signal('repository-rebuild', self.close)
self._add_db_signal('repository-delete', self.check_for_close)
def _setup_fields(self):
self.callno = MonitoredEntry(
self.top.get_object("call_number"),
self.source_ref.set_call_number,
self.source_ref.get_call_number,
self.db.readonly)
self.gid = MonitoredEntry(
self.top.get_object('gid'),
self.source.set_gramps_id,
self.source.get_gramps_id,
self.db.readonly)
self.privacy = PrivacyButton(
self.top.get_object("private"),
self.source,
self.db.readonly)
self.privacy = PrivacyButton(
self.top.get_object("private_ref"),
self.source_ref,
self.db.readonly)
self.title = MonitoredEntry(
self.top.get_object('repo_name'),
self.source.set_name,
self.source.get_name,
self.db.readonly)
self.type_selector = MonitoredDataType(
self.top.get_object("media_type"),
self.source_ref.set_media_type,
self.source_ref.get_media_type,
self.db.readonly,
self.db.get_source_media_types(),
)
self.media_type_selector = MonitoredDataType(
self.top.get_object("repo_type"),
self.source.set_type,
self.source.get_type,
self.db.readonly,
self.db.get_repository_types(),
)
def _create_tabbed_pages(self):
"""
Create the notebook tabs and inserts them into the main
window.
"""
notebook_src = self.top.get_object('notebook_src')
notebook_ref = self.top.get_object('notebook_ref')
self._add_tab(notebook_src, self.primtab)
self._add_tab(notebook_ref, self.reftab)
self.note_tab = self._add_tab(
notebook_src,
NoteTab(self.dbstate, self.uistate, self.track,
self.source.get_note_list(),
notetype=NoteType.REPO))
self.comment_tab = self._add_tab(
notebook_ref,
NoteTab(self.dbstate, self.uistate, self.track,
self.source_ref.get_note_list(),
notetype=NoteType.REPOREF))
self.address_tab = self._add_tab(
notebook_src,
AddrEmbedList(self.dbstate,self.uistate,self.track,
self.source.get_address_list()))
self.web_list = self._add_tab(
notebook_src,
WebEmbedList(self.dbstate,self.uistate,self.track,
self.source.get_url_list()))
self.backref_tab = self._add_tab(
notebook_src,
SourceBackRefList(self.dbstate, self.uistate, self.track,
self.db.find_backlink_handles(self.source.handle),
self.enable_warnbox))
self._setup_notebook_tabs( notebook_src)
self._setup_notebook_tabs( notebook_ref)
def build_menu_names(self,sourceref):
if self.source:
source_name = self.source.get_name()
submenu_label = _('Repository: %s') % source_name
else:
submenu_label = _('New Repository')
return (_('Repo Reference Editor'),submenu_label)
def ok_clicked(self, obj):
trans = self.db.transaction_begin()
if self.source.handle:
self.db.commit_repository(self.source,trans)
self.db.transaction_commit(trans,_("Modify Repository"))
else:
self.db.add_repository(self.source,trans)
self.db.transaction_commit(trans,_("Add Repository"))
self.source_ref.ref = self.source.handle
if self.update:
self.update((self.source_ref,self.source))
self.close()

View File

@@ -0,0 +1,215 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# Copyright (C) 2009 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$
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import gen.lib
from gui.widgets import MonitoredEntry, MonitoredDataType, PrivacyButton
from DisplayTabs import AddrEmbedList, WebEmbedList, NoteTab, SourceBackRefList
from editprimary import EditPrimary
from QuestionDialog import ErrorDialog
from glade import Glade
class EditRepository(EditPrimary):
def __init__(self, dbstate, uistate, track, repository):
EditPrimary.__init__(self, dbstate, uistate, track, repository,
dbstate.db.get_repository_from_handle,
dbstate.db.get_repository_from_gramps_id)
def empty_object(self):
return gen.lib.Repository()
def get_menu_title(self):
if self.obj.get_handle():
title = self.obj.get_name()
if title:
title = _('Repository') + ": " + title
else:
title = _('Repository')
else:
title = _('New Repository')
return title
def _local_init(self):
self.width_key = 'interface.repo-width'
self.height_key = 'interface.repo-height'
self.glade = Glade()
self.set_window(self.glade.toplevel, None,
self.get_menu_title())
def build_menu_names(self, source):
return (_('Edit Repository'), self.get_menu_title())
def _setup_fields(self):
self.name = MonitoredEntry(self.glade.get_object("repository_name"),
self.obj.set_name, self.obj.get_name,
self.db.readonly)
self.type = MonitoredDataType(self.glade.get_object("repository_type"),
self.obj.set_type, self.obj.get_type,
self.db.readonly,
self.db.get_repository_types(),
)
self.call_number = MonitoredEntry(self.glade.get_object('gid'),
self.obj.set_gramps_id,
self.obj.get_gramps_id,
self.db.readonly)
self.privacy = PrivacyButton(self.glade.get_object("private"),
self.obj, self.db.readonly)
def _create_tabbed_pages(self):
notebook = gtk.Notebook()
self.addr_tab = AddrEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj.get_address_list())
self._add_tab(notebook, self.addr_tab)
self.track_ref_for_deletion("addr_tab")
self.url_tab = WebEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj.get_url_list())
self._add_tab(notebook, self.url_tab)
self.track_ref_for_deletion("url_tab")
self.note_tab = NoteTab(self.dbstate,
self.uistate,
self.track,
self.obj.get_note_list(),
self.get_menu_title(),
notetype=gen.lib.NoteType.REPO)
self._add_tab(notebook, self.note_tab)
self.track_ref_for_deletion("note_tab")
self.backref_tab = SourceBackRefList(self.dbstate,
self.uistate,
self.track,
self.db.find_backlink_handles(self.obj.handle))
self.backref_list = self._add_tab(notebook, self.backref_tab)
self.track_ref_for_deletion("backref_tab")
self.track_ref_for_deletion("backref_list")
self._setup_notebook_tabs(notebook)
notebook.show_all()
self.glade.get_object("vbox").pack_start(notebook, True, True)
def _connect_signals(self):
self.define_help_button(self.glade.get_object('help'))
self.define_cancel_button(self.glade.get_object('cancel'))
self.define_ok_button(self.glade.get_object('ok'), self.save)
def _connect_db_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self._add_db_signal('repository-rebuild', self._do_close)
self._add_db_signal('repository-delete', self.check_for_close)
def save(self, *obj):
self.ok_button.set_sensitive(False)
if self.object_is_empty():
ErrorDialog(_("Cannot save repository"),
_("No data exists for this repository. Please "
"enter data or cancel the edit."))
self.ok_button.set_sensitive(True)
return
(uses_dupe_id, id) = self._uses_duplicate_id()
if uses_dupe_id:
prim_object = self.get_from_gramps_id(id)
name = prim_object.get_name()
msg1 = _("Cannot save repository. ID already exists.")
msg2 = _("You have attempted to use the existing Gramps ID with "
"value %(id)s. This value is already used by '"
"%(prim_object)s'. Please enter a different ID or leave "
"blank to get the next available ID value.") % {
'id' : id, 'prim_object' : name }
ErrorDialog(msg1, msg2)
self.ok_button.set_sensitive(True)
return
trans = self.db.transaction_begin()
if not self.obj.get_handle():
self.db.add_repository(self.obj, trans)
msg = _("Add Repository (%s)") % self.obj.get_name()
else:
if not self.obj.get_gramps_id():
self.obj.set_gramps_id(self.db.find_next_repository_gramps_id())
self.db.commit_repository(self.obj, trans)
msg = _("Edit Repository (%s)") % self.obj.get_name()
self.db.transaction_commit(trans, msg)
self.close()
def _cleanup_on_exit(self):
self.backref_list.close()
class DeleteRepositoryQuery(object):
def __init__(self, dbstate, uistate, repository, sources):
self.obj = repository
self.db = dbstate.db
self.uistate = uistate
self.sources = sources
def query_response(self):
trans = self.db.transaction_begin()
repos_handle_list = [self.obj.get_handle()]
for handle in self.sources:
source = self.db.get_source_from_handle(handle)
source.remove_repo_references(repos_handle_list)
self.db.commit_source(source, trans)
self.db.remove_repository(self.obj.get_handle(), trans)
self.db.transaction_commit(
trans, _("Delete Repository (%s)") % self.obj.get_name())

View File

@@ -0,0 +1,137 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# 2009 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$
import ManagedWindow
import GrampsDisplay
import config
from gui.dbguielement import DbGUIElement
class EditSecondary(ManagedWindow.ManagedWindow, DbGUIElement):
def __init__(self, state, uistate, track, obj, callback=None):
"""Create an edit window. Associates a person with the window."""
self.obj = obj
self.dbstate = state
self.uistate = uistate
self.db = state.db
self.callback = callback
self.__tabs = []
ManagedWindow.ManagedWindow.__init__(self, uistate, track, obj)
DbGUIElement.__init__(self, self.db)
self._local_init()
self._set_size()
self._create_tabbed_pages()
self._setup_fields()
self._connect_signals()
self.show()
self._post_init()
def _local_init(self):
"""
Derived class should do any pre-window initalization in this task.
"""
pass
def _post_init(self):
"""
Derived class should do any post-window initalization in this task.
"""
pass
def _connect_signals(self):
pass
def _setup_fields(self):
pass
def _create_tabbed_pages(self):
pass
def build_window_key(self, obj):
return id(obj)
def _setup_notebook_tabs(self, notebook):
for child in notebook.get_children():
label = notebook.get_tab_label(child)
page_no = notebook.page_num(child)
label.drag_dest_set(0, [], 0)
label.connect('drag_motion',
self._switch_page_on_dnd,
notebook,
page_no)
child.set_parent_notebook(notebook)
notebook.connect('key-press-event', self.key_pressed, notebook)
def key_pressed(self, obj, event, notebook):
"""
Handles the key being pressed on the notebook, pass to key press of
current page.
"""
pag = notebook.get_current_page()
if not pag == -1:
notebook.get_nth_page(pag).key_pressed(obj, event)
def _switch_page_on_dnd(self, widget, context, x, y, time, notebook, page_no):
if notebook.get_current_page() != page_no:
notebook.set_current_page(page_no)
def _add_tab(self, notebook,page):
self.__tabs.append(page)
notebook.insert_page(page, page.get_tab_widget())
page.label.set_use_underline(True)
return page
def _cleanup_on_exit(self):
pass
def define_ok_button(self,button,function):
button.connect('clicked',function)
button.set_sensitive(not self.db.readonly)
def define_cancel_button(self,button):
button.connect('clicked',self.close)
def define_help_button(self, button, webpage='', section=''):
button.connect('clicked', lambda x: GrampsDisplay.help(webpage,
section))
def close(self,*obj):
self._cleanup_db_connects()
self._cleanup_on_exit()
ManagedWindow.ManagedWindow.close(self)
def _cleanup_db_connects(self):
"""
All connects that happened to signals of the db must be removed on
closed. This implies two things:
1. The connects on the main view must be disconnected
2. Connects done in subelements must be disconnected
"""
#cleanup callbackmanager of this editor
self._cleanup_callbacks()
for tab in [tab for tab in self.__tabs if hasattr(tab, 'callman')]:
tab._cleanup_callbacks()

View File

@@ -0,0 +1,268 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# Copyright (C) 2009 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$
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
import logging
log = logging.getLogger(".")
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import gen.lib
from editprimary import EditPrimary
from DisplayTabs import (NoteTab, GalleryTab, DataEmbedList,
SourceBackRefList, RepoEmbedList)
from gui.widgets import MonitoredEntry, PrivacyButton
from QuestionDialog import ErrorDialog
from glade import Glade
#-------------------------------------------------------------------------
#
# EditSource class
#
#-------------------------------------------------------------------------
class EditSource(EditPrimary):
def __init__(self, dbstate, uistate, track, source):
EditPrimary.__init__(self, dbstate, uistate, track, source,
dbstate.db.get_source_from_handle,
dbstate.db.get_source_from_gramps_id)
def empty_object(self):
return gen.lib.Source()
def get_menu_title(self):
title = self.obj.get_title()
if title:
title = _('Source') + ": " + title
else:
title = _('New Source')
return title
def _local_init(self):
self.width_key = 'interface.source-width'
self.height_key = 'interface.source-height'
assert(self.obj)
self.glade = Glade()
self.set_window(self.glade.toplevel, None,
self.get_menu_title())
def _connect_signals(self):
self.define_ok_button(self.glade.get_object('ok'),self.save)
self.define_cancel_button(self.glade.get_object('cancel'))
self.define_help_button(self.glade.get_object('help'))
def _connect_db_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self._add_db_signal('source-rebuild', self._do_close)
self._add_db_signal('source-delete', self.check_for_close)
def _setup_fields(self):
self.author = MonitoredEntry(self.glade.get_object("author"),
self.obj.set_author, self.obj.get_author,
self.db.readonly)
self.pubinfo = MonitoredEntry(self.glade.get_object("pubinfo"),
self.obj.set_publication_info,
self.obj.get_publication_info,
self.db.readonly)
self.gid = MonitoredEntry(self.glade.get_object("gid"),
self.obj.set_gramps_id,
self.obj.get_gramps_id, self.db.readonly)
self.priv = PrivacyButton(self.glade.get_object("private"), self.obj,
self.db.readonly)
self.abbrev = MonitoredEntry(self.glade.get_object("abbrev"),
self.obj.set_abbreviation,
self.obj.get_abbreviation,
self.db.readonly)
self.title = MonitoredEntry(self.glade.get_object("source_title"),
self.obj.set_title, self.obj.get_title,
self.db.readonly)
def _create_tabbed_pages(self):
notebook = gtk.Notebook()
self.note_tab = NoteTab(self.dbstate,
self.uistate,
self.track,
self.obj.get_note_list(),
self.get_menu_title(),
gen.lib.NoteType.SOURCE)
self._add_tab(notebook, self.note_tab)
self.track_ref_for_deletion("note_tab")
self.gallery_tab = GalleryTab(self.dbstate,
self.uistate,
self.track,
self.obj.get_media_list())
self._add_tab(notebook, self.gallery_tab)
self.track_ref_for_deletion("gallery_tab")
self.data_tab = DataEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj)
self._add_tab(notebook, self.data_tab)
self.track_ref_for_deletion("data_tab")
self.repo_tab = RepoEmbedList(self.dbstate,
self.uistate,
self.track,
self.obj.get_reporef_list())
self._add_tab(notebook, self.repo_tab)
self.track_ref_for_deletion("repo_tab")
self.backref_list = SourceBackRefList(self.dbstate,
self.uistate,
self.track,
self.db.find_backlink_handles(self.obj.handle))
self.backref_tab = self._add_tab(notebook, self.backref_list)
self.track_ref_for_deletion("backref_tab")
self.track_ref_for_deletion("backref_list")
self._setup_notebook_tabs(notebook)
notebook.show_all()
self.glade.get_object('vbox').pack_start(notebook, True)
def build_menu_names(self, source):
return (_('Edit Source'), self.get_menu_title())
def save(self, *obj):
self.ok_button.set_sensitive(False)
if self.object_is_empty():
ErrorDialog(_("Cannot save source"),
_("No data exists for this source. Please "
"enter data or cancel the edit."))
self.ok_button.set_sensitive(True)
return
(uses_dupe_id, id) = self._uses_duplicate_id()
if uses_dupe_id:
prim_object = self.get_from_gramps_id(id)
name = prim_object.get_title()
msg1 = _("Cannot save source. ID already exists.")
msg2 = _("You have attempted to use the existing Gramps ID with "
"value %(id)s. This value is already used by '"
"%(prim_object)s'. Please enter a different ID or leave "
"blank to get the next available ID value.") % {
'id' : id, 'prim_object' : name }
ErrorDialog(msg1, msg2)
self.ok_button.set_sensitive(True)
return
trans = self.db.transaction_begin()
if not self.obj.get_handle():
self.db.add_source(self.obj, trans)
msg = _("Add Source (%s)") % self.obj.get_title()
else:
if not self.obj.get_gramps_id():
self.obj.set_gramps_id(self.db.find_next_source_gramps_id())
self.db.commit_source(self.obj, trans)
msg = _("Edit Source (%s)") % self.obj.get_title()
self.db.transaction_commit(trans, msg)
self.close()
def _cleanup_on_exit(self):
self.backref_tab.close()
class DeleteSrcQuery(object):
def __init__(self, dbstate, uistate, source, the_lists):
self.source = source
self.db = dbstate.db
self.uistate = uistate
self.the_lists = the_lists
def query_response(self):
trans = self.db.transaction_begin()
self.db.disable_signals()
(person_list, family_list, event_list, place_list, source_list,
media_list, repo_list) = self.the_lists
src_handle_list = [self.source.get_handle()]
for handle in person_list:
person = self.db.get_person_from_handle(handle)
person.remove_source_references(src_handle_list)
self.db.commit_person(person, trans)
for handle in family_list:
family = self.db.get_family_from_handle(handle)
family.remove_source_references(src_handle_list)
self.db.commit_family(family, trans)
for handle in event_list:
event = self.db.get_event_from_handle(handle)
event.remove_source_references(src_handle_list)
self.db.commit_event(event, trans)
for handle in place_list:
place = self.db.get_place_from_handle(handle)
place.remove_source_references(src_handle_list)
self.db.commit_place(place, trans)
for handle in source_list:
source = self.db.get_source_from_handle(handle)
source.remove_source_references(src_handle_list)
self.db.commit_source(source, trans)
for handle in media_list:
media = self.db.get_object_from_handle(handle)
media.remove_source_references(src_handle_list)
self.db.commit_media_object(media, trans)
for handle in repo_list:
repo = self.db.get_repository_from_handle(handle)
repo.remove_source_references(src_handle_list)
self.db.commit_repository(repo, trans)
self.db.enable_signals()
self.db.remove_source(self.source.get_handle(), trans)
self.db.transaction_commit(
trans, _("Delete Source (%s)") % self.source.get_title())

View File

@@ -0,0 +1,219 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# 2009 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$
#-------------------------------------------------------------------------
#
# Python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import gen.lib
from glade import Glade
from DisplayTabs import (NoteTab, GalleryTab, SourceBackRefList,
DataEmbedList, RepoEmbedList)
from gui.widgets import (PrivacyButton, MonitoredEntry, MonitoredMenu,
MonitoredDate)
from editreference import RefTab, EditReference
#-------------------------------------------------------------------------
#
# EditSourceRef class
#
#-------------------------------------------------------------------------
class EditSourceRef(EditReference):
def __init__(self, state, uistate, track, source, source_ref, update):
EditReference.__init__(self, state, uistate, track, source,
source_ref, update)
def _local_init(self):
self.width_key = 'interface.event-ref-width'
self.height_key = 'interface.event-ref-height'
self.top = Glade()
self.set_window(self.top.toplevel,
self.top.get_object('source_title'),
_('Source Reference Editor'))
self.define_warn_box(self.top.get_object("warn_box"))
self.define_expander(self.top.get_object("src_expander"))
tblref = self.top.get_object('table67')
notebook = self.top.get_object('notebook_ref')
#recreate start page as GrampsTab
notebook.remove_page(0)
self.reftab = RefTab(self.dbstate, self.uistate, self.track,
_('General'), tblref)
tblref = self.top.get_object('table68')
notebook = self.top.get_object('notebook_src')
#recreate start page as GrampsTab
notebook.remove_page(0)
self.primtab = RefTab(self.dbstate, self.uistate, self.track,
_('General'), tblref)
def _connect_signals(self):
self.define_ok_button(self.top.get_object('ok'),self.ok_clicked)
self.define_cancel_button(self.top.get_object('cancel'))
self.define_help_button(self.top.get_object("help"))
def _connect_db_signals(self):
"""
Connect any signals that need to be connected.
Called by the init routine of the base class (_EditPrimary).
"""
self._add_db_signal('source-rebuild', self.close)
self._add_db_signal('source-delete', self.check_for_close)
#note: at the moment, a source cannot be updated while an editor with
# that source shown is open. So no need to connect to source-update
def _setup_fields(self):
self.ref_privacy = PrivacyButton(
self.top.get_object('privacy'), self.source_ref, self.db.readonly)
self.volume = MonitoredEntry(
self.top.get_object("volume"), self.source_ref.set_page,
self.source_ref.get_page, self.db.readonly)
self.gid = MonitoredEntry(
self.top.get_object('gid'), self.source.set_gramps_id,
self.source.get_gramps_id,self.db.readonly)
self.source_privacy = PrivacyButton(
self.top.get_object("private"),
self.source, self.db.readonly)
self.title = MonitoredEntry(
self.top.get_object('title'),
self.source.set_title,
self.source.get_title,
self.db.readonly)
self.abbrev = MonitoredEntry(
self.top.get_object('abbrev'), self.source.set_abbreviation,
self.source.get_abbreviation,self.db.readonly)
self.author = MonitoredEntry(
self.top.get_object('author'), self.source.set_author,
self.source.get_author,self.db.readonly)
self.pubinfo = MonitoredEntry(
self.top.get_object('pub_info'), self.source.set_publication_info,
self.source.get_publication_info,self.db.readonly)
self.type_mon = MonitoredMenu(
self.top.get_object('confidence'),
self.source_ref.set_confidence_level,
self.source_ref.get_confidence_level, [
(_('Very Low'), gen.lib.SourceRef.CONF_VERY_LOW),
(_('Low'), gen.lib.SourceRef.CONF_LOW),
(_('Normal'), gen.lib.SourceRef.CONF_NORMAL),
(_('High'), gen.lib.SourceRef.CONF_HIGH),
(_('Very High'), gen.lib.SourceRef.CONF_VERY_HIGH)],
self.db.readonly)
self.date = MonitoredDate(
self.top.get_object("date_entry"),
self.top.get_object("date_stat"),
self.source_ref.get_date_object(),
self.uistate,
self.track,
self.db.readonly)
def _create_tabbed_pages(self):
"""
Create the notebook tabs and inserts them into the main
window.
"""
notebook_src = self.top.get_object('notebook_src')
notebook_ref = self.top.get_object('notebook_ref')
self._add_tab(notebook_src, self.primtab)
self._add_tab(notebook_ref, self.reftab)
self.note_tab = self._add_tab(
notebook_src,
NoteTab(self.dbstate, self.uistate, self.track,
self.source.get_note_list(),
notetype=gen.lib.NoteType.SOURCE))
self.gallery_tab = self._add_tab(
notebook_src,
GalleryTab(self.dbstate, self.uistate, self.track,
self.source.get_media_list()))
self.data_tab = self._add_tab(
notebook_src,
DataEmbedList(self.dbstate, self.uistate, self.track,
self.source))
self.repo_tab = self._add_tab(
notebook_src,
RepoEmbedList(self.dbstate, self.uistate, self.track,
self.source.get_reporef_list()))
self.srcref_list = self._add_tab(
notebook_src,
SourceBackRefList(self.dbstate,self.uistate, self.track,
self.db.find_backlink_handles(self.source.handle),
self.enable_warnbox
))
self.comment_tab = self._add_tab(
notebook_ref,
NoteTab(self.dbstate, self.uistate, self.track,
self.source_ref.get_note_list(),
notetype=gen.lib.NoteType.SOURCEREF))
self._setup_notebook_tabs( notebook_src)
self._setup_notebook_tabs( notebook_ref)
def build_menu_names(self,sourceref):
if self.source:
source_name = self.source.get_title()
submenu_label = _('Source: %s') % source_name
else:
submenu_label = _('New Source')
return (_('Source Reference Editor'),submenu_label)
def ok_clicked(self, obj):
trans = self.db.transaction_begin()
if self.source.handle:
self.db.commit_source(self.source,trans)
self.db.transaction_commit(trans,_("Modify Source"))
else:
self.db.add_source(self.source,trans)
self.db.transaction_commit(trans,_("Add Source"))
if self.update:
self.update(self.source_ref,self.source)
self.close()

View File

@@ -0,0 +1,96 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
# 2009 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$
#-------------------------------------------------------------------------
#
# python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
from editsecondary import EditSecondary
from gui.widgets import MonitoredEntry, PrivacyButton, MonitoredDataType
from glade import Glade
#-------------------------------------------------------------------------
#
# EditUrl class
#
#-------------------------------------------------------------------------
class EditUrl(EditSecondary):
def __init__(self, dbstate, uistate, track, name, url, callback):
EditSecondary.__init__(self, dbstate, uistate, track,
url, callback)
def _local_init(self):
self.width_key = 'interface.url-width'
self.height_key = 'interface.url-height'
self.top = Glade()
self.jump = self.top.get_object('jump')
self.set_window(self.top.toplevel,
self.top.get_object("title"),
_('Internet Address Editor'))
def _connect_signals(self):
self.jump.connect('clicked', self.jump_to)
self.define_cancel_button(self.top.get_object('button125'))
self.define_ok_button(self.top.get_object('button124'), self.save)
self.define_help_button(self.top.get_object('button130'))
def jump_to(self, obj):
if self.obj.get_path():
import GrampsDisplay
GrampsDisplay.url(self.obj.get_path())
def _setup_fields(self):
self.des = MonitoredEntry(self.top.get_object("url_des"),
self.obj.set_description,
self.obj.get_description, self.db.readonly)
self.addr = MonitoredEntry(self.top.get_object("url_addr"),
self.obj.set_path, self.obj.get_path,
self.db.readonly)
self.priv = PrivacyButton(self.top.get_object("priv"),
self.obj, self.db.readonly)
self.type_sel = MonitoredDataType(self.top.get_object("type"),
self.obj.set_type,
self.obj.get_type, self.db.readonly)
def build_menu_names(self, obj):
etitle =_('Internet Address Editor')
return (etitle, etitle)
def save(self,*obj):
self.callback(self.obj)
self.close()

View File

@@ -0,0 +1,412 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-2006 Donald N. Allingham
#
# 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$
#-------------------------------------------------------------------------
#
# Standard python modules
#
#-------------------------------------------------------------------------
from gettext import gettext as _
import cPickle as pickle
import logging
_LOG = logging.getLogger(".objectentries")
#-------------------------------------------------------------------------
#
# GTK/Gnome modules
#
#-------------------------------------------------------------------------
import gtk
from pango import ELLIPSIZE_END
#-------------------------------------------------------------------------
#
# Gramps modules
#
#-------------------------------------------------------------------------
from gen.lib import (Place, MediaObject, Note)
from editplace import EditPlace
from editmedia import EditMedia
from editnote import EditNote
from gui.selectors import SelectorFactory
from DdTargets import DdTargets
from Errors import WindowActiveError
#-------------------------------------------------------------------------
#
# ObjEntry
#
#-------------------------------------------------------------------------
class ObjEntry(object):
"""
Handles the selection of a existing or new Object. Supports Drag and Drop
to select the object.
This is the base class to create a real entry
"""
EMPTY_TEXT = ""
EMPTY_TEXT_RED = ""
EDIT_STR = ""
SHARE_STR = ""
ADD_STR = ""
DEL_STR = ""
def __init__(self, dbstate, uistate, track, label, set_val,
get_val, add_edt, share):
"""Pass the dbstate and uistate and present track.
label is a gtk.Label that shows the persent value
set_val is function that is called when handle changes, use it
to update the calling module
get_val is function that is called to obtain handle from calling
module
share is the gtk.Button to call the object selector or del connect
add_edt is the gtk.Button with add or edit value. Pass None if
this button should not be present.
"""
self.label = label
self.add_edt = add_edt
self.share = share
self.dbstate = dbstate
self.db = dbstate.db
self.get_val = get_val
self.set_val = set_val
self.uistate = uistate
self.track = track
#connect drag and drop
self._init_dnd()
#set the object specific code
self._init_object()
#check if valid object:
handle = self.get_val()
if handle:
obj = self.get_from_handle(handle)
if not obj:
#invalid val, set it to None
self.set_val(None)
if self.get_val():
self.set_button(True)
obj = self.get_from_handle(self.get_val())
name = self.get_label(obj)
else:
name = u""
self.set_button(False)
if self.db.readonly:
if self.add_edt is not None:
self.add_edt.set_sensitive(False)
self.share.set_sensitive(False)
else:
if self.add_edt is not None:
self.add_edt.set_sensitive(True)
self.share.set_sensitive(True)
if self.add_edt is not None:
self.add_edt.connect('clicked', self.add_edt_clicked)
self.share.connect('clicked', self.share_clicked)
if not self.db.readonly and not name:
if self.add_edt is None:
self.label.set_text(self.EMPTY_TEXT_RED)
else:
self.label.set_text(self.EMPTY_TEXT)
self.label.set_use_markup(True)
else:
self.label.set_text(name)
self.label.set_ellipsize(ELLIPSIZE_END)
def _init_dnd(self):
"""inheriting objects must set this
"""
pass
def _init_object(self):
"""inheriting objects can use this to set extra variables
"""
pass
def get_from_handle(self, handle):
""" return the object given the hande
inheriting objects must set this
"""
pass
def get_label(self, object):
""" return the label
inheriting objects must set this
"""
pass
def after_edit(self, obj):
name = self.get_label(obj)
self.label.set_text(name)
def add_edt_clicked(self, obj):
""" if value, edit, if no value, call editor on new object
"""
if self.get_val():
obj = self.get_from_handle(self.get_val())
self.call_editor(obj)
else:
self.call_editor()
def call_editor(self, obj):
"""inheriting objects must set this
"""
pass
def call_selector(self):
"""inheriting objects must set this
"""
pass
def drag_data_received(self, widget, context, x, y, selection, info, time):
(drag_type, idval, obj, val) = pickle.loads(selection.data)
data = self.db.get_place_from_handle(obj)
self.obj_added(data)
def obj_added(self, data):
""" callback from adding an object to the entry"""
self.set_val(data.handle)
self.label.set_text(self.get_label(data))
self.set_button(True)
def share_clicked(self, obj):
""" if value, delete connect, in no value, select existing object
"""
if self.get_val():
self.set_val(None)
self.label.set_text(self.EMPTY_TEXT)
self.label.set_use_markup(True)
self.set_button(False)
else:
select = self.call_selector()
obj = select.run()
if obj:
self.obj_added(obj)
def set_button(self, use_add):
""" This sets the correct image to the two buttons.
If False: select icon and add icon
If True: remove icon and edit icon
"""
if self.add_edt is not None:
for i in self.add_edt.get_children():
self.add_edt.remove(i)
for i in self.share.get_children():
self.share.remove(i)
if use_add:
image = gtk.Image()
image.set_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_BUTTON)
image.show()
self.share.add(image)
self.share.set_tooltip_text(self.DEL_STR)
if self.add_edt is not None:
image = gtk.Image()
image.set_from_stock(gtk.STOCK_EDIT, gtk.ICON_SIZE_BUTTON)
image.show()
self.add_edt.add(image)
self.add_edt.set_tooltip_text(self.EDIT_STR)
else:
image = gtk.Image()
image.set_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON)
image.show()
self.share.add(image)
self.share.set_tooltip_text(self.SHARE_STR)
if self.add_edt is not None:
image = gtk.Image()
image.set_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_BUTTON)
image.show()
self.add_edt.add(image)
self.add_edt.set_tooltip_text(self.ADD_STR)
class PlaceEntry(ObjEntry):
"""
Handles the selection of a existing or new Place. Supports Drag and Drop
to select a place.
"""
EMPTY_TEXT = "<i>%s</i>" % _('To select a place, use drag-and-drop '
'or use the buttons')
EMPTY_TEXT_RED = "<i>%s</i>" % _('No place given, click button to select one')
EDIT_STR = _('Edit place')
SHARE_STR = _('Select an existing place')
ADD_STR = _('Add a new place')
DEL_STR = _('Remove place')
def __init__(self, dbstate, uistate, track, label, set_val,
get_val, add_edt, share):
ObjEntry.__init__(self, dbstate, uistate, track, label, set_val,
get_val, add_edt, share)
def _init_dnd(self):
"""connect drag and drop of places
"""
self.label.drag_dest_set(gtk.DEST_DEFAULT_ALL, [DdTargets.PLACE_LINK.target()],
gtk.gdk.ACTION_COPY)
self.label.connect('drag_data_received', self.drag_data_received)
def get_from_handle(self, handle):
""" return the object given the hande
"""
return self.db.get_place_from_handle(handle)
def get_label(self, place):
return "%s [%s]" % (place.get_title(), place.gramps_id)
def call_editor(self, obj=None):
if obj is None:
place = Place()
func = self.obj_added
else:
place = obj
func = self.after_edit
try:
EditPlace(self.dbstate, self.uistate, self.track,
place, func)
except WindowActiveError:
pass
def call_selector(self):
cls = SelectorFactory('Place')
return cls(self.dbstate, self.uistate, self.track)
# FIXME isn't used anywhere
class MediaEntry(ObjEntry):
"""
Handles the selection of a existing or new media. Supports Drag and Drop
to select a media object.
"""
EMPTY_TEXT = "<i>%s</i>" % _('To select a media object, use drag-and-drop '
'or use the buttons')
EMPTY_TEXT_RED = "<i>%s</i>" % _('No image given, click button to select one')
EDIT_STR = _('Edit media object')
SHARE_STR = _('Select an existing media object')
ADD_STR = _('Add a new media object')
DEL_STR = _('Remove media object')
def __init__(self, dbstate, uistate, track, label, set_val,
get_val, add_edt, share):
ObjEntry.__init__(self, dbstate, uistate, track, label, set_val,
get_val, add_edt, share)
def _init_dnd(self):
"""connect drag and drop of places
"""
self.label.drag_dest_set(gtk.DEST_DEFAULT_ALL, [DdTargets.MEDIAOBJ.target()],
gtk.gdk.ACTION_COPY)
self.label.connect('drag_data_received', self.drag_data_received)
def get_from_handle(self, handle):
""" return the object given the hande
"""
return self.db.get_object_from_handle(handle)
def get_label(self, object):
return "%s [%s]" % (object.get_description(), object.gramps_id)
def call_editor(self, obj=None):
if obj is None:
object = MediaObject()
func = self.obj_added
else:
object = obj
func = self.after_edit
try:
EditMedia(self.dbstate, self.uistate, self.track,
object, func)
except WindowActiveError:
pass
def call_selector(self):
cls = SelectorFactory('MediaObject')
return cls(self.dbstate, self.uistate, self.track)
# FIXME isn't used anywhere
class NoteEntry(ObjEntry):
"""
Handles the selection of a existing or new Note. Supports Drag and Drop
to select a Note.
"""
EMPTY_TEXT = "<i>%s</i>" % _('To select a note, use drag-and-drop '
'or use the buttons')
EMPTY_TEXT_RED = "<i>%s</i>" % _('No note given, click button to select one')
EDIT_STR = _('Edit Note')
SHARE_STR = _('Select an existing note')
ADD_STR = _('Add a new note')
DEL_STR = _('Remove note')
def __init__(self, dbstate, uistate, track, label, set_val,
get_val, add_edt, share):
ObjEntry.__init__(self, dbstate, uistate, track, label, set_val,
get_val, add_edt, share)
self.notetype = None
def set_notetype(self, type):
""" set a notetype to use in new notes
"""
self.notetype = type
def get_notetype(self):
""" return the set notetype
"""
return self.notetype
def _init_dnd(self):
"""connect drag and drop of places
"""
self.label.drag_dest_set(gtk.DEST_DEFAULT_ALL, [DdTargets.NOTE_LINK.target()],
gtk.gdk.ACTION_COPY)
self.label.connect('drag_data_received', self.drag_data_received)
def get_from_handle(self, handle):
""" return the object given the hande
"""
return self.db.get_note_from_handle(handle)
def get_label(self, note):
txt = " ".join(note.get().split())
#String must be unicode for truncation to work for non ascii characters
txt = unicode(txt)
if len(txt) > 35:
txt = txt[:35] + "..."
return "%s [%s]" % (txt, note.gramps_id)
def call_editor(self, obj=None):
if obj is None:
note = Note()
note.set_type(self.get_notetype())
func = self.obj_added
else:
note = obj
func = self.after_edit
try:
EditNote(self.dbstate, self.uistate, self.track,
note, func)
except WindowActiveError:
pass
def call_selector(self):
cls = SelectorFactory('Note')
return cls(self.dbstate, self.uistate, self.track)

View File

@@ -52,7 +52,7 @@ import config
from QuestionDialog import ErrorDialog
from gui.pluginmanager import GuiPluginManager
from DdTargets import DdTargets
from Editors import EditPlace, DeletePlaceQuery
from gui.editors import EditPlace, DeletePlaceQuery
from Filters.SideBar import PlaceSidebarFilter
#-------------------------------------------------------------------------

View File

@@ -37,4 +37,4 @@ from toolcomboentry import *
from validatedcomboentry import *
from validatedmaskedentry import *
from valueaction import *
from valuetoolitem import *
from valuetoolitem import *