Add Place Details, Repository Details and Media Preview gramplets

svn: r16717
This commit is contained in:
Nick Hall 2011-02-25 22:03:41 +00:00
parent 1d66e9e3cf
commit b74edfca2d
12 changed files with 395 additions and 163 deletions

View File

@ -269,8 +269,10 @@ src/plugins/gramplet/Notes.py
src/plugins/gramplet/PedigreeGramplet.py
src/plugins/gramplet/PersonDetails.py
src/plugins/gramplet/PersonResidence.py
src/plugins/gramplet/PlaceDetails.py
src/plugins/gramplet/QuickViewGramplet.py
src/plugins/gramplet/RelativeGramplet.py
src/plugins/gramplet/RepositoryDetails.py
src/plugins/gramplet/SessionLogGramplet.py
src/plugins/gramplet/Sources.py
src/plugins/gramplet/StatsGramplet.py

View File

@ -294,6 +294,7 @@ src/plugins/tool/phpgedview.glade
# plugins/gramplet directory
src/plugins/gramplet/DeepConnections.py
src/plugins/gramplet/HeadlineNewsGramplet.py
src/plugins/gramplet/MediaPreview.py
src/plugins/gramplet/NoteGramplet.py
src/plugins/gramplet/Gallery.py
src/plugins/gramplet/PluginManagerGramplet.py

View File

@ -19,8 +19,8 @@
# $Id$
#
from gui.utils import open_file_with_default_application
from gen.plug import Gramplet
from gui.widgets import Photo
import Utils
import gtk
@ -37,9 +37,6 @@ class Gallery(Gramplet):
"""
Build the GUI interface.
"""
tip = _('Double-click on a picture to view it in the default image '
'viewer application.')
self.set_tooltip(tip)
self.image_list = []
self.top = gtk.HBox(False, 3)
return self.top
@ -57,59 +54,18 @@ class Gallery(Gramplet):
Load the primary image into the main form if it exists.
"""
media_list = obj.get_media_list()
for photo in media_list:
object_handle = photo.get_reference_handle()
for media_ref in media_list:
object_handle = media_ref.get_reference_handle()
obj = self.dbstate.db.get_object_from_handle(object_handle)
full_path = Utils.media_path_full(self.dbstate.db, obj.get_path())
mime_type = obj.get_mime_type()
if mime_type and mime_type.startswith("image"):
pb = self.get_pixbuf(full_path, photo.get_rectangle())
eb = gtk.EventBox()
eb.connect('button-press-event', self.display_image, full_path)
image = gtk.Image()
eb.add(image)
self.image_list.append(eb)
image.set_from_pixbuf(pb)
self.top.pack_start(eb, expand=False, fill=False)
photo = Photo(180.0)
photo.set_image(full_path, media_ref.get_rectangle())
self.image_list.append(photo)
self.top.pack_start(photo, expand=False, fill=False)
self.top.show_all()
def display_image(self, widget, event, path):
"""
Display the image with the default application.
"""
if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
open_file_with_default_application(path)
def get_pixbuf(self, path, rectangle=None):
"""
Load, scale and display the person's main photo from the path.
"""
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(180.0)/ratio
x = int(scale*(i.get_width()))
y = int(scale*(i.get_height()))
i = i.scale_simple(x, y, gtk.gdk.INTERP_BILINEAR)
return i
except:
return None
class PersonGallery(Gallery):
"""
Displays a gallery of media objects for a person.

View File

@ -20,13 +20,16 @@ pkgdata_PYTHON = \
Gallery.py \
GivenNameGramplet.py \
gramplet.gpr.py \
MediaPreview.py \
Notes.py \
PedigreeGramplet.py \
PersonDetails.py \
PersonResidence.py \
PlaceDetails.py \
PluginManagerGramplet.py\
QuickViewGramplet.py \
RelativeGramplet.py \
RepositoryDetails.py \
SessionLogGramplet.py \
Sources.py \
StatsGramplet.py \

View File

@ -0,0 +1,70 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2011 Nick Hall
#
# 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$
#
from gen.plug import Gramplet
from gui.widgets import Photo
import Utils
import gtk
class MediaPreview(Gramplet):
"""
Displays a preview of the media object.
"""
def init(self):
self.gui.WIDGET = self.build_gui()
self.gui.get_container_widget().remove(self.gui.textview)
self.gui.get_container_widget().add_with_viewport(self.gui.WIDGET)
def build_gui(self):
"""
Build the GUI interface.
"""
self.top = gtk.HBox()
self.photo = Photo(190.0)
self.top.pack_start(self.photo, fill=True, expand=False, padding=5)
self.top.show_all()
return self.top
def db_changed(self):
self.dbstate.db.connect('media-update', self.update)
self.connect_signal('Media', self.update)
self.update()
def main(self):
active_handle = self.get_active('Media')
media = self.dbstate.db.get_object_from_handle(active_handle)
self.top.hide()
if media:
self.load_image(media)
else:
self.photo.set_image(None)
self.top.show()
def load_image(self, media):
"""
Load the primary image if it exists.
"""
full_path = Utils.media_path_full(self.dbstate.db, media.get_path())
mime_type = media.get_mime_type()
if mime_type and mime_type.startswith("image"):
self.photo.set_image(full_path)
else:
self.photo.set_image(None)

View File

@ -21,6 +21,7 @@
from gen.lib import EventType, EventRoleType
from gen.plug import Gramplet
from gui.widgets import Photo
from gen.display.name import displayer as name_displayer
from gen.ggettext import gettext as _
import DateHandler
@ -46,11 +47,12 @@ class PersonDetails(Gramplet):
self.load_rect = None
self.top = gtk.HBox()
vbox = gtk.VBox()
self.obj_photo = gtk.Image()
self.photo = Photo(190.0)
self.photo.show()
self.name = gtk.Label()
self.name.set_alignment(0, 0)
self.name.modify_font(pango.FontDescription('sans bold 12'))
vbox.pack_start(self.name, fill=True, expand=False, padding=10)
vbox.pack_start(self.name, fill=True, expand=False, padding=7)
table = gtk.Table(2, 2)
self.father = self.make_row(table, 0, _('Father'))
self.mother = self.make_row(table, 1, _('Mother'))
@ -65,7 +67,7 @@ class PersonDetails(Gramplet):
self.occupation = self.make_row(table, 0, _('Occupation'))
vbox.pack_start(table, fill=True, expand=False, padding=5)
vbox.show_all()
self.top.pack_start(self.obj_photo, fill=True, expand=False, padding=5)
self.top.pack_start(self.photo, fill=True, expand=False, padding=5)
self.top.pack_start(vbox, fill=True, expand=True, padding=10)
return self.top
@ -116,7 +118,7 @@ class PersonDetails(Gramplet):
"""
Display empty details when no person is selected.
"""
self.load_photo(None)
self.photo.set_image(None)
self.name.set_text(_('No active person'))
self.father[1].set_text(_('Unknown'))
self.mother[1].set_text(_('Unknown'))
@ -206,53 +208,14 @@ class PersonDetails(Gramplet):
"""
media_list = person.get_media_list()
if media_list:
photo = media_list[0]
object_handle = photo.get_reference_handle()
media_ref = media_list[0]
object_handle = media_ref.get_reference_handle()
obj = self.dbstate.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)
mime_type = obj.get_mime_type()
if mime_type and mime_type.startswith("image"):
self.photo.set_image(full_path, media_ref.get_rectangle())
else:
self.photo.set_image(None)
else:
self.load_photo(None)
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(190.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()
self.photo.set_image(None)

View File

@ -0,0 +1,135 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2011 Nick Hall
#
# 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$
#
from gen.plug import Gramplet
from gui.widgets import LocationBox, Photo
from gen.ggettext import gettext as _
from PlaceUtils import conv_lat_lon
import Utils
import gtk
import pango
class PlaceDetails(Gramplet):
"""
Displays details for a place.
"""
def init(self):
self.gui.WIDGET = self.build_gui()
self.gui.get_container_widget().remove(self.gui.textview)
self.gui.get_container_widget().add_with_viewport(self.gui.WIDGET)
def build_gui(self):
"""
Build the GUI interface.
"""
self.top = gtk.HBox()
vbox = gtk.VBox()
self.photo = Photo(190.0)
self.title = gtk.Label()
self.title.set_alignment(0, 0)
self.title.modify_font(pango.FontDescription('sans bold 12'))
vbox.pack_start(self.title, fill=True, expand=False, padding=7)
table = gtk.Table(4, 2)
self.location = LocationBox()
label = gtk.Label(_('Location') + ':')
label.set_alignment(1, 0)
table.attach(label, 0, 1, 0, 1, xoptions=gtk.FILL, xpadding=10)
table.attach(self.location, 1, 2, 0, 1, xoptions=gtk.FILL)
table.attach(gtk.Label(), 0, 1, 1, 2, xoptions=gtk.FILL)
self.latitude = self.make_row(table, 2, _('Latitude'))
self.longitude = self.make_row(table, 3, _('Longitude'))
vbox.pack_start(table, fill=True, expand=False)
self.top.pack_start(self.photo, fill=True, expand=False, padding=5)
self.top.pack_start(vbox, fill=True, expand=False, padding=10)
self.top.show_all()
return self.top
def make_row(self, table, row, title):
"""
Make a row in a table.
"""
label = gtk.Label(title + ':')
label.set_alignment(1, 0)
widget = gtk.Label()
widget.set_alignment(0, 0)
table.attach(label, 0, 1, row, row + 1, xoptions=gtk.FILL, xpadding=10)
table.attach(widget, 1, 2, row, row + 1)
return (label, widget)
def db_changed(self):
self.dbstate.db.connect('place-update', self.update)
self.connect_signal('Place', self.update)
self.update()
def main(self):
active_handle = self.get_active('Place')
place = self.dbstate.db.get_place_from_handle(active_handle)
self.top.hide()
if place:
self.display_place(place)
else:
self.display_empty()
self.top.show()
def display_place(self, place):
"""
Display details of the active place.
"""
self.load_place_image(place)
self.title.set_text(place.get_title())
self.location.set_location(place.get_main_location())
lat, lon = conv_lat_lon(place.get_latitude(),
place.get_longitude(),
format='DEG')
self.latitude[1].set_text('')
self.longitude[1].set_text('')
if lat:
self.latitude[1].set_text(lat)
if lon:
self.longitude[1].set_text(lon)
def display_empty(self):
"""
Display empty details when no repository is selected.
"""
self.photo.set_image(None)
self.title.set_text('')
self.location.set_location(None)
self.latitude[1].set_text('')
self.longitude[1].set_text('')
def load_place_image(self, place):
"""
Load the primary image if it exists.
"""
media_list = place.get_media_list()
if media_list:
media_ref = media_list[0]
object_handle = media_ref.get_reference_handle()
obj = self.dbstate.db.get_object_from_handle(object_handle)
full_path = Utils.media_path_full(self.dbstate.db, obj.get_path())
mime_type = obj.get_mime_type()
if mime_type and mime_type.startswith("image"):
self.photo.set_image(full_path, media_ref.get_rectangle())
else:
self.photo.set_image(None)
else:
self.photo.set_image(None)

View File

@ -0,0 +1,118 @@
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2011 Nick Hall
#
# 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$
#
from gen.lib import UrlType
from gen.plug import Gramplet
from gui.widgets import LocationBox
from gen.ggettext import gettext as _
import gtk
import pango
class RepositoryDetails(Gramplet):
"""
Displays details for a repository.
"""
def init(self):
self.gui.WIDGET = self.build_gui()
self.gui.get_container_widget().remove(self.gui.textview)
self.gui.get_container_widget().add_with_viewport(self.gui.WIDGET)
def build_gui(self):
"""
Build the GUI interface.
"""
self.top = gtk.HBox()
vbox = gtk.VBox()
self.name = gtk.Label()
self.name.set_alignment(0, 0)
self.name.modify_font(pango.FontDescription('sans bold 12'))
vbox.pack_start(self.name, fill=True, expand=False, padding=7)
table = gtk.Table(4, 2)
self.address = LocationBox()
label = gtk.Label(_('Address') + ':')
label.set_alignment(1, 0)
table.attach(label, 0, 1, 0, 1, xoptions=gtk.FILL, xpadding=10)
table.attach(self.address, 1, 2, 0, 1, xoptions=gtk.FILL)
self.phone = self.make_row(table, 1, _('Phone'))
self.email = self.make_row(table, 2, _('Email'))
self.web = self.make_row(table, 3, _('Web'))
vbox.pack_start(table, fill=True, expand=False)
self.top.pack_start(vbox, fill=True, expand=False, padding=10)
self.top.show_all()
return self.top
def make_row(self, table, row, title):
"""
Make a row in a table.
"""
label = gtk.Label(title + ':')
label.set_alignment(1, 0)
widget = gtk.Label()
widget.set_alignment(0, 0)
table.attach(label, 0, 1, row, row + 1, xoptions=gtk.FILL, xpadding=10)
table.attach(widget, 1, 2, row, row + 1)
return (label, widget)
def db_changed(self):
self.dbstate.db.connect('repository-update', self.update)
self.connect_signal('Repository', self.update)
self.update()
def main(self):
active_handle = self.get_active('Repository')
repo = self.dbstate.db.get_repository_from_handle(active_handle)
self.top.hide()
if repo:
self.display_repo(repo)
else:
self.display_empty()
self.top.show()
def display_repo(self, repo):
"""
Display details of the active repository.
"""
self.name.set_text(repo.get_name())
address_list = repo.get_address_list()
if len(address_list) > 0:
self.address.set_location(address_list[0])
self.phone[1].set_text(address_list[0].get_phone())
else:
self.address.set_location(None)
self.phone[1].set_text('')
self.email[1].set_text('')
self.web[1].set_text('')
for url in repo.get_url_list():
if int(url.get_type()) == UrlType.EMAIL:
self.email[1].set_text(url.get_path())
if int(url.get_type()) == UrlType.WEB_HOME:
self.web[1].set_text(url.get_path())
def display_empty(self):
"""
Display empty details when no repository is selected.
"""
self.name.set_text('')
self.address.set_location(None)
self.phone[1].set_text('')
self.email[1].set_text('')
self.web[1].set_text('')

View File

@ -38,6 +38,45 @@ register(GRAMPLET,
gramplet_title=_("Details"),
)
register(GRAMPLET,
id="Repository Details Gramplet",
name=_("Repository Details Gramplet"),
description = _("Gramplet showing details of a repository"),
version="1.0.0",
gramps_target_version="3.3",
status = STABLE,
fname="RepositoryDetails.py",
height=200,
gramplet = 'RepositoryDetails',
gramplet_title=_("Details"),
)
register(GRAMPLET,
id="Place Details Gramplet",
name=_("Place Details Gramplet"),
description = _("Gramplet showing details of a place"),
version="1.0.0",
gramps_target_version="3.3",
status = STABLE,
fname="PlaceDetails.py",
height=200,
gramplet = 'PlaceDetails',
gramplet_title=_("Details"),
)
register(GRAMPLET,
id="Media Preview Gramplet",
name=_("Media Preview Gramplet"),
description = _("Gramplet showing a preview of a media object"),
version="1.0.0",
gramps_target_version="3.3",
status = STABLE,
fname="MediaPreview.py",
height=200,
gramplet = 'MediaPreview',
gramplet_title=_("Preview"),
)
register(GRAMPLET,
id="Person Residence Gramplet",
name=_("Person Residence Gramplet"),

View File

@ -425,7 +425,8 @@ class PlaceBaseView(ListView):
Define the default gramplets for the sidebar and bottombar.
"""
return (("Place Filter Gramplet",),
("Place Gallery Gramplet",
("Place Details Gramplet",
"Place Gallery Gramplet",
"Place Sources Gramplet",
"Place Notes Gramplet"))

View File

@ -278,64 +278,6 @@ class MediaView(ListView):
"""
return 'gramps-media'
def build_widget(self):
"""
Builds the View from GTK components
"""
base = ListView.build_widget(self)
vbox = gtk.VBox()
vbox.set_border_width(0)
vbox.set_spacing(4)
self.image = gtk.Image()
self.image.set_size_request(int(const.THUMBSCALE),
int(const.THUMBSCALE))
ebox = gtk.EventBox()
ebox.add(self.image)
ebox.connect('button-press-event', self.button_press_event)
ebox.set_tooltip_text(
_('Double click image to view in an external viewer'))
vbox.pack_start(ebox, False)
vbox.pack_start(base, True)
self.selection.connect('changed', self.row_change)
self._set_dnd()
return vbox
def button_press_event(self, obj, event):
"""
Event handler that catches a double click, and and launches a viewer for
the selected object.
"""
if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
self.view_media(obj)
def row_update(self, obj):
"""
Update the data in the row. we override this because the Media View adds
additional functionality to the normal List View. The Media View may
have to update the thumbnail image. So, we call the parent task to
handle the normal operation, then call row_change to make sure that
the thumbnail is updated properly if needed.
"""
ListView.row_update(self, obj)
if self.active:
self.row_change(obj)
def row_change(self, obj):
"""
Update the thumbnail on a row change. If nothing is selected, clear
the thumbnail image.
"""
handle = self.first_selected()
if not handle:
self.image.clear()
else:
obj = self.dbstate.db.get_object_from_handle(handle)
pix = ThumbNails.get_thumbnail_image(
Utils.media_path_full(self.dbstate.db, obj.get_path()))
self.image.set_from_pixbuf(pix)
def additional_ui(self):
"""
Return the UIManager XML description of the menus
@ -493,6 +435,7 @@ class MediaView(ListView):
Define the default gramplets for the sidebar and bottombar.
"""
return (("Media Filter Gramplet",),
("Media Sources Gramplet",
("Media Preview Gramplet",
"Media Sources Gramplet",
"Media Notes Gramplet",
"Media Attributes Gramplet"))

View File

@ -274,4 +274,5 @@ class RepositoryView(ListView):
Define the default gramplets for the sidebar and bottombar.
"""
return (("Repository Filter Gramplet",),
("Repository Notes Gramplet",))
("Repository Details Gramplet",
"Repository Notes Gramplet"))