Trim trailing white spaces.
[geeqie.git] / src / bar_exif.c
index 19bc921..9c1cc47 100644 (file)
@@ -1,8 +1,9 @@
 /*
- * GQview
+ * Geeqie
  * (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2012 The Geeqie Team
  *
- * Author: John Ellis
+ * Author: Vladimir Nadvornik
  *
  * This software is released under the GNU General Public License (GNU GPL).
  * Please read the included file COPYING for more information.
  */
 
 
-#include "gqview.h"
+#include "main.h"
 #include "bar_exif.h"
 
 #include "exif.h"
-#include "ui_bookmark.h"
+#include "metadata.h"
+#include "filedata.h"
+#include "history_list.h"
+#include "misc.h"
 #include "ui_misc.h"
-#include "filelist.h"
+#include "ui_menu.h"
+#include "bar.h"
+#include "rcfile.h"
+#include "dnd.h"
+#include "ui_utildlg.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",
-       "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 *));
 
+#include <math.h>
 
+#define MIN_HEIGHT 25
 /*
  *-------------------------------------------------------------------
- * table util
+ * EXIF widget
  *-------------------------------------------------------------------
  */
 
-static void table_add_line_custom(GtkWidget *table, gint x, gint y,
-                                  const gchar *text1, const gchar *text2,
-                                  GtkWidget **label1, GtkWidget **label2)
+typedef struct _ExifEntry ExifEntry;
+typedef struct _PaneExifData PaneExifData;
+
+struct _ExifEntry
+{
+       GtkWidget *ebox;
+       GtkWidget *box;
+       GtkWidget *title_label;
+       GtkWidget *value_widget;
+
+       gchar *key;
+       gchar *title;
+       gboolean if_set;
+       gboolean auto_title;
+       gboolean editable;
+
+       PaneExifData *ped;
+};
+       
+       
+struct _PaneExifData
 {
-       GtkWidget *label;
-       gchar *buf;
+       PaneData pane;
+       GtkWidget *vbox;
+       GtkWidget *widget;
+       GtkSizeGroup *size_group;
 
-       buf = g_strconcat((text1) ? text1 : "fixme", ":", NULL);
-       if (!text2) text2 = "";
+       gint min_height;
+       
+       gboolean all_hidden;
+       gboolean show_all;
+       
+       FileData *fd;
+};
 
-       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;
+typedef struct _ConfDialogData ConfDialogData;
+struct _ConfDialogData
+{
+       GtkWidget *widget; /* pane or entry, devidet by presenceof "pane_data" or "entry_data" */
+
+       /* dialog parts */
+       GenericDialog *gd;
+       GtkWidget *key_entry;
+       GtkWidget *title_entry;
+       gboolean if_set;
+       gboolean editable;
+};
 
-       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;
+static void bar_pane_exif_entry_dnd_init(GtkWidget *entry);
+static void bar_pane_exif_entry_update_title(ExifEntry *ee);
+static void bar_pane_exif_update(PaneExifData *ped);
+static gboolean bar_pane_exif_menu_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data);
+static void bar_pane_exif_notify_cb(FileData *fd, NotifyType type, gpointer data);
 
-       g_free(buf);
-}
 
-static GtkWidget *table_add_line(GtkWidget *table, gint x, gint y,
-                                const gchar *description, const gchar *text)
+static void bar_pane_exif_entry_changed(GtkEntry *text_entry, gpointer data)
 {
-       GtkWidget *key;
-       GtkWidget *label;
+       ExifEntry *ee = data;
+       gchar *text;
+       if (!ee->ped->fd) return;
 
-       table_add_line_custom(table, x, y, description, text, &key, &label);
-       gtk_widget_show(key);
-       gtk_widget_show(label);
-
-       return label;
+       text = text_widget_text_pull(ee->value_widget);
+       metadata_write_string(ee->ped->fd, ee->key, text);
+       g_free(text);
 }
 
+static void bar_pane_exif_entry_destroy(GtkWidget *widget, gpointer data)
+{
+       ExifEntry *ee = data;
 
-/*
- *-------------------------------------------------------------------
- * EXIF bar
- *-------------------------------------------------------------------
- */
+       g_free(ee->key);
+       g_free(ee->title);
+       g_free(ee);
+}
 
-typedef struct _ExifBar ExifBar;
-struct _ExifBar
+static void bar_pane_exif_setup_entry_box(PaneExifData *ped, ExifEntry *ee)
 {
-       GtkWidget *vbox;
-       GtkWidget *scrolled;
-       GtkWidget *table;
-       GtkWidget *advanced_scrolled;
-       GtkWidget *listview;
-       GtkWidget **labels;
+       gboolean horizontal = !ee->editable;
+       gboolean editable = ee->editable;
 
-       GtkWidget *custom_sep;
-       GtkWidget *custom_name[EXIF_BAR_CUSTOM_COUNT];
-       GtkWidget *custom_value[EXIF_BAR_CUSTOM_COUNT];
+       if (ee->box) gtk_widget_destroy(ee->box);
 
-       FileData *fd;
+       ee->box = horizontal ? gtk_hbox_new(FALSE, 0) : gtk_vbox_new(FALSE, 0);
+       gtk_container_add(GTK_CONTAINER(ee->ebox), ee->box);
+       gtk_widget_show(ee->box);
 
-       gint allow_search;
-};
+       ee->title_label = gtk_label_new(NULL);
+       gtk_misc_set_alignment(GTK_MISC(ee->title_label), horizontal ? 1.0 : 0.0, 0.5);
+       gtk_size_group_add_widget(ped->size_group, ee->title_label);
+       gtk_box_pack_start(GTK_BOX(ee->box), ee->title_label, FALSE, TRUE, 0);
+       gtk_widget_show(ee->title_label);
 
-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
-};
+       if (editable)
+               {
+               ee->value_widget = gtk_entry_new();
+               g_signal_connect(G_OBJECT(ee->value_widget), "changed",
+                        G_CALLBACK(bar_pane_exif_entry_changed), ee);
 
-gchar *bar_exif_validate_text(gchar *text)
-{
-       if (text && !g_utf8_validate(text, strlen(text), NULL))
+               }
+       else
                {
-               gchar *tmp = text;
-               text = g_convert(tmp, strlen(tmp), "UTF-8", "ISO-8859-1", NULL, NULL, NULL);
-               g_free(tmp);
+               ee->value_widget = gtk_label_new(NULL);
+//             gtk_label_set_width_chars(GTK_LABEL(ee->value_widget), 20);
+               gtk_label_set_ellipsize(GTK_LABEL(ee->value_widget), PANGO_ELLIPSIZE_END);
+//             gtk_widget_set_size_request(ee->value_widget, 100, -1);
+               gtk_misc_set_alignment(GTK_MISC(ee->value_widget), 0.0, 0.5);
                }
-       return text;
+               
+       gtk_box_pack_start(GTK_BOX(ee->box), ee->value_widget, TRUE, TRUE, 1);
+       gtk_widget_show(ee->value_widget);
 }
 
-static void bar_exif_sensitive(ExifBar *eb, gint enable)
+static GtkWidget *bar_pane_exif_add_entry(PaneExifData *ped, const gchar *key, const gchar *title, gboolean if_set, gboolean editable)
 {
-       gtk_widget_set_sensitive(eb->table, enable);
-       if (eb->advanced_scrolled) gtk_widget_set_sensitive(eb->advanced_scrolled, enable);
+       ExifEntry *ee = g_new0(ExifEntry, 1);
+       
+       ee->key = g_strdup(key);
+       if (title && title[0])
+               {
+               ee->title = g_strdup(title);
+               }
+       else
+               {
+               ee->title = exif_get_description_by_key(key);
+               ee->auto_title = TRUE;
+               }
+               
+       ee->if_set = if_set;
+       ee->editable = editable;
+       
+       ee->ped = ped;
+       
+       ee->ebox = gtk_event_box_new();
+       g_object_set_data(G_OBJECT(ee->ebox), "entry_data", ee);
+       g_signal_connect_after(G_OBJECT(ee->ebox), "destroy",
+                              G_CALLBACK(bar_pane_exif_entry_destroy), ee);
+       
+       gtk_box_pack_start(GTK_BOX(ped->vbox), ee->ebox, FALSE, FALSE, 0);
+
+       bar_pane_exif_entry_dnd_init(ee->ebox);
+       g_signal_connect(ee->ebox, "button_release_event", G_CALLBACK(bar_pane_exif_menu_cb), ped);
+       
+       bar_pane_exif_setup_entry_box(ped, ee);
+        
+       bar_pane_exif_entry_update_title(ee);
+       bar_pane_exif_update(ped);
+       
+       return ee->ebox;
 }
 
-static gint bar_exif_row_enabled(const gchar *name)
+static void bar_pane_exif_reparent_entry(GtkWidget *entry, GtkWidget *pane)
 {
-       GList *list;
+       PaneExifData *ped = g_object_get_data(G_OBJECT(pane), "pane_data");
+       PaneExifData *old_ped;
+       ExifEntry *ee = g_object_get_data(G_OBJECT(entry), "entry_data");
+       
+       if (!ped || !ee) return;
+       
+       old_ped = ee->ped;
+       
+       g_object_ref(entry);
+       
+       gtk_size_group_remove_widget(old_ped->size_group, ee->title_label);
+       gtk_container_remove(GTK_CONTAINER(old_ped->vbox), entry);
+       
+       ee->ped = ped;
+       gtk_size_group_add_widget(ped->size_group, ee->title_label);
+       gtk_box_pack_start(GTK_BOX(ped->vbox), entry, FALSE, FALSE, 0);
+}
 
-       list = history_list_get_by_key("exif_extras");
-       while (list)
-               {
-               if (name && strcmp(name, (gchar *)(list->data)) == 0) return TRUE;
-               list = list->next;
-       }
+static void bar_pane_exif_entry_update_title(ExifEntry *ee)
+{
+       gchar *markup;
 
-       return FALSE;
+       markup = g_markup_printf_escaped("<span size='small'>%s:</span>", (ee->title) ? ee->title : _("<empty label, fixme>"));
+       gtk_label_set_markup(GTK_LABEL(ee->title_label), markup);
+       g_free(markup);
 }
 
-static void bar_exif_update(ExifBar *eb)
+static void bar_pane_exif_update_entry(PaneExifData *ped, GtkWidget *entry, gboolean update_title)
 {
-       ExifData *exif;
-       gint len, i;
-
-       exif = exif_read(eb->fd->path, FALSE);
+       gchar *text;
+       ExifEntry *ee = g_object_get_data(G_OBJECT(entry), "entry_data");
+       
+       if (!ee) return;
+       text = metadata_read_string(ped->fd, ee->key, ee->editable ? METADATA_PLAIN : METADATA_FORMATTED);
 
-       if (!exif)
+       if (!ped->show_all && ee->if_set && !ee->editable && (!text || !*text))
                {
-               bar_exif_sensitive(eb, FALSE);
-               return;
+               gtk_label_set_text(GTK_LABEL(ee->value_widget), NULL);
+               gtk_widget_hide(entry);
                }
-
-       bar_exif_sensitive(eb, TRUE);
-
-       if (GTK_WIDGET_VISIBLE(eb->scrolled))
+       else
                {
-               GList *list;
-               len = bar_exif_key_count;
-               for (i = 0; i < len; i++)
+               if (ee->editable)
                        {
-                       gchar *text;
-                       text = exif_get_data_as_text(exif, bar_exif_key_list[i]);
-                       text = bar_exif_validate_text(text);
-                       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);
+                       g_signal_handlers_block_by_func(ee->value_widget, bar_pane_exif_entry_changed, ee);
+                       gtk_entry_set_text(GTK_ENTRY(ee->value_widget), text ? text : "");
+                       g_signal_handlers_unblock_by_func(ee->value_widget, bar_pane_exif_entry_changed, ee);
+                       gtk_widget_set_tooltip_text(ee->box, NULL);
                        }
                else
                        {
-                       gtk_widget_hide(eb->custom_sep);
+                       gtk_label_set_text(GTK_LABEL(ee->value_widget), text);
+                       gtk_widget_set_tooltip_text(ee->box, text);
                        }
-               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(entry);
+               ped->all_hidden = FALSE;
+               }
+               
+       g_free(text);
+       
+       if (update_title) bar_pane_exif_entry_update_title(ee);
+}
 
-                       gtk_widget_show(eb->custom_name[i]);
-                       gtk_widget_show(eb->custom_value[i]);
+static void bar_pane_exif_update(PaneExifData *ped)
+{
+       GList *list, *work;
 
-                       i++;
-                       }
-               while (i < EXIF_BAR_CUSTOM_COUNT)
-                       {
-                       gtk_widget_hide(eb->custom_name[i]);
-                       gtk_widget_hide(eb->custom_value[i]);
-                       i++;
-                       }
-               }
+       ped->all_hidden = TRUE;
 
-       if (eb->advanced_scrolled && GTK_WIDGET_VISIBLE(eb->advanced_scrolled))
+       list = gtk_container_get_children(GTK_CONTAINER(ped->vbox));
+       work = list;
+       while (work)
                {
-               GtkListStore *store;
-               GtkTreeIter iter;
-               GList *work;
-               ExifItem *item;
+               GtkWidget *entry = work->data;
+               work = work->next;
                
-               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;
-                       const gchar *tag_name;
-                       gchar *text;
-                       const gchar *format;
-                       gchar *elements;
-                       const 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);
-                       item = exif_get_next_item(exif);
-                       }
+               bar_pane_exif_update_entry(ped, entry, FALSE);
                }
+       g_list_free(list);
 
-       exif_free(exif);
+       gtk_widget_set_sensitive(ped->pane.title, !ped->all_hidden);
 }
 
-static void bar_exif_clear(ExifBar *eb)
+void bar_pane_exif_set_fd(GtkWidget *widget, FileData *fd)
 {
-       gint len;
-       gint i;
-
-       if (!GTK_WIDGET_SENSITIVE(eb->labels[0])) return;
+       PaneExifData *ped;
 
-       len = bar_exif_key_count;
-       for (i = 0; i < len; 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]), "");
-               }
+       ped = g_object_get_data(G_OBJECT(widget), "pane_data");
+       if (!ped) return;
 
-       if (eb->listview)
-               {
-               GtkListStore *store;
+       file_data_unref(ped->fd);
+       ped->fd = file_data_ref(fd);
 
-               store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(eb->listview)));
-               gtk_list_store_clear(store);
-               }
+       bar_pane_exif_update(ped);
 }
 
-void bar_exif_set(GtkWidget *bar, FileData *fd)
+gint bar_pane_exif_event(GtkWidget *bar, GdkEvent *event)
 {
-       ExifBar *eb;
+       PaneExifData *ped;
+       gboolean ret = FALSE;
+       GList *list, *work;
 
-       g_assert(fd);
-       
-       eb = g_object_get_data(G_OBJECT(bar), "bar_exif_data");
-       if (!eb) return;
+       ped = g_object_get_data(G_OBJECT(bar), "pane_data");
+       if (!ped) return FALSE;
 
-       /* store this, advanced view toggle needs to reload data */
-       file_data_unref(eb->fd);
-       eb->fd = file_data_ref(fd);
+       list = gtk_container_get_children(GTK_CONTAINER(ped->vbox));
+       work = list;
+       while (!ret && work)
+               {
+               GtkWidget *entry = work->data;
+               ExifEntry *ee = g_object_get_data(G_OBJECT(entry), "entry_data");
+               work = work->next;
 
-       bar_exif_clear(eb);
-       bar_exif_update(eb);
+               if (ee->editable && gtk_widget_has_focus(ee->value_widget)) ret = gtk_widget_event(ee->value_widget, event);
+               }
+       g_list_free(list);
+       return ret;
 }
 
-static void bar_exif_row_toggled_cb(GtkCellRendererToggle *toggle, const gchar *path, gpointer data)
+static void bar_pane_exif_notify_cb(FileData *fd, NotifyType type, gpointer data)
 {
-       GtkWidget *listview = data;
-       GtkTreeModel *store;
-       GtkTreeIter iter;
-       GtkTreePath *tpath;
-       gchar *name = NULL;
-       gboolean active;
+       PaneExifData *ped = data;
+       if ((type & (NOTIFY_REREAD | NOTIFY_CHANGE | NOTIFY_METADATA)) && fd == ped->fd)
+               {
+               DEBUG_1("Notify pane_exif: %s %04x", fd->path, type);
+               bar_pane_exif_update(ped);
+               }
+}
 
-       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);
+/*
+ *-------------------------------------------------------------------
+ * dnd
+ *-------------------------------------------------------------------
+ */
 
-       gtk_tree_model_get(store, &iter, EXIF_ADVCOL_ENABLED, &active,
-                                        EXIF_ADVCOL_NAME, &name, -1);
-       active = (!active);
+static GtkTargetEntry bar_pane_exif_drag_types[] = {
+       { TARGET_APP_EXIF_ENTRY_STRING, GTK_TARGET_SAME_APP, TARGET_APP_EXIF_ENTRY },
+       { "text/plain", 0, TARGET_TEXT_PLAIN }
+};
+static gint n_exif_entry_drag_types = 2;
 
-       if (active &&
-           g_list_length(history_list_get_by_key("exif_extras")) >= EXIF_BAR_CUSTOM_COUNT)
+static GtkTargetEntry bar_pane_exif_drop_types[] = {
+       { TARGET_APP_EXIF_ENTRY_STRING, GTK_TARGET_SAME_APP, TARGET_APP_EXIF_ENTRY },
+       { "text/plain", 0, TARGET_TEXT_PLAIN }
+};
+static gint n_exif_entry_drop_types = 2;
+
+
+static void bar_pane_exif_entry_dnd_get(GtkWidget *entry, GdkDragContext *context,
+                                    GtkSelectionData *selection_data, guint info,
+                                    guint time, gpointer data)
+{
+       ExifEntry *ee = g_object_get_data(G_OBJECT(entry), "entry_data");
+
+       switch (info)
                {
-               active = FALSE;
+               case TARGET_APP_EXIF_ENTRY:
+                       gtk_selection_data_set(selection_data, gtk_selection_data_get_target(selection_data),
+                                              8, (gpointer) &entry, sizeof(entry));
+                       break;
+
+               case TARGET_TEXT_PLAIN:
+               default:
+                       gtk_selection_data_set_text(selection_data, ee->key, -1);
+                       break;
                }
+       
+}
 
-       gtk_list_store_set(GTK_LIST_STORE(store), &iter, EXIF_ADVCOL_ENABLED, active, -1);
+static void bar_pane_exif_dnd_receive(GtkWidget *pane, GdkDragContext *context,
+                                         gint x, gint y,
+                                         GtkSelectionData *selection_data, guint info,
+                                         guint time, gpointer data)
+{
+       PaneExifData *ped;
+       GList *work, *list;
+       gint pos;
+       GtkWidget *new_entry = NULL;
+       
+       ped = g_object_get_data(G_OBJECT(pane), "pane_data");
+       if (!ped) return;
 
-       if (active)
+       switch (info)
                {
-               history_list_add_to_key("exif_extras", name, EXIF_BAR_CUSTOM_COUNT);
+               case TARGET_APP_EXIF_ENTRY:
+                       new_entry = *(gpointer *)gtk_selection_data_get_data(selection_data);
+                       
+                       if (gtk_widget_get_parent(new_entry) && gtk_widget_get_parent(new_entry) != ped->vbox) bar_pane_exif_reparent_entry(new_entry, pane);
+                       
+                       break;
+               default:
+                       /* FIXME: this needs a check for valid exif keys */
+                       new_entry = bar_pane_exif_add_entry(ped, (gchar *)gtk_selection_data_get_data(selection_data), NULL, TRUE, FALSE);
+                       break;
                }
-       else
+
+       list = gtk_container_get_children(GTK_CONTAINER(ped->vbox));
+       work = list;
+       pos = 0;
+       while (work)
                {
-               history_list_item_change("exif_extras", name, NULL);
+               gint nx, ny;
+               GtkWidget *entry = work->data;
+               GtkAllocation allocation;
+               work = work->next;
+               
+               if (entry == new_entry) continue;
+               
+               gtk_widget_get_allocation(entry, &allocation);
+               
+               if (gtk_widget_is_drawable(entry) &&
+                   gtk_widget_translate_coordinates(pane, entry, x, y, &nx, &ny) &&
+                   ny < allocation.height / 2) break;
+               pos++;
                }
+       g_list_free(list);
 
-       g_free(name);
+       gtk_box_reorder_child(GTK_BOX(ped->vbox), new_entry, pos);
 }
 
-static void bar_exif_add_column_check(GtkWidget *listview, const gchar *title, gint n)
+static void bar_pane_exif_entry_dnd_begin(GtkWidget *entry, GdkDragContext *context, gpointer data)
 {
-       GtkTreeViewColumn *column;
-       GtkCellRenderer *renderer;
+       ExifEntry *ee = g_object_get_data(G_OBJECT(entry), "entry_data");
+       
+       if (!ee) return;
+       dnd_set_drag_label(entry, context, ee->key);
+}
 
-       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);
+static void bar_pane_exif_entry_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
+{
+}
 
-       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);
+static void bar_pane_exif_entry_dnd_init(GtkWidget *entry)
+{
+       ExifEntry *ee = g_object_get_data(G_OBJECT(entry), "entry_data");
+
+       gtk_drag_source_set(entry, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
+                           bar_pane_exif_drag_types, n_exif_entry_drag_types,
+                           GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
+       g_signal_connect(G_OBJECT(entry), "drag_data_get",
+                        G_CALLBACK(bar_pane_exif_entry_dnd_get), ee);
+
+       g_signal_connect(G_OBJECT(entry), "drag_begin",
+                        G_CALLBACK(bar_pane_exif_entry_dnd_begin), ee);
+       g_signal_connect(G_OBJECT(entry), "drag_end",
+                        G_CALLBACK(bar_pane_exif_entry_dnd_end), ee);
+}
 
-       g_signal_connect(G_OBJECT(renderer), "toggled",
-                        G_CALLBACK(bar_exif_row_toggled_cb), listview);
+static void bar_pane_exif_dnd_init(GtkWidget *pane)
+{
+       gtk_drag_dest_set(pane,
+                         GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_HIGHLIGHT | GTK_DEST_DEFAULT_DROP,
+                         bar_pane_exif_drop_types, n_exif_entry_drop_types,
+                         GDK_ACTION_COPY | GDK_ACTION_MOVE);
+       g_signal_connect(G_OBJECT(pane), "drag_data_received",
+                        G_CALLBACK(bar_pane_exif_dnd_receive), NULL);
 }
 
-static void bar_exif_add_column(GtkWidget *listview, const gchar *title, gint n, gint sizable)
+static void bar_pane_exif_edit_close_cb(GtkWidget *widget, gpointer data)
 {
-       GtkTreeViewColumn *column;
-       GtkCellRenderer *renderer;
+       GenericDialog *gd = data;
+       generic_dialog_close(gd);
+}
 
-       column = gtk_tree_view_column_new();
-       gtk_tree_view_column_set_title(column, title);
+static void bar_pane_exif_edit_destroy_cb(GtkWidget *widget, gpointer data)
+{
+       ConfDialogData *cdd = data;
+       g_signal_handlers_disconnect_by_func(cdd->widget, G_CALLBACK(bar_pane_exif_edit_close_cb), cdd->gd);
+       g_free(cdd);
+}
 
-       if (sizable)
+static void bar_pane_exif_edit_cancel_cb(GenericDialog *gd, gpointer data)
+{
+}
+
+static void bar_pane_exif_edit_ok_cb(GenericDialog *gd, gpointer data)
+{
+       ConfDialogData *cdd = data;
+       
+       /* either one or the other */
+       PaneExifData *ped = g_object_get_data(G_OBJECT(cdd->widget), "pane_data");
+       ExifEntry *ee = g_object_get_data(G_OBJECT(cdd->widget), "entry_data");
+
+       if (ped)
                {
-               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);
+               bar_pane_exif_add_entry(ped,
+                                       gtk_entry_get_text(GTK_ENTRY(cdd->key_entry)),
+                                       gtk_entry_get_text(GTK_ENTRY(cdd->title_entry)),
+                                       cdd->if_set, cdd->editable);
                }
-       else
+
+       if (ee)
                {
-               gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
-               }
+               const gchar *title;
+               GtkWidget *pane = gtk_widget_get_parent(cdd->widget);
+               
+               while (pane)
+                       {
+                       ped = g_object_get_data(G_OBJECT(pane), "pane_data");
+                       if (ped) break;
+                       pane = gtk_widget_get_parent(pane);
+                       }
+               
+               if (!pane) return;
+               
+               g_free(ee->key);
+               ee->key = g_strdup(gtk_entry_get_text(GTK_ENTRY(cdd->key_entry)));
+               title = gtk_entry_get_text(GTK_ENTRY(cdd->title_entry));
+               if (!title || strlen(title) == 0)
+                       {
+                       g_free(ee->title);
+                       ee->title = exif_get_description_by_key(ee->key);
+                       ee->auto_title = TRUE;
+                       }
+               else if (!ee->title || strcmp(ee->title, title) != 0)
+                       {
+                       g_free(ee->title);
+                       ee->title = g_strdup(title);
+                       ee->auto_title = FALSE;
+                       }
+               
+               ee->if_set = cdd->if_set;
+               ee->editable = cdd->editable;
+               
+               bar_pane_exif_setup_entry_box(ped, ee);
 
-       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);
+               bar_pane_exif_entry_update_title(ee);
+               bar_pane_exif_update(ped);
+               }
 }
 
-static void bar_exif_advanced_build_view(ExifBar *eb)
+static void bar_pane_exif_conf_dialog(GtkWidget *widget)
 {
-       GtkListStore *store;
+       ConfDialogData *cdd;
+       GenericDialog *gd;
+       GtkWidget *table;
 
-       if (eb->listview) return;
+       /* the widget can be either ExifEntry (for editing) or Pane (for new entry)
+          we can decide it by the attached data */
+       ExifEntry *ee = g_object_get_data(G_OBJECT(widget), "entry_data");
 
-       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);
+       cdd = g_new0(ConfDialogData, 1);
+       
+       cdd->widget = widget;
 
-       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);
-               }
+       cdd->if_set = ee ? ee->if_set : TRUE;
+       cdd->editable = ee ? ee->editable : FALSE;
+       
+       cdd->gd = gd = generic_dialog_new(ee ? _("Configure entry") : _("Add entry"), "exif_entry_edit",
+                               widget, TRUE,
+                               bar_pane_exif_edit_cancel_cb, cdd);
+       g_signal_connect(G_OBJECT(gd->dialog), "destroy",
+                        G_CALLBACK(bar_pane_exif_edit_destroy_cb), cdd);
 
-       bar_exif_add_column_check(eb->listview, "", EXIF_ADVCOL_ENABLED);
+       /* in case the entry is deleted during editing */
+       g_signal_connect(G_OBJECT(widget), "destroy",
+                        G_CALLBACK(bar_pane_exif_edit_close_cb), gd);
 
-       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);
+       generic_dialog_add_message(gd, NULL, ee ? _("Configure entry") : _("Add entry"), NULL);
 
-       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);
-}
+       generic_dialog_add_button(gd, GTK_STOCK_OK, NULL,
+                                 bar_pane_exif_edit_ok_cb, TRUE);
 
-static void bar_exif_advanced_cb(GtkWidget *widget, gpointer data)
-{
-       ExifBar *eb = data;
-       gint advanced;
+       table = pref_table_new(gd->vbox, 3, 2, FALSE, TRUE);
+       pref_table_label(table, 0, 0, _("Key:"), 1.0);
 
-       advanced = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+       cdd->key_entry = gtk_entry_new();
+       gtk_widget_set_size_request(cdd->key_entry, 300, -1);
+       if (ee) gtk_entry_set_text(GTK_ENTRY(cdd->key_entry), ee->key);
+       gtk_table_attach_defaults(GTK_TABLE(table), cdd->key_entry, 1, 2, 0, 1);
+       generic_dialog_attach_default(gd, cdd->key_entry);
+       gtk_widget_show(cdd->key_entry);
 
-       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);
-               }
+       pref_table_label(table, 0, 1, _("Title:"), 1.0);
+
+       cdd->title_entry = gtk_entry_new();
+       gtk_widget_set_size_request(cdd->title_entry, 300, -1);
+       if (ee) gtk_entry_set_text(GTK_ENTRY(cdd->title_entry), ee->title);
+       gtk_table_attach_defaults(GTK_TABLE(table), cdd->title_entry, 1, 2, 1, 2);
+       generic_dialog_attach_default(gd, cdd->title_entry);
+       gtk_widget_show(cdd->title_entry);
 
-       bar_exif_update(eb);
+       pref_checkbox_new_int(gd->vbox, _("Show only if set"), cdd->if_set, &cdd->if_set);
+       pref_checkbox_new_int(gd->vbox, _("Editable (supported only for XMP)"), cdd->editable, &cdd->editable);
+
+       gtk_widget_show(gd->dialog);
 }
 
-gint bar_exif_is_advanced(GtkWidget *bar)
+static void bar_pane_exif_conf_dialog_cb(GtkWidget *menu_widget, gpointer data)
 {
-       ExifBar *eb;
+       GtkWidget *widget = data;
+       bar_pane_exif_conf_dialog(widget);
+}
 
-       eb = g_object_get_data(G_OBJECT(bar), "bar_exif_data");
-       if (!eb) return FALSE;
+static void bar_pane_exif_delete_entry_cb(GtkWidget *menu_widget, gpointer data)
+{
+       GtkWidget *entry = data;
+       gtk_widget_destroy(entry);
+}
 
-       return (eb->advanced_scrolled && GTK_WIDGET_VISIBLE(eb->advanced_scrolled));
+static void bar_pane_exif_toggle_show_all_cb(GtkWidget *menu_widget, gpointer data)
+{
+       PaneExifData *ped = data;
+       ped->show_all = !ped->show_all;
+       bar_pane_exif_update(ped);
 }
 
-void bar_exif_close(GtkWidget *bar)
+static void bar_pane_exif_menu_popup(GtkWidget *widget, PaneExifData *ped)
 {
-       ExifBar *eb;
+       GtkWidget *menu;
+       /* the widget can be either ExifEntry (for editing) or Pane (for new entry)
+          we can decide it by the attached data */
+       ExifEntry *ee = g_object_get_data(G_OBJECT(widget), "entry_data");
 
-       eb = g_object_get_data(G_OBJECT(bar), "bar_exif_data");
-       if (!eb) return;
+       menu = popup_menu_short_lived();
+
+       if (ee)
+               {
+               /* for the entry */
+               gchar *conf = g_strdup_printf(_("Configure \"%s\""), ee->title);
+               gchar *del = g_strdup_printf(_("Remove \"%s\""), ee->title);
+               
+               menu_item_add_stock(menu, conf, GTK_STOCK_EDIT, G_CALLBACK(bar_pane_exif_conf_dialog_cb), widget);
+               menu_item_add_stock(menu, del, GTK_STOCK_DELETE, G_CALLBACK(bar_pane_exif_delete_entry_cb), widget);
+               menu_item_add_divider(menu);
+               
+               g_free(conf);
+               g_free(del);
+               }
 
-       gtk_widget_destroy(eb->vbox);
+       /* for the pane */
+       menu_item_add_stock(menu, _("Add entry"), GTK_STOCK_ADD, G_CALLBACK(bar_pane_exif_conf_dialog_cb), ped->widget);
+       menu_item_add_check(menu, _("Show hidden entries"), ped->show_all, G_CALLBACK(bar_pane_exif_toggle_show_all_cb), ped);
+       
+       gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
 }
 
-static void bar_exif_size(ExifBar *eb, gint val)
+static gboolean bar_pane_exif_menu_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
 {
-       gint size;
+       PaneExifData *ped = data;
+       if (bevent->button == MOUSE_BUTTON_RIGHT)
+               {
+               bar_pane_exif_menu_popup(widget, ped);
+               return TRUE;
+               }
+       return FALSE;
+}
+
 
-       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_pane_exif_entry_write_config(GtkWidget *entry, GString *outstr, gint indent)
+{
+       ExifEntry *ee = g_object_get_data(G_OBJECT(entry), "entry_data");
+       if (!ee) return;
+
+       WRITE_NL(); WRITE_STRING("<entry ");
+       WRITE_CHAR(*ee, key);
+       if (!ee->auto_title) WRITE_CHAR(*ee, title);
+       WRITE_BOOL(*ee, if_set);
+       WRITE_BOOL(*ee, editable);
+       WRITE_STRING("/>");
 }
 
-static void bar_exif_larger(GtkWidget *widget, gpointer data)
+static void bar_pane_exif_write_config(GtkWidget *pane, GString *outstr, gint indent)
 {
-       ExifBar *eb = data;
+       PaneExifData *ped;
+       GList *work, *list;
+       
+       ped = g_object_get_data(G_OBJECT(pane), "pane_data");
+       if (!ped) return;
+
+       WRITE_NL(); WRITE_STRING("<pane_exif ");
+       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++;
+       
+       list = gtk_container_get_children(GTK_CONTAINER(ped->vbox));
+       work = list;
+       while (work)
+               {
+               GtkWidget *entry = work->data;
+               work = work->next;
+               
+               bar_pane_exif_entry_write_config(entry, outstr, indent);
+               }
+       g_list_free(list);
+       indent--;
+       WRITE_NL(); WRITE_STRING("</pane_exif>");
+}
+
 
-       bar_exif_size(eb, EXIF_BAR_SIZE_INCREMENT);
+void bar_pane_exif_close(GtkWidget *widget)
+{
+       PaneExifData *ped;
+
+       ped = g_object_get_data(G_OBJECT(widget), "pane_data");
+       if (!ped) return;
+
+       gtk_widget_destroy(ped->vbox);
 }
 
-static void bar_exif_smaller(GtkWidget *widget, gpointer data)
+static void bar_pane_exif_destroy(GtkWidget *widget, gpointer data)
 {
-       ExifBar *eb = data;
+       PaneExifData *ped = data;
 
-       bar_exif_size(eb, -EXIF_BAR_SIZE_INCREMENT);
+       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);
 }
 
-static void bar_exif_destroy(GtkWidget *widget, gpointer data)
+#if !GTK_CHECK_VERSION(3,0,0)
+static void bar_pane_exif_size_request(GtkWidget *pane, GtkRequisition *requisition, gpointer data)
 {
-       ExifBar *eb = data;
+       PaneExifData *ped = data;
+       if (requisition->height < ped->min_height)
+               {
+               requisition->height = ped->min_height;
+               }
+}
+#endif
 
-       g_free(eb->labels);
-       file_data_unref(eb->fd);
-       g_free(eb);
+static void bar_pane_exif_size_allocate(GtkWidget *pane, GtkAllocation *alloc, gpointer data)
+{
+       PaneExifData *ped = data;
+       ped->min_height = alloc->height;
+#if GTK_CHECK_VERSION(3,0,0)
+       gtk_widget_set_size_request(ped->widget, -1, ped->min_height);
+#endif
 }
 
-GtkWidget *bar_exif_new(gint show_title, FileData *fd, gint advanced, GtkWidget *bounding_widget)
+static GtkWidget *bar_pane_exif_new(const gchar *id, const gchar *title, gboolean expanded)
 {
-       ExifBar *eb;
-       GtkWidget *table;
-       GtkWidget *viewport;
-       GtkWidget *hbox;
-       GtkWidget *button;
-       gint len;
-       gint i;
+       PaneExifData *ped;
+
+       ped = g_new0(PaneExifData, 1);
+
+       ped->pane.pane_set_fd = bar_pane_exif_set_fd;
+       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();
+       ped->vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP);
+       gtk_container_add(GTK_CONTAINER(ped->widget), ped->vbox);
+       gtk_widget_show(ped->vbox);
+
+       ped->min_height = MIN_HEIGHT;
+       g_object_set_data(G_OBJECT(ped->widget), "pane_data", ped);
+       g_signal_connect_after(G_OBJECT(ped->widget), "destroy",
+                              G_CALLBACK(bar_pane_exif_destroy), ped);
+#if GTK_CHECK_VERSION(3,0,0)
+       gtk_widget_set_size_request(ped->widget, -1, ped->min_height);
+#else
+       g_signal_connect(G_OBJECT(ped->widget), "size-request",
+                        G_CALLBACK(bar_pane_exif_size_request), ped);
+#endif
+       g_signal_connect(G_OBJECT(ped->widget), "size-allocate",
+                        G_CALLBACK(bar_pane_exif_size_allocate), ped);
+       
+       bar_pane_exif_dnd_init(ped->widget);
+       g_signal_connect(ped->widget, "button_release_event", G_CALLBACK(bar_pane_exif_menu_cb), ped);
 
-       eb = g_new0(ExifBar, 1);
+       file_data_register_notify_func(bar_pane_exif_notify_cb, ped, NOTIFY_PRIORITY_LOW);
 
-       eb->labels = g_new0(GtkWidget *, bar_exif_key_count);
+       gtk_widget_show(ped->widget);
 
-       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);
+       return ped->widget;
+}
 
-       eb->allow_search = !show_title;
+GtkWidget *bar_pane_exif_new_from_config(const gchar **attribute_names, const gchar **attribute_values)
+{
+       gchar *title = NULL;
+       gchar *id = g_strdup("exif");
+       gboolean expanded = TRUE;
+       GtkWidget *ret;
 
-       if (show_title)
+       while (*attribute_names)
                {
-               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);
+               const gchar *option = *attribute_names++;
+               const gchar *value = *attribute_values++;
+
+               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);
                }
+       
+       bar_pane_translate_title(PANE_EXIF, id, &title);
+       ret = bar_pane_exif_new(id, title, expanded);
+       g_free(title);
+       g_free(id);
+       return ret;
+}
 
-       table = gtk_table_new(2, bar_exif_key_count + 1 + EXIF_BAR_CUSTOM_COUNT, FALSE);
+void bar_pane_exif_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values)
+{
+       PaneExifData *ped;
+       gchar *title = NULL;
 
-       eb->table = table;
+       ped = g_object_get_data(G_OBJECT(pane), "pane_data");
+       if (!ped) return;
 
-       len = bar_exif_key_count;
-       for (i = 0; i < len; i++)
+       while (*attribute_names)
                {
-               const gchar *text;
+               const gchar *option = *attribute_names++;
+               const gchar *value = *attribute_values++;
 
-               text = exif_get_description_by_key(bar_exif_key_list[i]);
-               eb->labels[i] = table_add_line(table, 0, i, text, NULL);
-               }
+               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;
+               
 
-       eb->custom_sep = gtk_hseparator_new();
-       gtk_table_attach(GTK_TABLE(table), eb->custom_sep, 0, 1,
-                                          bar_exif_key_count, bar_exif_key_count + 1,
-                                          GTK_FILL, GTK_FILL, 2, 2);
+               log_printf("unknown attribute %s = %s\n", option, value);
+               }
 
-       for (i = 0; i < EXIF_BAR_CUSTOM_COUNT; i++)
+       if (title)
                {
-               table_add_line_custom(table, 0, bar_exif_key_count + 1 + i,
-                                     "", "",  &eb->custom_name[i], &eb->custom_value[i]);
+               bar_pane_translate_title(PANE_EXIF, ped->pane.id, &title);
+               gtk_label_set_text(GTK_LABEL(ped->pane.title), title);
+               g_free(title);
                }
 
-       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);
+       bar_update_expander(pane);
+       bar_pane_exif_update(ped);
+}
 
-       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);
+void bar_pane_exif_entry_add_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values)
+{
+       PaneExifData *ped;
+       gchar *key = NULL;
+       gchar *title = NULL;
+       gboolean if_set = TRUE;
+       gboolean editable = FALSE;
 
-       eb->advanced_scrolled = NULL;
-       eb->listview = NULL;
+       ped = g_object_get_data(G_OBJECT(pane), "pane_data");
+       if (!ped) return;
 
-       if (advanced)
-               {
-               bar_exif_advanced_build_view(eb);
-               gtk_widget_show(eb->advanced_scrolled);
-               }
-       else
+       while (*attribute_names)
                {
-               gtk_widget_show(eb->scrolled);
-               }
-
-       eb->fd = file_data_ref(fd);
-       bar_exif_update(eb);
+               const gchar *option = *attribute_names++;
+               const gchar *value = *attribute_values++;
 
-       return eb->vbox;
+               if (READ_CHAR_FULL("key", key)) continue;
+               if (READ_CHAR_FULL("title", title)) continue;
+               if (READ_BOOL_FULL("if_set", if_set)) continue;
+               if (READ_BOOL_FULL("editable", editable)) continue;
+               
+               log_printf("unknown attribute %s = %s\n", option, value);
+               }
+       
+       if (key && key[0]) bar_pane_exif_add_entry(ped, key, title, if_set, editable);
 }
 
+
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */