prefs_customheader.c (20901B)
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 "main.h" 31 #include "prefs_gtk.h" 32 #include "prefs_customheader.h" 33 #include "prefs_account.h" 34 #include "mainwindow.h" 35 #include "foldersel.h" 36 #include "manage_window.h" 37 #include "customheader.h" 38 #include "folder.h" 39 #include "utils.h" 40 #include "gtkutils.h" 41 #include "alertpanel.h" 42 #include "filesel.h" 43 #include "combobox.h" 44 #include "file-utils.h" 45 46 #define CUSTOM_HEADER_RC "customheaderrc" 47 48 enum { 49 CUSTHDR_STRING, /*!< display string managed by list store */ 50 CUSTHDR_DATA, /*!< string managed by us */ 51 N_CUSTHDR_COLUMNS 52 }; 53 54 static struct CustomHdr { 55 GtkWidget *window; 56 57 GtkWidget *ok_btn; 58 GtkWidget *cancel_btn; 59 60 GtkWidget *hdr_combo; 61 GtkWidget *hdr_entry; 62 GtkWidget *val_entry; 63 GtkWidget *preview; 64 GtkWidget *list_view; 65 } customhdr; 66 67 /* widget creating functions */ 68 static void prefs_custom_header_create (void); 69 70 static void prefs_custom_header_set_dialog (PrefsAccount *ac); 71 static void prefs_custom_header_set_list (PrefsAccount *ac); 72 static void prefs_custom_header_list_view_set_row (PrefsAccount *ac); 73 74 /* callback functions */ 75 static void prefs_custom_header_add_cb (void); 76 static void prefs_custom_header_val_from_file_cb(void); 77 static void prefs_custom_header_delete_cb (void); 78 static void prefs_custom_header_up (void); 79 static void prefs_custom_header_down (void); 80 81 static void prefs_custom_header_ok (void); 82 static void prefs_custom_header_cancel (void); 83 static gint prefs_custom_header_deleted (GtkWidget *widget, 84 GdkEventAny *event, 85 gpointer data); 86 87 static GtkListStore* prefs_custom_header_create_data_store (void); 88 89 static void prefs_custom_header_list_view_insert_header (GtkWidget *list_view, 90 GtkTreeIter *row_iter, 91 gchar *header, 92 gpointer data); 93 94 static GtkWidget *prefs_custom_header_list_view_create (void); 95 96 static void prefs_custom_header_create_list_view_columns (GtkWidget *list_view); 97 98 static gboolean prefs_custom_header_selected (GtkTreeSelection *selector, 99 GtkTreeModel *model, 100 GtkTreePath *path, 101 gboolean currently_selected, 102 gpointer data); 103 104 105 static PrefsAccount *cur_ac = NULL; 106 107 void prefs_custom_header_open(PrefsAccount *ac) 108 { 109 if (!customhdr.window) { 110 prefs_custom_header_create(); 111 } 112 113 manage_window_set_transient(GTK_WINDOW(customhdr.window)); 114 gtk_widget_grab_focus(customhdr.ok_btn); 115 116 prefs_custom_header_set_dialog(ac); 117 118 cur_ac = ac; 119 120 gtk_widget_show(customhdr.window); 121 gtk_window_set_modal(GTK_WINDOW(customhdr.window), TRUE); 122 } 123 124 static void prefs_custom_header_create(void) 125 { 126 GtkWidget *window; 127 GtkWidget *vbox; 128 129 GtkWidget *ok_btn; 130 GtkWidget *cancel_btn; 131 132 GtkWidget *confirm_area; 133 134 GtkWidget *vbox1; 135 136 GtkWidget *table1; 137 GtkWidget *hdr_label; 138 GtkWidget *hdr_combo; 139 GtkWidget *val_label; 140 GtkWidget *val_entry; 141 GtkWidget *val_btn; 142 143 GtkWidget *reg_hbox; 144 GtkWidget *btn_hbox; 145 GtkWidget *arrow; 146 GtkWidget *add_btn; 147 GtkWidget *del_btn; 148 GtkWidget *preview; 149 150 GtkWidget *ch_hbox; 151 GtkWidget *ch_scrolledwin; 152 GtkWidget *list_view; 153 154 GtkWidget *btn_vbox; 155 GtkWidget *up_btn; 156 GtkWidget *down_btn; 157 158 debug_print("Creating custom header setting window...\n"); 159 160 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "prefs_customheader"); 161 gtk_container_set_border_width (GTK_CONTAINER (window), 8); 162 gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER); 163 gtk_window_set_resizable(GTK_WINDOW (window), TRUE); 164 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG); 165 166 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); 167 gtk_widget_show (vbox); 168 gtk_container_add (GTK_CONTAINER (window), vbox); 169 170 gtkut_stock_button_set_create(&confirm_area, &cancel_btn, NULL, _("_Cancel"), 171 &ok_btn, NULL, _("_OK"), NULL, NULL, NULL); 172 gtk_widget_show (confirm_area); 173 gtk_box_pack_end (GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0); 174 gtk_widget_grab_default (ok_btn); 175 176 gtk_window_set_title (GTK_WINDOW(window), _("Custom header configuration")); 177 MANAGE_WINDOW_SIGNALS_CONNECT (window); 178 g_signal_connect (G_OBJECT(window), "delete_event", 179 G_CALLBACK(prefs_custom_header_deleted), 180 NULL); 181 g_signal_connect (G_OBJECT(ok_btn), "clicked", 182 G_CALLBACK(prefs_custom_header_ok), NULL); 183 g_signal_connect (G_OBJECT(cancel_btn), "clicked", 184 G_CALLBACK(prefs_custom_header_cancel), NULL); 185 186 vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, VSPACING); 187 gtk_widget_show (vbox1); 188 gtk_box_pack_start (GTK_BOX (vbox), vbox1, TRUE, TRUE, 0); 189 gtk_container_set_border_width (GTK_CONTAINER (vbox1), 2); 190 191 table1 = gtk_grid_new(); 192 gtk_widget_show (table1); 193 gtk_box_pack_start (GTK_BOX (vbox1), table1, 194 FALSE, FALSE, 0); 195 gtk_grid_set_row_spacing(GTK_GRID(table1), 8); 196 gtk_grid_set_column_spacing(GTK_GRID(table1), 8); 197 198 hdr_label = gtk_label_new (_("Header")); 199 gtk_widget_show (hdr_label); 200 gtk_label_set_xalign(GTK_LABEL (hdr_label), 0.0); 201 gtk_grid_attach(GTK_GRID(table1), hdr_label, 0, 0, 1, 1); 202 203 hdr_combo = combobox_text_new(TRUE, "User-Agent", "Face", "X-Face", 204 "X-Operating-System", NULL); 205 gtk_grid_attach(GTK_GRID(table1), hdr_combo, 0, 1, 1, 1); 206 207 val_label = gtk_label_new (_("Value")); 208 gtk_widget_show (val_label); 209 gtk_label_set_xalign(GTK_LABEL (val_label), 0.0); 210 gtk_grid_attach(GTK_GRID(table1), val_label, 1, 0, 1, 1); 211 212 val_entry = gtk_entry_new (); 213 gtk_widget_show (val_entry); 214 gtk_grid_attach(GTK_GRID(table1), val_entry, 1, 1, 1, 1); 215 gtk_widget_set_hexpand(val_entry, TRUE); 216 gtk_widget_set_halign(val_entry, GTK_ALIGN_FILL); 217 218 val_btn = gtkut_get_browse_file_btn(_("Bro_wse")); 219 gtk_widget_show (val_btn); 220 gtk_grid_attach(GTK_GRID(table1), val_btn, 2, 1, 1, 1); 221 g_signal_connect (G_OBJECT (val_btn), "clicked", 222 G_CALLBACK (prefs_custom_header_val_from_file_cb), 223 NULL); 224 225 /* add / delete */ 226 227 reg_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); 228 gtk_widget_show (reg_hbox); 229 gtk_box_pack_start (GTK_BOX (vbox1), reg_hbox, FALSE, FALSE, 0); 230 231 arrow = gtk_image_new_from_icon_name("pan-down-symbolic", GTK_ICON_SIZE_MENU); 232 gtk_widget_show (arrow); 233 gtk_box_pack_start (GTK_BOX (reg_hbox), arrow, FALSE, FALSE, 0); 234 235 btn_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); 236 gtk_widget_show (btn_hbox); 237 gtk_box_pack_start (GTK_BOX (reg_hbox), btn_hbox, FALSE, FALSE, 0); 238 239 add_btn = gtkut_stock_button("list-add", _("_Add")); 240 gtk_widget_show (add_btn); 241 gtk_box_pack_start (GTK_BOX (btn_hbox), add_btn, FALSE, TRUE, 0); 242 g_signal_connect (G_OBJECT (add_btn), "clicked", 243 G_CALLBACK (prefs_custom_header_add_cb), 244 NULL); 245 246 del_btn = gtkut_stock_button("edit-delete", _("D_elete")); 247 gtk_widget_show (del_btn); 248 gtk_box_pack_start (GTK_BOX (btn_hbox), del_btn, FALSE, TRUE, 0); 249 g_signal_connect (G_OBJECT (del_btn), "clicked", 250 G_CALLBACK (prefs_custom_header_delete_cb), 251 NULL); 252 253 254 ch_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); 255 gtk_widget_show (ch_hbox); 256 gtk_box_pack_start (GTK_BOX (vbox1), ch_hbox, TRUE, TRUE, 0); 257 258 ch_scrolledwin = gtk_scrolled_window_new (NULL, NULL); 259 gtk_widget_show (ch_scrolledwin); 260 gtk_box_pack_start (GTK_BOX (ch_hbox), ch_scrolledwin, TRUE, TRUE, 0); 261 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (ch_scrolledwin), 262 GTK_POLICY_AUTOMATIC, 263 GTK_POLICY_AUTOMATIC); 264 265 list_view = prefs_custom_header_list_view_create(); 266 gtk_widget_show (list_view); 267 gtk_container_add (GTK_CONTAINER (ch_scrolledwin), list_view); 268 269 btn_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); 270 gtk_widget_show (btn_vbox); 271 gtk_box_pack_start (GTK_BOX (ch_hbox), btn_vbox, FALSE, FALSE, 0); 272 273 up_btn = gtkut_stock_button("go-up", _("_Up")); 274 gtk_widget_show (up_btn); 275 gtk_box_pack_start (GTK_BOX (btn_vbox), up_btn, FALSE, FALSE, 0); 276 g_signal_connect (G_OBJECT (up_btn), "clicked", 277 G_CALLBACK (prefs_custom_header_up), NULL); 278 279 down_btn = gtkut_stock_button("go-down", _("_Down")); 280 gtk_widget_show (down_btn); 281 gtk_box_pack_start (GTK_BOX (btn_vbox), down_btn, FALSE, FALSE, 0); 282 g_signal_connect (G_OBJECT (down_btn), "clicked", 283 G_CALLBACK (prefs_custom_header_down), NULL); 284 285 preview = gtk_image_new (); 286 gtk_widget_show (preview); 287 gtk_box_pack_start (GTK_BOX (btn_vbox), preview, FALSE, FALSE, 0); 288 289 gtk_widget_show_all(window); 290 291 customhdr.window = window; 292 customhdr.ok_btn = ok_btn; 293 customhdr.cancel_btn = cancel_btn; 294 customhdr.preview = preview; 295 296 customhdr.hdr_combo = hdr_combo; 297 customhdr.hdr_entry = gtk_bin_get_child(GTK_BIN((hdr_combo))); 298 customhdr.val_entry = val_entry; 299 300 customhdr.list_view = list_view; 301 } 302 303 void prefs_custom_header_read_config(PrefsAccount *ac) 304 { 305 gchar *rcpath; 306 FILE *fp; 307 gchar buf[PREFSBUFSIZE]; 308 CustomHeader *ch; 309 310 debug_print("Reading custom header configuration...\n"); 311 312 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, 313 CUSTOM_HEADER_RC, NULL); 314 if ((fp = g_fopen(rcpath, "rb")) == NULL) { 315 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "g_fopen"); 316 g_free(rcpath); 317 ac->customhdr_list = NULL; 318 return; 319 } 320 g_free(rcpath); 321 322 /* remove all previous headers list */ 323 while (ac->customhdr_list != NULL) { 324 ch = (CustomHeader *)ac->customhdr_list->data; 325 ac->customhdr_list = g_slist_remove(ac->customhdr_list, ch); 326 custom_header_free(ch); 327 } 328 329 while (fgets(buf, sizeof(buf), fp) != NULL) { 330 ch = custom_header_read_str(buf); 331 if (ch) { 332 if (ch->account_id == ac->account_id) { 333 ac->customhdr_list = 334 g_slist_append(ac->customhdr_list, ch); 335 } else 336 custom_header_free(ch); 337 } 338 } 339 340 fclose(fp); 341 } 342 343 static void prefs_custom_header_write_config(PrefsAccount *ac) 344 { 345 gchar *rcpath; 346 PrefFile *pfile; 347 GSList *cur; 348 gchar buf[PREFSBUFSIZE]; 349 FILE * fp; 350 CustomHeader *ch; 351 352 GSList *all_hdrs = NULL; 353 354 debug_print("Writing custom header configuration...\n"); 355 356 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, 357 CUSTOM_HEADER_RC, NULL); 358 359 if ((fp = g_fopen(rcpath, "rb")) == NULL) { 360 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "g_fopen"); 361 } else { 362 all_hdrs = NULL; 363 364 while (fgets(buf, sizeof(buf), fp) != NULL) { 365 ch = custom_header_read_str(buf); 366 if (ch) { 367 if (ch->account_id != ac->account_id) 368 all_hdrs = 369 g_slist_append(all_hdrs, ch); 370 else 371 custom_header_free(ch); 372 } 373 } 374 375 fclose(fp); 376 } 377 378 if ((pfile = prefs_write_open(rcpath)) == NULL) { 379 g_warning("failed to write configuration to file"); 380 g_free(rcpath); 381 return; 382 } 383 384 for (cur = all_hdrs; cur != NULL; cur = cur->next) { 385 CustomHeader *hdr = (CustomHeader *)cur->data; 386 gchar *chstr; 387 388 chstr = custom_header_get_str(hdr); 389 if (fputs(chstr, pfile->fp) == EOF || 390 fputc('\n', pfile->fp) == EOF) { 391 FILE_OP_ERROR(rcpath, "fputs || fputc"); 392 prefs_file_close_revert(pfile); 393 g_free(rcpath); 394 g_free(chstr); 395 return; 396 } 397 g_free(chstr); 398 } 399 400 for (cur = ac->customhdr_list; cur != NULL; cur = cur->next) { 401 CustomHeader *hdr = (CustomHeader *)cur->data; 402 gchar *chstr; 403 404 chstr = custom_header_get_str(hdr); 405 if (fputs(chstr, pfile->fp) == EOF || 406 fputc('\n', pfile->fp) == EOF) { 407 FILE_OP_ERROR(rcpath, "fputs || fputc"); 408 prefs_file_close_revert(pfile); 409 g_free(rcpath); 410 g_free(chstr); 411 return; 412 } 413 g_free(chstr); 414 } 415 416 g_free(rcpath); 417 418 while (all_hdrs != NULL) { 419 ch = (CustomHeader *)all_hdrs->data; 420 all_hdrs = g_slist_remove(all_hdrs, ch); 421 custom_header_free(ch); 422 } 423 424 if (prefs_file_close(pfile) < 0) { 425 g_warning("failed to write configuration to file"); 426 return; 427 } 428 } 429 430 static void prefs_custom_header_set_dialog(PrefsAccount *ac) 431 { 432 GtkListStore *store; 433 GSList *cur; 434 435 store = GTK_LIST_STORE(gtk_tree_view_get_model 436 (GTK_TREE_VIEW(customhdr.list_view))); 437 gtk_list_store_clear(store); 438 439 for (cur = ac->customhdr_list; cur != NULL; cur = cur->next) { 440 CustomHeader *ch = (CustomHeader *)cur->data; 441 gchar *ch_str; 442 443 ch_str = g_strdup_printf("%s: %s", ch->name, 444 ch->value ? ch->value : ""); 445 446 prefs_custom_header_list_view_insert_header 447 (customhdr.list_view, NULL, ch_str, ch); 448 449 g_free(ch_str); 450 } 451 } 452 453 static void prefs_custom_header_set_list(PrefsAccount *ac) 454 { 455 CustomHeader *ch; 456 GtkTreeIter iter; 457 GtkListStore *store; 458 459 g_slist_free(ac->customhdr_list); 460 ac->customhdr_list = NULL; 461 462 store = GTK_LIST_STORE(gtk_tree_view_get_model 463 (GTK_TREE_VIEW(customhdr.list_view))); 464 465 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) { 466 do { 467 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 468 CUSTHDR_DATA, &ch, 469 -1); 470 ac->customhdr_list = g_slist_append(ac->customhdr_list, ch); 471 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), 472 &iter)); 473 } 474 } 475 476 static void prefs_custom_header_list_view_set_row(PrefsAccount *ac) 477 { 478 CustomHeader *ch; 479 const gchar *entry_text; 480 gchar *ch_str; 481 482 entry_text = gtk_entry_get_text(GTK_ENTRY(customhdr.hdr_entry)); 483 if (entry_text[0] == '\0') { 484 alertpanel_error(_("Header name is not set.")); 485 return; 486 } 487 488 while (*entry_text && 489 (*entry_text == '\n' || *entry_text == '\r' || 490 *entry_text == '\t' || *entry_text == ' ')) 491 entry_text++; 492 493 if (strchr(entry_text, ':') != NULL) { 494 alertpanel_error(_("A colon (:) is not allowed in a custom header.")); 495 return; 496 } 497 498 if (!custom_header_is_allowed(entry_text)) { 499 alertpanel_error(_("This Header name is not allowed as a custom header.")); 500 return; 501 } 502 503 ch = g_new0(CustomHeader, 1); 504 505 ch->account_id = ac->account_id; 506 507 ch->name = g_strdup(entry_text); 508 unfold_line(ch->name); 509 g_strstrip(ch->name); 510 gtk_entry_set_text(GTK_ENTRY(customhdr.hdr_entry), ch->name); 511 512 entry_text = gtk_entry_get_text(GTK_ENTRY(customhdr.val_entry)); 513 while (*entry_text && 514 (*entry_text == '\n' || *entry_text == '\r' || 515 *entry_text == '\t' || *entry_text == ' ')) 516 entry_text++; 517 518 if (entry_text[0] != '\0') { 519 ch->value = g_strdup(entry_text); 520 unfold_line(ch->value); 521 g_strstrip(ch->value); 522 gtk_entry_set_text(GTK_ENTRY(customhdr.val_entry), ch->value); 523 } 524 525 ch_str = g_strdup_printf("%s: %s", ch->name, 526 ch->value ? ch->value : ""); 527 528 prefs_custom_header_list_view_insert_header 529 (customhdr.list_view, NULL, ch_str, ch); 530 531 g_free(ch_str); 532 533 prefs_custom_header_set_list(cur_ac); 534 535 } 536 537 static void prefs_custom_header_val_from_file_cb(void) 538 { 539 gchar *filename = NULL; 540 gchar *contents = NULL; 541 542 filename = filesel_select_file_open(_("Choose a text file"), NULL); 543 if (!filename) 544 return; 545 546 contents = file_read_to_str(filename); 547 if (strchr(contents, '\n') || strchr(contents,'\r')) { 548 alertpanel_error(_("This file contains newlines.")); 549 g_free(contents); 550 g_free(filename); 551 return; 552 } 553 554 if (contents && strlen(contents)) 555 gtk_entry_set_text(GTK_ENTRY(customhdr.val_entry), contents); 556 557 g_free(contents); 558 g_free(filename); 559 } 560 561 static void prefs_custom_header_add_cb(void) 562 { 563 prefs_custom_header_list_view_set_row(cur_ac); 564 } 565 566 static void prefs_custom_header_delete_cb(void) 567 { 568 GtkTreeIter sel; 569 GtkTreeModel *model; 570 CustomHeader *ch; 571 572 if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection 573 (GTK_TREE_VIEW(customhdr.list_view)), 574 &model, &sel)) 575 return; 576 577 if (alertpanel(_("Delete header"), 578 _("Do you really want to delete this header?"), 579 NULL, _("_Cancel"), "edit-delete", _("_Delete"), NULL, NULL, 580 ALERTFOCUS_FIRST) != G_ALERTALTERNATE) 581 return; 582 583 gtk_tree_model_get(model, &sel, 584 CUSTHDR_DATA, &ch, 585 -1); 586 gtk_list_store_remove(GTK_LIST_STORE(model), &sel); 587 588 cur_ac->customhdr_list = g_slist_remove(cur_ac->customhdr_list, ch); 589 590 custom_header_free(ch); 591 } 592 593 static void prefs_custom_header_up(void) 594 { 595 GtkTreePath *prev, *sel; 596 GtkTreeIter isel; 597 GtkListStore *store = NULL; 598 GtkTreeModel *model = NULL; 599 GtkTreeIter iprev; 600 601 if (!gtk_tree_selection_get_selected 602 (gtk_tree_view_get_selection 603 (GTK_TREE_VIEW(customhdr.list_view)), 604 &model, 605 &isel)) 606 return; 607 store = (GtkListStore *)model; 608 sel = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &isel); 609 if (!sel) 610 return; 611 612 /* no move if we're at row 0... */ 613 prev = gtk_tree_path_copy(sel); 614 if (!gtk_tree_path_prev(prev)) { 615 gtk_tree_path_free(prev); 616 gtk_tree_path_free(sel); 617 return; 618 } 619 620 gtk_tree_model_get_iter(GTK_TREE_MODEL(store), 621 &iprev, prev); 622 gtk_tree_path_free(sel); 623 gtk_tree_path_free(prev); 624 625 gtk_list_store_swap(store, &iprev, &isel); 626 prefs_custom_header_set_list(cur_ac); 627 } 628 629 static void prefs_custom_header_down(void) 630 { 631 GtkListStore *store = NULL; 632 GtkTreeModel *model = NULL; 633 GtkTreeIter next, sel; 634 635 if (!gtk_tree_selection_get_selected 636 (gtk_tree_view_get_selection 637 (GTK_TREE_VIEW(customhdr.list_view)), 638 &model, 639 &sel)) 640 return; 641 store = (GtkListStore *)model; 642 next = sel; 643 if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &next)) 644 return; 645 646 gtk_list_store_swap(store, &next, &sel); 647 prefs_custom_header_set_list(cur_ac); 648 } 649 650 static void prefs_custom_header_ok(void) 651 { 652 prefs_custom_header_write_config(cur_ac); 653 gtk_widget_hide(customhdr.window); 654 gtk_window_set_modal(GTK_WINDOW(customhdr.window), FALSE); 655 } 656 657 static void prefs_custom_header_cancel(void) 658 { 659 prefs_custom_header_read_config(cur_ac); 660 gtk_widget_hide(customhdr.window); 661 gtk_window_set_modal(GTK_WINDOW(customhdr.window), FALSE); 662 } 663 664 static gint prefs_custom_header_deleted(GtkWidget *widget, GdkEventAny *event, 665 gpointer data) 666 { 667 prefs_custom_header_cancel(); 668 return TRUE; 669 } 670 671 static GtkListStore* prefs_custom_header_create_data_store(void) 672 { 673 return gtk_list_store_new(N_CUSTHDR_COLUMNS, 674 G_TYPE_STRING, 675 G_TYPE_POINTER, 676 -1); 677 } 678 679 static void prefs_custom_header_list_view_insert_header(GtkWidget *list_view, 680 GtkTreeIter *row_iter, 681 gchar *header, 682 gpointer data) 683 { 684 GtkTreeIter iter; 685 GtkListStore *list_store = GTK_LIST_STORE(gtk_tree_view_get_model 686 (GTK_TREE_VIEW(list_view))); 687 688 if (row_iter == NULL) { 689 /* append new */ 690 gtk_list_store_append(list_store, &iter); 691 gtk_list_store_set(list_store, &iter, 692 CUSTHDR_STRING, header, 693 CUSTHDR_DATA, data, 694 -1); 695 } else { 696 /* change existing */ 697 CustomHeader *old_data; 698 699 gtk_tree_model_get(GTK_TREE_MODEL(list_store), row_iter, 700 CUSTHDR_DATA, &old_data, 701 -1); 702 703 custom_header_free(old_data); 704 705 gtk_list_store_set(list_store, row_iter, 706 CUSTHDR_STRING, header, 707 CUSTHDR_DATA, data, 708 -1); 709 } 710 } 711 712 static GtkWidget *prefs_custom_header_list_view_create(void) 713 { 714 GtkTreeView *list_view; 715 GtkTreeSelection *selector; 716 GtkTreeModel *model; 717 718 model = GTK_TREE_MODEL(prefs_custom_header_create_data_store()); 719 list_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(model)); 720 g_object_unref(model); 721 722 gtk_tree_view_set_reorderable(list_view, TRUE); 723 724 selector = gtk_tree_view_get_selection(list_view); 725 gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE); 726 gtk_tree_selection_set_select_function(selector, prefs_custom_header_selected, 727 NULL, NULL); 728 729 /* create the columns */ 730 prefs_custom_header_create_list_view_columns(GTK_WIDGET(list_view)); 731 732 return GTK_WIDGET(list_view); 733 } 734 735 static void prefs_custom_header_create_list_view_columns(GtkWidget *list_view) 736 { 737 GtkTreeViewColumn *column; 738 GtkCellRenderer *renderer; 739 740 renderer = gtk_cell_renderer_text_new(); 741 column = gtk_tree_view_column_new_with_attributes 742 (_("Current custom headers"), 743 renderer, 744 "text", CUSTHDR_STRING, 745 NULL); 746 gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column); 747 } 748 749 #define ENTRY_SET_TEXT(entry, str) \ 750 gtk_entry_set_text(GTK_ENTRY(entry), str ? str : "") 751 752 static gboolean prefs_custom_header_selected(GtkTreeSelection *selector, 753 GtkTreeModel *model, 754 GtkTreePath *path, 755 gboolean currently_selected, 756 gpointer data) 757 { 758 GtkTreeIter iter; 759 CustomHeader *ch; 760 CustomHeader default_ch = { 0, "", NULL }; 761 762 if (currently_selected) 763 return TRUE; 764 765 if (!gtk_tree_model_get_iter(model, &iter, path)) 766 return TRUE; 767 768 gtk_tree_model_get(model, &iter, 769 CUSTHDR_DATA, &ch, 770 -1); 771 772 if (!ch) ch = &default_ch; 773 774 ENTRY_SET_TEXT(customhdr.hdr_entry, ch->name); 775 ENTRY_SET_TEXT(customhdr.val_entry, ch->value); 776 gtk_widget_hide(customhdr.preview); 777 return TRUE; 778 } 779 780 #undef ENTRY_SET_TEXT