droped Preferences dialog, sidebar should replace it completely
[geeqie.git] / src / bar_keywords.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 "bar_keywords.h"
16
17 #include "filedata.h"
18 #include "history_list.h"
19 #include "metadata.h"
20 #include "misc.h"
21 #include "ui_fileops.h"
22 #include "ui_misc.h"
23 #include "ui_utildlg.h"
24 #include "utilops.h"
25 #include "bar.h"
26 #include "ui_menu.h"
27
28 static const gchar *keyword_favorite_defaults[] = {
29         N_("Favorite"),
30         N_("Todo"),
31         N_("People"),
32         N_("Places"),
33         N_("Art"),
34         N_("Nature"),
35         N_("Possessions"),
36         NULL
37 };
38
39
40 static void bar_pane_keywords_keyword_update_all(void);
41 static void bar_pane_keywords_changed(GtkTextBuffer *buffer, gpointer data);
42
43 /*
44  *-------------------------------------------------------------------
45  * keyword / comment utils
46  *-------------------------------------------------------------------
47  */
48
49
50 GList *keyword_list_pull(GtkWidget *text_widget)
51 {
52         GList *list;
53         gchar *text;
54
55         text = text_widget_text_pull(text_widget);
56         list = string_to_keywords_list(text);
57
58         g_free(text);
59
60         return list;
61 }
62
63 static void keyword_list_push(GtkWidget *textview, GList *list)
64 {
65         GtkTextBuffer *buffer;
66         GtkTextIter start, end;
67
68         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
69         gtk_text_buffer_get_bounds(buffer, &start, &end);
70         gtk_text_buffer_delete(buffer, &start, &end);
71
72         while (list)
73                 {
74                 const gchar *word = list->data;
75                 GtkTextIter iter;
76
77                 gtk_text_buffer_get_end_iter(buffer, &iter);
78                 if (word) gtk_text_buffer_insert(buffer, &iter, word, -1);
79                 gtk_text_buffer_get_end_iter(buffer, &iter);
80                 gtk_text_buffer_insert(buffer, &iter, "\n", -1);
81
82                 list = list->next;
83                 }
84 }
85
86
87 /*
88  *-------------------------------------------------------------------
89  * keyword list dialog
90  *-------------------------------------------------------------------
91  */
92
93 #define KEYWORD_DIALOG_WIDTH  200
94 #define KEYWORD_DIALOG_HEIGHT 250
95
96 typedef struct _KeywordDlg KeywordDlg;
97 struct _KeywordDlg
98 {
99         GenericDialog *gd;
100         GtkWidget *treeview;
101 };
102
103 static KeywordDlg *keyword_dialog = NULL;
104
105
106 static void keyword_dialog_cancel_cb(GenericDialog *gd, gpointer data)
107 {
108         g_free(keyword_dialog);
109         keyword_dialog = NULL;
110 }
111
112 static void keyword_dialog_ok_cb(GenericDialog *gd, gpointer data)
113 {
114         KeywordDlg *kd = data;
115         GtkTreeModel *store;
116         GtkTreeIter iter;
117         gint valid;
118
119         history_list_free_key("keywords");
120
121         store = gtk_tree_view_get_model(GTK_TREE_VIEW(kd->treeview));
122         valid = gtk_tree_model_get_iter_first(store, &iter);
123         while (valid)
124                 {
125                 gchar *key;
126
127                 gtk_tree_model_get(store, &iter, 0, &key, -1);
128                 valid = gtk_tree_model_iter_next(store, &iter);
129
130                 history_list_add_to_key("keywords", key, 0);
131                 }
132
133         keyword_dialog_cancel_cb(gd, data);
134
135         bar_pane_keywords_keyword_update_all();
136 }
137
138 static void keyword_dialog_add_cb(GtkWidget *button, gpointer data)
139 {
140         KeywordDlg *kd = data;
141         GtkTreeSelection *selection;
142         GtkTreeModel *store;
143         GtkTreeIter sibling;
144         GtkTreeIter iter;
145         GtkTreePath *tpath;
146
147         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(kd->treeview));
148         if (gtk_tree_selection_get_selected(selection, &store, &sibling))
149                 {
150                 gtk_list_store_insert_before(GTK_LIST_STORE(store), &iter, &sibling);
151                 }
152         else
153                 {
154                 store = gtk_tree_view_get_model(GTK_TREE_VIEW(kd->treeview));
155                 gtk_list_store_append(GTK_LIST_STORE(store), &iter);
156                 }
157
158         gtk_list_store_set(GTK_LIST_STORE(store), &iter, 1, TRUE, -1);
159
160         tpath = gtk_tree_model_get_path(store, &iter);
161         gtk_tree_view_set_cursor(GTK_TREE_VIEW(kd->treeview), tpath,
162                                  gtk_tree_view_get_column(GTK_TREE_VIEW(kd->treeview), 0), TRUE);
163         gtk_tree_path_free(tpath);
164 }
165
166 static void keyword_dialog_remove_cb(GtkWidget *button, gpointer data)
167 {
168         KeywordDlg *kd = data;
169         GtkTreeSelection *selection;
170         GtkTreeModel *store;
171         GtkTreeIter iter;
172         GtkTreeIter next;
173         GtkTreePath *tpath;
174
175         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(kd->treeview));
176         if (!gtk_tree_selection_get_selected(selection, &store, &iter)) return;
177
178         tpath = NULL;
179         next = iter;
180         if (gtk_tree_model_iter_next(store, &next))
181                 {
182                 tpath = gtk_tree_model_get_path(store, &next);
183                 }
184         else
185                 {
186                 tpath = gtk_tree_model_get_path(store, &iter);
187                 if (!gtk_tree_path_prev(tpath))
188                         {
189                         gtk_tree_path_free(tpath);
190                         tpath = NULL;
191                         }
192                 }
193         if (tpath)
194                 {
195                 gtk_tree_view_set_cursor(GTK_TREE_VIEW(kd->treeview), tpath,
196                                          gtk_tree_view_get_column(GTK_TREE_VIEW(kd->treeview), 0), FALSE);
197                 gtk_tree_path_free(tpath);
198                 }
199
200         gtk_list_store_remove(GTK_LIST_STORE(store), &iter);
201 }
202
203 static void keyword_dialog_edit_cb(GtkCellRendererText *renderer, const gchar *path,
204                                    const gchar *new_text, gpointer data)
205 {
206         KeywordDlg *kd = data;
207         GtkTreeModel *store;
208         GtkTreeIter iter;
209         GtkTreePath *tpath;
210
211         if (!new_text || strlen(new_text) == 0) return;
212
213         store = gtk_tree_view_get_model(GTK_TREE_VIEW(kd->treeview));
214
215         tpath = gtk_tree_path_new_from_string(path);
216         gtk_tree_model_get_iter(store, &iter, tpath);
217         gtk_tree_path_free(tpath);
218
219         gtk_list_store_set(GTK_LIST_STORE(store), &iter, 0, new_text, -1);
220 }
221
222 static void keyword_dialog_populate(KeywordDlg *kd)
223 {
224         GtkListStore *store;
225         GList *list;
226
227         store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(kd->treeview)));
228         gtk_list_store_clear(store);
229
230         list = history_list_get_by_key("keywords");
231         list = g_list_last(list);
232         while (list)
233                 {
234                 GtkTreeIter iter;
235
236                 gtk_list_store_append(store, &iter);
237                 gtk_list_store_set(store, &iter, 0, list->data,
238                                                  1, TRUE, -1);
239
240                 list = list->prev;
241                 }
242 }
243
244 static void keyword_dialog_show(void)
245 {
246         GtkWidget *scrolled;
247         GtkListStore *store;
248         GtkTreeViewColumn *column;
249         GtkCellRenderer *renderer;
250         GtkWidget *hbox;
251         GtkWidget *button;
252
253         if (keyword_dialog)
254                 {
255                 gtk_window_present(GTK_WINDOW(keyword_dialog->gd->dialog));
256                 return;
257                 }
258
259         keyword_dialog = g_new0(KeywordDlg, 1);
260
261         keyword_dialog->gd = generic_dialog_new(_("Keyword Presets"),
262                                                 "keyword_presets", NULL, TRUE,
263                                                 keyword_dialog_cancel_cb, keyword_dialog);
264         generic_dialog_add_message(keyword_dialog->gd, NULL, _("Favorite keywords list"), NULL);
265
266         generic_dialog_add_button(keyword_dialog->gd, GTK_STOCK_OK, NULL,
267                                  keyword_dialog_ok_cb, TRUE);
268
269         scrolled = gtk_scrolled_window_new(NULL, NULL);
270         gtk_widget_set_size_request(scrolled, KEYWORD_DIALOG_WIDTH, KEYWORD_DIALOG_HEIGHT);
271         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
272         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
273                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
274         gtk_box_pack_start(GTK_BOX(keyword_dialog->gd->vbox), scrolled, TRUE, TRUE, 5);
275         gtk_widget_show(scrolled);
276
277         store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_BOOLEAN);
278         keyword_dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
279         g_object_unref(store);
280
281         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(keyword_dialog->treeview), FALSE);
282         gtk_tree_view_set_search_column(GTK_TREE_VIEW(keyword_dialog->treeview), 0);
283         gtk_tree_view_set_reorderable(GTK_TREE_VIEW(keyword_dialog->treeview), TRUE);
284
285         column = gtk_tree_view_column_new();
286         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
287         renderer = gtk_cell_renderer_text_new();
288         g_signal_connect(G_OBJECT(renderer), "edited",
289                          G_CALLBACK(keyword_dialog_edit_cb), keyword_dialog);
290         gtk_tree_view_column_pack_start(column, renderer, TRUE);
291         gtk_tree_view_column_add_attribute(column, renderer, "text", 0);
292         gtk_tree_view_column_add_attribute(column, renderer, "editable", 1);
293         gtk_tree_view_append_column(GTK_TREE_VIEW(keyword_dialog->treeview), column);
294
295         gtk_container_add(GTK_CONTAINER(scrolled), keyword_dialog->treeview);
296         gtk_widget_show(keyword_dialog->treeview);
297
298         hbox = gtk_hbox_new(FALSE, 5);
299         gtk_box_pack_start(GTK_BOX(keyword_dialog->gd->vbox), hbox, FALSE, FALSE, 0);
300         gtk_widget_show(hbox);
301
302         button = gtk_button_new_from_stock(GTK_STOCK_ADD);
303         g_signal_connect(G_OBJECT(button), "clicked",
304                          G_CALLBACK(keyword_dialog_add_cb), keyword_dialog);
305         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
306         gtk_widget_show(button);
307
308         button = gtk_button_new_from_stock(GTK_STOCK_REMOVE);
309         g_signal_connect(G_OBJECT(button), "clicked",
310                          G_CALLBACK(keyword_dialog_remove_cb), keyword_dialog);
311         gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
312         gtk_widget_show(button);
313
314         keyword_dialog_populate(keyword_dialog);
315
316         gtk_widget_show(keyword_dialog->gd->dialog);
317 }
318
319
320 static void bar_keyword_edit_cb(GtkWidget *button, gpointer data)
321 {
322         keyword_dialog_show();
323 }
324
325
326 /*
327  *-------------------------------------------------------------------
328  * info bar
329  *-------------------------------------------------------------------
330  */
331
332 enum {
333         KEYWORD_COLUMN_TOGGLE = 0,
334         KEYWORD_COLUMN_TEXT,
335         KEYWORD_COLUMN_MARK
336 };
337
338 typedef struct _PaneKeywordsData PaneKeywordsData;
339 struct _PaneKeywordsData
340 {
341         PaneData pane;
342         GtkWidget *widget;
343
344         GtkWidget *keyword_view;
345         GtkWidget *keyword_treeview;
346
347         FileData *fd;
348         gchar *key;
349 };
350
351
352 static GList *bar_list = NULL;
353
354
355 static void bar_pane_keywords_write(PaneKeywordsData *pkd)
356 {
357         GList *list;
358
359         if (!pkd->fd) return;
360
361         list = keyword_list_pull(pkd->keyword_view);
362
363         metadata_write_list(pkd->fd, KEYWORD_KEY, list);
364
365         string_list_free(list);
366 }
367
368 static gchar *bar_pane_keywords_get_mark_text(const gchar *key)
369 {
370         gint i;
371         static gchar buf[10];
372         
373         for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
374                 {
375                 FileDataGetMarkFunc get_mark_func;
376                 FileDataSetMarkFunc set_mark_func;
377                 gpointer data;
378                 file_data_get_registered_mark_func(i, &get_mark_func, &set_mark_func, &data);
379                 if (get_mark_func == meta_data_get_keyword_mark && strcmp(data, key) == 0) 
380                         {
381                         sprintf(buf, " %d ", i + 1);
382                         return buf;
383                         }
384                 }
385         return " ... ";
386 }
387
388 static void bar_keyword_list_sync(PaneKeywordsData *pkd, GList *keywords)
389 {
390         GList *list;
391         GtkListStore *store;
392         GtkTreeIter iter;
393
394         list = history_list_get_by_key("keywords");
395         if (!list)
396                 {
397                 /* blank? set up a few example defaults */
398
399                 gint i = 0;
400
401                 while (keyword_favorite_defaults[i] != NULL)
402                         {
403                         history_list_add_to_key("keywords", _(keyword_favorite_defaults[i]), 0);
404                         i++;
405                         }
406
407                 list = history_list_get_by_key("keywords");
408                 }
409
410         store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(pkd->keyword_treeview)));
411
412         gtk_list_store_clear(store);
413
414         list = g_list_last(list);
415         while (list)
416                 {
417                 gchar *key = list->data;
418
419                 gtk_list_store_append(store, &iter);
420                 gtk_list_store_set(store, &iter, KEYWORD_COLUMN_TOGGLE, find_string_in_list(keywords, key),
421                                                  KEYWORD_COLUMN_TEXT, key,
422                                                  KEYWORD_COLUMN_MARK, bar_pane_keywords_get_mark_text(key), -1);
423
424                 list = list->prev;
425                 }
426 }
427
428 static void bar_pane_keywords_keyword_update_all(void)
429 {
430         GList *work;
431
432         work = bar_list;
433         while (work)
434                 {
435                 PaneKeywordsData *pkd;
436                 GList *keywords;
437
438                 pkd = work->data;
439                 work = work->next;
440
441                 keywords = keyword_list_pull(pkd->keyword_view);
442                 bar_keyword_list_sync(pkd, keywords);
443                 string_list_free(keywords);
444                 }
445 }
446
447 static void bar_pane_keywords_update(PaneKeywordsData *pkd)
448 {
449         GList *keywords = NULL;
450         GtkTextBuffer *keyword_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pkd->keyword_view));
451
452         g_signal_handlers_block_by_func(keyword_buffer, bar_pane_keywords_changed, pkd);
453
454         keywords = metadata_read_list(pkd->fd, KEYWORD_KEY, METADATA_PLAIN);
455         keyword_list_push(pkd->keyword_view, keywords);
456         bar_keyword_list_sync(pkd, keywords);
457         string_list_free(keywords);
458         
459         g_signal_handlers_unblock_by_func(keyword_buffer, bar_pane_keywords_changed, pkd);
460
461 }
462
463 void bar_pane_keywords_set_fd(GtkWidget *pane, FileData *fd)
464 {
465         PaneKeywordsData *pkd;
466
467         pkd = g_object_get_data(G_OBJECT(pane), "pane_data");
468         if (!pkd) return;
469
470         file_data_unref(pkd->fd);
471         pkd->fd = file_data_ref(fd);
472
473         bar_pane_keywords_update(pkd);
474 }
475
476 gint bar_pane_keywords_event(GtkWidget *bar, GdkEvent *event)
477 {
478         PaneKeywordsData *pkd;
479
480         pkd = g_object_get_data(G_OBJECT(bar), "pane_data");
481         if (!pkd) return FALSE;
482
483         if (GTK_WIDGET_HAS_FOCUS(pkd->keyword_view)) return gtk_widget_event(pkd->keyword_view, event);
484
485         return FALSE;
486 }
487
488 static void bar_pane_keywords_keyword_set(PaneKeywordsData *pkd, const gchar *keyword, gint active)
489 {
490         GList *list;
491         gint found;
492
493         if (!keyword) return;
494
495         list = keyword_list_pull(pkd->keyword_view);
496         found = find_string_in_list(list, keyword);
497
498         if (active != found)
499                 {
500                 if (found)
501                         {
502                         GList *work = list;
503
504                         while (work)
505                                 {
506                                 gchar *key = work->data;
507                                 work = work->next;
508
509                                 if (key && keyword && strcmp(key, keyword) == 0)
510                                         {
511                                         list = g_list_remove(list, key);
512                                         g_free(key);
513                                         }
514                                 }
515                         }
516                 else
517                         {
518                         list = g_list_append(list, g_strdup(keyword));
519                         }
520
521                 keyword_list_push(pkd->keyword_view, list);
522                 }
523
524         string_list_free(list);
525 }
526
527 static void bar_pane_keywords_keyword_toggle(GtkCellRendererToggle *toggle, const gchar *path, gpointer data)
528 {
529         PaneKeywordsData *pkd = data;
530         GtkTreeModel *store;
531         GtkTreeIter iter;
532         GtkTreePath *tpath;
533         gchar *key = NULL;
534         gboolean active;
535
536         store = gtk_tree_view_get_model(GTK_TREE_VIEW(pkd->keyword_treeview));
537
538         tpath = gtk_tree_path_new_from_string(path);
539         gtk_tree_model_get_iter(store, &iter, tpath);
540         gtk_tree_path_free(tpath);
541
542         gtk_tree_model_get(store, &iter, KEYWORD_COLUMN_TOGGLE, &active,
543                                          KEYWORD_COLUMN_TEXT, &key, -1);
544         active = (!active);
545         gtk_list_store_set(GTK_LIST_STORE(store), &iter, KEYWORD_COLUMN_TOGGLE, active, -1);
546
547         bar_pane_keywords_keyword_set(pkd, key, active);
548         g_free(key);
549 }
550
551 static void bar_pane_keywords_set_selection(PaneKeywordsData *pkd, gboolean append)
552 {
553         GList *keywords = NULL;
554         GList *list = NULL;
555         GList *work;
556
557         if (!pkd->pane.list_func) return;
558
559         keywords = keyword_list_pull(pkd->keyword_view);
560
561         list = pkd->pane.list_func(pkd->pane.list_data);
562         work = list;
563         while (work)
564                 {
565                 FileData *fd = work->data;
566                 work = work->next;
567
568                 if (append)
569                         {
570                         metadata_append_list(fd, KEYWORD_KEY, keywords);
571                         }
572                 else
573                         {
574                         metadata_write_list(fd, KEYWORD_KEY, keywords);
575                         }
576                 }
577
578         filelist_free(list);
579         string_list_free(keywords);
580 }
581
582 static void bar_pane_keywords_sel_add_cb(GtkWidget *button, gpointer data)
583 {
584         PaneKeywordsData *pkd = data;
585
586         bar_pane_keywords_set_selection(pkd, TRUE);
587 }
588
589 static void bar_pane_keywords_sel_replace_cb(GtkWidget *button, gpointer data)
590 {
591         PaneKeywordsData *pkd = data;
592
593         bar_pane_keywords_set_selection(pkd, FALSE);
594 }
595
596 static void bar_pane_keywords_populate_popup_cb(GtkTextView *textview, GtkMenu *menu, gpointer data)
597 {
598         PaneKeywordsData *pkd = data;
599
600         menu_item_add_divider(GTK_WIDGET(menu));
601         menu_item_add_stock(GTK_WIDGET(menu), _("Add keywords to selected files"), GTK_STOCK_ADD, G_CALLBACK(bar_pane_keywords_sel_add_cb), data);
602         menu_item_add_stock(GTK_WIDGET(menu), _("Replace existing keywords in selected files"), GTK_STOCK_CONVERT, G_CALLBACK(bar_pane_keywords_sel_replace_cb), data);
603 }
604
605
606 static void bar_pane_keywords_notify_cb(FileData *fd, NotifyType type, gpointer data)
607 {
608         PaneKeywordsData *pkd = data;
609         if (fd == pkd->fd) bar_pane_keywords_update(pkd);
610 }
611
612 static void bar_pane_keywords_changed(GtkTextBuffer *buffer, gpointer data)
613 {
614         PaneKeywordsData *pkd = data;
615
616         file_data_unregister_notify_func(bar_pane_keywords_notify_cb, pkd);
617         bar_pane_keywords_write(pkd);
618         file_data_register_notify_func(bar_pane_keywords_notify_cb, pkd, NOTIFY_PRIORITY_LOW);
619 }
620
621 static void bar_pane_keywords_mark_edited (GtkCellRendererText *cell, const gchar *path, const gchar *text, gpointer data)
622 {
623         PaneKeywordsData *pkd = data;
624         GtkTreeModel *store;
625         GtkTreeIter iter;
626         GtkTreePath *tpath;
627         gchar *key = NULL;
628         gint i;
629         FileDataGetMarkFunc get_mark_func;
630         FileDataSetMarkFunc set_mark_func;
631         gpointer mark_func_data;
632
633         file_data_unregister_notify_func(bar_pane_keywords_notify_cb, pkd);
634
635         store = gtk_tree_view_get_model(GTK_TREE_VIEW(pkd->keyword_treeview));
636
637         tpath = gtk_tree_path_new_from_string(path);
638         gtk_tree_model_get_iter(store, &iter, tpath);
639         gtk_tree_path_free(tpath);
640
641         gtk_tree_model_get(store, &iter, KEYWORD_COLUMN_TEXT, &key, -1);
642
643         for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
644                 {
645                 file_data_get_registered_mark_func(i, &get_mark_func, &set_mark_func, &mark_func_data);
646                 if (get_mark_func == meta_data_get_keyword_mark && strcmp(mark_func_data, key) == 0) 
647                         {
648                         g_free(mark_func_data);
649                         file_data_register_mark_func(i, NULL, NULL, NULL);
650                         }
651                 }
652
653         if (sscanf(text, " %d ", &i) &&i >=1 && i <= FILEDATA_MARKS_SIZE)
654                 {
655                 i--;
656                 file_data_get_registered_mark_func(i, &get_mark_func, &set_mark_func, &mark_func_data);
657                 if (get_mark_func == meta_data_get_keyword_mark && mark_func_data) g_free(mark_func_data); 
658                 file_data_register_mark_func(i, meta_data_get_keyword_mark, meta_data_set_keyword_mark, g_strdup(key));
659                 }
660
661         g_free(key);
662
663         file_data_register_notify_func(bar_pane_keywords_notify_cb, pkd, NOTIFY_PRIORITY_LOW);
664         bar_pane_keywords_update(pkd);
665 }
666
667 void bar_pane_keywords_close(GtkWidget *bar)
668 {
669         PaneKeywordsData *pkd;
670
671         pkd = g_object_get_data(G_OBJECT(bar), "pane_data");
672         if (!pkd) return;
673
674         gtk_widget_destroy(pkd->widget);
675 }
676
677 static void bar_pane_keywords_destroy(GtkWidget *widget, gpointer data)
678 {
679         PaneKeywordsData *pkd = data;
680
681         file_data_unregister_notify_func(bar_pane_keywords_notify_cb, pkd);
682
683         file_data_unref(pkd->fd);
684         g_free(pkd->key);
685
686         g_free(pkd);
687 }
688
689 static GtkTreeModel *create_marks_list(void)
690 {
691         GtkListStore *model;
692         GtkTreeIter iter;
693         gint i;
694
695         /* create list store */
696         model = gtk_list_store_new (1, G_TYPE_STRING);
697         for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
698                 {
699                 char str[10];
700                 sprintf(str, " %d ", i + 1);
701                 gtk_list_store_append (model, &iter);
702                 gtk_list_store_set(model, &iter, 0, str, -1);
703                 }
704         gtk_list_store_append (model, &iter);
705         gtk_list_store_set(model, &iter, 0, " ... ", -1);
706         return GTK_TREE_MODEL (model);
707 }
708
709 GtkWidget *bar_pane_keywords_new(const gchar *title, const gchar *key)
710 {
711         PaneKeywordsData *pkd;
712         GtkWidget *box;
713         GtkWidget *hbox;
714         GtkWidget *table;
715         GtkWidget *scrolled;
716         GtkTextBuffer *buffer;
717         GtkWidget *label;
718         GtkWidget *tbar;
719         GtkListStore *store;
720         GtkTreeViewColumn *column;
721         GtkCellRenderer *renderer;
722
723         pkd = g_new0(PaneKeywordsData, 1);
724
725         pkd->pane.pane_set_fd = bar_pane_keywords_set_fd;
726         pkd->pane.pane_event = bar_pane_keywords_event;
727         pkd->pane.title = g_strdup(title);
728
729         pkd->key = g_strdup(key);
730         
731
732         hbox = gtk_hbox_new(FALSE, PREF_PAD_GAP);
733
734         pkd->widget = hbox;
735         g_object_set_data(G_OBJECT(pkd->widget), "pane_data", pkd);
736         g_signal_connect(G_OBJECT(pkd->widget), "destroy",
737                          G_CALLBACK(bar_pane_keywords_destroy), pkd);
738         gtk_widget_show(hbox);
739
740         scrolled = gtk_scrolled_window_new(NULL, NULL);
741         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
742         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
743                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
744         gtk_box_pack_start(GTK_BOX(hbox), scrolled, TRUE, TRUE, 0);
745         gtk_widget_show(scrolled);
746
747         pkd->keyword_view = gtk_text_view_new();
748         gtk_container_add(GTK_CONTAINER(scrolled), pkd->keyword_view);
749         g_signal_connect(G_OBJECT(pkd->keyword_view), "populate-popup",
750                          G_CALLBACK(bar_pane_keywords_populate_popup_cb), pkd);
751         gtk_widget_show(pkd->keyword_view);
752
753         buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(pkd->keyword_view));
754         g_signal_connect(G_OBJECT(buffer), "changed",
755                          G_CALLBACK(bar_pane_keywords_changed), pkd);
756
757         scrolled = gtk_scrolled_window_new(NULL, NULL);
758         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
759         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
760                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
761         gtk_box_pack_start(GTK_BOX(hbox), scrolled, TRUE, TRUE, 0);
762         gtk_widget_show(scrolled);
763
764         store = gtk_list_store_new(3, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING);
765         pkd->keyword_treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
766         g_object_unref(store);
767         
768         gtk_widget_set_size_request(pkd->keyword_treeview, -1, 400);
769
770         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(pkd->keyword_treeview), FALSE);
771
772         gtk_tree_view_set_search_column(GTK_TREE_VIEW(pkd->keyword_treeview), KEYWORD_COLUMN_TEXT);
773
774         column = gtk_tree_view_column_new();
775         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
776
777         renderer = gtk_cell_renderer_toggle_new();
778         gtk_tree_view_column_pack_start(column, renderer, FALSE);
779         gtk_tree_view_column_add_attribute(column, renderer, "active", KEYWORD_COLUMN_TOGGLE);
780         g_signal_connect(G_OBJECT(renderer), "toggled",
781                          G_CALLBACK(bar_pane_keywords_keyword_toggle), pkd);
782
783         renderer = gtk_cell_renderer_text_new();
784         gtk_tree_view_column_pack_start(column, renderer, TRUE);
785         gtk_tree_view_column_add_attribute(column, renderer, "text", KEYWORD_COLUMN_TEXT);
786
787         gtk_tree_view_append_column(GTK_TREE_VIEW(pkd->keyword_treeview), column);
788
789         column = gtk_tree_view_column_new();
790         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
791
792         renderer = gtk_cell_renderer_combo_new();
793         g_object_set(G_OBJECT(renderer), "editable", (gboolean)TRUE,
794                                          "model", create_marks_list(),
795                                          "text-column", 0,
796                                          "has-entry", FALSE,
797                                          NULL);
798
799         gtk_tree_view_column_pack_start(column, renderer, TRUE);
800         gtk_tree_view_column_add_attribute(column, renderer, "text", KEYWORD_COLUMN_MARK);
801         g_signal_connect (renderer, "edited",
802                           G_CALLBACK (bar_pane_keywords_mark_edited), pkd);
803         gtk_tree_view_append_column(GTK_TREE_VIEW(pkd->keyword_treeview), column);
804
805
806         gtk_container_add(GTK_CONTAINER(scrolled), pkd->keyword_treeview);
807         gtk_widget_show(pkd->keyword_treeview);
808
809         file_data_register_notify_func(bar_pane_keywords_notify_cb, pkd, NOTIFY_PRIORITY_LOW);
810
811         return pkd->widget;
812 }
813 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */