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