prefs_folder_column.c (27064B)
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 26 #include "prefs_gtk.h" 27 #include "prefs_common.h" 28 #include "prefs_folder_column.h" 29 #include "manage_window.h" 30 #include "folderview.h" 31 #include "mainwindow.h" 32 #include "inc.h" 33 #include "gtkutils.h" 34 #include "utils.h" 35 36 static void prefs_folder_column_set_config(FolderColumnState *state); 37 38 enum { 39 SUMCOL_NAME, 40 SUMCOL_TYPE, 41 N_SUMCOL_COLUMNS 42 }; 43 44 #define TARGET_INFO_SUMCOL (0xFEEDBABE) 45 46 static const GtkTargetEntry row_targets[] = { 47 { "PREFS_SUM_COL_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_INFO_SUMCOL } 48 }; 49 50 51 static struct _FolderColumnDialog 52 { 53 GtkWidget *window; 54 55 GtkWidget *stock_list_view; 56 GtkWidget *shown_list_view; 57 58 GtkWidget *add_btn; 59 GtkWidget *remove_btn; 60 GtkWidget *up_btn; 61 GtkWidget *down_btn; 62 63 GtkWidget *default_btn; 64 65 GtkWidget *ok_btn; 66 GtkWidget *cancel_btn; 67 68 gboolean finished; 69 } folder_col; 70 71 static const gchar *const col_name[N_FOLDER_COLS] = { 72 N_("Folder"), /* F_COL_FOLDER */ 73 N_("New"), /* F_COL_NEW */ 74 N_("Unread"), /* F_COL_UNREAD */ 75 N_("Total"), /* F_COL_TOTAL */ 76 }; 77 78 static FolderColumnState default_state[N_FOLDER_COLS] = { 79 { F_COL_FOLDER , TRUE }, 80 { F_COL_NEW , TRUE }, 81 { F_COL_UNREAD , TRUE }, 82 { F_COL_TOTAL , TRUE }, 83 }; 84 85 static void prefs_folder_column_create (void); 86 87 static void prefs_folder_column_set_dialog (FolderColumnState *state); 88 static void prefs_folder_column_set_view (void); 89 90 /* callback functions */ 91 static void prefs_folder_column_add (void); 92 static void prefs_folder_column_remove (void); 93 94 static void prefs_folder_column_up (void); 95 static void prefs_folder_column_down (void); 96 97 static void prefs_folder_column_set_to_default (void); 98 99 static void prefs_folder_column_ok (void); 100 static void prefs_folder_column_cancel (void); 101 102 static gint prefs_folder_column_delete_event (GtkWidget *widget, 103 GdkEventAny *event, 104 gpointer data); 105 106 static GtkListStore *prefs_folder_column_create_store (void); 107 108 static void prefs_folder_column_insert_column (GtkListStore *store, 109 gint row, 110 const gchar *name, 111 FolderColumnType type); 112 113 static FolderColumnType prefs_folder_column_get_column (GtkWidget *list, 114 gint row); 115 116 static GtkWidget *prefs_folder_column_list_view_create (const gchar *name); 117 118 static void prefs_filtering_create_list_view_columns (GtkWidget *list_view, 119 const gchar *name); 120 121 static void drag_data_get (GtkTreeView *tree_view, 122 GdkDragContext *context, 123 GtkSelectionData *data, 124 guint info, 125 guint time, 126 GtkTreeModel *model); 127 128 static void drag_data_received (GtkTreeView *tree_view, 129 GdkDragContext *context, 130 gint x, gint y, 131 GtkSelectionData *data, 132 guint info, 133 guint time, 134 GtkTreeModel *model); 135 136 static void prefs_folder_column_shown_set_btn_sensitivity(void); 137 static void prefs_folder_column_shown_set_active(const gboolean active); 138 static void prefs_folder_column_stock_set_active(const gboolean active); 139 static void prefs_folder_column_shown_sel_changed(void); 140 static void prefs_folder_column_stock_sel_changed(void); 141 142 143 void prefs_folder_column_open(void) 144 { 145 inc_lock(); 146 147 if (!folder_col.window) 148 prefs_folder_column_create(); 149 150 manage_window_set_transient(GTK_WINDOW(folder_col.window)); 151 gtk_widget_grab_focus(folder_col.ok_btn); 152 153 prefs_folder_column_set_dialog(NULL); 154 155 gtk_widget_show(folder_col.window); 156 gtk_window_set_modal(GTK_WINDOW(folder_col.window), TRUE); 157 158 folder_col.finished = FALSE; 159 while (folder_col.finished == FALSE) 160 gtk_main_iteration(); 161 162 gtk_widget_hide(folder_col.window); 163 gtk_window_set_modal(GTK_WINDOW(folder_col.window), FALSE); 164 165 inc_unlock(); 166 } 167 168 static void prefs_folder_column_create(void) 169 { 170 GtkWidget *window; 171 GtkWidget *vbox; 172 173 GtkWidget *label_hbox; 174 GtkWidget *label; 175 176 GtkWidget *vbox1; 177 178 GtkWidget *hbox1; 179 GtkWidget *clist_hbox; 180 GtkWidget *scrolledwin; 181 GtkWidget *stock_list_view; 182 GtkWidget *shown_list_view; 183 184 GtkWidget *btn_vbox; 185 GtkWidget *add_btn; 186 GtkWidget *remove_btn; 187 GtkWidget *up_btn; 188 GtkWidget *down_btn; 189 190 GtkWidget *btn_hbox; 191 GtkWidget *default_btn; 192 GtkWidget *confirm_area; 193 GtkWidget *ok_btn; 194 GtkWidget *cancel_btn; 195 196 debug_print("Creating folder column setting window...\n"); 197 198 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "prefs_folder_column"); 199 gtk_container_set_border_width(GTK_CONTAINER(window), 8); 200 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); 201 gtk_window_set_resizable(GTK_WINDOW(window), FALSE); 202 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG); 203 gtk_window_set_title(GTK_WINDOW(window), 204 _("Folder list columns configuration")); 205 g_signal_connect(G_OBJECT(window), "delete_event", 206 G_CALLBACK(prefs_folder_column_delete_event), 207 NULL); 208 209 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6); 210 gtk_widget_show(vbox); 211 gtk_container_add(GTK_CONTAINER(window), vbox); 212 213 label_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); 214 gtk_widget_show(label_hbox); 215 gtk_box_pack_start(GTK_BOX(vbox), label_hbox, FALSE, FALSE, 4); 216 217 label = gtk_label_new 218 (_("Select columns to be displayed in the folder list. You can modify\n" 219 "the order by using the Up / Down buttons or by dragging the items.")); 220 gtk_widget_show(label); 221 gtk_box_pack_start(GTK_BOX(label_hbox), label, FALSE, FALSE, 4); 222 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); 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 clist_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); 234 gtk_widget_show(clist_hbox); 235 gtk_box_pack_start(GTK_BOX(hbox1), clist_hbox, TRUE, TRUE, 0); 236 237 scrolledwin = gtk_scrolled_window_new(NULL, NULL); 238 gtk_widget_set_size_request(scrolledwin, 180, 210); 239 gtk_widget_show(scrolledwin); 240 gtk_box_pack_start(GTK_BOX(clist_hbox), scrolledwin, TRUE, TRUE, 0); 241 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin), 242 GTK_POLICY_AUTOMATIC, 243 GTK_POLICY_AUTOMATIC); 244 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin), 245 GTK_SHADOW_IN); 246 247 stock_list_view = prefs_folder_column_list_view_create 248 (_("Hidden columns")); 249 g_signal_connect(G_OBJECT(stock_list_view), "cursor-changed", 250 G_CALLBACK(prefs_folder_column_stock_sel_changed), 251 NULL); 252 gtk_widget_show(stock_list_view); 253 gtk_container_add(GTK_CONTAINER(scrolledwin), stock_list_view); 254 255 /* add/remove button */ 256 btn_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); 257 gtk_widget_show(btn_vbox); 258 gtk_box_pack_start(GTK_BOX(hbox1), btn_vbox, FALSE, FALSE, 0); 259 260 add_btn = gtkut_stock_button("list-add", _("_Add")); 261 gtk_widget_show(add_btn); 262 gtk_box_pack_start(GTK_BOX(btn_vbox), add_btn, FALSE, TRUE, 0); 263 264 g_signal_connect(G_OBJECT(add_btn), "clicked", 265 G_CALLBACK(prefs_folder_column_add), NULL); 266 267 remove_btn = gtkut_stock_button("list-remove", _("_Remove")); 268 gtk_widget_show(remove_btn); 269 gtk_box_pack_start(GTK_BOX(btn_vbox), remove_btn, FALSE, TRUE, 0); 270 271 g_signal_connect(G_OBJECT(remove_btn), "clicked", 272 G_CALLBACK(prefs_folder_column_remove), NULL); 273 274 clist_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); 275 gtk_widget_show(clist_hbox); 276 gtk_box_pack_start(GTK_BOX(hbox1), clist_hbox, TRUE, TRUE, 0); 277 278 scrolledwin = gtk_scrolled_window_new(NULL, NULL); 279 gtk_widget_set_size_request(scrolledwin, 180, 210); 280 gtk_widget_show(scrolledwin); 281 gtk_box_pack_start(GTK_BOX(clist_hbox), scrolledwin, TRUE, TRUE, 0); 282 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin), 283 GTK_POLICY_AUTOMATIC, 284 GTK_POLICY_AUTOMATIC); 285 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin), 286 GTK_SHADOW_IN); 287 288 shown_list_view = prefs_folder_column_list_view_create 289 (_("Displayed columns")); 290 g_signal_connect(G_OBJECT(shown_list_view), "cursor-changed", 291 G_CALLBACK(prefs_folder_column_shown_sel_changed), 292 NULL); 293 gtk_widget_show(shown_list_view); 294 gtk_container_add(GTK_CONTAINER(scrolledwin), shown_list_view); 295 296 /* up/down button */ 297 btn_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8); 298 gtk_widget_show(btn_vbox); 299 gtk_box_pack_start(GTK_BOX(hbox1), btn_vbox, FALSE, FALSE, 0); 300 301 up_btn = gtkut_stock_button("go-up", _("_Up")); 302 gtk_widget_show(up_btn); 303 gtk_box_pack_start(GTK_BOX(btn_vbox), up_btn, FALSE, TRUE, 0); 304 305 down_btn = gtkut_stock_button("go-down", _("_Down")); 306 gtk_widget_show(down_btn); 307 gtk_box_pack_start(GTK_BOX(btn_vbox), down_btn, FALSE, TRUE, 0); 308 309 g_signal_connect(G_OBJECT(up_btn), "clicked", 310 G_CALLBACK(prefs_folder_column_up), NULL); 311 g_signal_connect(G_OBJECT(down_btn), "clicked", 312 G_CALLBACK(prefs_folder_column_down), NULL); 313 314 btn_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); 315 gtk_widget_show(btn_hbox); 316 gtk_box_pack_end(GTK_BOX(vbox), btn_hbox, FALSE, FALSE, 0); 317 318 btn_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); 319 gtk_widget_show(btn_vbox); 320 gtk_box_pack_start(GTK_BOX(btn_hbox), btn_vbox, FALSE, FALSE, 0); 321 322 default_btn = gtk_button_new_with_label(_(" Use default ")); 323 gtk_widget_show(default_btn); 324 gtk_box_pack_start(GTK_BOX(btn_vbox), default_btn, TRUE, FALSE, 0); 325 g_signal_connect(G_OBJECT(default_btn), "clicked", 326 G_CALLBACK(prefs_folder_column_set_to_default), 327 NULL); 328 329 gtkut_stock_button_set_create(&confirm_area, 330 &cancel_btn, NULL, _("_Cancel"), 331 &ok_btn, NULL, _("_OK"), 332 NULL, NULL, NULL); 333 gtk_widget_show(confirm_area); 334 gtk_box_pack_end(GTK_BOX(btn_hbox), confirm_area, FALSE, FALSE, 0); 335 gtk_widget_grab_default(ok_btn); 336 337 g_signal_connect(G_OBJECT(ok_btn), "clicked", 338 G_CALLBACK(prefs_folder_column_ok), NULL); 339 g_signal_connect(G_OBJECT(cancel_btn), "clicked", 340 G_CALLBACK(prefs_folder_column_cancel), NULL); 341 342 folder_col.window = window; 343 folder_col.add_btn = add_btn; 344 folder_col.remove_btn = remove_btn; 345 folder_col.up_btn = up_btn; 346 folder_col.down_btn = down_btn; 347 folder_col.ok_btn = ok_btn; 348 folder_col.cancel_btn = cancel_btn; 349 folder_col.stock_list_view = stock_list_view; 350 folder_col.shown_list_view = shown_list_view; 351 352 prefs_folder_column_shown_set_active(FALSE); 353 prefs_folder_column_stock_set_active(FALSE); 354 } 355 356 FolderColumnState *prefs_folder_column_get_config(void) 357 { 358 static FolderColumnState state[N_FOLDER_COLS]; 359 FolderColumnType type; 360 gint pos; 361 362 for (pos = 0; pos < N_FOLDER_COLS; pos++) 363 state[pos].type = -1; 364 365 for (type = 0; type < N_FOLDER_COLS; type++) { 366 pos = prefs_common.folder_col_pos[type]; 367 if (pos < 0 || pos >= N_FOLDER_COLS || 368 state[pos].type != -1) { 369 g_warning("wrong column position"); 370 prefs_folder_column_set_config(default_state); 371 return default_state; 372 } 373 374 state[pos].type = type; 375 state[pos].visible = prefs_common.folder_col_visible[type]; 376 } 377 378 return state; 379 } 380 381 static void prefs_folder_column_set_config(FolderColumnState *state) 382 { 383 FolderColumnType type; 384 gint pos; 385 386 for (pos = 0; pos < N_FOLDER_COLS; pos++) { 387 type = state[pos].type; 388 prefs_common.folder_col_visible[type] = state[pos].visible; 389 prefs_common.folder_col_pos[type] = pos; 390 } 391 } 392 393 static void prefs_folder_column_set_dialog(FolderColumnState *state) 394 { 395 GtkListStore *stock_store, *shown_store; 396 gint pos; 397 FolderColumnType type; 398 gchar *name; 399 400 stock_store = GTK_LIST_STORE(gtk_tree_view_get_model 401 (GTK_TREE_VIEW(folder_col.stock_list_view))); 402 shown_store = GTK_LIST_STORE(gtk_tree_view_get_model 403 (GTK_TREE_VIEW(folder_col.shown_list_view))); 404 405 gtk_list_store_clear(stock_store); 406 gtk_list_store_clear(shown_store); 407 408 if (!state) 409 state = prefs_folder_column_get_config(); 410 411 for (pos = 0; pos < N_FOLDER_COLS; pos++) { 412 type = state[pos].type; 413 name = col_name[type]; 414 415 if (state[pos].visible) 416 prefs_folder_column_insert_column(shown_store, 417 -1, name, 418 type); 419 else 420 prefs_folder_column_insert_column(stock_store, 421 -1, name, 422 type); 423 } 424 } 425 426 static void prefs_folder_column_set_view(void) 427 { 428 gint stock_n_rows, shown_n_rows; 429 FolderColumnState state[N_FOLDER_COLS]; 430 FolderColumnType type; 431 gint row, pos = 0; 432 433 stock_n_rows = gtk_tree_model_iter_n_children 434 (gtk_tree_view_get_model(GTK_TREE_VIEW 435 (folder_col.stock_list_view)), NULL); 436 shown_n_rows = gtk_tree_model_iter_n_children 437 (gtk_tree_view_get_model(GTK_TREE_VIEW 438 (folder_col.shown_list_view)), NULL); 439 440 cm_return_if_fail 441 (stock_n_rows + shown_n_rows == N_FOLDER_COLS); 442 443 for (row = 0; row < stock_n_rows; row++) { 444 type = prefs_folder_column_get_column 445 (folder_col.stock_list_view, row); 446 state[row].type = type; 447 state[row].visible = FALSE; 448 } 449 450 pos = row; 451 for (row = 0; row < shown_n_rows; row++) { 452 type = prefs_folder_column_get_column 453 (folder_col.shown_list_view, row); 454 state[pos + row].type = type; 455 state[pos + row].visible = TRUE; 456 } 457 458 prefs_folder_column_set_config(state); 459 main_window_set_folder_column(); 460 } 461 462 static void prefs_folder_column_add(void) 463 { 464 GtkListStore *stock_store, *shown_store; 465 GtkTreeIter stock_sel, shown_sel, shown_add; 466 gboolean shown_sel_valid; 467 gchar *name; 468 FolderColumnType type; 469 470 stock_store = GTK_LIST_STORE(gtk_tree_view_get_model 471 (GTK_TREE_VIEW(folder_col.stock_list_view))); 472 shown_store = GTK_LIST_STORE(gtk_tree_view_get_model 473 (GTK_TREE_VIEW(folder_col.shown_list_view))); 474 475 if (!gtk_tree_selection_get_selected 476 (gtk_tree_view_get_selection 477 (GTK_TREE_VIEW(folder_col.stock_list_view)), 478 NULL, 479 &stock_sel)) 480 return; 481 482 shown_sel_valid = gtk_tree_selection_get_selected 483 (gtk_tree_view_get_selection 484 (GTK_TREE_VIEW(folder_col.shown_list_view)), 485 NULL, 486 &shown_sel); 487 488 gtk_tree_model_get(GTK_TREE_MODEL(stock_store), &stock_sel, 489 SUMCOL_TYPE, &type, 490 -1); 491 492 gtk_list_store_remove(stock_store, &stock_sel); 493 494 gtk_list_store_insert_after(shown_store, &shown_add, 495 shown_sel_valid ? &shown_sel : NULL); 496 497 gtk_list_store_set(shown_store, &shown_add, 498 SUMCOL_NAME, col_name[type], 499 SUMCOL_TYPE, type, 500 -1); 501 502 gtk_tree_selection_select_iter(gtk_tree_view_get_selection 503 (GTK_TREE_VIEW(folder_col.shown_list_view)), 504 &shown_add); 505 prefs_folder_column_shown_set_active(TRUE); 506 prefs_folder_column_stock_set_active(FALSE); 507 } 508 509 static void prefs_folder_column_remove(void) 510 { 511 GtkListStore *stock_store, *shown_store; 512 GtkTreeIter shown_sel, stock_sel, stock_add; 513 gboolean stock_sel_valid; 514 FolderColumnType type; 515 516 stock_store = GTK_LIST_STORE(gtk_tree_view_get_model 517 (GTK_TREE_VIEW(folder_col.stock_list_view))); 518 shown_store = GTK_LIST_STORE(gtk_tree_view_get_model 519 (GTK_TREE_VIEW(folder_col.shown_list_view))); 520 521 if (!gtk_tree_selection_get_selected 522 (gtk_tree_view_get_selection 523 (GTK_TREE_VIEW(folder_col.shown_list_view)), 524 NULL, 525 &shown_sel)) 526 return; 527 528 stock_sel_valid = gtk_tree_selection_get_selected 529 (gtk_tree_view_get_selection 530 (GTK_TREE_VIEW(folder_col.stock_list_view)), 531 NULL, 532 &stock_sel); 533 534 gtk_tree_model_get(GTK_TREE_MODEL(shown_store), &shown_sel, 535 SUMCOL_TYPE, &type, 536 -1); 537 538 gtk_list_store_remove(shown_store, &shown_sel); 539 540 gtk_list_store_insert_after(stock_store, &stock_add, 541 stock_sel_valid ? &stock_sel : NULL); 542 543 gtk_list_store_set(stock_store, &stock_add, 544 SUMCOL_NAME, col_name[type], 545 SUMCOL_TYPE, type, 546 -1); 547 548 gtk_tree_selection_select_iter(gtk_tree_view_get_selection 549 (GTK_TREE_VIEW(folder_col.stock_list_view)), 550 &stock_add); 551 prefs_folder_column_shown_set_active(FALSE); 552 prefs_folder_column_stock_set_active(TRUE); 553 } 554 555 static void prefs_folder_column_up(void) 556 { 557 GtkTreePath *prev, *sel; 558 GtkTreeIter isel; 559 GtkListStore *shown_store; 560 GtkTreeIter iprev; 561 562 if (!gtk_tree_selection_get_selected 563 (gtk_tree_view_get_selection 564 (GTK_TREE_VIEW(folder_col.shown_list_view)), 565 NULL, 566 &isel)) 567 return; 568 569 shown_store = GTK_LIST_STORE(gtk_tree_view_get_model 570 (GTK_TREE_VIEW(folder_col.shown_list_view))); 571 572 sel = gtk_tree_model_get_path(GTK_TREE_MODEL(shown_store), 573 &isel); 574 if (!sel) 575 return; 576 577 prev = gtk_tree_path_copy(sel); 578 if (!gtk_tree_path_prev(prev)) { 579 gtk_tree_path_free(prev); 580 gtk_tree_path_free(sel); 581 return; 582 } 583 584 gtk_tree_model_get_iter(GTK_TREE_MODEL(shown_store), 585 &iprev, prev); 586 gtk_tree_path_free(sel); 587 gtk_tree_path_free(prev); 588 589 gtk_list_store_swap(shown_store, &iprev, &isel); 590 prefs_folder_column_shown_set_btn_sensitivity(); 591 } 592 593 static void prefs_folder_column_down(void) 594 { 595 GtkListStore *shown_store; 596 GtkTreeIter next, sel; 597 598 if (!gtk_tree_selection_get_selected 599 (gtk_tree_view_get_selection 600 (GTK_TREE_VIEW(folder_col.shown_list_view)), 601 NULL, 602 &sel)) 603 return; 604 605 shown_store = GTK_LIST_STORE(gtk_tree_view_get_model 606 (GTK_TREE_VIEW(folder_col.shown_list_view))); 607 608 next = sel; 609 if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(shown_store), &next)) 610 return; 611 612 gtk_list_store_swap(shown_store, &next, &sel); 613 prefs_folder_column_shown_set_btn_sensitivity(); 614 } 615 616 static void prefs_folder_column_set_to_default(void) 617 { 618 prefs_folder_column_set_dialog(default_state); 619 prefs_folder_column_shown_set_active(FALSE); 620 prefs_folder_column_stock_set_active(FALSE); 621 } 622 623 static void prefs_folder_column_ok(void) 624 { 625 if (!folder_col.finished) { 626 folder_col.finished = TRUE; 627 prefs_folder_column_set_view(); 628 } 629 } 630 631 static void prefs_folder_column_cancel(void) 632 { 633 folder_col.finished = TRUE; 634 } 635 636 static gint prefs_folder_column_delete_event(GtkWidget *widget, 637 GdkEventAny *event, 638 gpointer data) 639 { 640 folder_col.finished = TRUE; 641 return TRUE; 642 } 643 644 static GtkListStore *prefs_folder_column_create_store(void) 645 { 646 return gtk_list_store_new(N_SUMCOL_COLUMNS, 647 G_TYPE_STRING, 648 G_TYPE_INT, 649 -1); 650 } 651 652 static void prefs_folder_column_insert_column(GtkListStore *store, 653 gint row, 654 const gchar *name, 655 FolderColumnType type) 656 { 657 GtkTreeIter iter; 658 659 if (row >= 0) { 660 if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), 661 &iter, NULL, row)) 662 row = -1; 663 } 664 if (row < 0) { 665 /* add new */ 666 gtk_list_store_append(store, &iter); 667 gtk_list_store_set(store, &iter, 668 SUMCOL_NAME, name, 669 SUMCOL_TYPE, type, 670 -1); 671 return; 672 } else { 673 /* change existing */ 674 gtk_list_store_set(store, &iter, 675 SUMCOL_NAME, name, 676 SUMCOL_TYPE, type, 677 -1); 678 } 679 } 680 681 /*! 682 *\brief Return the columnn type for a row 683 */ 684 static FolderColumnType prefs_folder_column_get_column(GtkWidget *list, gint row) 685 { 686 GtkTreeView *list_view = GTK_TREE_VIEW(list); 687 GtkTreeModel *model = gtk_tree_view_get_model(list_view); 688 GtkTreeIter iter; 689 FolderColumnType result; 690 691 if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, row)) 692 return -1; 693 694 gtk_tree_model_get(model, &iter, 695 SUMCOL_TYPE, &result, 696 -1); 697 698 return result; 699 } 700 701 static GtkWidget *prefs_folder_column_list_view_create(const gchar *name) 702 { 703 GtkWidget *list_view; 704 GtkTreeSelection *selector; 705 GtkTreeModel *model; 706 707 model = GTK_TREE_MODEL(prefs_folder_column_create_store()); 708 list_view = gtk_tree_view_new_with_model(model); 709 g_object_unref(G_OBJECT(model)); 710 711 selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view)); 712 gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE); 713 714 prefs_filtering_create_list_view_columns(GTK_WIDGET(list_view), name); 715 716 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(list_view), 717 GDK_BUTTON1_MASK, 718 row_targets, 719 G_N_ELEMENTS(row_targets), 720 GDK_ACTION_MOVE); 721 722 gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(list_view), 723 row_targets, 724 G_N_ELEMENTS(row_targets), 725 GDK_ACTION_MOVE); 726 727 g_signal_connect(G_OBJECT(list_view), "drag_data_get", 728 G_CALLBACK(drag_data_get), 729 model); 730 731 g_signal_connect(G_OBJECT(list_view), "drag_data_received", 732 G_CALLBACK(drag_data_received), 733 model); 734 735 return list_view; 736 } 737 738 static void prefs_filtering_create_list_view_columns(GtkWidget *list_view, 739 const gchar *name) 740 { 741 GtkTreeViewColumn *column; 742 GtkCellRenderer *renderer; 743 744 renderer = gtk_cell_renderer_text_new(); 745 column = gtk_tree_view_column_new_with_attributes 746 (name, renderer, "text", SUMCOL_NAME, NULL); 747 gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column); 748 } 749 750 static void drag_data_get(GtkTreeView *tree_view, GdkDragContext *context, 751 GtkSelectionData *data, guint info, 752 guint time, GtkTreeModel *model) 753 { 754 GtkTreeIter iter; 755 FolderColumnType type; 756 GtkTreeModel *source_model; 757 758 if (info != TARGET_INFO_SUMCOL) 759 return; 760 761 if (!gtk_tree_selection_get_selected 762 (gtk_tree_view_get_selection(tree_view), 763 &source_model, &iter)) 764 return; 765 766 gtk_tree_model_get(source_model, &iter, 767 SUMCOL_TYPE, &type, 768 -1); 769 770 /* send the type */ 771 gtk_selection_data_set(data, gtk_selection_data_get_target(data), 8, 772 (gchar *) &type, sizeof type); 773 } 774 775 static void drag_data_received(GtkTreeView *tree_view, GdkDragContext *context, 776 gint x, gint y, GtkSelectionData *data, 777 guint info, guint time, GtkTreeModel *model) 778 { 779 GtkWidget *source; 780 GtkTreePath *dst = NULL, *sel = NULL; 781 GtkTreeIter isel, idst; 782 GtkTreeViewDropPosition pos; 783 FolderColumnType type; 784 GtkTreeModel *sel_model; 785 gchar *name; 786 787 source = gtk_drag_get_source_widget(context); 788 789 if (source == GTK_WIDGET(tree_view)) { 790 791 /* 792 * Same widget: re-order 793 */ 794 795 if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(tree_view), 796 NULL, &isel)) { 797 sel = gtk_tree_model_get_path(model, &isel); 798 gtk_tree_view_get_dest_row_at_pos(tree_view, x, y, 799 &dst, &pos); 800 801 /* NOTE: dst is invalid if selection beyond last row, in that 802 * case move beyond last one (XXX_move_before(..., NULL)) */ 803 804 if (dst) 805 gtk_tree_model_get_iter(model, &idst, dst); 806 else 807 gtk_list_store_move_before(GTK_LIST_STORE(model), 808 &isel, 809 NULL); 810 811 /* we do not drag if no valid dst and sel, and when 812 * dst and sel are the same (moving after or before 813 * itself doesn't change order...) */ 814 if ((dst && sel) && gtk_tree_path_compare(sel, dst) != 0) { 815 if (pos == GTK_TREE_VIEW_DROP_BEFORE 816 || pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE) 817 gtk_list_store_move_before(GTK_LIST_STORE(model), 818 &isel, 819 &idst); 820 else 821 gtk_list_store_move_after(GTK_LIST_STORE(model), 822 &isel, 823 &idst); 824 } 825 gtk_tree_path_free(dst); 826 gtk_tree_path_free(sel); 827 } 828 gtk_drag_finish(context, TRUE, FALSE, time); 829 830 } else if (source == folder_col.stock_list_view 831 || source == folder_col.shown_list_view) { 832 833 /* 834 * Other widget: change and update 835 */ 836 837 /* get source information and remove */ 838 if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection( 839 GTK_TREE_VIEW(source)), 840 &sel_model, &isel)) { 841 type = *((gint *) gtk_selection_data_get_data(data)); 842 name = col_name[type]; 843 gtk_list_store_remove(GTK_LIST_STORE(sel_model), &isel); 844 845 /* get insertion position */ 846 gtk_tree_view_get_dest_row_at_pos(tree_view, x, y, &dst, &pos); 847 848 /* NOTE: dst is invalid if insertion point beyond last row, 849 * just append to list in that case (XXX_store_append()) */ 850 851 if (dst) { 852 gtk_tree_model_get_iter(model, &idst, dst); 853 854 if (pos == GTK_TREE_VIEW_DROP_BEFORE 855 || pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE) 856 gtk_list_store_insert_before(GTK_LIST_STORE(model), 857 &isel, 858 &idst); 859 else 860 gtk_list_store_insert_after(GTK_LIST_STORE(model), 861 &isel, 862 &idst); 863 } else 864 gtk_list_store_append(GTK_LIST_STORE(model), 865 &isel); 866 867 gtk_list_store_set(GTK_LIST_STORE(model), &isel, 868 SUMCOL_NAME, name, 869 SUMCOL_TYPE, type, -1); 870 gtk_tree_path_free(dst); 871 } 872 gtk_drag_finish(context, TRUE, FALSE, time); 873 } 874 875 prefs_folder_column_shown_set_active(FALSE); 876 prefs_folder_column_stock_set_active(FALSE); 877 878 /* XXXX: should we call gtk_drag_finish() for other code paths? */ 879 } 880 881 static void prefs_folder_column_shown_set_btn_sensitivity(void) 882 { 883 GtkTreeModel *model = GTK_TREE_MODEL(gtk_tree_view_get_model( 884 GTK_TREE_VIEW(folder_col.shown_list_view))); 885 GtkTreeSelection *selection = gtk_tree_view_get_selection( 886 GTK_TREE_VIEW(folder_col.shown_list_view)); 887 GtkTreeIter iter; 888 GtkTreePath *path; 889 890 if(!gtk_tree_selection_get_selected(selection, NULL, &iter)) { 891 gtk_widget_set_sensitive(folder_col.remove_btn, FALSE); 892 gtk_widget_set_sensitive(folder_col.up_btn, FALSE); 893 gtk_widget_set_sensitive(folder_col.down_btn, FALSE); 894 return; 895 } 896 897 path = gtk_tree_model_get_path(model, &iter); 898 899 gtk_widget_set_sensitive(folder_col.up_btn, gtk_tree_path_prev(path)); 900 gtk_widget_set_sensitive(folder_col.down_btn, 901 gtk_tree_model_iter_next(model, &iter)); 902 gtk_tree_path_free(path); 903 } 904 905 static void prefs_folder_column_shown_set_active(const gboolean active) 906 { 907 GtkTreeSelection *selection = NULL; 908 909 gtk_widget_set_sensitive(folder_col.remove_btn, active); 910 911 if(active == FALSE) { 912 selection = gtk_tree_view_get_selection( 913 GTK_TREE_VIEW(folder_col.shown_list_view)); 914 gtk_tree_selection_unselect_all(selection); 915 916 gtk_widget_set_sensitive(folder_col.up_btn, FALSE); 917 gtk_widget_set_sensitive(folder_col.down_btn, FALSE); 918 } else { 919 prefs_folder_column_shown_set_btn_sensitivity(); 920 } 921 } 922 923 static void prefs_folder_column_stock_set_active(const gboolean active) 924 { 925 GtkTreeSelection *selection = NULL; 926 927 gtk_widget_set_sensitive(folder_col.add_btn, active); 928 929 if(active == FALSE) { 930 selection = gtk_tree_view_get_selection( 931 GTK_TREE_VIEW(folder_col.stock_list_view)); 932 gtk_tree_selection_unselect_all(selection); 933 } 934 } 935 936 static void prefs_folder_column_stock_sel_changed(void) 937 { 938 GtkTreeSelection *selection = gtk_tree_view_get_selection( 939 GTK_TREE_VIEW(folder_col.stock_list_view)); 940 prefs_folder_column_stock_set_active( 941 (selection != NULL) ? TRUE : FALSE); 942 prefs_folder_column_shown_set_active( 943 (selection != NULL) ? FALSE : TRUE); 944 } 945 946 static void prefs_folder_column_shown_sel_changed(void) 947 { 948 GtkTreeSelection *selection = gtk_tree_view_get_selection( 949 GTK_TREE_VIEW(folder_col.shown_list_view)); 950 prefs_folder_column_shown_set_active( 951 (selection != NULL) ? TRUE : FALSE); 952 prefs_folder_column_stock_set_active( 953 (selection != NULL) ? FALSE : TRUE); 954 }