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