view src/bar_exif.c @ 276:4f526d436873

Implement secure rc file saving. First data is written to a temporary file, then if nothing was wrong, this file is renamed to the final name. This way the risk of corrupted rc file is greatly reduced. The code is borrowed from ELinks (http://elinks.cz).
author zas_
date Tue, 08 Apr 2008 21:55:58 +0000
parents 395d7115df14
children 9995c5fb202a
line wrap: on
line source

/*
 * Geeqie
 * (C) 2004 John Ellis
 *
 * Author: John Ellis
 *
 * This software is released under the GNU General Public License (GNU GPL).
 * Please read the included file COPYING for more information.
 * This software comes with no warranty of any kind, use at your own risk!
 */


#include "gqview.h"
#include "bar_exif.h"

#include "exif.h"
#include "ui_bookmark.h"
#include "ui_misc.h"
#include "filelist.h"

#include <math.h>

#define EXIF_BAR_SIZE_INCREMENT 48
#define EXIF_BAR_ARROW_SIZE 7

#define EXIF_BAR_CUSTOM_COUNT 20

#define BAR_EXIF_DATA_COLUMN_WIDTH 250

static const gchar *bar_exif_key_list_real[] = {
	"fCamera",
	"fDateTime",
	"fShutterSpeed",
	"fAperture",
	"Exif.Photo.ExposureProgram",
	"fExposureBias",
	"fISOSpeedRating",
	"fFocalLength",
	"fFocalLength35mmFilm",
	"fSubjectDistance",
	"Exif.Photo.MeteringMode",
	"fFlash",
	"Exif.Photo.LightSource",
	"fResolution",
	"Exif.Image.Orientation",
	"Exif.Image.ImageDescription",
	"Exif.Image.Copyright" 
};

const gchar **bar_exif_key_list = bar_exif_key_list_real;
const gint bar_exif_key_count = (sizeof(bar_exif_key_list_real) / sizeof(gchar *));

ExifUI ExifUIList[]={
	{ 0, 0, EXIF_UI_ON,    "fCamera"},
	{ 0, 0, EXIF_UI_ON,    "fDateTime"},
	{ 0, 0, EXIF_UI_ON,    "fShutterSpeed"},
	{ 0, 0, EXIF_UI_ON,    "fAperture"},
	{ 0, 0, EXIF_UI_IFSET, "fExposureBias"},
	{ 0, 0, EXIF_UI_IFSET, "fISOSpeedRating"},
	{ 0, 0, EXIF_UI_ON,    "fFocalLength"},
	{ 0, 0, EXIF_UI_IFSET, "fFocalLength35mmFilm"},
	{ 0, 0, EXIF_UI_ON,    "fFlash"},
	{ 0, 0, EXIF_UI_IFSET, "fSubjectDistance"},
	{ 0, 0, EXIF_UI_IFSET, "Exif.Photo.ExposureProgram"},
	{ 0, 0, EXIF_UI_IFSET, "Exif.Photo.MeteringMode"},
	{ 0, 0, EXIF_UI_IFSET, "Exif.Photo.LightSource"},
	{ 0, 0, EXIF_UI_IFSET, "fSubjectDistance"},
	{ 0, 0, EXIF_UI_OFF,   "fResolution"},
	{ 0, 0, EXIF_UI_IFSET, "Exif.Image.Orientation"},
	{ 0, 0, EXIF_UI_IFSET, "Exif.Image.ImageDescription"},
	{ 0, 0, EXIF_UI_IFSET, "Exif.Image.Copyright"},
	{ 0, 0, EXIF_UI_OFF,   NULL}
};


/*
 *-------------------------------------------------------------------
 * table util
 *-------------------------------------------------------------------
 */

static void table_add_line_custom(GtkWidget *table, gint x, gint y,
                                  const gchar *text1, const gchar *text2,
                                  GtkWidget **label1, GtkWidget **label2)
{
	GtkWidget *label;
	gchar *buf;

	buf = g_strconcat((text1) ? text1 : "fixme", ":", NULL);
	if (!text2) text2 = "";

	label = gtk_label_new(buf);
	gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.0);
	pref_label_bold(label, TRUE, FALSE);
	gtk_table_attach(GTK_TABLE(table), label,
			 x, x + 1, y, y + 1,
			 GTK_FILL, GTK_FILL,
			 2, 2);
	*label1 = label;

	label = gtk_label_new(text2);
	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
	gtk_table_attach(GTK_TABLE(table), label,
			 x + 1, x + 2, y, y + 1,
			 GTK_FILL, GTK_FILL,
			 2, 2);
	*label2 = label;

	g_free(buf);
}

static GtkWidget *table_add_line(GtkWidget *table, gint x, gint y,
				 const gchar *description, const gchar *text,
				GtkWidget **keyret)
{
	GtkWidget *key;
	GtkWidget *label;

	table_add_line_custom(table, x, y, description, text, &key, &label);
	gtk_widget_show(key);
	gtk_widget_show(label);
	if (keyret) *keyret = key;

	return label;
}


/*
 *-------------------------------------------------------------------
 * EXIF bar
 *-------------------------------------------------------------------
 */

typedef struct _ExifBar ExifBar;
struct _ExifBar
{
	GtkWidget *vbox;
	GtkWidget *scrolled;
	GtkWidget *table;
	GtkWidget *advanced_scrolled;
	GtkWidget *listview;
	GtkWidget **keys;
	GtkWidget **labels;

	GtkWidget *custom_sep;
	GtkWidget *custom_name[EXIF_BAR_CUSTOM_COUNT];
	GtkWidget *custom_value[EXIF_BAR_CUSTOM_COUNT];

	FileData *fd;

	gint allow_search;
};

enum {
	EXIF_ADVCOL_ENABLED = 0,
	EXIF_ADVCOL_TAG,
	EXIF_ADVCOL_NAME,
	EXIF_ADVCOL_VALUE,
	EXIF_ADVCOL_FORMAT,
	EXIF_ADVCOL_ELEMENTS,
	EXIF_ADVCOL_DESCRIPTION,
	EXIF_ADVCOL_COUNT
};

gchar *bar_exif_validate_text(gchar *text)
{
	if (text && !g_utf8_validate(text, strlen(text), NULL))
		{
		gchar *tmp = text;
		text = g_convert(tmp, strlen(tmp), "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
		g_free(tmp);
		}
	return text;
}

static void bar_exif_sensitive(ExifBar *eb, gint enable)
{
	gtk_widget_set_sensitive(eb->table, enable);
	if (eb->advanced_scrolled) gtk_widget_set_sensitive(eb->advanced_scrolled, enable);
}

static gint bar_exif_row_enabled(const gchar *name)
{
	GList *list;

	list = history_list_get_by_key("exif_extras");
	while (list)
		{
		if (name && strcmp(name, (gchar *)(list->data)) == 0) return TRUE;
		list = list->next;
	}

	return FALSE;
}

static void bar_exif_update(ExifBar *eb)
{
	ExifData *exif;
	gint i;

	exif = exif_read_fd(eb->fd, FALSE);

	if (!exif)
		{
		bar_exif_sensitive(eb, FALSE);
		return;
		}

	bar_exif_sensitive(eb, TRUE);

	if (GTK_WIDGET_VISIBLE(eb->scrolled))
		{
		GList *list;
		for (i = 0; ExifUIList[i].key; i++)
			{
			gchar *text;

			if (ExifUIList[i].current == EXIF_UI_OFF)
				{
				gtk_widget_hide(eb->labels[i]);
				gtk_widget_hide(eb->keys[i]);
				continue;
				}
			text = exif_get_data_as_text(exif, ExifUIList[i].key);
			text = bar_exif_validate_text(text);
			if (ExifUIList[i].current == EXIF_UI_IFSET
			    && (!text || !*text))
			    	{
				gtk_widget_hide(eb->labels[i]);
				gtk_widget_hide(eb->keys[i]);
				continue;
				}
			gtk_widget_show(eb->labels[i]);
			gtk_widget_show(eb->keys[i]);
			gtk_label_set_text(GTK_LABEL(eb->labels[i]), text);
			g_free(text);
			}

		list = g_list_last(history_list_get_by_key("exif_extras"));
		if (list)
			{
			gtk_widget_show(eb->custom_sep);
			}
		else
			{
			gtk_widget_hide(eb->custom_sep);
			}
		i = 0;
		while (list && i < EXIF_BAR_CUSTOM_COUNT)
			{
			gchar *text;
			gchar *name;
			gchar *buf;

			name = list->data;
			list = list->prev;

			text = exif_get_data_as_text(exif, name);
			text = bar_exif_validate_text(text);

			buf = g_strconcat(name, ":", NULL);
			gtk_label_set_text(GTK_LABEL(eb->custom_name[i]), buf);
			g_free(buf);
			gtk_label_set_text(GTK_LABEL(eb->custom_value[i]), text);
			g_free(text);

			gtk_widget_show(eb->custom_name[i]);
			gtk_widget_show(eb->custom_value[i]);

			i++;
			}
		while (i < EXIF_BAR_CUSTOM_COUNT)
			{
			gtk_widget_hide(eb->custom_name[i]);
			gtk_widget_hide(eb->custom_value[i]);
			i++;
			}
		}

	if (eb->advanced_scrolled && GTK_WIDGET_VISIBLE(eb->advanced_scrolled))
		{
		GtkListStore *store;
		GtkTreeIter iter;
		ExifItem *item;
		
		store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(eb->listview)));
		gtk_list_store_clear(store);

		item = exif_get_first_item(exif);
		while (item)
			{
			gchar *tag;
			gchar *tag_name;
			gchar *text;
			const gchar *format;
			gchar *elements;
			gchar *description;

			tag = g_strdup_printf("0x%04x", exif_item_get_tag_id(item));
			tag_name = exif_item_get_tag_name(item);
			format = exif_item_get_format_name(item, TRUE);
			text = exif_item_get_data_as_text(item);
			text = bar_exif_validate_text(text);
			elements = g_strdup_printf("%d", exif_item_get_elements(item));
			description = exif_item_get_description(item);
			if (!description) description = g_strdup("");
			gtk_list_store_append(store, &iter);
			gtk_list_store_set(store, &iter,
					EXIF_ADVCOL_ENABLED, bar_exif_row_enabled(tag_name),
					EXIF_ADVCOL_TAG, tag,
					EXIF_ADVCOL_NAME, tag_name,
					EXIF_ADVCOL_VALUE, text,
					EXIF_ADVCOL_FORMAT, format,
					EXIF_ADVCOL_ELEMENTS, elements,
					EXIF_ADVCOL_DESCRIPTION, description, -1);
			g_free(tag);
			g_free(text);
			g_free(elements);
			g_free(description);
			g_free(tag_name);
			item = exif_get_next_item(exif);
			}
		}

	exif_free(exif);
}

static void bar_exif_clear(ExifBar *eb)
{
	gint i;

	if (!GTK_WIDGET_SENSITIVE(eb->labels[0])) return;

	for (i = 0; ExifUIList[i].key; i++)
		{
		gtk_label_set_text(GTK_LABEL(eb->labels[i]), "");
		}
	for (i = 0; i < EXIF_BAR_CUSTOM_COUNT; i++)
		{
		gtk_label_set_text(GTK_LABEL(eb->custom_value[i]), "");
		}

	if (eb->listview)
		{
		GtkListStore *store;

		store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(eb->listview)));
		gtk_list_store_clear(store);
		}
}

void bar_exif_set(GtkWidget *bar, FileData *fd)
{
	ExifBar *eb;

	eb = g_object_get_data(G_OBJECT(bar), "bar_exif_data");
	if (!eb) return;

	/* store this, advanced view toggle needs to reload data */
	file_data_unref(eb->fd);
	eb->fd = file_data_ref(fd);

	bar_exif_clear(eb);
	bar_exif_update(eb);
}

static void bar_exif_row_toggled_cb(GtkCellRendererToggle *toggle, const gchar *path, gpointer data)
{
	GtkWidget *listview = data;
	GtkTreeModel *store;
	GtkTreeIter iter;
	GtkTreePath *tpath;
	gchar *name = NULL;
	gboolean active;

	store = gtk_tree_view_get_model(GTK_TREE_VIEW(listview));

	tpath = gtk_tree_path_new_from_string(path);
	gtk_tree_model_get_iter(store, &iter, tpath);
	gtk_tree_path_free(tpath);

	gtk_tree_model_get(store, &iter, EXIF_ADVCOL_ENABLED, &active,
					 EXIF_ADVCOL_NAME, &name, -1);
	active = (!active);

	if (active &&
	    g_list_length(history_list_get_by_key("exif_extras")) >= EXIF_BAR_CUSTOM_COUNT)
		{
		active = FALSE;
		}

	gtk_list_store_set(GTK_LIST_STORE(store), &iter, EXIF_ADVCOL_ENABLED, active, -1);

	if (active)
		{
		history_list_add_to_key("exif_extras", name, EXIF_BAR_CUSTOM_COUNT);
		}
	else
		{
		history_list_item_change("exif_extras", name, NULL);
		}

	g_free(name);
}

static void bar_exif_add_column_check(GtkWidget *listview, const gchar *title, gint n)
{
	GtkTreeViewColumn *column;
	GtkCellRenderer *renderer;

	column = gtk_tree_view_column_new();
	gtk_tree_view_column_set_title(column, title);
	gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);

	renderer = gtk_cell_renderer_toggle_new();
	gtk_tree_view_column_pack_start(column, renderer, TRUE);
	gtk_tree_view_column_add_attribute(column, renderer, "active", n);
	gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);

	g_signal_connect(G_OBJECT(renderer), "toggled",
			 G_CALLBACK(bar_exif_row_toggled_cb), listview);
}

static void bar_exif_add_column(GtkWidget *listview, const gchar *title, gint n, gint sizable)
{
	GtkTreeViewColumn *column;
	GtkCellRenderer *renderer;

	column = gtk_tree_view_column_new();
	gtk_tree_view_column_set_title(column, title);

	if (sizable)
		{
		gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
		gtk_tree_view_column_set_fixed_width(column, BAR_EXIF_DATA_COLUMN_WIDTH);
		gtk_tree_view_column_set_resizable(column, TRUE);
		}
	else
		{
		gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
		}

	renderer = gtk_cell_renderer_text_new();
	gtk_tree_view_column_pack_start(column, renderer, TRUE);
	gtk_tree_view_column_add_attribute(column, renderer, "text", n);
	gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
}

static void bar_exif_advanced_build_view(ExifBar *eb)
{
	GtkListStore *store;

	if (eb->listview) return;

	store = gtk_list_store_new(7, G_TYPE_BOOLEAN,
				      G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
				      G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
	eb->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
	g_object_unref(store);

	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(eb->listview), TRUE);
	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(eb->listview), TRUE);

	if (eb->allow_search)
		{
		gtk_tree_view_set_search_column(GTK_TREE_VIEW(eb->listview), EXIF_ADVCOL_NAME);
		}
	else
		{
		gtk_tree_view_set_enable_search(GTK_TREE_VIEW(eb->listview), FALSE);
		}

	bar_exif_add_column_check(eb->listview, "", EXIF_ADVCOL_ENABLED);

	bar_exif_add_column(eb->listview, _("Tag"), EXIF_ADVCOL_TAG, FALSE);
	bar_exif_add_column(eb->listview, _("Name"), EXIF_ADVCOL_NAME, FALSE);
	bar_exif_add_column(eb->listview, _("Value"), EXIF_ADVCOL_VALUE, TRUE);
	bar_exif_add_column(eb->listview, _("Format"), EXIF_ADVCOL_FORMAT, FALSE);
	bar_exif_add_column(eb->listview, _("Elements"), EXIF_ADVCOL_ELEMENTS, FALSE);
	bar_exif_add_column(eb->listview, _("Description"), EXIF_ADVCOL_DESCRIPTION, FALSE);

	eb->advanced_scrolled = gtk_scrolled_window_new(NULL, NULL);
	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(eb->advanced_scrolled), GTK_SHADOW_IN);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(eb->advanced_scrolled),
				       GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
	gtk_box_pack_start(GTK_BOX(eb->vbox), eb->advanced_scrolled, TRUE, TRUE, 0);
	gtk_container_add(GTK_CONTAINER(eb->advanced_scrolled), eb->listview);
	gtk_widget_show(eb->listview);
}

static void bar_exif_advanced_cb(GtkWidget *widget, gpointer data)
{
	ExifBar *eb = data;
	gint advanced;

	advanced = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));

	if (advanced)
		{
		gtk_widget_hide(eb->scrolled);
		bar_exif_advanced_build_view(eb);
		gtk_widget_show(eb->advanced_scrolled);
		}
	else
		{
		gtk_widget_hide(eb->advanced_scrolled);
		gtk_widget_show(eb->scrolled);
		}

	bar_exif_update(eb);
}

gint bar_exif_is_advanced(GtkWidget *bar)
{
	ExifBar *eb;

	eb = g_object_get_data(G_OBJECT(bar), "bar_exif_data");
	if (!eb) return FALSE;

	return (eb->advanced_scrolled && GTK_WIDGET_VISIBLE(eb->advanced_scrolled));
}

void bar_exif_close(GtkWidget *bar)
{
	ExifBar *eb;

	eb = g_object_get_data(G_OBJECT(bar), "bar_exif_data");
	if (!eb) return;

	gtk_widget_destroy(eb->vbox);
}

static void bar_exif_size(ExifBar *eb, gint val)
{
	gint size;

	size = eb->vbox->allocation.width;
	size = CLAMP(size + val, EXIF_BAR_SIZE_INCREMENT * 2, EXIF_BAR_SIZE_INCREMENT * 16);

	gtk_widget_set_size_request(eb->vbox, size, -1);
}

static void bar_exif_larger(GtkWidget *widget, gpointer data)
{
	ExifBar *eb = data;

	bar_exif_size(eb, EXIF_BAR_SIZE_INCREMENT);
}

static void bar_exif_smaller(GtkWidget *widget, gpointer data)
{
	ExifBar *eb = data;

	bar_exif_size(eb, -EXIF_BAR_SIZE_INCREMENT);
}

static void bar_exif_destroy(GtkWidget *widget, gpointer data)
{
	ExifBar *eb = data;

	g_free(eb->keys);
	g_free(eb->labels);
	file_data_unref(eb->fd);
	g_free(eb);
}

GtkWidget *bar_exif_new(gint show_title, FileData *fd, gint advanced, GtkWidget *bounding_widget)
{
	ExifBar *eb;
	GtkWidget *table;
	GtkWidget *viewport;
	GtkWidget *hbox;
	GtkWidget *button;
	gint i;
	gint exif_len;

	for (exif_len = 0; ExifUIList[exif_len].key; exif_len++)
	      ;

	eb = g_new0(ExifBar, 1);

	eb->keys = g_new0(GtkWidget *, exif_len);
	eb->labels = g_new0(GtkWidget *, exif_len);

	eb->vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP);
	g_object_set_data(G_OBJECT(eb->vbox), "bar_exif_data", eb);
	g_signal_connect_after(G_OBJECT(eb->vbox), "destroy",
			       G_CALLBACK(bar_exif_destroy), eb);

	eb->allow_search = !show_title;

	if (show_title)
		{
		GtkWidget *box;
		GtkWidget *label;
		GtkWidget *button;
		GtkWidget *arrow;

		box = gtk_hbox_new(FALSE, 0);

		label = sizer_new(eb->vbox, bounding_widget, SIZER_POS_LEFT);
		sizer_set_limits(label, EXIF_BAR_SIZE_INCREMENT * 2, -1, -1 , -1);
		gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
		gtk_widget_show(label);

		label = gtk_label_new(_("Exif"));
		pref_label_bold(label, TRUE, FALSE);
		gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
		gtk_widget_show(label);

		button = gtk_button_new();
		gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
		g_signal_connect(G_OBJECT(button), "clicked",
				 G_CALLBACK(bar_exif_smaller), eb);
		gtk_box_pack_end(GTK_BOX(box), button, FALSE, FALSE, 0);
		arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
		gtk_widget_set_size_request(arrow, EXIF_BAR_ARROW_SIZE, EXIF_BAR_ARROW_SIZE);
		gtk_container_add(GTK_CONTAINER(button), arrow);
		gtk_widget_show(arrow);
		gtk_widget_show(button);

		button = gtk_button_new();
		gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
		g_signal_connect(G_OBJECT(button), "clicked",
				 G_CALLBACK(bar_exif_larger), eb);
		gtk_box_pack_end(GTK_BOX(box), button, FALSE, FALSE, 0);
		arrow = gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_NONE);
		gtk_widget_set_size_request(arrow, EXIF_BAR_ARROW_SIZE, EXIF_BAR_ARROW_SIZE);
		gtk_container_add(GTK_CONTAINER(button), arrow);
		gtk_widget_show(arrow);
		gtk_widget_show(button);

		gtk_box_pack_start(GTK_BOX(eb->vbox), box, FALSE, FALSE, 0);
		gtk_widget_show(box);
		}


	table = gtk_table_new(2, exif_len + 1 + EXIF_BAR_CUSTOM_COUNT, FALSE);

	eb->table = table;

	for (i = 0; ExifUIList[i].key; i++)
		{
		const gchar *text;

		text = exif_get_description_by_key(ExifUIList[i].key);
		eb->labels[i] = table_add_line(table, 0, i, text, NULL, 
		      &eb->keys[i]);
		}

	eb->custom_sep = gtk_hseparator_new();
	gtk_table_attach(GTK_TABLE(table), eb->custom_sep, 0, 1,
					   exif_len, exif_len + 1,
					   GTK_FILL, GTK_FILL, 2, 2);

	for (i = 0; i < EXIF_BAR_CUSTOM_COUNT; i++)
		{
		table_add_line_custom(table, 0, exif_len + 1 + i,
				      "", "",  &eb->custom_name[i], &eb->custom_value[i]);
		}

	eb->scrolled = gtk_scrolled_window_new(NULL, NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(eb->scrolled),
				       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

	viewport = gtk_viewport_new(NULL, NULL);
	gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
	gtk_container_add(GTK_CONTAINER(eb->scrolled), viewport);
	gtk_widget_show(viewport);

	gtk_container_add(GTK_CONTAINER(viewport), table);
	gtk_widget_show(table);

	gtk_box_pack_start(GTK_BOX(eb->vbox), eb->scrolled, TRUE, TRUE, 0);

	hbox = gtk_hbox_new(FALSE, PREF_PAD_SPACE);
	gtk_box_pack_end(GTK_BOX(eb->vbox), hbox, FALSE, FALSE, 0);
	gtk_widget_show(hbox);

	button = gtk_check_button_new_with_label(_("Advanced view"));
	if (advanced) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
	g_signal_connect(G_OBJECT(button), "toggled",
			 G_CALLBACK(bar_exif_advanced_cb), eb);
	gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
	gtk_widget_show(button);

	eb->advanced_scrolled = NULL;
	eb->listview = NULL;

	if (advanced)
		{
		bar_exif_advanced_build_view(eb);
		gtk_widget_show(eb->advanced_scrolled);
		}
	else
		{
		gtk_widget_show(eb->scrolled);
		}

	eb->fd = file_data_ref(fd);
	bar_exif_update(eb);

	return eb->vbox;
}