talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

prefs_display_header.c (21809B)


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