[eog] Make Exif/XMP summaries available as sidebar



commit 7ac112f2dde1dcf76b5693d3036dd2d2625a193f
Author: Felix Riemann <friemann gnome org>
Date:   Mon Dec 19 18:20:30 2011 +0100

    Make Exif/XMP summaries available as sidebar
    
    Makes the data from the properties dialog available as a sidebar.
    A button opens the details tab in the properties dialog.
    This is graphically still a bit roughg.
    Committing it in hopes to get some early feedback.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=616438

 src/Makefile.am             |    2 +
 src/eog-exif-util.c         |   91 ++++++
 src/eog-exif-util.h         |   20 +-
 src/eog-metadata-sidebar.c  |  634 +++++++++++++++++++++++++++++++++++++++++++
 src/eog-metadata-sidebar.h  |   61 ++++
 src/eog-properties-dialog.c |  118 +-------
 src/eog-window.c            |   46 +++-
 src/eog-window.h            |    2 +
 8 files changed, 853 insertions(+), 121 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index e4ab3f9..5540401 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,6 +23,7 @@ NOINST_H_FILES =			\
 	eog-error-message-area.h	\
 	eog-image-jpeg.h		\
 	eog-image-private.h		\
+	eog-metadata-sidebar.h		\
 	eog-metadata-reader.h		\
 	eog-metadata-reader-jpg.h	\
 	eog-metadata-reader-png.h	\
@@ -75,6 +76,7 @@ libeog_c_files = 			\
 	eog-job-queue.c			\
 	eog-jobs.c			\
 	eog-list-store.c		\
+	eog-metadata-sidebar.c		\
 	eog-metadata-reader.c		\
 	eog-metadata-reader-jpg.c	\
 	eog-metadata-reader-png.c	\
diff --git a/src/eog-exif-util.c b/src/eog-exif-util.c
index 3495fd6..c2f723f 100644
--- a/src/eog-exif-util.c
+++ b/src/eog-exif-util.c
@@ -34,6 +34,7 @@
 #include <time.h>
 
 #include "eog-exif-util.h"
+#include "eog-util.h"
 
 #include <string.h>
 #include <glib/gi18n.h>
@@ -189,6 +190,96 @@ eog_exif_util_format_date (const gchar *date)
 	return new_date;
 }
 
+void
+eog_exif_util_set_label_text (GtkLabel *label,
+			      EogExifData *exif_data,
+			      gint tag_id)
+{
+	gchar exif_buffer[512];
+	const gchar *buf_ptr;
+	gchar *label_text = NULL;
+
+	g_return_if_fail (GTK_IS_LABEL (label));
+
+	if (exif_data) {
+		buf_ptr = eog_exif_data_get_value (exif_data, tag_id,
+						   exif_buffer, 512);
+
+		if (tag_id == EXIF_TAG_DATE_TIME_ORIGINAL && buf_ptr)
+			label_text = eog_exif_util_format_date (buf_ptr);
+		else
+			label_text = eog_util_make_valid_utf8 (buf_ptr);
+	}
+
+	gtk_label_set_text (label, label_text);
+	g_free (label_text);
+}
+
+void
+eog_exif_util_set_focal_length_label_text (GtkLabel *label,
+					   EogExifData *exif_data)
+{
+	ExifEntry *entry = NULL, *entry35mm = NULL;
+	ExifByteOrder byte_order;
+	gfloat f_val = 0.0;
+	gchar *fl_text = NULL,*fl35_text = NULL;
+
+	/* If no ExifData is supplied the label will be
+	 * cleared later as fl35_text is NULL. */
+	if (exif_data != NULL) {
+		entry = exif_data_get_entry (exif_data, EXIF_TAG_FOCAL_LENGTH);
+		entry35mm = exif_data_get_entry (exif_data,
+					    EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM);
+		byte_order = exif_data_get_byte_order (exif_data);
+	}
+
+	if (entry && G_LIKELY (entry->format == EXIF_FORMAT_RATIONAL)) {
+		ExifRational value;
+
+		/* Decode value by hand as libexif is not necessarily returning
+		 * it in the format we want it to be.
+		 */
+		value = exif_get_rational (entry->data, byte_order);
+		/* Guard against div by zero */
+		if (G_LIKELY(value.denominator != 0))
+			f_val = (gfloat)value.numerator/
+				(gfloat)value.denominator;
+
+		/* TRANSLATORS: This is the actual focal length used when
+		   the image was taken.*/
+		fl_text = g_strdup_printf (_("%.1f (lens)"), f_val);
+
+	}
+	if (entry35mm && G_LIKELY (entry35mm->format == EXIF_FORMAT_SHORT)) {
+		ExifShort s_val;
+
+		s_val = exif_get_short (entry35mm->data, byte_order);
+
+		/* Print as float to get a similar look as above. */
+		/* TRANSLATORS: This is the equivalent focal length assuming
+		   a 35mm film camera. */
+		fl35_text = g_strdup_printf(_("%.1f (35mm film)"),(float)s_val);
+	}
+
+	if (fl_text) {
+		if (fl35_text) {
+			gchar *merged_txt;
+
+			merged_txt = g_strconcat (fl35_text,", ", fl_text, NULL);
+			gtk_label_set_text (label, merged_txt);
+			g_free (merged_txt);
+		} else {
+			gtk_label_set_text (label, fl_text);
+		}
+	} else {
+		/* This will also clear the label if no ExifData was supplied */
+		gtk_label_set_text (label, fl35_text);
+	}
+
+	g_free (fl35_text);
+	g_free (fl_text);
+}
+
 /**
  * eog_exif_data_get_value:
  * @exif_data: pointer to an <structname>ExifData</structname> struct
diff --git a/src/eog-exif-util.h b/src/eog-exif-util.h
index 1b00c41..7646234 100644
--- a/src/eog-exif-util.h
+++ b/src/eog-exif-util.h
@@ -29,20 +29,30 @@
 
 #include <glib.h>
 #include <glib-object.h>
+#include <gtk/gtk.h>
 #include <libexif/exif-data.h>
 
 G_BEGIN_DECLS
 
 #define EOG_TYPE_EXIF_DATA eog_exif_data_get_type ()
 
-gchar*       eog_exif_util_format_date           (const gchar *date);
+gchar       *eog_exif_util_format_date           (const gchar *date);
+void         eog_exif_util_set_label_text        (GtkLabel *label,
+                                                  ExifData *exif_data,
+                                                  gint tag_id);
 
-const gchar *eog_exif_data_get_value             (ExifData *exif_data, gint tag_id, gchar *buffer, guint buf_size);
+void         eog_exif_util_set_focal_length_label_text (GtkLabel *label,
+                                                        ExifData *exif_data);
 
-GType                 eog_exif_data_get_type           (void) G_GNUC_CONST;
 
-ExifData * eog_exif_data_copy (ExifData *data);
-void          eog_exif_data_free (ExifData *data);
+const gchar *eog_exif_data_get_value             (ExifData *exif_data,
+                                                  gint tag_id, gchar *buffer,
+                                                  guint buf_size);
+
+GType        eog_exif_data_get_type              (void) G_GNUC_CONST;
+
+ExifData    *eog_exif_data_copy                  (ExifData *data);
+void         eog_exif_data_free                  (ExifData *data);
 
 G_END_DECLS
 
diff --git a/src/eog-metadata-sidebar.c b/src/eog-metadata-sidebar.c
new file mode 100644
index 0000000..145d307
--- /dev/null
+++ b/src/eog-metadata-sidebar.c
@@ -0,0 +1,634 @@
+/*
+ * eog-metadata-sidebar.c
+ * This file is part of eog
+ *
+ * Author: Felix Riemann <friemann gnome org>
+ *
+ * Portions based on code by: Lucas Rocha <lucasr gnome org>
+ *                            Hubert Figuiere <hub figuiere net> (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 "eog-dialog.h"
+#include "eog-image.h"
+#include "eog-metadata-sidebar.h"
+#include "eog-properties-dialog.h"
+#include "eog-scroll-view.h"
+#include "eog-util.h"
+#include "eog-window.h"
+
+#if HAVE_EXEMPI
+#include <exempi/xmp.h>
+#include <exempi/xmpconsts.h>
+#endif
+
+enum {
+	PROP_0,
+	PROP_IMAGE,
+	PROP_PARENT_WINDOW
+};
+
+struct _EogMetadataSidebarPrivate {
+	EogWindow *parent_window;
+	EogImage *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 EOG_METADATA_SIDEBAR_GET_PRIVATE(object) \
+	(G_TYPE_INSTANCE_GET_PRIVATE ((object), EOG_TYPE_METADATA_SIDEBAR, EogMetadataSidebarPrivate))
+
+G_DEFINE_TYPE(EogMetadataSidebar, eog_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
+eog_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
+eog_metadata_sidebar_update_general_section (EogMetadataSidebar *sidebar)
+{
+	EogMetadataSidebarPrivate *priv = sidebar->priv;
+	EogImage *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),
+			    eog_image_get_caption (img));
+	eog_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 = eog_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 = eog_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
+eog_metadata_sidebar_update_metadata_section (EogMetadataSidebar *sidebar)
+{
+	EogMetadataSidebarPrivate *priv = sidebar->priv;
+	EogImage *img = priv->image;
+	ExifData *exif_data = NULL;
+	XmpPtr xmp_data = NULL;
+
+
+	if (img) {
+		exif_data = eog_image_get_exif_info (img);
+		xmp_data =  eog_image_get_xmp_info (img);
+	}
+
+
+	eog_exif_util_set_label_text (GTK_LABEL (priv->aperture_label),
+				      exif_data, EXIF_TAG_FNUMBER);
+	eog_exif_util_set_label_text (GTK_LABEL (priv->exposure_label),
+				      exif_data,
+				      EXIF_TAG_EXPOSURE_TIME);
+	eog_exif_util_set_focal_length_label_text (
+				       GTK_LABEL (priv->focallen_label),
+				       exif_data);
+	eog_exif_util_set_label_text (GTK_LABEL (priv->flash_label),
+				      exif_data, EXIF_TAG_FLASH);
+	eog_exif_util_set_label_text (GTK_LABEL (priv->iso_label),
+				      exif_data,
+				      EXIF_TAG_ISO_SPEED_RATINGS);
+	eog_exif_util_set_label_text (GTK_LABEL (priv->metering_label),
+				      exif_data,
+				      EXIF_TAG_METERING_MODE);
+	eog_exif_util_set_label_text (GTK_LABEL (priv->model_label),
+				      exif_data, EXIF_TAG_MODEL);
+	eog_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
+ 	eog_xmp_set_label (xmp_data,
+			   NS_IPTC4XMP,
+			   "Location",
+			   priv->location_label);
+
+	eog_xmp_set_label (xmp_data,
+			   NS_DC,
+			   "description",
+			   priv->desc_label);
+
+	eog_xmp_set_label (xmp_data,
+			   NS_DC,
+			   "subject",
+			   priv->keyword_label);
+
+	eog_xmp_set_label (xmp_data,
+			   NS_DC,
+       	                   "creator",
+			   priv->creator_label);
+
+	eog_xmp_set_label (xmp_data,
+			   NS_DC,
+			   "rights",
+			   priv->rights_label);
+
+
+	if (xmp_data != NULL)
+		xmp_free (xmp_data);
+#endif
+		
+}
+
+static void
+eog_metadata_sidebar_update (EogMetadataSidebar *sidebar)
+{
+	g_return_if_fail (EOG_IS_METADATA_SIDEBAR (sidebar));
+
+	eog_metadata_sidebar_update_general_section (sidebar);
+	eog_metadata_sidebar_update_metadata_section (sidebar);
+}
+
+static void
+_thumbnail_changed_cb (EogImage *image, gpointer user_data)
+{
+	eog_metadata_sidebar_update (EOG_METADATA_SIDEBAR (user_data));
+}
+
+static void
+eog_metadata_sidebar_set_image (EogMetadataSidebar *sidebar, EogImage *image)
+{
+	EogMetadataSidebarPrivate *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);
+		eog_metadata_sidebar_update (sidebar);
+	}
+	
+	g_object_notify (G_OBJECT (sidebar), "image");
+}
+
+static void
+_notify_image_cb (GObject *gobject, GParamSpec *pspec, gpointer user_data)
+{
+	EogImage *image;
+
+	g_return_if_fail (EOG_IS_METADATA_SIDEBAR (user_data));
+	g_return_if_fail (EOG_IS_SCROLL_VIEW (gobject));
+
+	image = eog_scroll_view_get_image (EOG_SCROLL_VIEW (gobject));
+
+	eog_metadata_sidebar_set_image (EOG_METADATA_SIDEBAR (user_data),
+					image);
+
+	if (image)
+		g_object_unref (image);
+}
+
+static void
+_folder_button_clicked_cb (GtkButton *button, gpointer user_data)
+{
+	EogMetadataSidebarPrivate *priv = EOG_METADATA_SIDEBAR(user_data)->priv;
+	EogImage *img;
+	GdkScreen *screen;
+	GFile *file;
+
+	g_return_if_fail (priv->parent_window != NULL);
+
+	img = eog_window_get_image (priv->parent_window);
+	screen = gtk_widget_get_screen (GTK_WIDGET (priv->parent_window));
+	file = eog_image_get_file (img);
+
+	eog_util_show_file_in_filemanager (file, screen);
+
+	g_object_unref (file);
+}
+
+static void
+_details_button_clicked_cb (GtkButton *button, gpointer user_data)
+{
+	EogMetadataSidebarPrivate *priv = EOG_METADATA_SIDEBAR(user_data)->priv;
+	EogDialog *dlg;
+
+	g_return_if_fail (priv->parent_window != NULL);
+
+	dlg = eog_window_get_properties_dialog (
+					EOG_WINDOW (priv->parent_window));
+	g_return_if_fail (dlg != NULL);
+	eog_properties_dialog_set_page (EOG_PROPERTIES_DIALOG (dlg),
+					EOG_PROPERTIES_DIALOG_PAGE_DETAILS);
+	eog_dialog_show (dlg);
+}
+
+
+static void
+eog_metadata_sidebar_set_parent_window (EogMetadataSidebar *sidebar,
+					EogWindow *window)
+{
+	EogMetadataSidebarPrivate *priv;
+	GtkWidget *view;
+
+	g_return_if_fail (EOG_IS_METADATA_SIDEBAR (sidebar));
+	priv = sidebar->priv;
+	g_return_if_fail (priv->parent_window == NULL);
+
+	priv->parent_window = g_object_ref (window);
+	eog_metadata_sidebar_update (sidebar);
+	view = eog_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
+eog_metadata_sidebar_init (EogMetadataSidebar *sidebar)
+{
+	EogMetadataSidebarPrivate *priv;
+	GtkWidget *label;
+
+	priv = sidebar->priv = EOG_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
+eog_metadata_sidebar_constructed (GObject *object)
+{
+	EogMetadataSidebarPrivate *priv;
+
+	priv = EOG_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 (eog_metadata_sidebar_parent_class)->constructed (object);
+}
+
+static void
+eog_metadata_sidebar_get_property (GObject *object, guint property_id,
+				   GValue *value, GParamSpec *pspec)
+{
+	EogMetadataSidebar *sidebar;
+
+	g_return_if_fail (EOG_IS_METADATA_SIDEBAR (object));
+
+	sidebar = EOG_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
+eog_metadata_sidebar_set_property (GObject *object, guint property_id,
+				   const GValue *value, GParamSpec *pspec)
+{
+	EogMetadataSidebar *sidebar;
+
+	g_return_if_fail (EOG_IS_METADATA_SIDEBAR (object));
+
+	sidebar = EOG_METADATA_SIDEBAR (object);
+
+	switch (property_id) {
+	case PROP_IMAGE:
+	{
+		break;
+	}
+	case PROP_PARENT_WINDOW:
+	{
+		EogWindow *window;
+
+		window = g_value_get_object (value);
+		eog_metadata_sidebar_set_parent_window (sidebar, window);
+		break;
+	}
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+
+}
+static void
+eog_metadata_sidebar_class_init (EogMetadataSidebarClass *klass)
+{
+	GObjectClass *g_obj_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof(EogMetadataSidebarPrivate));
+
+	g_obj_class->constructed = eog_metadata_sidebar_constructed;
+	g_obj_class->get_property = eog_metadata_sidebar_get_property;
+	g_obj_class->set_property = eog_metadata_sidebar_set_property;
+/*	g_obj_class->dispose = eog_metadata_sidebar_dispose;*/
+
+	g_object_class_install_property (
+		g_obj_class, PROP_PARENT_WINDOW,
+		g_param_spec_object ("parent-window", NULL, NULL,
+				     EOG_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, EOG_TYPE_IMAGE,
+				     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
+				    );
+}
+
+
+GtkWidget*
+eog_metadata_sidebar_new (EogWindow *window)
+{
+	return gtk_widget_new (EOG_TYPE_METADATA_SIDEBAR,
+			       "hadjustment", NULL,
+			       "vadjustment", NULL,
+	                       "hscrollbar-policy", GTK_POLICY_NEVER,
+			       "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
+			       "border-width", 6,
+			       "parent-window", window,
+			       NULL);
+}
diff --git a/src/eog-metadata-sidebar.h b/src/eog-metadata-sidebar.h
new file mode 100644
index 0000000..7cc46db
--- /dev/null
+++ b/src/eog-metadata-sidebar.h
@@ -0,0 +1,61 @@
+/*
+ * eog-metadata-sidebar.h
+ * This file is part of eog
+ *
+ * Author: Felix Riemann <friemann gnome org>
+ *
+ * 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.
+ */
+
+#ifndef __EOG_METADATA_SIDEBAR_H__
+#define __EOG_METADATA_SIDEBAR_H_
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "eog-window.h"
+
+G_BEGIN_DECLS
+
+#define EOG_TYPE_METADATA_SIDEBAR          (eog_metadata_sidebar_get_type ())
+#define EOG_METADATA_SIDEBAR(o)            (G_TYPE_CHECK_INSTANCE_CAST ((o), EOG_TYPE_METADATA_SIDEBAR, EogMetadataSidebar))
+#define EOG_METADATA_SIDEBAR_CLASS(k)      (G_TYPE_CHECK_CLASS_CAST((k), EOG_TYPE_METADATA_SIDEBAR, EogMetadataSidebarClass))
+#define EOG_IS_METADATA_SIDEBAR(o)         (G_TYPE_CHECK_INSTANCE_TYPE ((o), EOG_TYPE_METADATA_SIDEBAR))
+#define EOG_IS_METADATA_SIDEBAR_CLASS(k)   (G_TYPE_CHECK_CLASS_TYPE ((k), EOG_TYPE_METADATA_SIDEBAR))
+#define EOG_METADATA_SIDEBAR_GET_CLASS(o)  (G_TYPE_INSTANCE_GET_CLASS ((o), EOG_TYPE_METADATA_SIDEBAR, EogMetadataSidebarClass))
+
+typedef struct _EogMetadataSidebar EogMetadataSidebar;
+typedef struct _EogMetadataSidebarClass EogMetadataSidebarClass;
+typedef struct _EogMetadataSidebarPrivate EogMetadataSidebarPrivate;
+
+struct _EogMetadataSidebar {
+	GtkScrolledWindow parent;
+
+	EogMetadataSidebarPrivate *priv;
+};
+
+struct _EogMetadataSidebarClass {
+	GtkScrolledWindowClass parent_klass;
+};
+
+GType eog_metadata_sidebar_get_type (void) G_GNUC_CONST;
+
+GtkWidget* eog_metadata_sidebar_new (EogWindow *window);
+
+G_END_DECLS
+
+#endif /* __EOG_METADATA_SIDEBAR_H__ */
diff --git a/src/eog-properties-dialog.c b/src/eog-properties-dialog.c
index a650c69..abcbd8f 100644
--- a/src/eog-properties-dialog.c
+++ b/src/eog-properties-dialog.c
@@ -183,94 +183,6 @@ pd_update_general_tab (EogPropertiesDialog *prop_dlg,
 	g_free (dir_str);
 }
 
-#if HAVE_EXIF
-static void
-eog_exif_set_label (GtkWidget *w, ExifData *exif_data, gint tag_id)
-{
-	gchar exif_buffer[512];
-	const gchar *buf_ptr;
-	gchar *label_text = NULL;
-
-	if (exif_data) {
-		buf_ptr = eog_exif_data_get_value (exif_data, tag_id,
-						   exif_buffer, 512);
-
-		if (tag_id == EXIF_TAG_DATE_TIME_ORIGINAL && buf_ptr)
-			label_text = eog_exif_util_format_date (buf_ptr);
-		else
-			label_text = eog_util_make_valid_utf8 (buf_ptr);
-	}
-
-	gtk_label_set_text (GTK_LABEL (w), label_text);
-	g_free (label_text);
-}
-
-static void
-eog_exif_set_focal_length_label (GtkWidget *w, ExifData *exif_data)
-{
-	ExifEntry *entry = NULL, *entry35mm = NULL;
-	ExifByteOrder byte_order;
-	gfloat f_val = 0.0;
-	gchar *fl_text = NULL,*fl35_text = NULL;
-
-	/* If no ExifData is supplied the label will be
-	 * cleared later as fl35_text is NULL. */
-	if (exif_data != NULL) {
-		entry = exif_data_get_entry (exif_data, EXIF_TAG_FOCAL_LENGTH);
-		entry35mm = exif_data_get_entry (exif_data,
-					    EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM);
-		byte_order = exif_data_get_byte_order (exif_data);
-	}
-
-	if (entry && G_LIKELY (entry->format == EXIF_FORMAT_RATIONAL)) {
-		ExifRational value;
-
-		/* Decode value by hand as libexif is not necessarily returning
-		 * it in the format we want it to be.
-		 */
-		value = exif_get_rational (entry->data, byte_order);
-		/* Guard against div by zero */
-		if (G_LIKELY(value.denominator != 0))
-			f_val = (gfloat)value.numerator/
-				(gfloat)value.denominator;
-
-		/* TRANSLATORS: This is the actual focal length used when
-		   the image was taken.*/
-		fl_text = g_strdup_printf (_("%.1f (lens)"), f_val);
-
-	}
-	if (entry35mm && G_LIKELY (entry35mm->format == EXIF_FORMAT_SHORT)) {
-		ExifShort s_val;
-
-		s_val = exif_get_short (entry35mm->data, byte_order);
-
-		/* Print as float to get a similar look as above. */
-		/* TRANSLATORS: This is the equivalent focal length assuming
-		   a 35mm film camera. */
-		fl35_text = g_strdup_printf(_("%.1f (35mm film)"),(float)s_val);
-	}
-
-	if (fl_text) {
-		if (fl35_text) {
-			gchar *merged_txt;
-
-			merged_txt = g_strconcat (fl35_text,", ", fl_text, NULL);
-			gtk_label_set_text (GTK_LABEL (w), merged_txt);
-			g_free (merged_txt);
-		} else {
-			gtk_label_set_text (GTK_LABEL (w), fl_text);
-		}
-	} else {
-		/* This will also clear the label if no ExifData was supplied */
-		gtk_label_set_text (GTK_LABEL (w), fl35_text);
-	}
-
-	g_free (fl35_text);
-	g_free (fl_text);
-
-}
-#endif
-
 #if HAVE_EXEMPI
 static void
 eog_xmp_set_label (XmpPtr xmp,
@@ -381,29 +293,29 @@ pd_update_metadata_tab (EogPropertiesDialog *prop_dlg,
 #if HAVE_EXIF
 	exif_data = (ExifData *) eog_image_get_exif_info (image);
 
-	eog_exif_set_label (priv->exif_aperture_label,
-			    exif_data, EXIF_TAG_FNUMBER);
+	eog_exif_util_set_label_text (GTK_LABEL (priv->exif_aperture_label),
+				      exif_data, EXIF_TAG_FNUMBER);
 
-	eog_exif_set_label (priv->exif_exposure_label,
-			    exif_data, EXIF_TAG_EXPOSURE_TIME);
+	eog_exif_util_set_label_text (GTK_LABEL (priv->exif_exposure_label),
+				      exif_data, EXIF_TAG_EXPOSURE_TIME);
 
-	eog_exif_set_focal_length_label (priv->exif_focal_label, exif_data);
+	eog_exif_util_set_focal_length_label_text (GTK_LABEL (priv->exif_focal_label), exif_data);
 
-	eog_exif_set_label (priv->exif_flash_label,
-			    exif_data, EXIF_TAG_FLASH);
+	eog_exif_util_set_label_text (GTK_LABEL (priv->exif_flash_label),
+				      exif_data, EXIF_TAG_FLASH);
 
-	eog_exif_set_label (priv->exif_iso_label,
-			    exif_data, EXIF_TAG_ISO_SPEED_RATINGS);
+	eog_exif_util_set_label_text (GTK_LABEL (priv->exif_iso_label),
+				      exif_data, EXIF_TAG_ISO_SPEED_RATINGS);
 
 
-	eog_exif_set_label (priv->exif_metering_label,
-			    exif_data, EXIF_TAG_METERING_MODE);
+	eog_exif_util_set_label_text (GTK_LABEL (priv->exif_metering_label),
+				      exif_data, EXIF_TAG_METERING_MODE);
 
-	eog_exif_set_label (priv->exif_model_label,
-			    exif_data, EXIF_TAG_MODEL);
+	eog_exif_util_set_label_text (GTK_LABEL (priv->exif_model_label),
+				      exif_data, EXIF_TAG_MODEL);
 
-	eog_exif_set_label (priv->exif_date_label,
-			    exif_data, EXIF_TAG_DATE_TIME_ORIGINAL);
+	eog_exif_util_set_label_text (GTK_LABEL (priv->exif_date_label),
+				      exif_data, EXIF_TAG_DATE_TIME_ORIGINAL);
 
 	eog_exif_details_update (EOG_EXIF_DETAILS (priv->exif_details),
 				 exif_data);
diff --git a/src/eog-window.c b/src/eog-window.c
index 311f263..171fb0f 100644
--- a/src/eog-window.c
+++ b/src/eog-window.c
@@ -54,6 +54,7 @@
 #include "eog-close-confirmation-dialog.h"
 #include "eog-clipboard-handler.h"
 #include "eog-window-activatable.h"
+#include "eog-metadata-sidebar.h"
 
 #include "eog-enum-types.h"
 
@@ -3128,25 +3129,26 @@ eog_window_cmd_print (GtkAction *action, gpointer user_data)
 	eog_window_print (window);
 }
 
-static void
-eog_window_cmd_properties (GtkAction *action, gpointer user_data)
+EogDialog*
+eog_window_get_properties_dialog (EogWindow *window)
 {
-	EogWindow *window = EOG_WINDOW (user_data);
 	EogWindowPrivate *priv;
-	GtkAction *next_image_action, *previous_image_action;
+
+	g_return_val_if_fail (EOG_IS_WINDOW (window), NULL);
 
 	priv = window->priv;
 
-	next_image_action =
-		gtk_action_group_get_action (priv->actions_gallery,
-					     "GoNext");
+	if (priv->properties_dlg == NULL) {
+		GtkAction *next_image_action, *previous_image_action;
 
-	previous_image_action =
-		gtk_action_group_get_action (priv->actions_gallery,
-					     "GoPrevious");
+		next_image_action =
+			gtk_action_group_get_action (priv->actions_gallery,
+						     "GoNext");
 
-	if (window->priv->properties_dlg == NULL) {
-		window->priv->properties_dlg =
+		previous_image_action =
+			gtk_action_group_get_action (priv->actions_gallery,
+						     "GoPrevious");
+		priv->properties_dlg =
 			eog_properties_dialog_new (GTK_WINDOW (window),
 						   EOG_THUMB_VIEW (priv->thumbview),
 						   next_image_action,
@@ -3160,7 +3162,20 @@ eog_window_cmd_properties (GtkAction *action, gpointer user_data)
 				 G_SETTINGS_BIND_GET);
 	}
 
-	eog_dialog_show (EOG_DIALOG (window->priv->properties_dlg));
+	return EOG_DIALOG (priv->properties_dlg);
+}
+
+static void
+eog_window_cmd_properties (GtkAction *action, gpointer user_data)
+{
+	EogWindow *window = EOG_WINDOW (user_data);
+	EogWindowPrivate *priv;
+	EogDialog *dialog;
+
+	priv = window->priv;
+
+	dialog = eog_window_get_properties_dialog (window);
+	eog_dialog_show (dialog);
 }
 
 static void
@@ -4599,6 +4614,11 @@ eog_window_construct_ui (EogWindow *window)
 				window);
 
  	priv->view = eog_scroll_view_new ();
+
+	eog_sidebar_add_page (EOG_SIDEBAR (priv->sidebar),
+			      _("Image Properties"),
+			      GTK_WIDGET (eog_metadata_sidebar_new (window)));
+
 	gtk_widget_set_size_request (GTK_WIDGET (priv->view), 100, 100);
 	g_signal_connect (G_OBJECT (priv->view),
 			  "zoom_changed",
diff --git a/src/eog-window.h b/src/eog-window.h
index fc337dc..00ce93a 100644
--- a/src/eog-window.h
+++ b/src/eog-window.h
@@ -30,6 +30,7 @@
 
 #include "eog-list-store.h"
 #include "eog-image.h"
+#include "eog-dialog.h"
 
 #include <glib.h>
 #include <glib-object.h>
@@ -125,6 +126,7 @@ void          eog_window_open_file_list	(EogWindow       *window,
 gboolean      eog_window_is_empty 	(EogWindow       *window);
 
 void          eog_window_reload_image (EogWindow *window);
+EogDialog    *eog_window_get_properties_dialog (EogWindow *window);
 G_END_DECLS
 
 #endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]