1 /* Eye Of Mate - Image Properties Dialog
2  *
3  * Copyright (C) 2006 The Free Software Foundation
4  *
5  * Author: Lucas Rocha <lucasr@gnome.org>
6  *         Hubert Figuiere <hub@figuiere.net> (XMP support)
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "eom-properties-dialog.h"
28 #include "eom-image.h"
29 #include "eom-util.h"
30 #include "eom-thumb-view.h"
31 
32 #if HAVE_EXIF
33 #include "eom-exif-util.h"
34 #endif
35 
36 #include <glib.h>
37 #include <glib/gi18n.h>
38 #include <glib-object.h>
39 #include <gio/gio.h>
40 #include <gtk/gtk.h>
41 
42 #if HAVE_EXEMPI
43 #include <exempi/xmp.h>
44 #include <exempi/xmpconsts.h>
45 #endif
46 #if HAVE_EXIF || HAVE_EXEMPI
47 #define HAVE_METADATA 1
48 #endif
49 
50 #if HAVE_METADATA
51 #include "eom-metadata-details.h"
52 #endif
53 
54 enum {
55         PROP_0,
56         PROP_THUMBVIEW,
57         PROP_NETBOOK_MODE
58 };
59 
60 struct _EomPropertiesDialogPrivate {
61 	EomThumbView   *thumbview;
62 
63 	gboolean        update_page;
64 	EomPropertiesDialogPage current_page;
65 
66 	GtkWidget      *notebook;
67 	GtkWidget      *close_button;
68 	GtkWidget      *next_button;
69 	GtkWidget      *previous_button;
70 
71 	GtkWidget      *general_box;
72 	GtkWidget      *thumbnail_image;
73 	GtkWidget      *name_label;
74 	GtkWidget      *width_label;
75 	GtkWidget      *height_label;
76 	GtkWidget      *type_label;
77 	GtkWidget      *bytes_label;
78 	GtkWidget      *folder_button;
79 	gchar          *folder_button_uri;
80 #ifdef HAVE_EXIF
81 	GtkWidget      *exif_aperture_label;
82 	GtkWidget      *exif_exposure_label;
83 	GtkWidget      *exif_focal_label;
84 	GtkWidget      *exif_flash_label;
85 	GtkWidget      *exif_iso_label;
86 	GtkWidget      *exif_metering_label;
87 	GtkWidget      *exif_model_label;
88 	GtkWidget      *exif_date_label;
89 #endif
90 #ifdef HAVE_EXEMPI
91 	GtkWidget      *xmp_location_label;
92 	GtkWidget      *xmp_description_label;
93 	GtkWidget      *xmp_keywords_label;
94 	GtkWidget      *xmp_creator_label;
95 	GtkWidget      *xmp_rights_label;
96 #else
97 	GtkWidget      *xmp_box;
98 	GtkWidget      *xmp_box_label;
99 #endif
100 #if HAVE_METADATA
101 	GtkWidget      *metadata_box;
102 	GtkWidget      *metadata_details_expander;
103 	GtkWidget      *metadata_details;
104 	GtkWidget      *metadata_details_box;
105 	GtkWidget      *metadata_details_sw;
106 #endif
107 
108 	gboolean        netbook_mode;
109 };
110 
111 G_DEFINE_TYPE_WITH_PRIVATE (EomPropertiesDialog, eom_properties_dialog, GTK_TYPE_DIALOG);
112 
113 static void
parent_file_display_name_query_info_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)114 parent_file_display_name_query_info_cb (GObject *source_object,
115 					GAsyncResult *res,
116 					gpointer user_data)
117 {
118 	EomPropertiesDialog *prop_dlg = EOM_PROPERTIES_DIALOG (user_data);
119 	GFile *parent_file = G_FILE (source_object);
120 	GFileInfo *file_info;
121 	gchar *display_name;
122 
123 
124 	file_info = g_file_query_info_finish (parent_file, res, NULL);
125 	if (file_info == NULL) {
126 		display_name = g_file_get_basename (parent_file);
127 	} else {
128 		display_name = g_strdup (
129 			g_file_info_get_display_name (file_info));
130 		g_object_unref (file_info);
131 	}
132 	gtk_button_set_label (GTK_BUTTON (prop_dlg->priv->folder_button),
133 			      display_name);
134 	gtk_widget_set_sensitive (prop_dlg->priv->folder_button, TRUE);
135 
136 	g_free (display_name);
137 	g_object_unref (prop_dlg);
138 }
139 
140 static void
pd_update_general_tab(EomPropertiesDialog * prop_dlg,EomImage * image)141 pd_update_general_tab (EomPropertiesDialog *prop_dlg,
142 		       EomImage            *image)
143 {
144 	gchar *bytes_str, *dir_str_long;
145 	gchar *width_str, *height_str;
146 	GFile *file, *parent_file;
147 	GFileInfo *file_info;
148 	const char *mime_str;
149 	char *type_str;
150 	gint width, height;
151 	goffset bytes;
152 
153 	g_object_set (G_OBJECT (prop_dlg->priv->thumbnail_image),
154 		      "pixbuf", eom_image_get_thumbnail (image),
155 		      NULL);
156 
157 	gtk_label_set_text (GTK_LABEL (prop_dlg->priv->name_label),
158 			    eom_image_get_caption (image));
159 
160 	eom_image_get_size (image, &width, &height);
161 
162 	width_str = g_strdup_printf ("%d %s", width,
163 				     ngettext ("pixel", "pixels", width));
164 	height_str = g_strdup_printf ("%d %s", height,
165 				      ngettext ("pixel", "pixels", height));
166 
167 	gtk_label_set_text (GTK_LABEL (prop_dlg->priv->width_label), width_str);
168 
169 	gtk_label_set_text (GTK_LABEL (prop_dlg->priv->height_label),
170 			    height_str);
171 
172 	g_free (height_str);
173 	g_free (width_str);
174 
175 	file = eom_image_get_file (image);
176 	file_info = g_file_query_info (file,
177 				       G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
178 				       0, NULL, NULL);
179 	if (file_info == NULL) {
180 		type_str = g_strdup (_("Unknown"));
181 	} else {
182 		mime_str = g_file_info_get_content_type (file_info);
183 		type_str = g_content_type_get_description (mime_str);
184 		g_object_unref (file_info);
185 	}
186 
187 	gtk_label_set_text (GTK_LABEL (prop_dlg->priv->type_label), type_str);
188 
189 	bytes = eom_image_get_bytes (image);
190 	bytes_str = g_format_size (bytes);
191 
192 	gtk_label_set_text (GTK_LABEL (prop_dlg->priv->bytes_label), bytes_str);
193 
194 	parent_file = g_file_get_parent (file);
195 	if (parent_file == NULL) {
196 		/* file is root directory itself */
197 		parent_file = g_object_ref (file);
198 	}
199 
200 	gtk_widget_set_sensitive (prop_dlg->priv->folder_button, FALSE);
201 	gtk_button_set_label (GTK_BUTTON (prop_dlg->priv->folder_button), NULL);
202 
203 	dir_str_long = g_file_get_path (parent_file);
204 	gtk_widget_set_tooltip_text (GTK_WIDGET (prop_dlg->priv->folder_button),
205 	                             dir_str_long);
206 
207 	g_free (prop_dlg->priv->folder_button_uri);
208 	prop_dlg->priv->folder_button_uri = g_file_get_uri (parent_file);
209 
210 	g_file_query_info_async (parent_file,
211 				 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
212 				 G_FILE_QUERY_INFO_NONE,
213 				 G_PRIORITY_DEFAULT,
214 				 NULL,
215 				 parent_file_display_name_query_info_cb,
216 				 g_object_ref (prop_dlg));
217 
218 	g_object_unref (parent_file);
219 
220 	g_free (type_str);
221 	g_free (bytes_str);
222 	g_free (dir_str_long);
223 }
224 
225 #if HAVE_EXEMPI
226 static void
eom_xmp_set_label(XmpPtr xmp,const char * ns,const char * propname,GtkWidget * w)227 eom_xmp_set_label (XmpPtr xmp,
228 		   const char *ns,
229 		   const char *propname,
230 		   GtkWidget *w)
231 {
232 	uint32_t options;
233 
234 	XmpStringPtr value = xmp_string_new ();
235 
236 	if (xmp_get_property (xmp, ns, propname, value, &options)) {
237 		if (XMP_IS_PROP_SIMPLE (options)) {
238 			gtk_label_set_text (GTK_LABEL (w), xmp_string_cstr (value));
239 		} else if (XMP_IS_PROP_ARRAY (options)) {
240 			XmpIteratorPtr iter = xmp_iterator_new (xmp,
241 							        ns,
242 								propname,
243 								XMP_ITER_JUSTLEAFNODES);
244 
245 			GString *string = g_string_new ("");
246 
247 			if (iter) {
248 				gboolean first = TRUE;
249 
250 				while (xmp_iterator_next (iter, NULL, NULL, value, &options)
251 				       && !XMP_IS_PROP_QUALIFIER (options)) {
252 
253 					if (!first) {
254 						g_string_append_printf(string, ", ");
255 					} else {
256 						first = FALSE;
257 					}
258 
259 					g_string_append_printf (string,
260 								"%s",
261 								xmp_string_cstr (value));
262 				}
263 
264 				xmp_iterator_free (iter);
265 			}
266 
267 			gtk_label_set_text (GTK_LABEL (w), string->str);
268 			g_string_free (string, TRUE);
269 		}
270 	} else {
271 		/* Property was not found */
272 		/* Clear label so it won't show bogus data */
273 		gtk_label_set_text (GTK_LABEL (w), NULL);
274 	}
275 
276 	xmp_string_free (value);
277 }
278 #endif
279 
280 #if HAVE_METADATA
281 static void
pd_update_metadata_tab(EomPropertiesDialog * prop_dlg,EomImage * image)282 pd_update_metadata_tab (EomPropertiesDialog *prop_dlg,
283 			EomImage            *image)
284 {
285 	EomPropertiesDialogPrivate *priv;
286 	GtkNotebook *notebook;
287 #if HAVE_EXIF
288 	ExifData    *exif_data;
289 #endif
290 #if HAVE_EXEMPI
291 	XmpPtr      xmp_data;
292 #endif
293 
294 	g_return_if_fail (EOM_IS_PROPERTIES_DIALOG (prop_dlg));
295 
296 	priv = prop_dlg->priv;
297 
298 	notebook = GTK_NOTEBOOK (priv->notebook);
299 
300 	if (TRUE
301 #if HAVE_EXIF
302 	    && !eom_image_has_data (image, EOM_IMAGE_DATA_EXIF)
303 #endif
304 #if HAVE_EXEMPI
305 	    && !eom_image_has_data (image, EOM_IMAGE_DATA_XMP)
306 #endif
307 	    ) {
308 		if (gtk_notebook_get_current_page (notebook) ==	EOM_PROPERTIES_DIALOG_PAGE_EXIF) {
309 			gtk_notebook_prev_page (notebook);
310 		} else if (gtk_notebook_get_current_page (notebook) == EOM_PROPERTIES_DIALOG_PAGE_DETAILS) {
311 			gtk_notebook_set_current_page (notebook, EOM_PROPERTIES_DIALOG_PAGE_GENERAL);
312 		}
313 
314 		if (gtk_widget_get_visible (priv->metadata_box)) {
315 			gtk_widget_hide (priv->metadata_box);
316 		}
317 		if (gtk_widget_get_visible (priv->metadata_details_box)) {
318 			gtk_widget_hide (priv->metadata_details_box);
319 		}
320 
321 		return;
322 	} else {
323 		if (!gtk_widget_get_visible (priv->metadata_box))
324 			gtk_widget_show_all (priv->metadata_box);
325 		if (priv->netbook_mode &&
326 		    !gtk_widget_get_visible (priv->metadata_details_box)) {
327 			gtk_widget_show_all (priv->metadata_details_box);
328 			gtk_widget_hide (priv->metadata_details_expander);
329 		}
330 	}
331 
332 #if HAVE_EXIF
333 	exif_data = (ExifData *) eom_image_get_exif_info (image);
334 
335 	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_aperture_label),
336 				      exif_data, EXIF_TAG_FNUMBER);
337 
338 	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_exposure_label),
339 				      exif_data, EXIF_TAG_EXPOSURE_TIME);
340 
341 	eom_exif_util_set_focal_length_label_text (GTK_LABEL (priv->exif_focal_label), exif_data);
342 
343 	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_flash_label),
344 				      exif_data, EXIF_TAG_FLASH);
345 
346 	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_iso_label),
347 				      exif_data, EXIF_TAG_ISO_SPEED_RATINGS);
348 
349 
350 	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_metering_label),
351 				      exif_data, EXIF_TAG_METERING_MODE);
352 
353 	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_model_label),
354 				      exif_data, EXIF_TAG_MODEL);
355 
356 	eom_exif_util_set_label_text (GTK_LABEL (priv->exif_date_label),
357 				      exif_data, EXIF_TAG_DATE_TIME_ORIGINAL);
358 
359 	eom_metadata_details_update (EOM_METADATA_DETAILS (priv->metadata_details),
360 				 exif_data);
361 
362 	/* exif_data_unref can handle NULL-values */
363 	exif_data_unref(exif_data);
364 #endif
365 
366 #if HAVE_EXEMPI
367 	xmp_data = (XmpPtr) eom_image_get_xmp_info (image);
368 
369  	if (xmp_data != NULL) {
370 		eom_xmp_set_label (xmp_data,
371 				   NS_IPTC4XMP,
372 				   "Location",
373 				   priv->xmp_location_label);
374 
375 		eom_xmp_set_label (xmp_data,
376 				   NS_DC,
377 				   "description",
378 				   priv->xmp_description_label);
379 
380 		eom_xmp_set_label (xmp_data,
381 				   NS_DC,
382 				   "subject",
383 				   priv->xmp_keywords_label);
384 
385 		eom_xmp_set_label (xmp_data,
386 				   NS_DC,
387         	                   "creator",
388 				   priv->xmp_creator_label);
389 
390 		eom_xmp_set_label (xmp_data,
391 				   NS_DC,
392 				   "rights",
393 				   priv->xmp_rights_label);
394 
395 		eom_metadata_details_xmp_update (EOM_METADATA_DETAILS (priv->metadata_details), xmp_data);
396 
397 		xmp_free (xmp_data);
398 	} else {
399 		/* Image has no XMP data */
400 
401 		/* Clear the labels so they won't display foreign data.*/
402 
403 		gtk_label_set_text (GTK_LABEL (priv->xmp_location_label), NULL);
404 		gtk_label_set_text (GTK_LABEL (priv->xmp_description_label),
405 				    NULL);
406 		gtk_label_set_text (GTK_LABEL (priv->xmp_keywords_label), NULL);
407 		gtk_label_set_text (GTK_LABEL (priv->xmp_creator_label), NULL);
408 		gtk_label_set_text (GTK_LABEL (priv->xmp_rights_label), NULL);
409 	}
410 #endif
411 }
412 
413 static gboolean
pd_resize_dialog(gpointer user_data)414 pd_resize_dialog (gpointer user_data)
415 {
416 	gint width, height;
417 
418 	gtk_window_get_size (GTK_WINDOW (user_data),
419 			     &width,
420 			     &height);
421 
422 	gtk_window_resize (GTK_WINDOW (user_data), width, 1);
423 
424 	return FALSE;
425 }
426 
427 static void
pd_exif_details_activated_cb(GtkExpander * expander,GParamSpec * param_spec,GtkWidget * dialog)428 pd_exif_details_activated_cb (GtkExpander *expander,
429 			      GParamSpec *param_spec,
430 			      GtkWidget *dialog)
431 {
432 	gboolean expanded;
433 
434 	expanded = gtk_expander_get_expanded (expander);
435 
436 	/*FIXME: this is depending on the expander animation
437          * duration. Need to find a safer way for doing that. */
438 	if (!expanded)
439 		g_timeout_add (150, pd_resize_dialog, dialog);
440 }
441 #endif
442 
443 static void
pd_folder_button_clicked_cb(GtkButton * button,gpointer data)444 pd_folder_button_clicked_cb (GtkButton *button, gpointer data)
445 {
446 	EomPropertiesDialogPrivate *priv = EOM_PROPERTIES_DIALOG (data)->priv;
447 	GtkWindow *window;
448 	guint32 timestamp;
449 
450 	if (!priv->folder_button_uri)
451 		return;
452 
453 	timestamp = gtk_get_current_event_time ();
454 
455 	window = GTK_WINDOW (data);
456 	gtk_show_uri_on_window (window, priv->folder_button_uri, timestamp, NULL);
457 }
458 
459 static gboolean
eom_properties_dialog_page_switch(GtkNotebook * notebook,gpointer page,guint page_index,EomPropertiesDialog * prop_dlg)460 eom_properties_dialog_page_switch (GtkNotebook     *notebook,
461 				   gpointer         page,
462 				   guint            page_index,
463 				   EomPropertiesDialog *prop_dlg)
464 {
465 	if (prop_dlg->priv->update_page)
466 		prop_dlg->priv->current_page = page_index;
467 
468 	return TRUE;
469 }
470 
471 void
eom_properties_dialog_set_netbook_mode(EomPropertiesDialog * dlg,gboolean enable)472 eom_properties_dialog_set_netbook_mode (EomPropertiesDialog *dlg,
473 					gboolean enable)
474 {
475 	EomPropertiesDialogPrivate *priv;
476 
477 	g_return_if_fail (EOM_IS_PROPERTIES_DIALOG (dlg));
478 
479 	priv = dlg->priv;
480 
481 	if (priv->netbook_mode == enable)
482 		return;
483 
484 	priv->netbook_mode = enable;
485 
486 #ifdef HAVE_METADATA
487 	if (enable) {
488 		g_object_ref (priv->metadata_details_sw);
489 		gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (priv->metadata_details_sw)),
490 				      priv->metadata_details_sw);
491 		gtk_container_add (GTK_CONTAINER (priv->metadata_details_box), priv->metadata_details_sw);
492 		g_object_unref (priv->metadata_details_sw);
493 		// Only show details box if metadata is being displayed
494 		if (gtk_widget_get_visible (priv->metadata_box))
495 			gtk_widget_show_all (priv->metadata_details_box);
496 
497 		gtk_widget_hide (priv->metadata_details_expander);
498 	} else {
499 		g_object_ref (priv->metadata_details_sw);
500 		gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (priv->metadata_details_sw)),
501 				      priv->metadata_details_sw);
502 		gtk_container_add (GTK_CONTAINER (priv->metadata_details_expander), priv->metadata_details_sw);
503 		g_object_unref (priv->metadata_details_sw);
504 		gtk_widget_show_all (priv->metadata_details_expander);
505 
506 		if (gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)) == EOM_PROPERTIES_DIALOG_PAGE_DETAILS)
507 			gtk_notebook_prev_page (GTK_NOTEBOOK (priv->notebook));
508 		gtk_widget_hide (priv->metadata_details_box);
509 	}
510 #endif
511 }
512 
513 static void
eom_properties_dialog_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)514 eom_properties_dialog_set_property (GObject      *object,
515 				    guint         prop_id,
516 				    const GValue *value,
517 				    GParamSpec   *pspec)
518 {
519 	EomPropertiesDialog *prop_dlg = EOM_PROPERTIES_DIALOG (object);
520 
521 	switch (prop_id) {
522 		case PROP_THUMBVIEW:
523 			prop_dlg->priv->thumbview = g_value_get_object (value);
524 			break;
525 		case PROP_NETBOOK_MODE:
526 			eom_properties_dialog_set_netbook_mode (prop_dlg,
527 						   g_value_get_boolean (value));
528 			break;
529 		default:
530 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id,
531 							   pspec);
532 			break;
533 	}
534 }
535 
536 static void
eom_properties_dialog_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)537 eom_properties_dialog_get_property (GObject    *object,
538 				    guint       prop_id,
539 				    GValue     *value,
540 				    GParamSpec *pspec)
541 {
542 	EomPropertiesDialog *prop_dlg = EOM_PROPERTIES_DIALOG (object);
543 
544 	switch (prop_id) {
545 		case PROP_THUMBVIEW:
546 			g_value_set_object (value, prop_dlg->priv->thumbview);
547 			break;
548 		case PROP_NETBOOK_MODE:
549 			g_value_set_boolean (value,
550 					     prop_dlg->priv->netbook_mode);
551 			break;
552 		default:
553 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id,
554 							   pspec);
555 			break;
556 	}
557 }
558 
559 static void
eom_properties_dialog_dispose(GObject * object)560 eom_properties_dialog_dispose (GObject *object)
561 {
562 	EomPropertiesDialog *prop_dlg;
563 	EomPropertiesDialogPrivate *priv;
564 
565 	g_return_if_fail (object != NULL);
566 	g_return_if_fail (EOM_IS_PROPERTIES_DIALOG (object));
567 
568 	prop_dlg = EOM_PROPERTIES_DIALOG (object);
569 	priv = prop_dlg->priv;
570 
571 	if (priv->thumbview) {
572 		g_object_unref (priv->thumbview);
573 		priv->thumbview = NULL;
574 	}
575 
576 	g_free (priv->folder_button_uri);
577 	priv->folder_button_uri = NULL;
578 
579 	G_OBJECT_CLASS (eom_properties_dialog_parent_class)->dispose (object);
580 }
581 
582 static void
eom_properties_dialog_class_init(EomPropertiesDialogClass * klass)583 eom_properties_dialog_class_init (EomPropertiesDialogClass *klass)
584 {
585 	GObjectClass *g_object_class = (GObjectClass *) klass;
586 
587 	g_object_class->dispose = eom_properties_dialog_dispose;
588 	g_object_class->set_property = eom_properties_dialog_set_property;
589 	g_object_class->get_property = eom_properties_dialog_get_property;
590 
591 	g_object_class_install_property (g_object_class,
592 					 PROP_THUMBVIEW,
593 					 g_param_spec_object ("thumbview",
594 							      "Thumbview",
595 							      "Thumbview",
596 							      EOM_TYPE_THUMB_VIEW,
597 							      G_PARAM_READWRITE |
598 							      G_PARAM_CONSTRUCT_ONLY |
599 							      G_PARAM_STATIC_NAME |
600 							      G_PARAM_STATIC_NICK |
601 							      G_PARAM_STATIC_BLURB));
602 	g_object_class_install_property (g_object_class, PROP_NETBOOK_MODE,
603 					 g_param_spec_boolean ("netbook-mode",
604 					 		      "Netbook Mode",
605 							      "Netbook Mode",
606 							      FALSE,
607 							      G_PARAM_READWRITE |
608 							      G_PARAM_STATIC_STRINGS));
609 
610 	GtkWidgetClass *wklass = (GtkWidgetClass*) klass;
611 
612 	gtk_widget_class_set_template_from_resource (wklass,
613 	                                             "/org/mate/eom/ui/eom-image-properties-dialog.ui");
614 
615 	gtk_widget_class_bind_template_child_private(wklass,
616 						     EomPropertiesDialog,
617 						     notebook);
618 	gtk_widget_class_bind_template_child_private(wklass,
619 						     EomPropertiesDialog,
620 						     previous_button);
621 	gtk_widget_class_bind_template_child_private(wklass,
622 						     EomPropertiesDialog,
623 						     next_button);
624 	gtk_widget_class_bind_template_child_private(wklass,
625 						     EomPropertiesDialog,
626 						     close_button);
627 	gtk_widget_class_bind_template_child_private(wklass,
628 						     EomPropertiesDialog,
629 						     thumbnail_image);
630 	gtk_widget_class_bind_template_child_private(wklass,
631 						     EomPropertiesDialog,
632 						     general_box);
633 	gtk_widget_class_bind_template_child_private(wklass,
634 						     EomPropertiesDialog,
635 						     name_label);
636 	gtk_widget_class_bind_template_child_private(wklass,
637 						     EomPropertiesDialog,
638 						     width_label);
639 	gtk_widget_class_bind_template_child_private(wklass,
640 						     EomPropertiesDialog,
641 						     height_label);
642 	gtk_widget_class_bind_template_child_private(wklass,
643 						     EomPropertiesDialog,
644 						     type_label);
645 	gtk_widget_class_bind_template_child_private(wklass,
646 						     EomPropertiesDialog,
647 						     bytes_label);
648 	gtk_widget_class_bind_template_child_private(wklass,
649 						     EomPropertiesDialog,
650 						     folder_button);
651 
652 #if HAVE_EXIF
653 	gtk_widget_class_bind_template_child_private(wklass,
654 						     EomPropertiesDialog,
655 						     exif_aperture_label);
656 	gtk_widget_class_bind_template_child_private(wklass,
657 						     EomPropertiesDialog,
658 						     exif_exposure_label);
659 	gtk_widget_class_bind_template_child_private(wklass,
660 						     EomPropertiesDialog,
661 						     exif_focal_label);
662 	gtk_widget_class_bind_template_child_private(wklass,
663 						     EomPropertiesDialog,
664 						     exif_flash_label);
665 	gtk_widget_class_bind_template_child_private(wklass,
666 						     EomPropertiesDialog,
667 						     exif_iso_label);
668 	gtk_widget_class_bind_template_child_private(wklass,
669 						     EomPropertiesDialog,
670 						     exif_metering_label);
671 	gtk_widget_class_bind_template_child_private(wklass,
672 						     EomPropertiesDialog,
673 						     exif_model_label);
674 	gtk_widget_class_bind_template_child_private(wklass,
675 						     EomPropertiesDialog,
676 						     exif_date_label);
677 #endif
678 #if HAVE_EXEMPI
679 	gtk_widget_class_bind_template_child_private(wklass,
680 						     EomPropertiesDialog,
681 						     xmp_location_label);
682 	gtk_widget_class_bind_template_child_private(wklass,
683 						     EomPropertiesDialog,
684 						     xmp_description_label);
685 	gtk_widget_class_bind_template_child_private(wklass,
686 						     EomPropertiesDialog,
687 						     xmp_keywords_label);
688 	gtk_widget_class_bind_template_child_private(wklass,
689 						     EomPropertiesDialog,
690 						     xmp_creator_label);
691 	gtk_widget_class_bind_template_child_private(wklass,
692 						     EomPropertiesDialog,
693 						     xmp_rights_label);
694 #else
695 	gtk_widget_class_bind_template_child_private(wklass,
696 						     EomPropertiesDialog,
697 						     xmp_box);
698 	gtk_widget_class_bind_template_child_private(wklass,
699 						     EomPropertiesDialog,
700 						     xmp_box_label);
701 #endif
702 #ifdef HAVE_METADATA
703 	gtk_widget_class_bind_template_child_private(wklass,
704 						     EomPropertiesDialog,
705 						     metadata_box);
706 	gtk_widget_class_bind_template_child_private(wklass,
707 						     EomPropertiesDialog,
708 						     metadata_details_expander);
709 	gtk_widget_class_bind_template_child_private(wklass,
710 						     EomPropertiesDialog,
711 						     metadata_details_box);
712 
713 	gtk_widget_class_bind_template_callback(wklass,
714 						pd_exif_details_activated_cb);
715 #endif
716 	gtk_widget_class_bind_template_callback(wklass,
717 						eom_properties_dialog_page_switch);
718 	gtk_widget_class_bind_template_callback(wklass,
719 						pd_folder_button_clicked_cb);
720 }
721 
722 static void
eom_properties_dialog_init(EomPropertiesDialog * prop_dlg)723 eom_properties_dialog_init (EomPropertiesDialog *prop_dlg)
724 {
725 	EomPropertiesDialogPrivate *priv;
726 #if HAVE_METADATA
727 	GtkWidget *sw;
728 #endif
729 
730 	prop_dlg->priv = eom_properties_dialog_get_instance_private (prop_dlg);
731 
732 	priv = prop_dlg->priv;
733 
734 	priv->update_page = FALSE;
735 
736 	gtk_widget_init_template (GTK_WIDGET (prop_dlg));
737 
738 	g_signal_connect (prop_dlg,
739 	                  "delete-event",
740 	                 G_CALLBACK (gtk_widget_hide_on_delete),
741 	                 prop_dlg);
742 
743 	g_signal_connect_swapped (priv->close_button,
744 	                          "clicked",
745 	                          G_CALLBACK (gtk_widget_hide_on_delete),
746 	                          prop_dlg);
747 
748 	gtk_widget_set_size_request (priv->thumbnail_image, 100, 100);
749 
750 #ifdef HAVE_METADATA
751  	sw = gtk_scrolled_window_new (NULL, NULL);
752 
753 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
754 					     GTK_SHADOW_IN);
755 
756 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
757 					GTK_POLICY_AUTOMATIC,
758 					GTK_POLICY_AUTOMATIC);
759 
760 	priv->metadata_details = eom_metadata_details_new ();
761 	gtk_widget_set_size_request (priv->metadata_details, -1, 170);
762 	gtk_container_set_border_width (GTK_CONTAINER (sw), 6);
763 	gtk_widget_set_vexpand (priv->metadata_details, TRUE);
764 
765 	gtk_container_add (GTK_CONTAINER (sw), priv->metadata_details);
766 	gtk_widget_show_all (sw);
767 
768 	priv->metadata_details_sw = sw;
769 
770 	if (priv->netbook_mode) {
771 		gtk_widget_hide (priv->metadata_details_expander);
772 		gtk_box_pack_start (GTK_BOX (priv->metadata_details_box),
773 				    sw, TRUE, TRUE, 6);
774 	} else {
775 		gtk_container_add (GTK_CONTAINER (priv->metadata_details_expander),
776 				   sw);
777 	}
778 
779 #ifndef HAVE_EXEMPI
780 	gtk_widget_hide (priv->xmp_box);
781 	gtk_widget_hide (priv->xmp_box_label);
782 #endif
783 
784 #else
785 	/* Remove pages from back to front. Otherwise the page index
786 	 * needs to be adjusted when deleting the next page. */
787 	gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook),
788 				  EOM_PROPERTIES_DIALOG_PAGE_DETAILS);
789 	gtk_notebook_remove_page (GTK_NOTEBOOK (priv->notebook),
790 				  EOM_PROPERTIES_DIALOG_PAGE_EXIF);
791 #endif
792 
793     /* Add tab scrolling support for GTK3 */
794     gtk_widget_add_events (priv->notebook, GDK_SCROLL_MASK);
795     g_signal_connect (priv->notebook,
796                       "scroll-event",
797                       G_CALLBACK (eom_notebook_scroll_event_cb),
798                       NULL);
799 }
800 
801 /**
802  * eom_properties_dialog_new:
803  * @parent: the dialog's parent window
804  * @thumbview:
805  * @next_image_action:
806  * @previous_image_action:
807  *
808  *
809  *
810  * Returns: (transfer full) (type EomPropertiesDialog): a new #EomPropertiesDialog
811  **/
812 
813 GtkWidget *
eom_properties_dialog_new(GtkWindow * parent,EomThumbView * thumbview,GtkAction * next_image_action,GtkAction * previous_image_action)814 eom_properties_dialog_new (GtkWindow    *parent,
815 			   EomThumbView *thumbview,
816 			   GtkAction    *next_image_action,
817 			   GtkAction    *previous_image_action)
818 {
819 	GObject *prop_dlg;
820 
821 	g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);
822 	g_return_val_if_fail (EOM_IS_THUMB_VIEW (thumbview), NULL);
823 	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
824 	g_return_val_if_fail (GTK_IS_ACTION (next_image_action), NULL);
825 	g_return_val_if_fail (GTK_IS_ACTION (previous_image_action), NULL);
826 
827 	prop_dlg = g_object_new (EOM_TYPE_PROPERTIES_DIALOG,
828 	                         "thumbview", thumbview,
829 	                         NULL);
830 
831 	if (parent) {
832 		gtk_window_set_transient_for (GTK_WINDOW (prop_dlg), parent);
833 	}
834 
835 	gtk_activatable_set_related_action (GTK_ACTIVATABLE (EOM_PROPERTIES_DIALOG (prop_dlg)->priv->next_button), next_image_action);
836 
837 	gtk_activatable_set_related_action (GTK_ACTIVATABLE (EOM_PROPERTIES_DIALOG (prop_dlg)->priv->previous_button), previous_image_action);
838 	G_GNUC_END_IGNORE_DEPRECATIONS;
839 
840 	return GTK_WIDGET (prop_dlg);
841 }
842 
843 void
eom_properties_dialog_update(EomPropertiesDialog * prop_dlg,EomImage * image)844 eom_properties_dialog_update (EomPropertiesDialog *prop_dlg,
845 			      EomImage            *image)
846 {
847 	g_return_if_fail (EOM_IS_PROPERTIES_DIALOG (prop_dlg));
848 
849 	prop_dlg->priv->update_page = FALSE;
850 
851 	pd_update_general_tab (prop_dlg, image);
852 
853 #ifdef HAVE_METADATA
854 	pd_update_metadata_tab (prop_dlg, image);
855 #endif
856 	gtk_notebook_set_current_page (GTK_NOTEBOOK (prop_dlg->priv->notebook),
857 				       prop_dlg->priv->current_page);
858 
859 	prop_dlg->priv->update_page = TRUE;
860 }
861 
862 void
eom_properties_dialog_set_page(EomPropertiesDialog * prop_dlg,EomPropertiesDialogPage page)863 eom_properties_dialog_set_page (EomPropertiesDialog *prop_dlg,
864 			        EomPropertiesDialogPage page)
865 {
866 	g_return_if_fail (EOM_IS_PROPERTIES_DIALOG (prop_dlg));
867 
868 	prop_dlg->priv->current_page = page;
869 
870 	gtk_notebook_set_current_page (GTK_NOTEBOOK (prop_dlg->priv->notebook),
871 				       page);
872 }
873