2011-11-19 [mones] 3.7.10cvs93
[claws.git] / src / prefs_display_header.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2011 Hiroyuki Yamamoto and the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  * 
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include "defs.h"
25
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <gtk/gtk.h>
29 #include <gdk/gdkkeysyms.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34
35 #include "prefs_gtk.h"
36 #include "prefs_display_header.h"
37 #include "prefs_common.h"
38 #include "manage_window.h"
39 #include "alertpanel.h"
40 #include "displayheader.h"
41 #include "utils.h"
42 #include "gtkutils.h"
43
44 enum {
45         PREFS_HDR_HEADER,
46         PREFS_HDR_DATA,
47         N_PREFS_HDR_COLUMNS
48 };
49
50 static struct DisplayHeader {
51         GtkWidget *window;
52
53         GtkWidget *ok_btn;
54         GtkWidget *cancel_btn;
55
56         GtkWidget *hdr_combo;
57         GtkWidget *key_check;
58         GtkWidget *headers_list_view;
59         GtkWidget *hidden_headers_list_view;
60
61         GtkWidget *other_headers;
62 } dispheader;
63
64 /* widget creating functions */
65 static void prefs_display_header_create (void);
66
67 static void prefs_display_header_set_dialog     (void);
68 static void prefs_display_header_set_list       (void);
69 static void prefs_display_header_list_view_set_row      (gboolean hidden);
70
71 /* callback functions */
72 static void prefs_display_header_register_cb    (GtkButton      *btn,
73                                                  gpointer        hidden_data);
74 static void prefs_display_header_delete_cb      (GtkButton      *btn,
75                                                  gpointer        list_view_data);
76 static void prefs_display_header_up             (void);
77 static void prefs_display_header_down           (void);
78
79 static gboolean prefs_display_header_key_pressed        (GtkWidget      *widget,
80                                                          GdkEventKey    *event,
81                                                          gpointer        data);
82 static void prefs_display_header_ok             (void);
83 static void prefs_display_header_cancel         (void);
84 static gint prefs_display_header_deleted        (GtkWidget      *widget,
85                                                  GdkEventAny    *event,
86                                                  gpointer        data);
87
88
89 static GtkListStore *prefs_display_header_create_store  (void);
90 static void prefs_display_header_insert_header          (GtkListStore *store,
91                                                          gchar *name,
92                                                          DisplayHeaderProp *dp);
93 static GtkWidget *prefs_display_header_list_view_create (const gchar *name);
94 static void prefs_filtering_create_list_view_columns    (GtkWidget *list_view, 
95                                                          const gchar *name);
96 static void headers_list_model_rows_reordered           (GtkTreeModel *model,
97                                                          GtkTreePath  *path, 
98                                                          GtkTreeIter  *iter,
99                                                          gpointer      arg,
100                                                          GtkTreeView  *list_view);
101                                                          
102 static void drag_end    (GtkTreeView *list_view,
103                          GdkDragContext *context,
104                          gpointer data);
105
106 #ifndef GENERIC_UMPC
107 static gchar *defaults[] =
108 {
109         "From",
110         "To",
111         "Cc",
112         "Subject",
113         "Date", 
114         "Reply-To",
115         "Sender",
116         "User-Agent",
117         "X-Mailer",     
118         "Newsgroups",
119         "Followup-To",
120         "Organization",
121         "X-Newsreader",
122         "-Received",
123         "-Message-ID",
124         "-In-Reply-To",
125         "-References",
126         "-Mime-Version",
127         "-Content-Type",
128         "-Content-Transfer-Encoding",
129         "-X-UIDL",
130         "-Precedence",
131         "-Status",
132         "-Priority",
133         "-X-Face"
134 };
135 #else
136 static gchar *defaults[] =
137 {
138         "From",
139         "To",
140         "Cc",
141         "Subject",
142         "Date", 
143         "Newsgroups",
144         "Followup-To",
145         "-Reply-To",
146         "-Sender",
147         "-User-Agent",
148         "-X-Mailer",    
149         "-Organization",
150         "-X-Newsreader",
151         "-Received",
152         "-Message-ID",
153         "-In-Reply-To",
154         "-References",
155         "-Mime-Version",
156         "-Content-Type",
157         "-Content-Transfer-Encoding",
158         "-X-UIDL",
159         "-Precedence",
160         "-Status",
161         "-Priority",
162         "-X-Face"
163 };
164 #endif
165 static void prefs_display_header_set_default(void)
166 {
167         gint i;
168         DisplayHeaderProp *dp;
169
170         for(i = 0; i < sizeof(defaults) / sizeof(defaults[0]); i++) {
171                 dp = display_header_prop_read_str(defaults[i]);
172                 prefs_common.disphdr_list =
173                         g_slist_append(prefs_common.disphdr_list, dp);
174         }
175 }
176
177 void prefs_display_header_open(void)
178 {
179         if (prefs_rc_is_readonly(DISPLAY_HEADER_RC))
180                 return;
181
182         if (!dispheader.window) {
183                 prefs_display_header_create();
184         }
185
186         manage_window_set_transient(GTK_WINDOW(dispheader.window));
187         gtk_widget_grab_focus(dispheader.ok_btn);
188
189         prefs_display_header_set_dialog();
190
191         gtk_widget_show(dispheader.window);
192         gtk_window_set_modal(GTK_WINDOW(dispheader.window), TRUE);
193 }
194
195 static void prefs_display_header_create(void)
196 {
197         GtkWidget *window;
198         GtkWidget *vbox;
199         GtkWidget *btn_hbox;
200         GtkWidget *ok_btn;
201         GtkWidget *cancel_btn;
202         GtkWidget *confirm_area;
203
204         GtkWidget *vbox1;
205
206         GtkWidget *hbox1;
207         GtkWidget *hdr_label;
208         GtkWidget *hdr_combo;
209
210         GtkWidget *btn_vbox;
211         GtkWidget *reg_btn;
212         GtkWidget *del_btn;
213         GtkWidget *up_btn;
214         GtkWidget *down_btn;
215
216         GtkWidget *list_view_hbox;
217         GtkWidget *list_view_hbox1;
218         GtkWidget *list_view_hbox2;
219         GtkWidget *list_view_scrolledwin;
220         GtkWidget *headers_list_view;
221         GtkWidget *hidden_headers_list_view;
222
223         GtkWidget *checkbtn_other_headers;
224         gint i;
225         
226         debug_print("Creating display header setting window...\n");
227
228         window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "prefs_display_header");
229         gtk_container_set_border_width (GTK_CONTAINER (window), 8);
230         gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
231         gtk_window_set_resizable(GTK_WINDOW (window), TRUE);
232
233         vbox = gtk_vbox_new (FALSE, 6);
234         gtk_widget_show (vbox);
235         gtk_container_add (GTK_CONTAINER (window), vbox);
236
237         btn_hbox = gtk_hbox_new (FALSE, 8);
238         gtk_widget_show (btn_hbox);
239         gtk_box_pack_end (GTK_BOX (vbox), btn_hbox, FALSE, FALSE, 0);
240
241         gtkut_stock_button_set_create(&confirm_area, &cancel_btn, GTK_STOCK_CANCEL,
242                                       &ok_btn, GTK_STOCK_OK,
243                                       NULL, NULL);
244         gtk_widget_show (confirm_area);
245         gtk_box_pack_end (GTK_BOX(btn_hbox), confirm_area, FALSE, FALSE, 0);
246         gtk_widget_grab_default (ok_btn);
247
248         gtk_window_set_title (GTK_WINDOW(window),
249                               _("Displayed header configuration"));
250         MANAGE_WINDOW_SIGNALS_CONNECT(window);
251         g_signal_connect (G_OBJECT(window), "delete_event",
252                           G_CALLBACK(prefs_display_header_deleted),
253                           NULL);
254         g_signal_connect (G_OBJECT(window), "key_press_event",
255                           G_CALLBACK(prefs_display_header_key_pressed),
256                           NULL);
257         g_signal_connect (G_OBJECT(ok_btn), "clicked",
258                           G_CALLBACK(prefs_display_header_ok),
259                           NULL);
260         g_signal_connect (G_OBJECT(cancel_btn), "clicked",
261                           G_CALLBACK(prefs_display_header_cancel),
262                           NULL);
263
264         vbox1 = gtk_vbox_new (FALSE, VSPACING);
265         gtk_widget_show (vbox1);
266         gtk_box_pack_start (GTK_BOX (vbox), vbox1, TRUE, TRUE, 0);
267         gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2);
268
269         hbox1 = gtk_hbox_new (FALSE, 8);
270         gtk_widget_show (hbox1);
271         gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, TRUE, 0);
272
273         hdr_label = gtk_label_new (_("Header name"));
274         gtk_widget_show (hdr_label);
275         gtk_box_pack_start (GTK_BOX (hbox1), hdr_label, FALSE, FALSE, 0);
276
277         hdr_combo = gtk_combo_box_entry_new_text();
278         for(i=0; i < 9 ; i++)
279                 gtk_combo_box_append_text(GTK_COMBO_BOX (hdr_combo),
280                         (*defaults[i] == '-') ? defaults[i]+1 : defaults[i]);
281         gtk_combo_box_set_active(GTK_COMBO_BOX(hdr_combo), 0);
282         gtk_widget_show (hdr_combo);
283         gtk_box_pack_start (GTK_BOX (hbox1), hdr_combo, TRUE, TRUE, 0);
284         gtk_widget_set_size_request (hdr_combo, 150, -1);
285
286         list_view_hbox = gtk_hbox_new (FALSE, 10);
287         gtk_widget_show (list_view_hbox);
288         gtk_box_pack_start (GTK_BOX (vbox1), list_view_hbox, TRUE, TRUE, 0);
289
290         /* display headers list */
291
292         list_view_hbox1 = gtk_hbox_new (FALSE, 8);
293         gtk_widget_show (list_view_hbox1);
294         gtk_box_pack_start (GTK_BOX (list_view_hbox), list_view_hbox1, TRUE, TRUE, 0);
295
296         list_view_scrolledwin = gtk_scrolled_window_new (NULL, NULL);
297         gtk_widget_set_size_request (list_view_scrolledwin, 200, 210);
298         gtk_widget_show (list_view_scrolledwin);
299         gtk_box_pack_start (GTK_BOX (list_view_hbox1), list_view_scrolledwin,
300                             TRUE, TRUE, 0);
301         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (list_view_scrolledwin),
302                                         GTK_POLICY_AUTOMATIC,
303                                         GTK_POLICY_AUTOMATIC);
304         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(list_view_scrolledwin),
305                                             GTK_SHADOW_IN);
306
307         headers_list_view = prefs_display_header_list_view_create
308                                 (_("Displayed Headers"));
309         gtk_widget_show (headers_list_view);
310         gtk_container_add(GTK_CONTAINER(list_view_scrolledwin), headers_list_view);
311         gtk_tree_view_set_reorderable(GTK_TREE_VIEW(headers_list_view), TRUE);
312
313         g_signal_connect(G_OBJECT(headers_list_view), "drag_end",                        
314                          G_CALLBACK(drag_end),
315                          headers_list_view);
316         
317         /* connect rows change for this list view's model */
318         g_signal_connect(G_OBJECT(gtk_tree_view_get_model(GTK_TREE_VIEW(headers_list_view))),
319                          "rows-reordered", 
320                          G_CALLBACK(headers_list_model_rows_reordered),
321                          headers_list_view);
322
323         btn_vbox = gtk_vbox_new (FALSE, 8);
324         gtk_widget_show (btn_vbox);
325         gtk_box_pack_start (GTK_BOX (list_view_hbox1), btn_vbox, FALSE, FALSE, 0);
326
327         reg_btn = gtk_button_new_from_stock (GTK_STOCK_ADD);
328         gtk_widget_show (reg_btn);
329         gtk_box_pack_start (GTK_BOX (btn_vbox), reg_btn, FALSE, TRUE, 0);
330         g_signal_connect (G_OBJECT (reg_btn), "clicked",
331                           G_CALLBACK (prefs_display_header_register_cb),
332                             GINT_TO_POINTER(FALSE));
333         del_btn = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
334         gtk_widget_show (del_btn);
335         gtk_box_pack_start (GTK_BOX (btn_vbox), del_btn, FALSE, TRUE, 0);
336         g_signal_connect (G_OBJECT (del_btn), "clicked",
337                           G_CALLBACK (prefs_display_header_delete_cb),
338                           headers_list_view);
339
340         up_btn = gtk_button_new_from_stock (GTK_STOCK_GO_UP);
341         gtk_widget_show (up_btn);
342         gtk_box_pack_start (GTK_BOX (btn_vbox), up_btn, FALSE, FALSE, 0);
343         g_signal_connect (G_OBJECT (up_btn), "clicked",
344                           G_CALLBACK (prefs_display_header_up), NULL);
345
346         down_btn = gtk_button_new_from_stock (GTK_STOCK_GO_DOWN);
347         gtk_widget_show (down_btn);
348         gtk_box_pack_start (GTK_BOX (btn_vbox), down_btn, FALSE, FALSE, 0);
349         g_signal_connect (G_OBJECT (down_btn), "clicked",
350                           G_CALLBACK (prefs_display_header_down), NULL);
351
352         /* hidden headers list */
353
354         list_view_hbox2 = gtk_hbox_new (FALSE, 8);
355         gtk_widget_show (list_view_hbox2);
356         gtk_box_pack_start (GTK_BOX (list_view_hbox), list_view_hbox2, TRUE, TRUE, 0);
357
358         list_view_scrolledwin = gtk_scrolled_window_new (NULL, NULL);
359         gtk_widget_set_size_request (list_view_scrolledwin, 200, 210);
360         gtk_widget_show (list_view_scrolledwin);
361         gtk_box_pack_start (GTK_BOX (list_view_hbox2), list_view_scrolledwin,
362                             TRUE, TRUE, 0);
363         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (list_view_scrolledwin),
364                                         GTK_POLICY_AUTOMATIC,
365                                         GTK_POLICY_AUTOMATIC);
366         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(list_view_scrolledwin),
367                                             GTK_SHADOW_IN);
368
369         hidden_headers_list_view = prefs_display_header_list_view_create
370                                         (_("Hidden headers"));
371         gtk_widget_show (hidden_headers_list_view);
372         gtk_container_add (GTK_CONTAINER (list_view_scrolledwin),
373                            hidden_headers_list_view);
374
375         btn_vbox = gtk_vbox_new (FALSE, 8);
376         gtk_widget_show (btn_vbox);
377         gtk_box_pack_start (GTK_BOX (list_view_hbox2), btn_vbox, FALSE, FALSE, 0);
378
379         reg_btn = gtk_button_new_from_stock (GTK_STOCK_ADD);
380         gtk_widget_show (reg_btn);
381         gtk_box_pack_start (GTK_BOX (btn_vbox), reg_btn, FALSE, TRUE, 0);
382         g_signal_connect (G_OBJECT (reg_btn), "clicked",
383                             G_CALLBACK
384                             (prefs_display_header_register_cb),
385                             GINT_TO_POINTER(TRUE));
386         del_btn = gtk_button_new_from_stock (GTK_STOCK_DELETE);
387         gtk_widget_show (del_btn);
388         gtk_box_pack_start (GTK_BOX (btn_vbox), del_btn, FALSE, TRUE, 0);
389         g_signal_connect (G_OBJECT       (del_btn), "clicked",
390                             G_CALLBACK (prefs_display_header_delete_cb),
391                             hidden_headers_list_view);
392
393         
394
395         PACK_CHECK_BUTTON (vbox, checkbtn_other_headers,
396                            _("Show all unspecified headers"));
397         SET_TOGGLE_SENSITIVITY (checkbtn_other_headers, list_view_hbox2);
398
399         gtk_widget_show_all(window);
400
401         dispheader.window        = window;
402         dispheader.ok_btn        = ok_btn;
403         dispheader.cancel_btn    = cancel_btn;
404
405         dispheader.hdr_combo     = hdr_combo;
406
407         dispheader.headers_list_view        = headers_list_view;
408         dispheader.hidden_headers_list_view = hidden_headers_list_view;
409
410         dispheader.other_headers = checkbtn_other_headers;
411 }
412
413 void prefs_display_header_read_config(void)
414 {
415         gchar *rcpath;
416         FILE *fp;
417         gchar buf[PREFSBUFSIZE];
418         DisplayHeaderProp *dp;
419
420         debug_print("Reading configuration for displaying headers...\n");
421
422         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
423                              DISPLAY_HEADER_RC, NULL);
424         if ((fp = g_fopen(rcpath, "rb")) == NULL) {
425                 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
426                 g_free(rcpath);
427                 prefs_common.disphdr_list = NULL;
428                 prefs_display_header_set_default();
429                 return;
430         }
431         g_free(rcpath);
432
433         /* remove all previous headers list */
434         while (prefs_common.disphdr_list != NULL) {
435                 dp = (DisplayHeaderProp *)prefs_common.disphdr_list->data;
436                 display_header_prop_free(dp);
437                 prefs_common.disphdr_list =
438                         g_slist_remove(prefs_common.disphdr_list, dp);
439         }
440
441         while (fgets(buf, sizeof(buf), fp) != NULL) {
442                 g_strdelimit(buf, "\r\n", '\0');
443                 dp = display_header_prop_read_str(buf);
444                 if (dp)
445                         prefs_common.disphdr_list =
446                                 g_slist_append(prefs_common.disphdr_list, dp);
447         }
448
449         fclose(fp);
450 }
451
452 static void prefs_display_header_write_config(void)
453 {
454         gchar *rcpath;
455         PrefFile *pfile;
456         GSList *cur;
457
458         debug_print("Writing configuration for displaying headers...\n");
459
460         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
461                              DISPLAY_HEADER_RC, NULL);
462
463         if ((pfile = prefs_write_open(rcpath)) == NULL) {
464                 g_warning("failed to write configuration to file\n");
465                 g_free(rcpath);
466                 return;
467         }
468
469         for (cur = prefs_common.disphdr_list; cur != NULL;
470              cur = cur->next) {
471                 DisplayHeaderProp *dp = (DisplayHeaderProp *)cur->data;
472                 gchar *dpstr;
473
474                 dpstr = display_header_prop_get_str(dp);
475                 if (fputs(dpstr, pfile->fp) == EOF ||
476                     fputc('\n', pfile->fp) == EOF) {
477                         FILE_OP_ERROR(rcpath, "fputs || fputc");
478                         prefs_file_close_revert(pfile);
479                         g_free(rcpath);
480                         g_free(dpstr);
481                         return;
482                 }
483                 g_free(dpstr);
484         }
485
486         g_free(rcpath);
487
488         if (prefs_file_close(pfile) < 0) {
489                 g_warning("failed to write configuration to file\n");
490                 return;
491         }
492 }
493
494 static void prefs_display_header_set_dialog(void)
495 {
496         GtkTreeView *list_view = GTK_TREE_VIEW(dispheader.headers_list_view);
497         GtkTreeView *hidden_list_view = GTK_TREE_VIEW(dispheader.hidden_headers_list_view);
498         GSList *cur;
499         GtkTreeModel *model_list, *model_hidden;
500
501         model_list = gtk_tree_view_get_model(list_view);
502         model_hidden = gtk_tree_view_get_model(hidden_list_view);
503
504         gtk_list_store_clear(GTK_LIST_STORE(model_list));
505         gtk_list_store_clear(GTK_LIST_STORE(model_hidden));
506
507         for (cur = prefs_common.disphdr_list; cur != NULL;
508              cur = cur->next) {
509                 DisplayHeaderProp *dp = (DisplayHeaderProp *)cur->data;
510
511                 if (dp->hidden)
512                         prefs_display_header_insert_header(GTK_LIST_STORE
513                                                 (model_hidden), dp->name, dp);  
514                 else
515                         prefs_display_header_insert_header(GTK_LIST_STORE
516                                                 (model_list), dp->name, dp);
517         }
518
519         gtk_toggle_button_set_active
520                 (GTK_TOGGLE_BUTTON(dispheader.other_headers),
521                  prefs_common.show_other_header);
522 }
523
524 static void prefs_display_header_set_list(void)
525 {
526         gint row = 0;
527         DisplayHeaderProp *dp;
528         GtkTreeModel *model;
529         GtkTreeIter iter;
530
531         g_slist_free(prefs_common.disphdr_list);
532         prefs_common.disphdr_list = NULL;
533
534         model = gtk_tree_view_get_model(GTK_TREE_VIEW(dispheader.headers_list_view));
535         while (gtk_tree_model_iter_nth_child(model, &iter, NULL, row)) {
536                 gtk_tree_model_get(model, &iter, PREFS_HDR_DATA, &dp, -1);
537                 if (dp)
538                         prefs_common.disphdr_list =
539                                 g_slist_append(prefs_common.disphdr_list, dp);
540                 row++;                          
541         }
542
543         model = gtk_tree_view_get_model
544                         (GTK_TREE_VIEW(dispheader.hidden_headers_list_view));
545         row = 0;
546         while (gtk_tree_model_iter_nth_child(model, &iter, NULL, row)) {
547                 gtk_tree_model_get(model, &iter, PREFS_HDR_DATA, &dp, -1);
548                 if (dp) 
549                         prefs_common.disphdr_list =
550                                 g_slist_append(prefs_common.disphdr_list, dp);
551                 row++;
552         }
553 }
554
555 static gint prefs_display_header_find_header(GtkTreeView *list_view,
556                                              const gchar *header)
557 {
558         gint row = 0;
559         DisplayHeaderProp *dp;
560         GtkTreeModel *model;
561         GtkTreeIter iter;
562
563         model = gtk_tree_view_get_model(list_view);
564         while (gtk_tree_model_iter_nth_child(model, &iter, NULL, row)) {
565                 gtk_tree_model_get(model, &iter, PREFS_HDR_DATA, &dp, -1);
566                 if (dp && g_ascii_strcasecmp(dp->name, header) == 0)
567                         return row;
568                 row++;
569         }
570
571         return -1;
572 }
573
574 static void prefs_display_header_list_view_set_row(gboolean hidden)
575 {
576         GtkTreeView *list_view;
577         DisplayHeaderProp *dp;
578         gchar *entry_text;
579         GtkTreeModel *model;
580
581         entry_text = gtk_combo_box_get_active_text(GTK_COMBO_BOX(dispheader.hdr_combo));
582         if (!entry_text)
583                 entry_text = gtk_editable_get_chars(
584                                 GTK_EDITABLE(gtk_bin_get_child(GTK_BIN(dispheader.hdr_combo))),0,-1);
585         if (!entry_text || entry_text[0] == '\0') {
586                 alertpanel_error(_("Header name is not set."));
587                 return;
588         }
589
590         if (hidden)
591                 list_view = GTK_TREE_VIEW(dispheader.hidden_headers_list_view);
592         else
593                 list_view = GTK_TREE_VIEW(dispheader.headers_list_view);
594
595         if (prefs_display_header_find_header(list_view, entry_text) != -1) {
596                 alertpanel_error(_("This header is already in the list."));
597                 return;
598         }
599
600         dp = g_new0(DisplayHeaderProp, 1);
601
602         dp->name = g_strdup(entry_text);
603         dp->hidden = hidden;
604
605         model = gtk_tree_view_get_model(list_view);
606         prefs_display_header_insert_header(GTK_LIST_STORE(model),
607                                            dp->name, dp);
608
609         prefs_display_header_set_list();
610         
611         g_free(entry_text);
612 }
613
614 static void prefs_display_header_register_cb(GtkButton *btn,
615                                              gpointer hidden_data)
616 {
617         prefs_display_header_list_view_set_row(GPOINTER_TO_INT(hidden_data));
618 }
619
620 static void prefs_display_header_delete_cb(GtkButton *btn, gpointer list_view_data)
621 {
622         GtkTreeView *list_view = GTK_TREE_VIEW(list_view_data);
623         DisplayHeaderProp *dp;
624         GtkListStore *store = GTK_LIST_STORE(gtk_tree_view_get_model(list_view));
625         GtkTreeSelection *selection = gtk_tree_view_get_selection(list_view);
626         GtkTreeIter iter;
627
628         if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
629                 return;
630
631         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, PREFS_HDR_DATA, &dp, -1);
632         if (!dp) 
633                 return;
634
635         prefs_common.disphdr_list =
636                 g_slist_remove(prefs_common.disphdr_list, dp);
637         display_header_prop_free(dp);
638         gtk_list_store_remove(store, &iter);
639 }
640
641 static void prefs_display_header_up(void)
642 {
643         GtkTreePath *prev, *sel, *try;
644         GtkTreeIter isel;
645         GtkListStore *store = NULL;
646         GtkTreeModel *model = NULL;
647         GtkTreeIter iprev;
648         
649         if (!gtk_tree_selection_get_selected
650                 (gtk_tree_view_get_selection
651                         (GTK_TREE_VIEW(dispheader.headers_list_view)),
652                  &model,        
653                  &isel))
654                 return;
655         store = (GtkListStore *)model;
656         sel = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &isel);
657         if (!sel)
658                 return;
659         
660         /* no move if we're at row 0... */
661         try = gtk_tree_path_copy(sel);
662         if (!gtk_tree_path_prev(try)) {
663                 gtk_tree_path_free(try);
664                 gtk_tree_path_free(sel);
665                 return;
666         }
667
668         prev = try;
669         gtk_tree_model_get_iter(GTK_TREE_MODEL(store),
670                                 &iprev, prev);
671         gtk_list_store_swap(store, &iprev, &isel);
672
673         gtk_tree_path_free(sel);
674         gtk_tree_path_free(prev);
675 }
676
677 static void prefs_display_header_down(void)
678 {
679         GtkListStore *store = NULL;
680         GtkTreeModel *model = NULL;
681         GtkTreeIter next, sel;
682         GtkTreePath *try;
683         
684         if (!gtk_tree_selection_get_selected
685                 (gtk_tree_view_get_selection
686                         (GTK_TREE_VIEW(dispheader.headers_list_view)),
687                  &model,
688                  &sel))
689                 return;
690         store = (GtkListStore *)model;
691         try = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &sel);
692         if (!try) 
693                 return;
694         
695         next = sel;
696         if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &next))
697                 gtk_list_store_swap(store, &next, &sel);
698                 
699         gtk_tree_path_free(try);
700 }
701
702 static gboolean prefs_display_header_key_pressed(GtkWidget *widget,
703                                              GdkEventKey *event,
704                                              gpointer data)
705 {
706         if (event && event->keyval == GDK_KEY_Escape)
707                 prefs_display_header_cancel();
708         return FALSE;
709 }
710
711 static void prefs_display_header_ok(void)
712 {
713         prefs_common.show_other_header =
714                 gtk_toggle_button_get_active
715                         (GTK_TOGGLE_BUTTON(dispheader.other_headers));
716         prefs_display_header_write_config();
717         gtk_widget_hide(dispheader.window);
718         gtk_window_set_modal(GTK_WINDOW(dispheader.window), FALSE);
719 }
720
721 static void prefs_display_header_cancel(void)
722 {
723         prefs_display_header_read_config();
724         gtk_widget_hide(dispheader.window);
725         gtk_window_set_modal(GTK_WINDOW(dispheader.window), FALSE);
726 }
727
728 static gint prefs_display_header_deleted(GtkWidget *widget, GdkEventAny *event,
729                                          gpointer data)
730 {
731         prefs_display_header_cancel();
732         return TRUE;
733 }
734
735 static GtkListStore *prefs_display_header_create_store(void)
736 {
737         return gtk_list_store_new(N_PREFS_HDR_COLUMNS,
738                                   G_TYPE_STRING,
739                                   G_TYPE_POINTER,
740                                   -1);
741 }
742
743 static void prefs_display_header_insert_header(GtkListStore *store,
744                                                gchar *name,
745                                                DisplayHeaderProp *dp)
746 {
747         GtkTreeIter iter;
748
749         /* add new */
750         gtk_list_store_append(store, &iter);
751         gtk_list_store_set(store, &iter,
752                            PREFS_HDR_HEADER,
753                            name,
754                            PREFS_HDR_DATA, dp,
755                            -1);
756 }
757
758 static GtkWidget *prefs_display_header_list_view_create(const gchar *name)
759 {
760         GtkWidget *list_view;
761         GtkTreeSelection *selector;
762         GtkTreeModel *model;
763
764         model = GTK_TREE_MODEL(prefs_display_header_create_store());
765         list_view = gtk_tree_view_new_with_model(model);
766         g_object_unref(G_OBJECT(model));
767         
768         gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(list_view),
769                                      prefs_common.use_stripes_everywhere);
770         
771         selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
772         gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
773
774         prefs_filtering_create_list_view_columns(GTK_WIDGET(list_view), name);
775
776         return list_view;
777 }
778
779 static void prefs_filtering_create_list_view_columns(GtkWidget *list_view, 
780                                                      const gchar *name)
781 {
782         GtkTreeViewColumn *column;
783         GtkCellRenderer *renderer;
784
785         renderer = gtk_cell_renderer_text_new();
786         column = gtk_tree_view_column_new_with_attributes
787                 (name, renderer, "text", PREFS_HDR_HEADER, NULL);
788         gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);          
789 }
790
791 /*!
792  *\brief        Called as a result of a gtk_list_store_swap()
793  */
794 static void headers_list_model_rows_reordered(GtkTreeModel *model,
795                                               GtkTreePath  *path, 
796                                               GtkTreeIter  *iter,
797                                               gpointer      arg,
798                                               GtkTreeView  *list_view)
799 {
800         prefs_display_header_set_list();
801 }
802
803 /*!
804  *\brief        Called as a result of a drag & drop
805  */
806 static void drag_end(GtkTreeView *list_view,
807                     GdkDragContext *context,
808                     gpointer data)
809 {
810         prefs_display_header_set_list();
811 }
812