diff options
Diffstat (limited to 'src/eom-metadata-sidebar.c')
-rw-r--r-- | src/eom-metadata-sidebar.c | 634 |
1 files changed, 634 insertions, 0 deletions
diff --git a/src/eom-metadata-sidebar.c b/src/eom-metadata-sidebar.c new file mode 100644 index 0000000..1f8da5a --- /dev/null +++ b/src/eom-metadata-sidebar.c @@ -0,0 +1,634 @@ +/* + * eom-metadata-sidebar.c + * This file is part of eom + * + * Author: Felix Riemann <[email protected]> + * + * Portions based on code by: Lucas Rocha <[email protected]> + * Hubert Figuiere <[email protected]> (XMP support) + * + * Copyright (C) 2011 GNOME Foundation + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib.h> +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +#include "eom-dialog.h" +#include "eom-image.h" +#include "eom-metadata-sidebar.h" +#include "eom-properties-dialog.h" +#include "eom-scroll-view.h" +#include "eom-util.h" +#include "eom-window.h" + +#if HAVE_EXEMPI +#include <exempi/xmp.h> +#include <exempi/xmpconsts.h> +#endif + +enum { + PROP_0, + PROP_IMAGE, + PROP_PARENT_WINDOW +}; + +struct _EomMetadataSidebarPrivate { + EomWindow *parent_window; + EomImage *image; + + gulong image_changed_id; + gulong thumb_changed_id; + + GtkWidget *grid; + + GtkWidget *name_label; + GtkWidget *height_label; + GtkWidget *width_label; + GtkWidget *type_label; + GtkWidget *size_label; + GtkWidget *folder_button; + + GtkWidget *aperture_label; + GtkWidget *exposure_label; + GtkWidget *focallen_label; + GtkWidget *flash_label; + GtkWidget *iso_label; + GtkWidget *metering_label; + GtkWidget *model_label; + GtkWidget *date_label; + + GtkWidget *location_label; + GtkWidget *desc_label; + GtkWidget *keyword_label; + GtkWidget *creator_label; + GtkWidget *rights_label; + + GtkWidget *details_button; +}; + +#define EOM_METADATA_SIDEBAR_GET_PRIVATE(object) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((object), EOM_TYPE_METADATA_SIDEBAR, EomMetadataSidebarPrivate)) + +G_DEFINE_TYPE(EomMetadataSidebar, eom_metadata_sidebar, GTK_TYPE_SCROLLED_WINDOW) + +static GtkWidget* +_gtk_grid_append_title_line (GtkGrid *grid, GtkWidget *sibling, + const gchar *text) +{ + GtkWidget *label; + gchar *markup; + + label = gtk_label_new (NULL); + + markup = g_markup_printf_escaped ("<b>%s</b>", text); + gtk_label_set_markup (GTK_LABEL (label), markup); + + gtk_grid_attach_next_to (grid, label, sibling, GTK_POS_BOTTOM, 2, 1); + return label; +} + +static GtkWidget* +_gtk_grid_append_prop_line (GtkGrid *grid, GtkWidget *sibling, + GtkWidget **data_label, const gchar *text) +{ + GtkWidget *label; + + label = gtk_label_new (text); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + + gtk_grid_attach_next_to (grid, label, sibling, GTK_POS_BOTTOM, 1, 1); + + if (G_LIKELY (data_label != NULL)) { + *data_label = gtk_label_new (NULL); + gtk_label_set_ellipsize (GTK_LABEL (*data_label), PANGO_ELLIPSIZE_END); + gtk_misc_set_alignment (GTK_MISC (*data_label), 0.0, 0.5); + gtk_grid_attach_next_to (grid, *data_label, label, + GTK_POS_RIGHT, 1, 1); + } + + return label; +} + +#if HAVE_EXEMPI +static void +eom_xmp_set_label (XmpPtr xmp, + const char *ns, + const char *propname, + GtkWidget *w) +{ + uint32_t options; + + XmpStringPtr value = xmp_string_new (); + + if (xmp && xmp_get_property (xmp, ns, propname, value, &options)) { + if (XMP_IS_PROP_SIMPLE (options)) { + gtk_label_set_text (GTK_LABEL (w), xmp_string_cstr (value)); + } else if (XMP_IS_PROP_ARRAY (options)) { + XmpIteratorPtr iter = xmp_iterator_new (xmp, + ns, + propname, + XMP_ITER_JUSTLEAFNODES); + + GString *string = g_string_new (""); + + if (iter) { + gboolean first = TRUE; + + while (xmp_iterator_next (iter, NULL, NULL, value, &options) + && !XMP_IS_PROP_QUALIFIER (options)) { + + if (!first) { + g_string_append_printf(string, ", "); + } else { + first = FALSE; + } + + g_string_append_printf (string, + "%s", + xmp_string_cstr (value)); + } + + xmp_iterator_free (iter); + } + + gtk_label_set_text (GTK_LABEL (w), string->str); + g_string_free (string, TRUE); + } + } else { + /* Property was not found */ + /* Clear label so it won't show bogus data */ + gtk_label_set_text (GTK_LABEL (w), NULL); + } + + xmp_string_free (value); +} +#endif + +static void +eom_metadata_sidebar_update_general_section (EomMetadataSidebar *sidebar) +{ + EomMetadataSidebarPrivate *priv = sidebar->priv; + EomImage *img = priv->image; + GFile *file, *parent_file; + GFileInfo *file_info; + gchar *str; + goffset bytes; + gint width, height; + + if (G_UNLIKELY (img == NULL)) { + gtk_label_set_text (GTK_LABEL (priv->name_label), NULL); + gtk_label_set_text (GTK_LABEL (priv->height_label), NULL); + gtk_label_set_text (GTK_LABEL (priv->width_label), NULL); + gtk_label_set_text (GTK_LABEL (priv->type_label), NULL); + gtk_label_set_text (GTK_LABEL (priv->size_label), NULL); + return; + } + + gtk_label_set_text (GTK_LABEL (priv->name_label), + eom_image_get_caption (img)); + eom_image_get_size (img, &width, &height); + str = g_strdup_printf ("%d %s", height, + ngettext ("pixel", "pixels", height)); + gtk_label_set_text (GTK_LABEL (priv->height_label), str); + g_free (str); + str = g_strdup_printf ("%d %s", width, + ngettext ("pixel", "pixels", width)); + gtk_label_set_text (GTK_LABEL (priv->width_label), str); + g_free (str); + + file = eom_image_get_file (img); + file_info = g_file_query_info (file, + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, + 0, NULL, NULL); + if (file_info == NULL) { + str = g_strdup (_("Unknown")); + } else { + const gchar *mime_str; + + mime_str = g_file_info_get_content_type (file_info); + str = g_content_type_get_description (mime_str); + g_object_unref (file_info); + } + gtk_label_set_text (GTK_LABEL (priv->type_label), str); + g_free (str); + + bytes = eom_image_get_bytes (img); + str = g_format_size (bytes); + gtk_label_set_text (GTK_LABEL (priv->size_label), str); + g_free (str); + + parent_file = g_file_get_parent (file); + if (parent_file == NULL) { + /* file is root directory itself */ + parent_file = g_object_ref (file); + } + str = g_file_get_basename (parent_file); + gtk_button_set_label (GTK_BUTTON (priv->folder_button), str); + g_free (str); + g_object_unref (parent_file); +} + +static void +eom_metadata_sidebar_update_metadata_section (EomMetadataSidebar *sidebar) +{ + EomMetadataSidebarPrivate *priv = sidebar->priv; + EomImage *img = priv->image; + ExifData *exif_data = NULL; + XmpPtr xmp_data = NULL; + + + if (img) { + exif_data = eom_image_get_exif_info (img); + xmp_data = eom_image_get_xmp_info (img); + } + + + eom_exif_util_set_label_text (GTK_LABEL (priv->aperture_label), + exif_data, EXIF_TAG_FNUMBER); + eom_exif_util_set_label_text (GTK_LABEL (priv->exposure_label), + exif_data, + EXIF_TAG_EXPOSURE_TIME); + eom_exif_util_set_focal_length_label_text ( + GTK_LABEL (priv->focallen_label), + exif_data); + eom_exif_util_set_label_text (GTK_LABEL (priv->flash_label), + exif_data, EXIF_TAG_FLASH); + eom_exif_util_set_label_text (GTK_LABEL (priv->iso_label), + exif_data, + EXIF_TAG_ISO_SPEED_RATINGS); + eom_exif_util_set_label_text (GTK_LABEL (priv->metering_label), + exif_data, + EXIF_TAG_METERING_MODE); + eom_exif_util_set_label_text (GTK_LABEL (priv->model_label), + exif_data, EXIF_TAG_MODEL); + eom_exif_util_set_label_text (GTK_LABEL (priv->date_label), + exif_data, + EXIF_TAG_DATE_TIME_ORIGINAL); + + /* exif_data_unref can handle NULL-values */ + exif_data_unref(exif_data); + +#if HAVE_EXEMPI + eom_xmp_set_label (xmp_data, + NS_IPTC4XMP, + "Location", + priv->location_label); + + eom_xmp_set_label (xmp_data, + NS_DC, + "description", + priv->desc_label); + + eom_xmp_set_label (xmp_data, + NS_DC, + "subject", + priv->keyword_label); + + eom_xmp_set_label (xmp_data, + NS_DC, + "creator", + priv->creator_label); + + eom_xmp_set_label (xmp_data, + NS_DC, + "rights", + priv->rights_label); + + + if (xmp_data != NULL) + xmp_free (xmp_data); +#endif + +} + +static void +eom_metadata_sidebar_update (EomMetadataSidebar *sidebar) +{ + g_return_if_fail (EOM_IS_METADATA_SIDEBAR (sidebar)); + + eom_metadata_sidebar_update_general_section (sidebar); + eom_metadata_sidebar_update_metadata_section (sidebar); +} + +static void +_thumbnail_changed_cb (EomImage *image, gpointer user_data) +{ + eom_metadata_sidebar_update (EOM_METADATA_SIDEBAR (user_data)); +} + +static void +eom_metadata_sidebar_set_image (EomMetadataSidebar *sidebar, EomImage *image) +{ + EomMetadataSidebarPrivate *priv = sidebar->priv; + + if (image == priv->image) + return; + + + if (priv->thumb_changed_id != 0) { + g_signal_handler_disconnect (priv->image, + priv->thumb_changed_id); + priv->thumb_changed_id = 0; + } + + if (priv->image) + g_object_unref (priv->image); + + priv->image = image; + + if (priv->image) { + g_object_ref (priv->image); + priv->thumb_changed_id = + g_signal_connect (priv->image, "thumbnail-changed", + G_CALLBACK (_thumbnail_changed_cb), + sidebar); + eom_metadata_sidebar_update (sidebar); + } + + g_object_notify (G_OBJECT (sidebar), "image"); +} + +static void +_notify_image_cb (GObject *gobject, GParamSpec *pspec, gpointer user_data) +{ + EomImage *image; + + g_return_if_fail (EOM_IS_METADATA_SIDEBAR (user_data)); + g_return_if_fail (EOM_IS_SCROLL_VIEW (gobject)); + + image = eom_scroll_view_get_image (EOM_SCROLL_VIEW (gobject)); + + eom_metadata_sidebar_set_image (EOM_METADATA_SIDEBAR (user_data), + image); + + if (image) + g_object_unref (image); +} + +static void +_folder_button_clicked_cb (GtkButton *button, gpointer user_data) +{ + EomMetadataSidebarPrivate *priv = EOM_METADATA_SIDEBAR(user_data)->priv; + EomImage *img; + GdkScreen *screen; + GFile *file; + + g_return_if_fail (priv->parent_window != NULL); + + img = eom_window_get_image (priv->parent_window); + screen = gtk_widget_get_screen (GTK_WIDGET (priv->parent_window)); + file = eom_image_get_file (img); + + eom_util_show_file_in_filemanager (file, screen); + + g_object_unref (file); +} + +static void +_details_button_clicked_cb (GtkButton *button, gpointer user_data) +{ + EomMetadataSidebarPrivate *priv = EOM_METADATA_SIDEBAR(user_data)->priv; + EomDialog *dlg; + + g_return_if_fail (priv->parent_window != NULL); + + dlg = eom_window_get_properties_dialog ( + EOM_WINDOW (priv->parent_window)); + g_return_if_fail (dlg != NULL); + eom_properties_dialog_set_page (EOM_PROPERTIES_DIALOG (dlg), + EOM_PROPERTIES_DIALOG_PAGE_DETAILS); + eom_dialog_show (dlg); +} + + +static void +eom_metadata_sidebar_set_parent_window (EomMetadataSidebar *sidebar, + EomWindow *window) +{ + EomMetadataSidebarPrivate *priv; + GtkWidget *view; + + g_return_if_fail (EOM_IS_METADATA_SIDEBAR (sidebar)); + priv = sidebar->priv; + g_return_if_fail (priv->parent_window == NULL); + + priv->parent_window = g_object_ref (window); + eom_metadata_sidebar_update (sidebar); + view = eom_window_get_view (window); + priv->image_changed_id = g_signal_connect (view, "notify::image", + G_CALLBACK (_notify_image_cb), + sidebar); + + g_object_notify (G_OBJECT (sidebar), "parent-window"); + +} + +static void +eom_metadata_sidebar_init (EomMetadataSidebar *sidebar) +{ + EomMetadataSidebarPrivate *priv; + GtkWidget *label; + + priv = sidebar->priv = EOM_METADATA_SIDEBAR_GET_PRIVATE (sidebar); + priv->grid = gtk_grid_new (); + g_object_set (G_OBJECT (priv->grid), + "row-spacing", 6, + "column-spacing", 6, + NULL); + + label = _gtk_grid_append_title_line (GTK_GRID (priv->grid), + NULL, _("General")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->name_label, _("Name:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->width_label, _("Width:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->height_label, _("Height:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->type_label, _("Type:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->size_label, _("File size:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + NULL, _("Folder:")); + + priv->folder_button = gtk_button_new_with_label (""); + g_signal_connect (priv->folder_button, "clicked", + G_CALLBACK (_folder_button_clicked_cb), sidebar); + gtk_grid_attach_next_to (GTK_GRID (priv->grid), priv->folder_button, + label, GTK_POS_RIGHT, 1, 1); + + label = _gtk_grid_append_title_line (GTK_GRID (priv->grid), + label, _("Metadata")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->aperture_label, + _("Aperture Value:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->exposure_label, + _("Exposure Time:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->focallen_label, + _("Focal Length:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->flash_label, _("Flash:")); + gtk_label_set_line_wrap (GTK_LABEL (priv->flash_label), TRUE); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->iso_label, + _("ISO Speed Rating:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->metering_label, + _("Metering Mode:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->model_label, + _("Camera Model:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->date_label, _("Date/Time:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->desc_label, + _("Description:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->location_label, + _("Location:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->keyword_label, + _("Keywords:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->creator_label, _("Author:")); + label = _gtk_grid_append_prop_line (GTK_GRID (priv->grid), label, + &priv->rights_label, + _("Copyright:")); + + priv->details_button = gtk_button_new_with_label (_("Details")); + g_signal_connect (priv->details_button, "clicked", + G_CALLBACK (_details_button_clicked_cb), sidebar); + gtk_grid_attach_next_to (GTK_GRID (priv->grid), priv->details_button, + label, GTK_POS_BOTTOM, 1, 1); + + + gtk_widget_show_all (priv->grid); +} + +static void +eom_metadata_sidebar_constructed (GObject *object) +{ + EomMetadataSidebarPrivate *priv; + + priv = EOM_METADATA_SIDEBAR (object)->priv; + + /* This can only happen after all construct properties for + * GtkScrolledWindow are set/handled. */ + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (object), + priv->grid); + gtk_widget_show (GTK_WIDGET (object)); + + G_OBJECT_CLASS (eom_metadata_sidebar_parent_class)->constructed (object); +} + +static void +eom_metadata_sidebar_get_property (GObject *object, guint property_id, + GValue *value, GParamSpec *pspec) +{ + EomMetadataSidebar *sidebar; + + g_return_if_fail (EOM_IS_METADATA_SIDEBAR (object)); + + sidebar = EOM_METADATA_SIDEBAR (object); + + switch (property_id) { + case PROP_IMAGE: + { + g_value_set_object (value, sidebar->priv->image); + break; + } + case PROP_PARENT_WINDOW: + g_value_set_object (value, sidebar->priv->parent_window); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +eom_metadata_sidebar_set_property (GObject *object, guint property_id, + const GValue *value, GParamSpec *pspec) +{ + EomMetadataSidebar *sidebar; + + g_return_if_fail (EOM_IS_METADATA_SIDEBAR (object)); + + sidebar = EOM_METADATA_SIDEBAR (object); + + switch (property_id) { + case PROP_IMAGE: + { + break; + } + case PROP_PARENT_WINDOW: + { + EomWindow *window; + + window = g_value_get_object (value); + eom_metadata_sidebar_set_parent_window (sidebar, window); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } + +} +static void +eom_metadata_sidebar_class_init (EomMetadataSidebarClass *klass) +{ + GObjectClass *g_obj_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof(EomMetadataSidebarPrivate)); + + g_obj_class->constructed = eom_metadata_sidebar_constructed; + g_obj_class->get_property = eom_metadata_sidebar_get_property; + g_obj_class->set_property = eom_metadata_sidebar_set_property; +/* g_obj_class->dispose = eom_metadata_sidebar_dispose;*/ + + g_object_class_install_property ( + g_obj_class, PROP_PARENT_WINDOW, + g_param_spec_object ("parent-window", NULL, NULL, + EOM_TYPE_WINDOW, G_PARAM_READWRITE + | G_PARAM_CONSTRUCT_ONLY + | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property ( + g_obj_class, PROP_IMAGE, + g_param_spec_object ("image", NULL, NULL, EOM_TYPE_IMAGE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS) + ); +} + + +GtkWidget* +eom_metadata_sidebar_new (EomWindow *window) +{ + return gtk_widget_new (EOM_TYPE_METADATA_SIDEBAR, + "hadjustment", NULL, + "vadjustment", NULL, + "hscrollbar-policy", GTK_POLICY_NEVER, + "vscrollbar-policy", GTK_POLICY_AUTOMATIC, + "border-width", 6, + "parent-window", window, + NULL); +} |