4881: Convert bottombar gramplets to use the thumbnailer

svn: r17399
This commit is contained in:
Nick Hall 2011-05-03 21:32:32 +00:00
parent b5b49c440f
commit 7b88401b1d
8 changed files with 65 additions and 81 deletions

View File

@ -61,6 +61,14 @@ try:
except ImportError: except ImportError:
GCONF = False GCONF = False
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
SIZE_NORMAL = 0
SIZE_LARGE = 1
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# __get_gconf_string # __get_gconf_string
@ -108,7 +116,7 @@ def __get_gconf_bool(key):
# __build_thumb_path # __build_thumb_path
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
def __build_thumb_path(path, rectangle=None): def __build_thumb_path(path, rectangle=None, size=SIZE_NORMAL):
""" """
Convert the specified path into a corresponding path for the thumbnail Convert the specified path into a corresponding path for the thumbnail
image. We do this by converting the original path into an MD5SUM value image. We do this by converting the original path into an MD5SUM value
@ -126,14 +134,19 @@ def __build_thumb_path(path, rectangle=None):
if rectangle is not None: if rectangle is not None:
extra = "?" + str(rectangle) extra = "?" + str(rectangle)
md5_hash = md5(path+extra) md5_hash = md5(path+extra)
return os.path.join(const.THUMB_DIR, md5_hash.hexdigest()+'.png') if size == SIZE_LARGE:
base_dir = const.THUMB_LARGE
else:
base_dir = const.THUMB_NORMAL
return os.path.join(base_dir, md5_hash.hexdigest()+'.png')
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# __create_thumbnail_image # __create_thumbnail_image
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
def __create_thumbnail_image(src_file, mtype=None, rectangle=None): def __create_thumbnail_image(src_file, mtype=None, rectangle=None,
size=SIZE_NORMAL):
""" """
Generates the thumbnail image for a file. If the mime type is specified, Generates the thumbnail image for a file. If the mime type is specified,
and is not an 'image', then we attempt to find and run a thumbnailer and is not an 'image', then we attempt to find and run a thumbnailer
@ -147,7 +160,7 @@ def __create_thumbnail_image(src_file, mtype=None, rectangle=None):
:param rectangle: subsection rectangle :param rectangle: subsection rectangle
:type rectangle: tuple :type rectangle: tuple
""" """
filename = __build_thumb_path(src_file, rectangle) filename = __build_thumb_path(src_file, rectangle, size)
if mtype and not mtype.startswith('image/'): if mtype and not mtype.startswith('image/'):
# Not an image, so run the thumbnailer # Not an image, so run the thumbnailer
@ -174,7 +187,11 @@ def __create_thumbnail_image(src_file, mtype=None, rectangle=None):
width = sub_width width = sub_width
height = sub_height height = sub_height
scale = const.THUMBSCALE / (float(max(width, height))) if size == SIZE_LARGE:
thumbscale = const.THUMBSCALE_LARGE
else:
thumbscale = const.THUMBSCALE
scale = thumbscale / (float(max(width, height)))
scaled_width = int(width * scale) scaled_width = int(width * scale)
scaled_height = int(height * scale) scaled_height = int(height * scale)
@ -213,7 +230,7 @@ def find_mime_type_pixbuf(mime_type):
# run_thumbnailer # run_thumbnailer
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
def run_thumbnailer(mime_type, src_file, dest_file, size=const.THUMBSCALE): def run_thumbnailer(mime_type, src_file, dest_file, size=SIZE_NORMAL):
""" """
This function attempts to generate a thumbnail image for a non-image. This function attempts to generate a thumbnail image for a non-image.
This includes things such as video and PDF files. This will currently This includes things such as video and PDF files. This will currently
@ -232,7 +249,6 @@ def run_thumbnailer(mime_type, src_file, dest_file, size=const.THUMBSCALE):
:rtype: bool :rtype: bool
:returns: True if the thumbnail was successfully generated :returns: True if the thumbnail was successfully generated
""" """
# only try this if GCONF is present, the thumbnailer has not been # only try this if GCONF is present, the thumbnailer has not been
# disabled, and if the src_file actually exists # disabled, and if the src_file actually exists
if GCONF and const.USE_THUMBNAILER and os.path.isfile(src_file): if GCONF and const.USE_THUMBNAILER and os.path.isfile(src_file):
@ -246,8 +262,12 @@ def run_thumbnailer(mime_type, src_file, dest_file, size=const.THUMBSCALE):
# if we found the command and it has been enabled, then spawn # if we found the command and it has been enabled, then spawn
# of the command to build the thumbnail # of the command to build the thumbnail
if cmd and enable: if cmd and enable:
if size == SIZE_LARGE:
thumbscale = const.THUMBSCALE_LARGE
else:
thumbscale = const.THUMBSCALE
sublist = { sublist = {
'%s' : "%d" % int(size), '%s' : "%d" % int(thumbscale),
'%u' : src_file, '%u' : src_file,
'%o' : dest_file, '%o' : dest_file,
} }
@ -261,7 +281,7 @@ def run_thumbnailer(mime_type, src_file, dest_file, size=const.THUMBSCALE):
# get_thumbnail_image # get_thumbnail_image
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
def get_thumbnail_image(src_file, mtype=None, rectangle=None): def get_thumbnail_image(src_file, mtype=None, rectangle=None, size=SIZE_NORMAL):
""" """
Return the thumbnail image (in GTK Pixbuf format) associated with the Return the thumbnail image (in GTK Pixbuf format) associated with the
source file passed to the function. If no thumbnail could be found, source file passed to the function. If no thumbnail could be found,
@ -281,7 +301,7 @@ def get_thumbnail_image(src_file, mtype=None, rectangle=None):
:rtype: gtk.gdk.Pixbuf :rtype: gtk.gdk.Pixbuf
""" """
try: try:
filename = get_thumbnail_path(src_file, mtype, rectangle) filename = get_thumbnail_path(src_file, mtype, rectangle, size)
return gtk.gdk.pixbuf_new_from_file(filename) return gtk.gdk.pixbuf_new_from_file(filename)
except (gobject.GError, OSError): except (gobject.GError, OSError):
if mtype: if mtype:
@ -295,7 +315,7 @@ def get_thumbnail_image(src_file, mtype=None, rectangle=None):
# get_thumbnail_path # get_thumbnail_path
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
def get_thumbnail_path(src_file, mtype=None, rectangle=None): def get_thumbnail_path(src_file, mtype=None, rectangle=None, size=SIZE_NORMAL):
""" """
Return the path to the thumbnail image associated with the Return the path to the thumbnail image associated with the
source file passed to the function. If the thumbnail does not exist, source file passed to the function. If the thumbnail does not exist,
@ -310,13 +330,13 @@ def get_thumbnail_path(src_file, mtype=None, rectangle=None):
:returns: thumbnail representing the source file :returns: thumbnail representing the source file
:rtype: gtk.gdk.Pixbuf :rtype: gtk.gdk.Pixbuf
""" """
filename = __build_thumb_path(src_file, rectangle) filename = __build_thumb_path(src_file, rectangle, size)
if not os.path.isfile(src_file): if not os.path.isfile(src_file):
return os.path.join(const.IMAGE_DIR, "image-missing.png") return os.path.join(const.IMAGE_DIR, "image-missing.png")
else: else:
if not os.path.isfile(filename): if not os.path.isfile(filename):
__create_thumbnail_image(src_file, mtype, rectangle) __create_thumbnail_image(src_file, mtype, rectangle, size)
elif os.path.getmtime(src_file) > os.path.getmtime(filename): elif os.path.getmtime(src_file) > os.path.getmtime(filename):
__create_thumbnail_image(src_file, mtype, rectangle) __create_thumbnail_image(src_file, mtype, rectangle, size)
return os.path.abspath(filename) return os.path.abspath(filename)

View File

@ -152,10 +152,12 @@ TOOL_OPTIONS = os.path.join(HOME_DIR, "tool_options.xml")
ENV_DIR = os.path.join(HOME_DIR, "env") ENV_DIR = os.path.join(HOME_DIR, "env")
TEMP_DIR = os.path.join(HOME_DIR, "temp") TEMP_DIR = os.path.join(HOME_DIR, "temp")
THUMB_DIR = os.path.join(HOME_DIR, "thumb") THUMB_DIR = os.path.join(HOME_DIR, "thumb")
THUMB_NORMAL = os.path.join(THUMB_DIR, "normal")
THUMB_LARGE = os.path.join(THUMB_DIR, "large")
USER_PLUGINS = os.path.join(VERSION_DIR, "plugins") USER_PLUGINS = os.path.join(VERSION_DIR, "plugins")
# dirs checked/made for each Gramps session # dirs checked/made for each Gramps session
USER_DIRLIST = (HOME_DIR, VERSION_DIR, ENV_DIR, TEMP_DIR, THUMB_DIR, USER_DIRLIST = (HOME_DIR, VERSION_DIR, ENV_DIR, TEMP_DIR, THUMB_DIR,
USER_PLUGINS) THUMB_NORMAL, THUMB_LARGE, USER_PLUGINS)
ICON = os.path.join(ROOT_DIR, "images", "gramps.png") ICON = os.path.join(ROOT_DIR, "images", "gramps.png")
LOGO = os.path.join(ROOT_DIR, "images", "logo.png") LOGO = os.path.join(ROOT_DIR, "images", "logo.png")
@ -227,6 +229,7 @@ TRANSLATORS = _('TRANSLATORS: Translate this to your '
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
THUMBSCALE = 96.0 THUMBSCALE = 96.0
THUMBSCALE_LARGE = 180.0
XMLFILE = "data.gramps" XMLFILE = "data.gramps"
NO_SURNAME = "(%s)" % _("none") NO_SURNAME = "(%s)" % _("none")
NO_GIVEN = "(%s)" % _("none") NO_GIVEN = "(%s)" % _("none")

View File

@ -31,6 +31,7 @@ import gtk
# Gramps modules # Gramps modules
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
import ThumbNails
from gui.utils import open_file_with_default_application from gui.utils import open_file_with_default_application
from gen.ggettext import gettext as _ from gen.ggettext import gettext as _
@ -43,9 +44,8 @@ class Photo(gtk.EventBox):
""" """
Displays an image and allows it to be viewed in an external image viewer. Displays an image and allows it to be viewed in an external image viewer.
""" """
def __init__(self, size=100.0): def __init__(self):
gtk.EventBox.__init__(self) gtk.EventBox.__init__(self)
self.size = size
self.full_path = None self.full_path = None
self.photo = gtk.Image() self.photo = gtk.Image()
self.add(self.photo) self.add(self.photo)
@ -54,14 +54,17 @@ class Photo(gtk.EventBox):
'viewer application.') 'viewer application.')
self.set_tooltip_text(tip) self.set_tooltip_text(tip)
def set_image(self, full_path, rectangle=None): def set_image(self, full_path, mime_type=None, rectangle=None):
""" """
Set the image to be displayed. Set the image to be displayed.
""" """
self.full_path = full_path self.full_path = full_path
if full_path: if full_path:
pb = self.get_pixbuf(full_path, rectangle, self.size) pixbuf = ThumbNails.get_thumbnail_image(full_path,
self.photo.set_from_pixbuf(pb) mime_type,
rectangle,
ThumbNails.SIZE_LARGE)
self.photo.set_from_pixbuf(pixbuf)
self.photo.show() self.photo.show()
else: else:
self.photo.hide() self.photo.hide()
@ -72,33 +75,3 @@ class Photo(gtk.EventBox):
""" """
if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1: if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
open_file_with_default_application(self.full_path) open_file_with_default_application(self.full_path)
def get_pixbuf(self, full_path, rectangle=None, size=100.0):
"""
Load, scale and display the image from the path.
"""
try:
image = gtk.gdk.pixbuf_new_from_file(full_path)
except:
return None
width = image.get_width()
height = image.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:
image = image.subpixbuf(sub_x, sub_y, sub_width, sub_height)
ratio = float(max(image.get_height(), image.get_width()))
scale = float(size)/ratio
x = int(scale*(image.get_width()))
y = int(scale*(image.get_height()))
image = image.scale_simple(x, y, gtk.gdk.INTERP_BILINEAR)
return image

View File

@ -61,8 +61,8 @@ class Gallery(Gramplet):
full_path = Utils.media_path_full(self.dbstate.db, media.get_path()) full_path = Utils.media_path_full(self.dbstate.db, media.get_path())
mime_type = media.get_mime_type() mime_type = media.get_mime_type()
if mime_type and mime_type.startswith("image"): if mime_type and mime_type.startswith("image"):
photo = Photo(180.0) photo = Photo()
photo.set_image(full_path, media_ref.get_rectangle()) photo.set_image(full_path, mime_type, media_ref.get_rectangle())
self.image_list.append(photo) self.image_list.append(photo)
self.top.pack_start(photo, expand=False, fill=False) self.top.pack_start(photo, expand=False, fill=False)
self.top.show_all() self.top.show_all()

View File

@ -20,9 +20,7 @@
# #
from gen.plug import Gramplet from gen.plug import Gramplet
from gui.utils import open_file_with_default_application from gui.widgets import Photo
import ThumbNails
import const
import Utils import Utils
import gtk import gtk
@ -40,13 +38,8 @@ class MediaPreview(Gramplet):
Build the GUI interface. Build the GUI interface.
""" """
self.top = gtk.HBox() self.top = gtk.HBox()
self.thumbnail = gtk.Image() self.photo = Photo()
ebox = gtk.EventBox() self.top.pack_start(self.photo, fill=True, expand=False, padding=5)
ebox.add(self.thumbnail)
ebox.connect('button-press-event', self.display_image)
ebox.set_tooltip_text(
_('Double click image to view in an external viewer'))
self.top.pack_start(ebox, fill=True, expand=False, padding=5)
self.top.show_all() self.top.show_all()
return self.top return self.top
@ -68,7 +61,7 @@ class MediaPreview(Gramplet):
self.load_image(media) self.load_image(media)
self.set_has_data(True) self.set_has_data(True)
else: else:
self.thumbnail.clear() self.photo.set_image(None)
self.set_has_data(False) self.set_has_data(False)
self.top.show() self.top.show()
@ -79,13 +72,4 @@ class MediaPreview(Gramplet):
self.full_path = Utils.media_path_full(self.dbstate.db, self.full_path = Utils.media_path_full(self.dbstate.db,
media.get_path()) media.get_path())
mime_type = media.get_mime_type() mime_type = media.get_mime_type()
pixbuf = ThumbNails.get_thumbnail_image(self.full_path, mime_type) self.photo.set_image(self.full_path, mime_type)
self.thumbnail.set_from_pixbuf(pixbuf)
def display_image(self, widget, event):
"""
Display the image with the default external viewer.
"""
if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
open_file_with_default_application(self.full_path)

View File

@ -45,7 +45,7 @@ class PersonDetails(Gramplet):
""" """
self.top = gtk.HBox() self.top = gtk.HBox()
vbox = gtk.VBox() vbox = gtk.VBox()
self.photo = Photo(190.0) self.photo = Photo()
self.photo.show() self.photo.show()
self.name = gtk.Label() self.name = gtk.Label()
self.name.set_alignment(0, 0) self.name.set_alignment(0, 0)
@ -227,7 +227,8 @@ class PersonDetails(Gramplet):
full_path = Utils.media_path_full(self.dbstate.db, obj.get_path()) full_path = Utils.media_path_full(self.dbstate.db, obj.get_path())
mime_type = obj.get_mime_type() mime_type = obj.get_mime_type()
if mime_type and mime_type.startswith("image"): if mime_type and mime_type.startswith("image"):
self.photo.set_image(full_path, media_ref.get_rectangle()) self.photo.set_image(full_path, mime_type,
media_ref.get_rectangle())
else: else:
self.photo.set_image(None) self.photo.set_image(None)
else: else:

View File

@ -42,7 +42,7 @@ class PlaceDetails(Gramplet):
""" """
self.top = gtk.HBox() self.top = gtk.HBox()
vbox = gtk.VBox() vbox = gtk.VBox()
self.photo = Photo(190.0) self.photo = Photo()
self.title = gtk.Label() self.title = gtk.Label()
self.title.set_alignment(0, 0) self.title.set_alignment(0, 0)
self.title.modify_font(pango.FontDescription('sans bold 12')) self.title.modify_font(pango.FontDescription('sans bold 12'))
@ -157,7 +157,8 @@ class PlaceDetails(Gramplet):
full_path = Utils.media_path_full(self.dbstate.db, obj.get_path()) full_path = Utils.media_path_full(self.dbstate.db, obj.get_path())
mime_type = obj.get_mime_type() mime_type = obj.get_mime_type()
if mime_type and mime_type.startswith("image"): if mime_type and mime_type.startswith("image"):
self.photo.set_image(full_path, media_ref.get_rectangle()) self.photo.set_image(full_path, mime_type,
media_ref.get_rectangle())
else: else:
self.photo.set_image(None) self.photo.set_image(None)
else: else:

View File

@ -113,6 +113,8 @@ class RepositoryDetails(Gramplet):
self.display_url(repo, UrlType(UrlType.EMAIL)) self.display_url(repo, UrlType(UrlType.EMAIL))
self.display_url(repo, UrlType(UrlType.WEB_HOME)) self.display_url(repo, UrlType(UrlType.WEB_HOME))
self.display_url(repo, UrlType(UrlType.WEB_SEARCH))
self.display_url(repo, UrlType(UrlType.WEB_FTP))
def display_address(self, address): def display_address(self, address):
""" """