dnd in keywords tree
[geeqie.git] / src / advanced_exif.c
1 /*
2  * Geeqie
3  * (C) 2004 John Ellis
4  * Copyright (C) 2008 - 2009 The Geeqie Team
5  *
6  * Author: John Ellis
7  *
8  * This software is released under the GNU General Public License (GNU GPL).
9  * Please read the included file COPYING for more information.
10  * This software comes with no warranty of any kind, use at your own risk!
11  */
12
13
14 #include "main.h"
15 #include "advanced_exif.h"
16
17 #include "exif.h"
18 #include "metadata.h"
19 #include "filedata.h"
20 #include "history_list.h"
21 #include "misc.h"
22 #include "ui_misc.h"
23 #include "window.h"
24 #include "dnd.h"
25
26 /* FIXME: not needed when bar_exif.c is improved */
27 #include "bar_exif.h"
28
29 #include <math.h>
30
31 #define ADVANCED_EXIF_DATA_COLUMN_WIDTH 200
32
33 /*
34  *-------------------------------------------------------------------
35  * EXIF window
36  *-------------------------------------------------------------------
37  */
38
39 typedef struct _ExifWin ExifWin;
40 struct _ExifWin
41 {
42         GtkWidget *window;
43         GtkWidget *vbox;
44         GtkWidget *scrolled;
45         GtkWidget *listview;
46
47         FileData *fd;
48 };
49
50 enum {
51         EXIF_ADVCOL_ENABLED = 0,
52         EXIF_ADVCOL_TAG,
53         EXIF_ADVCOL_NAME,
54         EXIF_ADVCOL_VALUE,
55         EXIF_ADVCOL_FORMAT,
56         EXIF_ADVCOL_ELEMENTS,
57         EXIF_ADVCOL_DESCRIPTION,
58         EXIF_ADVCOL_COUNT
59 };
60
61 static gint advanced_exif_row_enabled(const gchar *name)
62 {
63         GList *list;
64
65         if (!name) return FALSE;
66
67         list = history_list_get_by_key("exif_extras");
68         while (list)
69                 {
70                 if (strcmp(name, (gchar *)(list->data)) == 0) return TRUE;
71                 list = list->next;
72         }
73
74         return FALSE;
75 }
76
77 static void advanced_exif_update(ExifWin *ew)
78 {
79         ExifData *exif;
80
81         GtkListStore *store;
82         GtkTreeIter iter;
83         ExifData *exif_original;
84         ExifItem *item;
85
86         exif = exif_read_fd(ew->fd);
87         
88         gtk_widget_set_sensitive(ew->scrolled, !!exif);
89
90         if (!exif) return;
91         
92         exif_original = exif_get_original(exif);
93
94         store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ew->listview)));
95         gtk_list_store_clear(store);
96
97         item = exif_get_first_item(exif_original);
98         while (item)
99                 {
100                 gchar *tag;
101                 gchar *tag_name;
102                 gchar *text;
103                 gchar *utf8_text;
104                 const gchar *format;
105                 gchar *elements;
106                 gchar *description;
107
108                 tag = g_strdup_printf("0x%04x", exif_item_get_tag_id(item));
109                 tag_name = exif_item_get_tag_name(item);
110                 format = exif_item_get_format_name(item, TRUE);
111                 text = exif_item_get_data_as_text(item);
112                 utf8_text = utf8_validate_or_convert(text);
113                 g_free(text);
114                 elements = g_strdup_printf("%d", exif_item_get_elements(item));
115                 description = exif_item_get_description(item);
116                 if (!description || *description == '\0') 
117                         {
118                         g_free(description);
119                         description = g_strdup(tag_name);
120                         }
121
122                 gtk_list_store_append(store, &iter);
123                 gtk_list_store_set(store, &iter,
124                                 EXIF_ADVCOL_ENABLED, advanced_exif_row_enabled(tag_name),
125                                 EXIF_ADVCOL_TAG, tag,
126                                 EXIF_ADVCOL_NAME, tag_name,
127                                 EXIF_ADVCOL_VALUE, utf8_text,
128                                 EXIF_ADVCOL_FORMAT, format,
129                                 EXIF_ADVCOL_ELEMENTS, elements,
130                                 EXIF_ADVCOL_DESCRIPTION, description, -1);
131                 g_free(tag);
132                 g_free(utf8_text);
133                 g_free(elements);
134                 g_free(description);
135                 g_free(tag_name);
136                 item = exif_get_next_item(exif_original);
137                 }
138         exif_free_fd(ew->fd, exif);
139
140 }
141
142 static void advanced_exif_clear(ExifWin *ew)
143 {
144         GtkListStore *store;
145
146         store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(ew->listview)));
147         gtk_list_store_clear(store);
148 }
149
150 void advanced_exif_set_fd(GtkWidget *window, FileData *fd)
151 {
152         ExifWin *ew;
153
154         ew = g_object_get_data(G_OBJECT(window), "advanced_exif_data");
155         if (!ew) return;
156
157         /* store this, advanced view toggle needs to reload data */
158         file_data_unref(ew->fd);
159         ew->fd = file_data_ref(fd);
160
161         advanced_exif_clear(ew);
162         advanced_exif_update(ew);
163 }
164
165 #if 0
166 static void advanced_exif_row_toggled_cb(GtkCellRendererToggle *toggle, const gchar *path, gpointer data)
167 {
168         GtkWidget *listview = data;
169         GtkTreeModel *store;
170         GtkTreeIter iter;
171         GtkTreePath *tpath;
172         gchar *name = NULL;
173         gboolean active;
174
175         store = gtk_tree_view_get_model(GTK_TREE_VIEW(listview));
176
177         tpath = gtk_tree_path_new_from_string(path);
178         gtk_tree_model_get_iter(store, &iter, tpath);
179         gtk_tree_path_free(tpath);
180
181         gtk_tree_model_get(store, &iter, EXIF_ADVCOL_ENABLED, &active,
182                                          EXIF_ADVCOL_NAME, &name, -1);
183         active = (!active);
184
185         if (active &&
186             g_list_length(history_list_get_by_key("exif_extras")) >= EXIF_BAR_CUSTOM_COUNT)
187                 {
188                 active = FALSE;
189                 }
190
191         gtk_list_store_set(GTK_LIST_STORE(store), &iter, EXIF_ADVCOL_ENABLED, active, -1);
192
193         if (active)
194                 {
195                 history_list_add_to_key("exif_extras", name, EXIF_BAR_CUSTOM_COUNT);
196                 }
197         else
198                 {
199                 history_list_item_change("exif_extras", name, NULL);
200                 }
201
202         g_free(name);
203 }
204 #endif 
205
206 #if 0
207 static void advanced_exif_add_column_check(GtkWidget *listview, const gchar *title, gint n)
208 {
209         GtkTreeViewColumn *column;
210         GtkCellRenderer *renderer;
211
212         column = gtk_tree_view_column_new();
213         gtk_tree_view_column_set_title(column, title);
214         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
215
216         renderer = gtk_cell_renderer_toggle_new();
217         gtk_tree_view_column_pack_start(column, renderer, TRUE);
218         gtk_tree_view_column_add_attribute(column, renderer, "active", n);
219         gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
220
221         g_signal_connect(G_OBJECT(renderer), "toggled",
222                          G_CALLBACK(advanced_exif_row_toggled_cb), listview);
223 }
224 #endif
225
226 static GtkTargetEntry advanced_exif_drag_types[] = {
227         { "text/plain", 0, TARGET_TEXT_PLAIN }
228 };
229 static gint n_exif_drag_types = 1;
230
231
232 static void advanced_exif_dnd_get(GtkWidget *listview, GdkDragContext *context,
233                                      GtkSelectionData *selection_data, guint info,
234                                      guint time, gpointer data)
235 {
236         ExifWin *ew = data;
237         GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(listview)); 
238         GtkTreeIter iter;
239
240         if (gtk_tree_selection_get_selected(sel, NULL, &iter)) 
241                 {
242                 GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(listview));
243                 gchar *key;
244
245                 gtk_tree_model_get(store, &iter, EXIF_ADVCOL_NAME, &key, -1);
246                 gtk_selection_data_set_text(selection_data, key, -1);
247                 printf("%s\n",key);
248                 g_free(key);
249                 }
250
251 }
252
253 static void advanced_exif_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
254 {
255         GtkWidget *window = data;
256         gtk_widget_destroy(window);
257 }
258
259 static void advanced_exif_dnd_begin(GtkWidget *listview, GdkDragContext *context, gpointer data)
260 {
261         ExifWin *ew = data;
262         GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(listview)); 
263         GtkTreeIter iter;
264
265         if (gtk_tree_selection_get_selected(sel, NULL, &iter)) 
266                 {
267                 GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(listview));
268                 gchar *key;
269                 GtkWidget *window;
270                 GtkWidget *label;
271
272                 gtk_tree_model_get(store, &iter, EXIF_ADVCOL_NAME, &key, -1);
273
274                 window = gtk_window_new(GTK_WINDOW_POPUP);
275                 gtk_widget_realize (window);
276
277                 label = gtk_label_new(key);
278                 gtk_container_add(GTK_CONTAINER (window), label);
279                 gtk_widget_show(label);
280                 gtk_drag_set_icon_widget(context, window, -15, 10);
281                 g_signal_connect(G_OBJECT(listview), "drag_end",
282                                  G_CALLBACK(advanced_exif_dnd_end), window);
283
284                 g_free(key);
285                 }
286 }
287
288
289
290 static void advanced_exif_add_column(GtkWidget *listview, const gchar *title, gint n, gint sizable)
291 {
292         GtkTreeViewColumn *column;
293         GtkCellRenderer *renderer;
294
295         column = gtk_tree_view_column_new();
296         gtk_tree_view_column_set_title(column, title);
297
298         if (sizable)
299                 {
300                 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
301                 gtk_tree_view_column_set_fixed_width(column, ADVANCED_EXIF_DATA_COLUMN_WIDTH);
302                 gtk_tree_view_column_set_resizable(column, TRUE);
303                 }
304         else
305                 {
306                 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
307                 }
308
309         renderer = gtk_cell_renderer_text_new();
310         gtk_tree_view_column_pack_start(column, renderer, TRUE);
311         gtk_tree_view_column_add_attribute(column, renderer, "text", n);
312         gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
313 }
314
315 void advanced_exif_close(GtkWidget *window)
316 {
317         ExifWin *ew;
318
319         ew = g_object_get_data(G_OBJECT(window), "advanced_exif_data");
320         if (!ew) return;
321
322         gtk_widget_destroy(ew->vbox);
323 }
324
325 static void advanced_exif_destroy(GtkWidget *widget, gpointer data)
326 {
327         ExifWin *ew = data;
328         file_data_unref(ew->fd);
329         g_free(ew);
330 }
331
332 GtkWidget *advanced_exif_new(void)
333 {
334         ExifWin *ew;
335         GtkListStore *store;
336         GdkGeometry geometry;
337
338         ew = g_new0(ExifWin, 1);
339
340
341         ew->window = window_new(GTK_WINDOW_TOPLEVEL, "view", NULL, NULL, _("Metadata"));
342
343         geometry.min_width = 900;
344         geometry.min_height = 600;
345         gtk_window_set_geometry_hints(GTK_WINDOW(ew->window), NULL, &geometry, GDK_HINT_MIN_SIZE);
346
347         gtk_window_set_resizable(GTK_WINDOW(ew->window), TRUE);
348
349         g_object_set_data(G_OBJECT(ew->window), "advanced_exif_data", ew);
350         g_signal_connect_after(G_OBJECT(ew->window), "destroy",
351                                G_CALLBACK(advanced_exif_destroy), ew);
352
353         ew->vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP);
354         gtk_container_add(GTK_CONTAINER(ew->window), ew->vbox);
355         gtk_widget_show(ew->vbox);
356
357
358         store = gtk_list_store_new(7, G_TYPE_BOOLEAN,
359                                       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
360                                       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
361         ew->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
362         g_object_unref(store);
363
364         gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(ew->listview), TRUE);
365         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(ew->listview), TRUE);
366
367         gtk_tree_view_set_search_column(GTK_TREE_VIEW(ew->listview), EXIF_ADVCOL_NAME);
368
369         advanced_exif_add_column(ew->listview, _("Description"), EXIF_ADVCOL_DESCRIPTION, FALSE);
370         advanced_exif_add_column(ew->listview, _("Value"), EXIF_ADVCOL_VALUE, TRUE);
371         advanced_exif_add_column(ew->listview, _("Name"), EXIF_ADVCOL_NAME, FALSE);
372         advanced_exif_add_column(ew->listview, _("Tag"), EXIF_ADVCOL_TAG, FALSE);
373         advanced_exif_add_column(ew->listview, _("Format"), EXIF_ADVCOL_FORMAT, FALSE);
374         advanced_exif_add_column(ew->listview, _("Elements"), EXIF_ADVCOL_ELEMENTS, FALSE);
375
376         gtk_drag_source_set(ew->listview,
377                            GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
378                            advanced_exif_drag_types, n_exif_drag_types,
379                            GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
380
381         g_signal_connect(G_OBJECT(ew->listview), "drag_data_get",
382                          G_CALLBACK(advanced_exif_dnd_get), ew);
383
384         g_signal_connect(G_OBJECT(ew->listview), "drag_begin",
385                          G_CALLBACK(advanced_exif_dnd_begin), ew);
386
387         ew->scrolled = gtk_scrolled_window_new(NULL, NULL);
388         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(ew->scrolled), GTK_SHADOW_IN);
389         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ew->scrolled),
390                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
391         gtk_box_pack_start(GTK_BOX(ew->vbox), ew->scrolled, TRUE, TRUE, 0);
392         gtk_container_add(GTK_CONTAINER(ew->scrolled), ew->listview);
393         gtk_widget_show(ew->listview);
394         gtk_widget_show(ew->scrolled);
395
396         gtk_widget_show(ew->window);
397         return ew->window;
398 }
399 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */