changeset 1469:607c60506863

added a possibility to update existing bars from config
author nadvornik
date Fri, 20 Mar 2009 21:28:31 +0000
parents e9f9d3da3f43
children 38925ff71a46
files src/bar.c src/bar.h src/bar_comment.c src/bar_comment.h src/bar_exif.c src/bar_exif.h src/bar_histogram.c src/bar_histogram.h src/bar_keywords.c src/bar_keywords.h src/layout_util.c src/rcfile.c
diffstat 12 files changed, 380 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/src/bar.c	Fri Mar 20 17:02:00 2009 +0000
+++ b/src/bar.c	Fri Mar 20 21:28:31 2009 +0000
@@ -151,6 +151,57 @@
 	return ret;
 }
 
+GtkWidget *bar_find_pane_by_id(GtkWidget *bar, PaneType type, const gchar *id)
+{
+	BarData *bd;
+	GList *list, *work;
+	GtkWidget *ret = NULL;
+	
+	if (!id || !id[0]) return NULL;
+	
+	bd = g_object_get_data(G_OBJECT(bar), "bar_data");
+	if (!bd) return NULL;
+
+	list = gtk_container_get_children(GTK_CONTAINER(bd->vbox));
+	
+	work = list;
+	while (work)
+		{
+		GtkWidget *widget = gtk_bin_get_child(GTK_BIN(work->data));
+		PaneData *pd = g_object_get_data(G_OBJECT(widget), "pane_data");
+		if (!pd) continue;
+	
+		if (type == pd->type && strcmp(id, pd->id) == 0)
+			{
+			ret = widget;
+			break;
+			}
+		work = work->next;
+		}
+	g_list_free(list);
+	return ret;
+}
+
+void bar_clear(GtkWidget *bar)
+{
+	BarData *bd;
+	GList *list, *work;
+	
+	bd = g_object_get_data(G_OBJECT(bar), "bar_data");
+	if (!bd) return;
+
+	list = gtk_container_get_children(GTK_CONTAINER(bd->vbox));
+	
+	work = list;
+	while (work)
+		{
+		GtkWidget *widget = work->data;
+		gtk_widget_destroy(widget);
+		work = work->next;
+		}
+	g_list_free(list);
+}
+
 void bar_write_config(GtkWidget *bar, GString *outstr, gint indent)
 {
 	BarData *bd;
@@ -165,6 +216,9 @@
 	write_bool_option(outstr, indent, "enabled", GTK_WIDGET_VISIBLE(bar));
 	write_uint_option(outstr, indent, "width", bd->width);
 	WRITE_STRING(">");
+	
+	indent++;
+	WRITE_NL(); WRITE_STRING("<clear/>");
 
 	list = gtk_container_get_children(GTK_CONTAINER(bd->vbox));	
 	work = list;
@@ -178,15 +232,26 @@
 		pd->expanded = gtk_expander_get_expanded(GTK_EXPANDER(expander));
 
 		if (pd->pane_write_config)
-			pd->pane_write_config(widget, outstr, indent + 1);
+			pd->pane_write_config(widget, outstr, indent);
 
 		work = work->next;
 		}
 	g_list_free(list);
-
+	indent--;
 	WRITE_NL(); WRITE_STRING("</bar>");
 }
 
+void bar_update_expander(GtkWidget *pane)
+{
+	PaneData *pd = g_object_get_data(G_OBJECT(pane), "pane_data");
+	GtkWidget *expander;
+	
+	if (!pd) return;
+
+	expander = pane->parent;
+	
+	gtk_expander_set_expanded(GTK_EXPANDER(expander), pd->expanded);
+}
 
 void bar_add(GtkWidget *bar, GtkWidget *pane)
 {
@@ -224,19 +289,19 @@
 {
 	GtkWidget *widget;
 	
-	widget = bar_pane_histogram_new(_("Histogram"), 80, TRUE, HCHAN_RGB, 0);
+	widget = bar_pane_histogram_new("histogram", _("Histogram"), 80, TRUE, HCHAN_RGB, 0);
 	bar_add(bar, widget);
 
-	widget = bar_pane_comment_new(_("Title"), "Xmp.dc.title", TRUE, 40);
+	widget = bar_pane_comment_new("title", _("Title"), "Xmp.dc.title", TRUE, 40);
 	bar_add(bar, widget);
 
-	widget = bar_pane_keywords_new(_("Keywords"), KEYWORD_KEY, TRUE);
+	widget = bar_pane_keywords_new("keywords", _("Keywords"), KEYWORD_KEY, TRUE);
 	bar_add(bar, widget);
 
-	widget = bar_pane_comment_new(_("Comment"), "Xmp.dc.description", TRUE, 150);
+	widget = bar_pane_comment_new("comment", _("Comment"), "Xmp.dc.description", TRUE, 150);
 	bar_add(bar, widget);
 
-	widget = bar_pane_exif_new(_("Exif"), TRUE, TRUE);
+	widget = bar_pane_exif_new("exif", _("Exif"), TRUE, TRUE);
 	bar_add(bar, widget);
 }
 
@@ -335,10 +400,8 @@
 	return bar;
 }
 
-GtkWidget *bar_new_from_config(LayoutWindow *lw, const gchar **attribute_names, const gchar **attribute_values)
+GtkWidget *bar_update_from_config(GtkWidget *bar, const gchar **attribute_names, const gchar **attribute_values)
 {
-	GtkWidget *bar = bar_new(lw);
-	
 	gboolean enabled = TRUE;
 	gint width = SIDEBAR_DEFAULT_WIDTH;
 
@@ -355,10 +418,23 @@
 		}
 	
 	gtk_widget_set_size_request(bar, width, -1);
-	if (enabled) gtk_widget_show(bar);
+	if (enabled) 
+		{
+		gtk_widget_show(bar);
+		}
+	else
+		{
+		gtk_widget_hide(bar);
+		}
 	return bar;
 }
 
+GtkWidget *bar_new_from_config(LayoutWindow *lw, const gchar **attribute_names, const gchar **attribute_values)
+{
+	GtkWidget *bar = bar_new(lw);
+	return bar_update_from_config(bar, attribute_names, attribute_values);
+}
+
 GtkWidget *bar_pane_expander_title(const gchar *title)
 {
 	GtkWidget *widget = gtk_label_new(title);
--- a/src/bar.h	Fri Mar 20 17:02:00 2009 +0000
+++ b/src/bar.h	Fri Mar 20 21:28:31 2009 +0000
@@ -14,6 +14,13 @@
 #ifndef BAR_H
 #define BAR_H
 
+typedef enum {
+	PANE_COMMENT,
+	PANE_EXIF,
+	PANE_HISTOGRAM,
+	PANE_KEYWORDS
+} PaneType;
+
 typedef struct _PaneData PaneData;
 
 struct _PaneData {
@@ -23,6 +30,8 @@
 	void (*pane_write_config)(GtkWidget *pane, GString *outstr, gint indent);
 	GtkWidget *title;
 	gboolean expanded;
+	gchar *id;
+	PaneType type;
 	
 	/* filled in by bar */
 	GtkWidget *bar;
@@ -31,16 +40,20 @@
 
 
 
+
 GtkWidget *bar_new(LayoutWindow *lw);
 GtkWidget *bar_new_default(LayoutWindow *lw);
 GtkWidget *bar_new_from_config(LayoutWindow *lw, const gchar **attribute_names, const gchar **attribute_values);
+GtkWidget *bar_update_from_config(GtkWidget *bar, const gchar **attribute_names, const gchar **attribute_values);
 
 void bar_close(GtkWidget *bar);
 
 void bar_write_config(GtkWidget *bar, GString *outstr, gint indent);
 
 void bar_add(GtkWidget *bar, GtkWidget *pane);
+GtkWidget *bar_find_pane_by_id(GtkWidget *bar, PaneType type, const gchar *id);
 
+void bar_clear(GtkWidget *bar);
 
 void bar_set_fd(GtkWidget *bar, FileData *fd);
 gboolean bar_event(GtkWidget *bar, GdkEvent *event);
@@ -48,6 +61,6 @@
 gint bar_get_width(GtkWidget *bar);
 
 GtkWidget *bar_pane_expander_title(const gchar *title);
-
+void bar_update_expander(GtkWidget *pane);
 #endif
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/bar_comment.c	Fri Mar 20 17:02:00 2009 +0000
+++ b/src/bar_comment.c	Fri Mar 20 21:28:31 2009 +0000
@@ -151,8 +151,9 @@
 	if (!pcd) return;
 
 	WRITE_NL(); WRITE_STRING("<pane_comment ");
-	write_char_option(outstr, indent, "pane.title", gtk_label_get_text(GTK_LABEL(pcd->pane.title)));
-	WRITE_BOOL(*pcd, pane.expanded);
+	write_char_option(outstr, indent, "id", pcd->pane.id);
+	write_char_option(outstr, indent, "title", gtk_label_get_text(GTK_LABEL(pcd->pane.title)));
+	WRITE_BOOL(pcd->pane, expanded);
 	WRITE_CHAR(*pcd, key);
 	WRITE_INT(*pcd, height); 
 	WRITE_STRING("/>");
@@ -202,13 +203,14 @@
 
 	file_data_unref(pcd->fd);
 	g_free(pcd->key);
-	
+
+	g_free(pcd->pane.id);
 
 	g_free(pcd);
 }
 
 
-GtkWidget *bar_pane_comment_new(const gchar *title, const gchar *key, gboolean expanded, gint height)
+GtkWidget *bar_pane_comment_new(const gchar *id, const gchar *title, const gchar *key, gboolean expanded, gint height)
 {
 	PaneCommentData *pcd;
 	GtkWidget *scrolled;
@@ -220,6 +222,8 @@
 	pcd->pane.pane_event = bar_pane_comment_event;
 	pcd->pane.pane_write_config = bar_pane_comment_write_config;
 	pcd->pane.title = bar_pane_expander_title(title);
+	pcd->pane.id = g_strdup(id);
+	pcd->pane.type = PANE_COMMENT;
 
 	pcd->pane.expanded = expanded;
 	
@@ -237,7 +241,7 @@
 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
 				       GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 
-	gtk_widget_set_size_request(scrolled, -1, height);
+	gtk_widget_set_size_request(pcd->widget, -1, height);
 	gtk_widget_show(scrolled);
 
 	pcd->comment_view = gtk_text_view_new();
@@ -259,26 +263,67 @@
 
 GtkWidget *bar_pane_comment_new_from_config(const gchar **attribute_names, const gchar **attribute_values)
 {
-	gchar *title = g_strdup(_("NoName"));
+	gchar *title = g_strdup(_("Comment"));
 	gchar *key = g_strdup(COMMENT_KEY);
 	gboolean expanded = TRUE;
 	gint height = 50;
+	gchar *id = g_strdup("comment");
+	GtkWidget *ret;
 
 	while (*attribute_names)
 		{
 		const gchar *option = *attribute_names++;
 		const gchar *value = *attribute_values++;
 
-		if (READ_CHAR_FULL("pane.title", title)) continue;
+		if (READ_CHAR_FULL("title", title)) continue;
 		if (READ_CHAR_FULL("key", key)) continue;
-		if (READ_BOOL_FULL("pane.expanded", expanded)) continue;
+		if (READ_BOOL_FULL("expanded", expanded)) continue;
 		if (READ_INT_FULL("height", height)) continue;
+		if (READ_CHAR_FULL("id", id)) continue;
 		
 
 		log_printf("unknown attribute %s = %s\n", option, value);
 		}
 	
-	return bar_pane_comment_new(title, key, expanded, height);
+	ret = bar_pane_comment_new(id, title, key, expanded, height);
+	g_free(title);
+	g_free(key);
+	g_free(id);
+	return ret;
+}
+
+void bar_pane_comment_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values)
+{
+	PaneCommentData *pcd;
+
+	pcd = g_object_get_data(G_OBJECT(pane), "pane_data");
+	if (!pcd) return;
+
+	gchar *title = NULL;
+
+	while (*attribute_names)
+		{
+		const gchar *option = *attribute_names++;
+		const gchar *value = *attribute_values++;
+
+		if (READ_CHAR_FULL("title", title)) continue;
+		if (READ_CHAR_FULL("key", pcd->key)) continue;
+		if (READ_BOOL_FULL("expanded", pcd->pane.expanded)) continue;
+		if (READ_INT_FULL("height", pcd->height)) continue;
+		if (READ_CHAR_FULL("id", pcd->pane.id)) continue;
+		
+
+		log_printf("unknown attribute %s = %s\n", option, value);
+		}
+
+	if (title)
+		{
+		gtk_label_set_text(GTK_LABEL(pcd->pane.title), title);
+		g_free(title);
+		}
+	gtk_widget_set_size_request(pcd->widget, -1, pcd->height);
+	bar_update_expander(pane);
+	bar_pane_comment_update(pcd);
 }
 
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/bar_comment.h	Fri Mar 20 17:02:00 2009 +0000
+++ b/src/bar_comment.h	Fri Mar 20 21:28:31 2009 +0000
@@ -14,8 +14,9 @@
 #ifndef BAR_COMMENT_H
 #define BAR_COMMENT_H
 
-GtkWidget *bar_pane_comment_new(const gchar *title, const gchar *key, gboolean expanded, gint height);
+GtkWidget *bar_pane_comment_new(const gchar *id, const gchar *title, const gchar *key, gboolean expanded, gint height);
 GtkWidget *bar_pane_comment_new_from_config(const gchar **attribute_names, const gchar **attribute_values);
+void bar_pane_comment_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values);
 
 #endif
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/bar_exif.c	Fri Mar 20 17:02:00 2009 +0000
+++ b/src/bar_exif.c	Fri Mar 20 21:28:31 2009 +0000
@@ -653,8 +653,9 @@
 	if (!ped) return;
 
 	WRITE_NL(); WRITE_STRING("<pane_exif ");
-	write_char_option(outstr, indent, "pane.title", gtk_label_get_text(GTK_LABEL(ped->pane.title)));
-	WRITE_BOOL(*ped, pane.expanded);
+	write_char_option(outstr, indent, "id", ped->pane.id);
+	write_char_option(outstr, indent, "title", gtk_label_get_text(GTK_LABEL(ped->pane.title)));
+	WRITE_BOOL(ped->pane, expanded);
 	WRITE_STRING(">");
 	indent++;
 	
@@ -690,6 +691,7 @@
 	file_data_unregister_notify_func(bar_pane_exif_notify_cb, ped);
 	g_object_unref(ped->size_group);
 	file_data_unref(ped->fd);
+	g_free(ped->pane.id);
 	g_free(ped);
 }
 
@@ -708,7 +710,7 @@
 	ped->min_height = alloc->height;
 }
 
-GtkWidget *bar_pane_exif_new(const gchar *title, gboolean expanded, gboolean populate)
+GtkWidget *bar_pane_exif_new(const gchar *id, const gchar *title, gboolean expanded, gboolean populate)
 {
 	PaneExifData *ped;
 
@@ -718,7 +720,9 @@
 	ped->pane.pane_write_config = bar_pane_exif_write_config;
 	ped->pane.pane_event = bar_pane_exif_event;
 	ped->pane.title = bar_pane_expander_title(title);
+	ped->pane.id = g_strdup(id);
 	ped->pane.expanded = expanded;
+	ped->pane.type = PANE_EXIF;
 
 	ped->size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
 	ped->widget = gtk_event_box_new();
@@ -771,23 +775,62 @@
 
 GtkWidget *bar_pane_exif_new_from_config(const gchar **attribute_names, const gchar **attribute_values)
 {
-	gchar *title = g_strdup(_("NoName"));
+	gchar *title = g_strdup(_("Exif"));
+	gchar *id = g_strdup("exif");
 	gboolean expanded = TRUE;
+	GtkWidget *ret;
 
 	while (*attribute_names)
 		{
 		const gchar *option = *attribute_names++;
 		const gchar *value = *attribute_values++;
 
-		if (READ_CHAR_FULL("pane.title", title)) continue;
-		if (READ_BOOL_FULL("pane.expanded", expanded)) continue;
+		if (READ_CHAR_FULL("id", id)) continue;
+		if (READ_CHAR_FULL("title", title)) continue;
+		if (READ_BOOL_FULL("expanded", expanded)) continue;
 
 		log_printf("unknown attribute %s = %s\n", option, value);
 		}
 	
-	return bar_pane_exif_new(title, expanded, FALSE);
+	ret = bar_pane_exif_new(id, title, expanded, FALSE);
+	g_free(title);
+	g_free(id);
+	return ret;
 }
 
+void bar_pane_exif_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values)
+{
+	PaneExifData *ped;
+
+	ped = g_object_get_data(G_OBJECT(pane), "pane_data");
+	if (!ped) return;
+
+	gchar *title = NULL;
+
+	while (*attribute_names)
+		{
+		const gchar *option = *attribute_names++;
+		const gchar *value = *attribute_values++;
+
+		if (READ_CHAR_FULL("title", title)) continue;
+		if (READ_BOOL_FULL("expanded", ped->pane.expanded)) continue;
+		if (READ_CHAR_FULL("id", ped->pane.id)) continue;
+		
+
+		log_printf("unknown attribute %s = %s\n", option, value);
+		}
+
+	if (title)
+		{
+		gtk_label_set_text(GTK_LABEL(ped->pane.title), title);
+		g_free(title);
+		}
+
+	bar_update_expander(pane);
+	bar_pane_exif_update(ped);
+}
+
+
 void bar_pane_exif_entry_add_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values)
 {
 	PaneExifData *ped;
--- a/src/bar_exif.h	Fri Mar 20 17:02:00 2009 +0000
+++ b/src/bar_exif.h	Fri Mar 20 21:28:31 2009 +0000
@@ -14,8 +14,10 @@
 #ifndef BAR_EXIF_H
 #define BAR_EXIF_H
 
-GtkWidget *bar_pane_exif_new(const gchar *title, gboolean expanded, gboolean populate);
+GtkWidget *bar_pane_exif_new(const gchar *id, const gchar *title, gboolean expanded, gboolean populate);
 GtkWidget *bar_pane_exif_new_from_config(const gchar **attribute_names, const gchar **attribute_values);
+void bar_pane_exif_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values);
+
 void bar_pane_exif_entry_add_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values);
 
 /* these are exposed for when duplication of the exif bar's text is needed */
--- a/src/bar_histogram.c	Fri Mar 20 17:02:00 2009 +0000
+++ b/src/bar_histogram.c	Fri Mar 20 21:28:31 2009 +0000
@@ -118,8 +118,9 @@
 	if (!phd) return;
 
 	WRITE_NL(); WRITE_STRING("<pane_histogram ");
-	write_char_option(outstr, indent, "pane.title", gtk_label_get_text(GTK_LABEL(phd->pane.title)));
-	WRITE_BOOL(*phd, pane.expanded);
+	write_char_option(outstr, indent, "id", phd->pane.id);
+	write_char_option(outstr, indent, "title", gtk_label_get_text(GTK_LABEL(phd->pane.title)));
+	WRITE_BOOL(phd->pane, expanded);
 	WRITE_INT(*phd->histogram, histogram_channel);
 	WRITE_INT(*phd->histogram, histogram_mode);
 	WRITE_STRING("/>");
@@ -182,6 +183,7 @@
 	file_data_unref(phd->fd);
 	histogram_free(phd->histogram);
 	if (phd->pixbuf) g_object_unref(phd->pixbuf);
+	g_free(phd->pane.id);
 
 	g_free(phd);
 }
@@ -326,7 +328,7 @@
 }
 
 
-GtkWidget *bar_pane_histogram_new(const gchar *title, gint height, gboolean expanded, gint histogram_channel, gint histogram_mode)
+GtkWidget *bar_pane_histogram_new(const gchar *id, const gchar *title, gint height, gboolean expanded, gint histogram_channel, gint histogram_mode)
 {
 	PaneHistogramData *phd;
 
@@ -335,6 +337,8 @@
 	phd->pane.pane_set_fd = bar_pane_histogram_set_fd;
 	phd->pane.pane_write_config = bar_pane_histogram_write_config;
 	phd->pane.title = bar_pane_expander_title(title);
+	phd->pane.id = g_strdup(id);
+	phd->pane.type = PANE_HISTOGRAM;
 
 	phd->pane.expanded = expanded;
 	phd->idle_id = -1;
@@ -376,25 +380,64 @@
 GtkWidget *bar_pane_histogram_new_from_config(const gchar **attribute_names, const gchar **attribute_values)
 {
 	gchar *title = g_strdup(_("NoName"));
+	gchar *id = g_strdup("histogram");
 	gboolean expanded = TRUE;
 	gint height = 80;
 	gint histogram_channel = HCHAN_RGB;
 	gint histogram_mode = 0;
+	GtkWidget *ret;
 
 	while (*attribute_names)
 		{
 		const gchar *option = *attribute_names++;
 		const gchar *value = *attribute_values++;
 
-		if (READ_CHAR_FULL("pane.title", title)) continue;
-		if (READ_BOOL_FULL("pane.expanded", expanded)) continue;
+		if (READ_CHAR_FULL("id", id)) continue;
+		if (READ_CHAR_FULL("title", title)) continue;
+		if (READ_BOOL_FULL("expanded", expanded)) continue;
 		if (READ_INT_FULL("histogram_channel", histogram_channel)) continue;
 		if (READ_INT_FULL("histogram_mode", histogram_mode)) continue;
 
 		log_printf("unknown attribute %s = %s\n", option, value);
 		}
 	
-	return bar_pane_histogram_new(title, height, expanded, histogram_channel, histogram_mode);
+	ret = bar_pane_histogram_new(id, title, height, expanded, histogram_channel, histogram_mode);
+	g_free(title);
+	g_free(id);
+	return ret;
 }
 
+void bar_pane_histogram_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values)
+{
+	PaneHistogramData *phd;
+
+	phd = g_object_get_data(G_OBJECT(pane), "pane_data");
+	if (!phd) return;
+
+	gint histogram_channel = phd->histogram->histogram_channel;
+	gint histogram_mode = phd->histogram->histogram_mode;
+
+	while (*attribute_names)
+		{
+		const gchar *option = *attribute_names++;
+		const gchar *value = *attribute_values++;
+
+		if (READ_CHAR_FULL("id", phd->pane.id)) continue;
+//		if (READ_CHAR_FULL("pane.title", title)) continue;
+		if (READ_BOOL_FULL("expanded", phd->pane.expanded)) continue;
+		if (READ_INT_FULL("histogram_channel", histogram_channel)) continue;
+		if (READ_INT_FULL("histogram_mode", histogram_mode)) continue;
+		
+
+		log_printf("unknown attribute %s = %s\n", option, value);
+		}
+	
+	histogram_set_channel(phd->histogram, histogram_channel);
+	histogram_set_mode(phd->histogram, histogram_mode);
+
+	bar_update_expander(pane);
+	bar_pane_histogram_update(phd);
+}
+
+
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/bar_histogram.h	Fri Mar 20 17:02:00 2009 +0000
+++ b/src/bar_histogram.h	Fri Mar 20 21:28:31 2009 +0000
@@ -14,8 +14,9 @@
 #ifndef BAR_HISTOGRAM_H
 #define BAR_HISTOGRAM_H
 
-GtkWidget *bar_pane_histogram_new(const gchar *title, gint height, gboolean expanded, gint histogram_channel, gint histogram_mode);
+GtkWidget *bar_pane_histogram_new(const gchar *id, const gchar *title, gint height, gboolean expanded, gint histogram_channel, gint histogram_mode);
 GtkWidget *bar_pane_histogram_new_from_config(const gchar **attribute_names, const gchar **attribute_values);
+void bar_pane_histogram_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values);
 
 #endif
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/bar_keywords.c	Fri Mar 20 17:02:00 2009 +0000
+++ b/src/bar_keywords.c	Fri Mar 20 21:28:31 2009 +0000
@@ -248,8 +248,9 @@
 	if (!pkd) return;
 
 	WRITE_NL(); WRITE_STRING("<pane_keywords ");
-	write_char_option(outstr, indent, "pane.title", gtk_label_get_text(GTK_LABEL(pkd->pane.title)));
-	WRITE_BOOL(*pkd, pane.expanded);
+	write_char_option(outstr, indent, "id", pkd->pane.id);
+	write_char_option(outstr, indent, "title", gtk_label_get_text(GTK_LABEL(pkd->pane.title)));
+	WRITE_BOOL(pkd->pane, expanded);
 	WRITE_CHAR(*pkd, key);
 	WRITE_STRING("/>");
 }
@@ -1181,7 +1182,8 @@
 
 	pkd = g_object_get_data(G_OBJECT(bar), "pane_data");
 	if (!pkd) return;
-
+	
+	g_free(pkd->pane.id);
 	gtk_widget_destroy(pkd->widget);
 }
 
@@ -1200,7 +1202,7 @@
 }
 
 
-GtkWidget *bar_pane_keywords_new(const gchar *title, const gchar *key, gboolean expanded)
+GtkWidget *bar_pane_keywords_new(const gchar *id, const gchar *title, const gchar *key, gboolean expanded)
 {
 	PaneKeywordsData *pkd;
 	GtkWidget *hbox;
@@ -1216,6 +1218,8 @@
 	pkd->pane.pane_event = bar_pane_keywords_event;
 	pkd->pane.pane_write_config = bar_pane_keywords_write_config;
 	pkd->pane.title = bar_pane_expander_title(title);
+	pkd->pane.id = g_strdup(id);
+	pkd->pane.type = PANE_KEYWORDS;
 
 	pkd->pane.expanded = expanded;
 
@@ -1345,24 +1349,65 @@
 
 GtkWidget *bar_pane_keywords_new_from_config(const gchar **attribute_names, const gchar **attribute_values)
 {
-	gchar *title = g_strdup(_("NoName"));
+	gchar *id = g_strdup("keywords");
+	gchar *title = g_strdup(_("Keywords"));
 	gchar *key = g_strdup(COMMENT_KEY);
 	gboolean expanded = TRUE;
+	GtkWidget *ret;
 
 	while (*attribute_names)
 		{
 		const gchar *option = *attribute_names++;
 		const gchar *value = *attribute_values++;
 
-		if (READ_CHAR_FULL("pane.title", title)) continue;
+		if (READ_CHAR_FULL("id", id)) continue;
+		if (READ_CHAR_FULL("title", title)) continue;
 		if (READ_CHAR_FULL("key", key)) continue;
-		if (READ_BOOL_FULL("pane.expanded", expanded)) continue;
+		if (READ_BOOL_FULL("expanded", expanded)) continue;
 		
 
 		log_printf("unknown attribute %s = %s\n", option, value);
 		}
 	
-	return bar_pane_keywords_new(title, key, expanded);
+	ret = bar_pane_keywords_new(id, title, key, expanded);
+	g_free(id);
+	g_free(title);
+	g_free(key);
+	return ret;
 }
 
+void bar_pane_keywords_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values)
+{
+	PaneKeywordsData *pkd;
+
+	pkd = g_object_get_data(G_OBJECT(pane), "pane_data");
+	if (!pkd) return;
+
+	gchar *title = NULL;
+
+	while (*attribute_names)
+		{
+		const gchar *option = *attribute_names++;
+		const gchar *value = *attribute_values++;
+
+		if (READ_CHAR_FULL("title", title)) continue;
+		if (READ_CHAR_FULL("key", pkd->key)) continue;
+		if (READ_BOOL_FULL("expanded", pkd->pane.expanded)) continue;
+		if (READ_CHAR_FULL("id", pkd->pane.id)) continue;
+		
+
+		log_printf("unknown attribute %s = %s\n", option, value);
+		}
+
+	if (title)
+		{
+		gtk_label_set_text(GTK_LABEL(pkd->pane.title), title);
+		g_free(title);
+		}
+
+	bar_update_expander(pane);
+	bar_pane_keywords_update(pkd);
+}
+
+
 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */
--- a/src/bar_keywords.h	Fri Mar 20 17:02:00 2009 +0000
+++ b/src/bar_keywords.h	Fri Mar 20 21:28:31 2009 +0000
@@ -14,8 +14,9 @@
 #ifndef BAR_KEYWORDS_H
 #define BAR_KEYWORDS_H
 
-GtkWidget *bar_pane_keywords_new(const gchar *title, const gchar *key, gboolean expanded);
+GtkWidget *bar_pane_keywords_new(const gchar *id, const gchar *title, const gchar *key, gboolean expanded);
 GtkWidget *bar_pane_keywords_new_from_config(const gchar **attribute_names, const gchar **attribute_values);
+void bar_pane_keywords_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values);
 
 /* used in search.c */
 GList *keyword_list_pull(GtkWidget *text_widget);
--- a/src/layout_util.c	Fri Mar 20 17:02:00 2009 +0000
+++ b/src/layout_util.c	Fri Mar 20 21:28:31 2009 +0000
@@ -1828,6 +1828,9 @@
 void layout_toolbar_add(LayoutWindow *lw, const gchar *action)
 {
 	if (!action || !lw->ui_manager) return;
+	
+	if (g_list_find_custom(lw->toolbar_actions, action, (GCompareFunc)strcmp)) return;
+	
 	gtk_ui_manager_add_ui(lw->ui_manager, lw->toolbar_merge_id, "/ToolBar", action, action, GTK_UI_MANAGER_TOOLITEM, FALSE); 
 	lw->toolbar_actions = g_list_append(lw->toolbar_actions, g_strdup(action));
 }
@@ -1852,6 +1855,7 @@
 	GList *work = lw->toolbar_actions;
 	WRITE_NL(); WRITE_STRING("<toolbar>");
 	indent++;
+	WRITE_NL(); WRITE_STRING("<clear/>");
 	while (work)
 		{
 		gchar *action = work->data;
--- a/src/rcfile.c	Fri Mar 20 17:02:00 2009 +0000
+++ b/src/rcfile.c	Fri Mar 20 21:28:31 2009 +0000
@@ -919,26 +919,63 @@
 	GtkWidget *bar = data;
 	if (g_ascii_strcasecmp(element_name, "pane_comment") == 0)
 		{
-		GtkWidget *pane = bar_pane_comment_new_from_config(attribute_names, attribute_values);
-		bar_add(bar, pane);
+		GtkWidget *pane = bar_find_pane_by_id(bar, PANE_COMMENT, options_get_id(attribute_names, attribute_values));
+		if (pane)
+			{
+			bar_pane_comment_update_from_config(pane, attribute_names, attribute_values);
+			}
+		else
+			{
+			pane = bar_pane_comment_new_from_config(attribute_names, attribute_values);
+			bar_add(bar, pane);
+			}
 		options_parse_func_push(parser_data, options_parse_leaf, NULL, NULL);
 		}
 	else if (g_ascii_strcasecmp(element_name, "pane_exif") == 0)
 		{
-		GtkWidget *pane = bar_pane_exif_new_from_config(attribute_names, attribute_values);
-		bar_add(bar, pane);
+		GtkWidget *pane = bar_find_pane_by_id(bar, PANE_EXIF, options_get_id(attribute_names, attribute_values));
+		if (pane)
+			{
+			bar_pane_exif_update_from_config(pane, attribute_names, attribute_values);
+			}
+		else
+			{
+			pane = bar_pane_exif_new_from_config(attribute_names, attribute_values);
+			bar_add(bar, pane);
+			}
 		options_parse_func_push(parser_data, options_parse_pane_exif, NULL, pane);
 		}
 	else if (g_ascii_strcasecmp(element_name, "pane_histogram") == 0)
 		{
-		GtkWidget *pane = bar_pane_histogram_new_from_config(attribute_names, attribute_values);
-		bar_add(bar, pane);
+		GtkWidget *pane = bar_find_pane_by_id(bar, PANE_HISTOGRAM, options_get_id(attribute_names, attribute_values));
+		if (pane)
+			{
+			bar_pane_histogram_update_from_config(pane, attribute_names, attribute_values);
+			}
+		else
+			{
+			pane = bar_pane_histogram_new_from_config(attribute_names, attribute_values);
+			bar_add(bar, pane);
+			}
 		options_parse_func_push(parser_data, options_parse_leaf, NULL, NULL);
 		}
 	else if (g_ascii_strcasecmp(element_name, "pane_keywords") == 0)
 		{
-		GtkWidget *pane = bar_pane_keywords_new_from_config(attribute_names, attribute_values);
-		bar_add(bar, pane);
+		GtkWidget *pane = bar_find_pane_by_id(bar, PANE_KEYWORDS, options_get_id(attribute_names, attribute_values));
+		if (pane)
+			{
+			bar_pane_keywords_update_from_config(pane, attribute_names, attribute_values);
+			}
+		else
+			{
+			pane = bar_pane_keywords_new_from_config(attribute_names, attribute_values);
+			bar_add(bar, pane);
+			}
+		options_parse_func_push(parser_data, options_parse_leaf, NULL, NULL);
+		}
+	else if (g_ascii_strcasecmp(element_name, "clear") == 0)
+		{
+		bar_clear(bar);
 		options_parse_func_push(parser_data, options_parse_leaf, NULL, NULL);
 		}
 	else
@@ -956,6 +993,11 @@
 		layout_toolbar_add_from_config(lw, attribute_names, attribute_values);
 		options_parse_func_push(parser_data, options_parse_leaf, NULL, NULL);
 		}
+	else if (g_ascii_strcasecmp(element_name, "clear") == 0)
+		{
+		layout_toolbar_clear(lw);
+		options_parse_func_push(parser_data, options_parse_leaf, NULL, NULL);
+		}
 	else
 		{
 		log_printf("unexpected in <toolbar>: <%s>\n", element_name);
@@ -968,8 +1010,16 @@
 	LayoutWindow *lw = data;
 	if (g_ascii_strcasecmp(element_name, "bar") == 0)
 		{
-		GtkWidget *bar = bar_new_from_config(lw, attribute_names, attribute_values);
-		layout_bar_set(lw, bar);
+		if (!lw->bar)
+			{
+			GtkWidget *bar = bar_new_from_config(lw, attribute_names, attribute_values);
+			layout_bar_set(lw, bar);
+			}
+		else
+			{
+			bar_update_from_config(lw->bar, attribute_names, attribute_values);
+			}
+			
 		options_parse_func_push(parser_data, options_parse_bar, NULL, lw->bar);
 		}
 	else if (g_ascii_strcasecmp(element_name, "bar_sort") == 0)
@@ -980,7 +1030,6 @@
 		}
 	else if (g_ascii_strcasecmp(element_name, "toolbar") == 0)
 		{
-		layout_toolbar_clear(lw);
 		options_parse_func_push(parser_data, options_parse_toolbar, NULL, lw);
 		}
 	else