Re- sized the width and height of the Edit window for Exif metadata. I hope that this will be a better layout.

svn: r17899
This commit is contained in:
Rob G. Healey 2011-07-07 05:45:07 +00:00
parent 768fe26346
commit 3c89080193

View File

@ -41,6 +41,7 @@ from fractions import Fraction
import subprocess import subprocess
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# GTK modules # GTK modules
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -70,8 +71,8 @@ from PlaceUtils import conv_lat_lon
from gen.db import DbTxn from gen.db import DbTxn
from ListModel import ListModel from ListModel import ListModel
import pyexiv2
import pyexiv2
# v0.1 has a different API to v0.2 and above # v0.1 has a different API to v0.2 and above
if hasattr(pyexiv2, 'version_info'): if hasattr(pyexiv2, 'version_info'):
OLD_API = False OLD_API = False
@ -79,15 +80,15 @@ else:
# version_info attribute does not exist prior to v0.2.0 # version_info attribute does not exist prior to v0.2.0
OLD_API = True OLD_API = True
# ----------------------------------------------- #------------------------------------------------
# Support Functions # support helpers
# ----------------------------------------------- #------------------------------------------------
def _format_datetime(exif_dt): def _format_datetime(exif_dt):
""" """
Convert a python datetime object into a string for display, using the Convert a python datetime object into a string for display, using the
standard Gramps date format. standard Gramps date format.
""" """
if type(exif_dt) is not datetime: if type(exif_dt) is not datetime.datetime:
return '' return ''
date_part = gen.lib.date.Date() date_part = gen.lib.date.Date()
@ -101,10 +102,49 @@ def _format_datetime(exif_dt):
def _format_gps(tag_value): def _format_gps(tag_value):
""" """
Convert a (degrees, minutes, seconds) tuple into a string for display. Convert a (degrees, minutes, seconds) tuple into a string for display.
""" """
return "%d° %02d' %05.2f\"" % (tag_value[0], tag_value[1], tag_value[2]) return "%d° %02d' %05.2f\"" % (tag_value[0], tag_value[1], tag_value[2])
def _parse_datetime(value):
"""
Parse date and time and return a datetime object.
"""
value = value.rstrip()
if not value:
return None
if value.find(u':') >= 0:
# Time part present
if value.find(u' ') >= 0:
# Both date and time part
date_text, time_text = value.rsplit(u' ', 1)
else:
# Time only
date_text = u''
time_text = value
else:
# Date only
date_text = value
time_text = u'00:00:00'
date_part = _dp.parse(date_text)
try:
time_part = time.strptime(time_text, "%H:%M:%S")
except ValueError:
time_part = None
if date_part.get_modifier() == Date.MOD_NONE and time_part is not None:
return datetime(date_part.get_year(),
date_part.get_month(),
date_part.get_day(),
time_part.tm_hour,
time_part.tm_min,
time_part.tm_sec)
else:
return None
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Constants # Constants
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -126,20 +166,17 @@ GPS = _('GPS')
ADVANCED = _("Advanced") ADVANCED = _("Advanced")
# All of the exiv2 tag reference... # All of the exiv2 tag reference...
TAGS = [ TAGS_ = [
# Description subclass... # Description subclass...
(DESCRIPTION, 'Exif.Image.XPSubject', None, None), (DESCRIPTION, 'Exif.Image.Artist', None, None),
(DESCRIPTION, 'Exif.Image.Copyright', None, None),
(DESCRIPTION, 'Exif.Photo.DateTimeOriginal', None, _format_datetime),
(DESCRIPTION, 'Exif.Photo.DateTimeDigitized', None, _format_datetime),
(DESCRIPTION, 'Exif.Image.Rating', None, None), (DESCRIPTION, 'Exif.Image.Rating', None, None),
(DESCRIPTION, 'Exif.Image.XPKeywords', None, None),
(DESCRIPTION, 'Exif.Image.XPComment', None, None),
# Origin subclass... # Origin subclass...
(ORIGIN, 'Exif.Image.Artist', None, None),
(ORIGIN, 'Exif.Photo.DateTimeOriginal', None, _format_datetime),
(ORIGIN, 'Exif.Photo.DateTimeDigitized', None, _format_datetime),
(ORIGIN, 'Exif.Image.Software', None, None), (ORIGIN, 'Exif.Image.Software', None, None),
(ORIGIN, 'Xmp.MicrosoftPhoto.DateAcquired', None, None), (ORIGIN, 'Xmp.MicrosoftPhoto.DateAcquired', None, None),
(ORIGIN, 'Exif.Image.Copyright', None, None),
(ORIGIN, 'Exif.Image.TimeZoneOffset', None, None), (ORIGIN, 'Exif.Image.TimeZoneOffset', None, None),
(ORIGIN, 'Exif.Image.SubjectDistance', None, None), (ORIGIN, 'Exif.Image.SubjectDistance', None, None),
@ -190,7 +227,10 @@ TAGS = [
(ADVANCED, 'Exif.Photo.Sharpness', None, None), (ADVANCED, 'Exif.Photo.Sharpness', None, None),
(ADVANCED, 'Exif.Photo.WhiteBalance', None, None), (ADVANCED, 'Exif.Photo.WhiteBalance', None, None),
(ADVANCED, 'Exif.Image.ExifTag', None, None), (ADVANCED, 'Exif.Image.ExifTag', None, None),
(ADVANCED, 'Exif.Image.BatteryLevel', None, None) ] (ADVANCED, 'Exif.Image.BatteryLevel', None, None),
(ADVANCED, 'Exif.Image.XPKeywords', None, None),
(ADVANCED, 'Exif.Image.XPComment', None, None),
(ADVANCED, 'Exif.Image.XPSubject', None, None) ]
# set up Exif keys for Image Exif metadata keypairs... # set up Exif keys for Image Exif metadata keypairs...
_DATAMAP = { _DATAMAP = {
@ -401,7 +441,7 @@ class EditExifMetadata(Gramplet):
hed_box.add(self.__create_button( hed_box.add(self.__create_button(
"Delete", False, [self.__wipe_dialog], gtk.STOCK_DELETE) ) "Delete", False, [self.__wipe_dialog], gtk.STOCK_DELETE) )
new_vbox = self.__build_shaded_display() new_vbox = self.__build_shaded_gui()
main_vbox.pack_start(new_vbox, expand =False, fill =False, padding =10) main_vbox.pack_start(new_vbox, expand =False, fill =False, padding =10)
# number of key/value pairs shown... # number of key/value pairs shown...
@ -412,6 +452,17 @@ class EditExifMetadata(Gramplet):
main_vbox.show_all() main_vbox.show_all()
return main_vbox return main_vbox
def __build_shaded_gui(self):
"""
Build the GUI interface.
"""
top = gtk.TreeView()
titles = [(_('Key'), 1, 180),
(_('Value'), 2, 310)]
self.model = ListModel(top, titles, list_mode="tree")
return top
def db_changed(self): def db_changed(self):
self.dbstate.db.connect('media-update', self.update) self.dbstate.db.connect('media-update', self.update)
self.connect_signal('Media', self.update) self.connect_signal('Media', self.update)
@ -538,7 +589,7 @@ class EditExifMetadata(Gramplet):
self.activate_buttons(["Edit"]) self.activate_buttons(["Edit"])
# display all exif metadata... # display all exif metadata...
self.display_metadata(self.orig_image) self.__display_exif_tags()
# has mime, but not an image... # has mime, but not an image...
else: else:
@ -550,6 +601,66 @@ class EditExifMetadata(Gramplet):
self.exif_widgets["MessageArea"].set_text(_("Please choose a different image...")) self.exif_widgets["MessageArea"].set_text(_("Please choose a different image..."))
return return
def __display_exif_tags(self):
"""
Display the exif tags.
"""
metadatatags_ = _get_exif_keypairs(self.plugin_image)
if not metadatatags_:
return
if OLD_API: # prior to v0.2.0
try:
self.plugin_image.readMetadata()
metadata_yes = True
except (IOError, OSError):
metadata_yes = False
if metadata_yes:
for section, key, key2, func in TAGS_:
if key in metadatatags_:
if section not in self.sections:
node = self.model.add([section, ''])
self.sections[section] = node
else:
node = self.sections[section]
label = self.plugin_image.tagDetails(key)[0]
if func:
human_value = func(self.plugin_image[key])
else:
human_value = self.plugin_image.interpretedExifValue(key)
if key2:
human_value += ' ' + self.plugin_image.interpretedExifValue(key2)
self.model.add((label, human_value), node =node)
self.model.tree.expand_all()
else: # v0.2.0 and above
try:
self.plugin_image.read()
metadata_yes = True
except (IOError, OSError):
metadata_yes = False
if metadata_yes:
for section, key, key2, func in TAGS_:
if key in metadatatags_:
if section not in self.sections:
node = self.model.add([section, ''])
self.sections[section] = node
else:
node = self.sections[section]
tag = self.plugin_image[key]
if func:
human_value = func(tag.value)
else:
human_value = tag.human_value
if key2:
human_value += ' ' + self.plugin_image[key2].human_value
self.model.add((tag.label, human_value), node =node)
self.model.tree.expand_all()
def changed_cb(self, object): def changed_cb(self, object):
""" """
will show the Convert Button once an Image Type has been selected, and if will show the Convert Button once an Image Type has been selected, and if
@ -770,18 +881,6 @@ class EditExifMetadata(Gramplet):
return label return label
def __build_shaded_display(self):
"""
Build the GUI interface.
"""
top = gtk.TreeView()
titles = [(_('Key'), 1, 180),
(_('Value'), 2, 310)]
self.model = ListModel(top, titles, list_mode="tree")
return top
def thumbnail_view(self, object): def thumbnail_view(self, object):
""" """
will allow a display area for a thumbnail pop-up window. will allow a display area for a thumbnail pop-up window.
@ -1064,14 +1163,14 @@ class EditExifMetadata(Gramplet):
self.edtarea = gtk.Window(gtk.WINDOW_TOPLEVEL) self.edtarea = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.edtarea.tooltip = tip self.edtarea.tooltip = tip
self.edtarea.set_title( self.orig_image.get_description() ) self.edtarea.set_title( self.orig_image.get_description() )
self.edtarea.set_default_size(600, 582) self.edtarea.set_default_size(520, 582)
self.edtarea.set_border_width(10) self.edtarea.set_border_width(10)
self.edtarea.connect("destroy", lambda w: self.edtarea.destroy() ) self.edtarea.connect("destroy", lambda w: self.edtarea.destroy() )
# create a new scrolled window. # create a new scrolled window.
scrollwindow = gtk.ScrolledWindow() scrollwindow = gtk.ScrolledWindow()
scrollwindow.set_border_width(10) scrollwindow.set_border_width(10)
scrollwindow.set_size_request(600, 500) scrollwindow.set_size_request(520, 500)
scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
self.edtarea.add(scrollwindow) self.edtarea.add(scrollwindow)
@ -1118,7 +1217,7 @@ class EditExifMetadata(Gramplet):
""" """
main_vbox = gtk.VBox() main_vbox = gtk.VBox()
main_vbox.set_border_width(10) main_vbox.set_border_width(10)
main_vbox.set_size_request(560, 500) main_vbox.set_size_request(480, 480)
label = self.__create_label("Edit:Message", False, False, False) label = self.__create_label("Edit:Message", False, False, False)
main_vbox.pack_start(label, expand =False, fill =False, padding =0) main_vbox.pack_start(label, expand =False, fill =False, padding =0)
@ -1127,7 +1226,7 @@ class EditExifMetadata(Gramplet):
# create the data fields... # create the data fields...
# ***Label/ Title, Description, Artist, and Copyright # ***Label/ Title, Description, Artist, and Copyright
gen_frame = gtk.Frame(_("General Data")) gen_frame = gtk.Frame(_("General Data"))
gen_frame.set_size_request(550, 200) gen_frame.set_size_request(470, 170)
main_vbox.pack_start(gen_frame, expand =False, fill =True, padding =10) main_vbox.pack_start(gen_frame, expand =False, fill =True, padding =10)
gen_frame.show() gen_frame.show()
@ -1149,7 +1248,7 @@ class EditExifMetadata(Gramplet):
label.show() label.show()
event_box = gtk.EventBox() event_box = gtk.EventBox()
event_box.set_size_request(430, 30) event_box.set_size_request(360, 30)
new_hbox.pack_start(event_box, expand =False, fill =False, padding =0) new_hbox.pack_start(event_box, expand =False, fill =False, padding =0)
event_box.show() event_box.show()
@ -1160,7 +1259,7 @@ class EditExifMetadata(Gramplet):
# iso format: Year, Month, Day spinners... # iso format: Year, Month, Day spinners...
datetime_frame = gtk.Frame(_("Date/ Time")) datetime_frame = gtk.Frame(_("Date/ Time"))
datetime_frame.set_size_request(550, 110) datetime_frame.set_size_request(470, 110)
main_vbox.pack_start(datetime_frame, expand =False, fill =False, padding =0) main_vbox.pack_start(datetime_frame, expand =False, fill =False, padding =0)
datetime_frame.show() datetime_frame.show()
@ -1186,7 +1285,7 @@ class EditExifMetadata(Gramplet):
label.show() label.show()
event_box = gtk.EventBox() event_box = gtk.EventBox()
event_box.set_size_request(250, 30) event_box.set_size_request(215, 30)
vbox2.pack_start(event_box, expand =False, fill =False, padding =0) vbox2.pack_start(event_box, expand =False, fill =False, padding =0)
event_box.show() event_box.show()
@ -1205,7 +1304,7 @@ class EditExifMetadata(Gramplet):
# GPS coordinates... # GPS coordinates...
latlong_frame = gtk.Frame(_("Latitude/ Longitude/ Altitude GPS coordinates")) latlong_frame = gtk.Frame(_("Latitude/ Longitude/ Altitude GPS coordinates"))
latlong_frame.set_size_request(550, 125) latlong_frame.set_size_request(470, 125)
main_vbox.pack_start(latlong_frame, expand =False, fill =False, padding =0) main_vbox.pack_start(latlong_frame, expand =False, fill =False, padding =0)
latlong_frame.show() latlong_frame.show()
@ -1231,7 +1330,7 @@ class EditExifMetadata(Gramplet):
label.show() label.show()
event_box = gtk.EventBox() event_box = gtk.EventBox()
event_box.set_size_request(167, 30) event_box.set_size_request(141, 30)
vbox2.pack_start(event_box, expand =False, fill =False, padding =0) vbox2.pack_start(event_box, expand =False, fill =False, padding =0)
event_box.show() event_box.show()
@ -1723,21 +1822,6 @@ class EditExifMetadata(Gramplet):
self.exif_widgets["MessageArea"].set_text(_("There was an error " self.exif_widgets["MessageArea"].set_text(_("There was an error "
"in stripping the Exif metadata from this image...")) "in stripping the Exif metadata from this image..."))
def _get_exif_keypairs(plugin_image):
"""
Will be used to retrieve and update the Exif metadata from the image.
"""
if not plugin_image:
return False
mediadatatags_ = [keytag_ for keytag_ in (plugin_image.exifKeys() if OLD_API
else chain( plugin_image.exif_keys,
plugin_image.xmp_keys,
plugin_image.iptc_keys) ) ]
return mediadatatags_
def _removesymbolsb4saving(latitude, longitude): def _removesymbolsb4saving(latitude, longitude):
""" """
will recieve a DMS with symbols and return it without them will recieve a DMS with symbols and return it without them
@ -1819,40 +1903,18 @@ def rational_to_dms(coordinates):
# or [Fraction(38, 1), Fraction(38, 1), Fraction(318, 100)] # or [Fraction(38, 1), Fraction(38, 1), Fraction(318, 100)]
return [convert_value(coordinate) for coordinate in coordinates] return [convert_value(coordinate) for coordinate in coordinates]
def _parse_datetime(value):
def _get_exif_keypairs(plugin_image):
""" """
Parse date and time and return a datetime object. Will be used to retrieve and update the Exif metadata from the image.
""" """
value = value.rstrip()
if not value:
return None
if value.find(u':') >= 0: if not plugin_image:
# Time part present return False
if value.find(u' ') >= 0:
# Both date and time part mediadatatags_ = [keytag_ for keytag_ in (plugin_image.exifKeys() if OLD_API
date_text, time_text = value.rsplit(u' ', 1) else chain( plugin_image.exif_keys,
else: plugin_image.xmp_keys,
# Time only plugin_image.iptc_keys) ) ]
date_text = u''
time_text = value
else:
# Date only
date_text = value
time_text = u'00:00:00'
date_part = _dp.parse(date_text) return mediadatatags_
try:
time_part = time.strptime(time_text, "%H:%M:%S")
except ValueError:
time_part = None
if date_part.get_modifier() == Date.MOD_NONE and time_part is not None:
return datetime(date_part.get_year(),
date_part.get_month(),
date_part.get_day(),
time_part.tm_hour,
time_part.tm_min,
time_part.tm_sec)
else:
return None