Fix CID 1491093: attrib leaked if attvalue is null
[claws.git] / src / prefs_folder_column.c
blobd0633625b583cd357b94ac29b314e59af2a7bcc7
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
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.
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.
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/>.
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #include "claws-features.h"
22 #endif
24 #include "defs.h"
26 #include <glib.h>
27 #include <glib/gi18n.h>
28 #include <gtk/gtk.h>
29 #include <gdk/gdkkeysyms.h>
31 #include "prefs_gtk.h"
32 #include "prefs_common.h"
33 #include "prefs_folder_column.h"
34 #include "manage_window.h"
35 #include "folderview.h"
36 #include "mainwindow.h"
37 #include "inc.h"
38 #include "gtkutils.h"
39 #include "utils.h"
41 static void prefs_folder_column_set_config(FolderColumnState *state);
43 enum {
44 SUMCOL_NAME,
45 SUMCOL_TYPE,
46 N_SUMCOL_COLUMNS
49 #define TARGET_INFO_SUMCOL (0xFEEDBABE)
51 static const GtkTargetEntry row_targets[] = {
52 { "PREFS_SUM_COL_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_INFO_SUMCOL }
56 static struct _FolderColumnDialog
58 GtkWidget *window;
60 GtkWidget *stock_list_view;
61 GtkWidget *shown_list_view;
63 GtkWidget *add_btn;
64 GtkWidget *remove_btn;
65 GtkWidget *up_btn;
66 GtkWidget *down_btn;
68 GtkWidget *default_btn;
70 GtkWidget *ok_btn;
71 GtkWidget *cancel_btn;
73 gboolean finished;
74 } folder_col;
76 static const gchar *const col_name[N_FOLDER_COLS] = {
77 N_("Folder"), /* F_COL_FOLDER */
78 N_("New"), /* F_COL_NEW */
79 N_("Unread"), /* F_COL_UNREAD */
80 N_("Total"), /* F_COL_TOTAL */
83 static FolderColumnState default_state[N_FOLDER_COLS] = {
84 { F_COL_FOLDER , TRUE },
85 { F_COL_NEW , TRUE },
86 { F_COL_UNREAD , TRUE },
87 { F_COL_TOTAL , TRUE },
90 static void prefs_folder_column_create (void);
92 static void prefs_folder_column_set_dialog (FolderColumnState *state);
93 static void prefs_folder_column_set_view (void);
95 /* callback functions */
96 static void prefs_folder_column_add (void);
97 static void prefs_folder_column_remove (void);
99 static void prefs_folder_column_up (void);
100 static void prefs_folder_column_down (void);
102 static void prefs_folder_column_set_to_default (void);
104 static void prefs_folder_column_ok (void);
105 static void prefs_folder_column_cancel (void);
107 static gint prefs_folder_column_delete_event (GtkWidget *widget,
108 GdkEventAny *event,
109 gpointer data);
110 static gboolean prefs_folder_column_key_pressed(GtkWidget *widget,
111 GdkEventKey *event,
112 gpointer data);
114 static GtkListStore *prefs_folder_column_create_store (void);
116 static void prefs_folder_column_insert_column (GtkListStore *store,
117 gint row,
118 const gchar *name,
119 FolderColumnType type);
121 static FolderColumnType prefs_folder_column_get_column (GtkWidget *list,
122 gint row);
124 static GtkWidget *prefs_folder_column_list_view_create (const gchar *name);
126 static void prefs_filtering_create_list_view_columns (GtkWidget *list_view,
127 const gchar *name);
129 static void drag_data_get (GtkTreeView *tree_view,
130 GdkDragContext *context,
131 GtkSelectionData *data,
132 guint info,
133 guint time,
134 GtkTreeModel *model);
136 static void drag_data_received (GtkTreeView *tree_view,
137 GdkDragContext *context,
138 gint x, gint y,
139 GtkSelectionData *data,
140 guint info,
141 guint time,
142 GtkTreeModel *model);
144 static void prefs_folder_column_shown_set_btn_sensitivity(void);
145 static void prefs_folder_column_shown_set_active(const gboolean active);
146 static void prefs_folder_column_stock_set_active(const gboolean active);
147 static void prefs_folder_column_shown_sel_changed(void);
148 static void prefs_folder_column_stock_sel_changed(void);
151 void prefs_folder_column_open(void)
153 inc_lock();
155 if (!folder_col.window)
156 prefs_folder_column_create();
158 manage_window_set_transient(GTK_WINDOW(folder_col.window));
159 gtk_widget_grab_focus(folder_col.ok_btn);
161 prefs_folder_column_set_dialog(NULL);
163 gtk_widget_show(folder_col.window);
164 gtk_window_set_modal(GTK_WINDOW(folder_col.window), TRUE);
166 folder_col.finished = FALSE;
167 while (folder_col.finished == FALSE)
168 gtk_main_iteration();
170 gtk_widget_hide(folder_col.window);
171 gtk_window_set_modal(GTK_WINDOW(folder_col.window), FALSE);
173 inc_unlock();
176 static void prefs_folder_column_create(void)
178 GtkWidget *window;
179 GtkWidget *vbox;
181 GtkWidget *label_hbox;
182 GtkWidget *label;
184 GtkWidget *vbox1;
186 GtkWidget *hbox1;
187 GtkWidget *clist_hbox;
188 GtkWidget *scrolledwin;
189 GtkWidget *stock_list_view;
190 GtkWidget *shown_list_view;
192 GtkWidget *btn_vbox;
193 GtkWidget *add_btn;
194 GtkWidget *remove_btn;
195 GtkWidget *up_btn;
196 GtkWidget *down_btn;
198 GtkWidget *btn_hbox;
199 GtkWidget *default_btn;
200 GtkWidget *confirm_area;
201 GtkWidget *ok_btn;
202 GtkWidget *cancel_btn;
204 debug_print("Creating folder column setting window...\n");
206 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "prefs_folder_column");
207 gtk_container_set_border_width(GTK_CONTAINER(window), 8);
208 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
209 gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
210 gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
211 gtk_window_set_title(GTK_WINDOW(window),
212 _("Folder list columns configuration"));
213 g_signal_connect(G_OBJECT(window), "delete_event",
214 G_CALLBACK(prefs_folder_column_delete_event),
215 NULL);
216 g_signal_connect(G_OBJECT(window), "key_press_event",
217 G_CALLBACK(prefs_folder_column_key_pressed),
218 NULL);
220 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
221 gtk_widget_show(vbox);
222 gtk_container_add(GTK_CONTAINER(window), vbox);
224 label_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
225 gtk_widget_show(label_hbox);
226 gtk_box_pack_start(GTK_BOX(vbox), label_hbox, FALSE, FALSE, 4);
228 label = gtk_label_new
229 (_("Select columns to be displayed in the folder list. You can modify\n"
230 "the order by using the Up / Down buttons or by dragging the items."));
231 gtk_widget_show(label);
232 gtk_box_pack_start(GTK_BOX(label_hbox), label, FALSE, FALSE, 4);
233 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
235 vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, VSPACING);
236 gtk_widget_show(vbox1);
237 gtk_box_pack_start(GTK_BOX(vbox), vbox1, TRUE, TRUE, 0);
238 gtk_container_set_border_width(GTK_CONTAINER(vbox1), 2);
240 hbox1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
241 gtk_widget_show(hbox1);
242 gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, TRUE, 0);
244 clist_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
245 gtk_widget_show(clist_hbox);
246 gtk_box_pack_start(GTK_BOX(hbox1), clist_hbox, TRUE, TRUE, 0);
248 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
249 gtk_widget_set_size_request(scrolledwin, 180, 210);
250 gtk_widget_show(scrolledwin);
251 gtk_box_pack_start(GTK_BOX(clist_hbox), scrolledwin, TRUE, TRUE, 0);
252 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
253 GTK_POLICY_AUTOMATIC,
254 GTK_POLICY_AUTOMATIC);
255 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
256 GTK_SHADOW_IN);
258 stock_list_view = prefs_folder_column_list_view_create
259 (_("Hidden columns"));
260 g_signal_connect(G_OBJECT(stock_list_view), "cursor-changed",
261 G_CALLBACK(prefs_folder_column_stock_sel_changed),
262 NULL);
263 gtk_widget_show(stock_list_view);
264 gtk_container_add(GTK_CONTAINER(scrolledwin), stock_list_view);
266 /* add/remove button */
267 btn_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
268 gtk_widget_show(btn_vbox);
269 gtk_box_pack_start(GTK_BOX(hbox1), btn_vbox, FALSE, FALSE, 0);
271 add_btn = gtkut_stock_button("list-add", _("_Add"));
272 gtk_widget_show(add_btn);
273 gtk_box_pack_start(GTK_BOX(btn_vbox), add_btn, FALSE, TRUE, 0);
275 g_signal_connect(G_OBJECT(add_btn), "clicked",
276 G_CALLBACK(prefs_folder_column_add), NULL);
278 remove_btn = gtkut_stock_button("list-remove", _("_Remove"));
279 gtk_widget_show(remove_btn);
280 gtk_box_pack_start(GTK_BOX(btn_vbox), remove_btn, FALSE, TRUE, 0);
282 g_signal_connect(G_OBJECT(remove_btn), "clicked",
283 G_CALLBACK(prefs_folder_column_remove), NULL);
285 clist_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
286 gtk_widget_show(clist_hbox);
287 gtk_box_pack_start(GTK_BOX(hbox1), clist_hbox, TRUE, TRUE, 0);
289 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
290 gtk_widget_set_size_request(scrolledwin, 180, 210);
291 gtk_widget_show(scrolledwin);
292 gtk_box_pack_start(GTK_BOX(clist_hbox), scrolledwin, TRUE, TRUE, 0);
293 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
294 GTK_POLICY_AUTOMATIC,
295 GTK_POLICY_AUTOMATIC);
296 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
297 GTK_SHADOW_IN);
299 shown_list_view = prefs_folder_column_list_view_create
300 (_("Displayed columns"));
301 g_signal_connect(G_OBJECT(shown_list_view), "cursor-changed",
302 G_CALLBACK(prefs_folder_column_shown_sel_changed),
303 NULL);
304 gtk_widget_show(shown_list_view);
305 gtk_container_add(GTK_CONTAINER(scrolledwin), shown_list_view);
307 /* up/down button */
308 btn_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
309 gtk_widget_show(btn_vbox);
310 gtk_box_pack_start(GTK_BOX(hbox1), btn_vbox, FALSE, FALSE, 0);
312 up_btn = gtkut_stock_button("go-up", _("_Up"));
313 gtk_widget_show(up_btn);
314 gtk_box_pack_start(GTK_BOX(btn_vbox), up_btn, FALSE, TRUE, 0);
316 down_btn = gtkut_stock_button("go-down", _("_Down"));
317 gtk_widget_show(down_btn);
318 gtk_box_pack_start(GTK_BOX(btn_vbox), down_btn, FALSE, TRUE, 0);
320 g_signal_connect(G_OBJECT(up_btn), "clicked",
321 G_CALLBACK(prefs_folder_column_up), NULL);
322 g_signal_connect(G_OBJECT(down_btn), "clicked",
323 G_CALLBACK(prefs_folder_column_down), NULL);
325 btn_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
326 gtk_widget_show(btn_hbox);
327 gtk_box_pack_end(GTK_BOX(vbox), btn_hbox, FALSE, FALSE, 0);
329 btn_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
330 gtk_widget_show(btn_vbox);
331 gtk_box_pack_start(GTK_BOX(btn_hbox), btn_vbox, FALSE, FALSE, 0);
333 default_btn = gtk_button_new_with_label(_(" Use default "));
334 gtk_widget_show(default_btn);
335 gtk_box_pack_start(GTK_BOX(btn_vbox), default_btn, TRUE, FALSE, 0);
336 g_signal_connect(G_OBJECT(default_btn), "clicked",
337 G_CALLBACK(prefs_folder_column_set_to_default),
338 NULL);
340 gtkut_stock_button_set_create(&confirm_area,
341 &cancel_btn, NULL, _("_Cancel"),
342 &ok_btn, NULL, _("_OK"),
343 NULL, NULL, NULL);
344 gtk_widget_show(confirm_area);
345 gtk_box_pack_end(GTK_BOX(btn_hbox), confirm_area, FALSE, FALSE, 0);
346 gtk_widget_grab_default(ok_btn);
348 g_signal_connect(G_OBJECT(ok_btn), "clicked",
349 G_CALLBACK(prefs_folder_column_ok), NULL);
350 g_signal_connect(G_OBJECT(cancel_btn), "clicked",
351 G_CALLBACK(prefs_folder_column_cancel), NULL);
353 folder_col.window = window;
354 folder_col.add_btn = add_btn;
355 folder_col.remove_btn = remove_btn;
356 folder_col.up_btn = up_btn;
357 folder_col.down_btn = down_btn;
358 folder_col.ok_btn = ok_btn;
359 folder_col.cancel_btn = cancel_btn;
360 folder_col.stock_list_view = stock_list_view;
361 folder_col.shown_list_view = shown_list_view;
363 prefs_folder_column_shown_set_active(FALSE);
364 prefs_folder_column_stock_set_active(FALSE);
367 FolderColumnState *prefs_folder_column_get_config(void)
369 static FolderColumnState state[N_FOLDER_COLS];
370 FolderColumnType type;
371 gint pos;
373 for (pos = 0; pos < N_FOLDER_COLS; pos++)
374 state[pos].type = -1;
376 for (type = 0; type < N_FOLDER_COLS; type++) {
377 pos = prefs_common.folder_col_pos[type];
378 if (pos < 0 || pos >= N_FOLDER_COLS ||
379 state[pos].type != -1) {
380 g_warning("wrong column position");
381 prefs_folder_column_set_config(default_state);
382 return default_state;
385 state[pos].type = type;
386 state[pos].visible = prefs_common.folder_col_visible[type];
389 return state;
392 static void prefs_folder_column_set_config(FolderColumnState *state)
394 FolderColumnType type;
395 gint pos;
397 for (pos = 0; pos < N_FOLDER_COLS; pos++) {
398 type = state[pos].type;
399 prefs_common.folder_col_visible[type] = state[pos].visible;
400 prefs_common.folder_col_pos[type] = pos;
404 static void prefs_folder_column_set_dialog(FolderColumnState *state)
406 GtkListStore *stock_store, *shown_store;
407 gint pos;
408 FolderColumnType type;
409 gchar *name;
411 stock_store = GTK_LIST_STORE(gtk_tree_view_get_model
412 (GTK_TREE_VIEW(folder_col.stock_list_view)));
413 shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
414 (GTK_TREE_VIEW(folder_col.shown_list_view)));
416 gtk_list_store_clear(stock_store);
417 gtk_list_store_clear(shown_store);
419 if (!state)
420 state = prefs_folder_column_get_config();
422 for (pos = 0; pos < N_FOLDER_COLS; pos++) {
423 type = state[pos].type;
424 name = gettext(col_name[type]);
426 if (state[pos].visible)
427 prefs_folder_column_insert_column(shown_store,
428 -1, name,
429 type);
430 else
431 prefs_folder_column_insert_column(stock_store,
432 -1, name,
433 type);
437 static void prefs_folder_column_set_view(void)
439 gint stock_n_rows, shown_n_rows;
440 FolderColumnState state[N_FOLDER_COLS];
441 FolderColumnType type;
442 gint row, pos = 0;
444 stock_n_rows = gtk_tree_model_iter_n_children
445 (gtk_tree_view_get_model(GTK_TREE_VIEW
446 (folder_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 (folder_col.shown_list_view)), NULL);
451 cm_return_if_fail
452 (stock_n_rows + shown_n_rows == N_FOLDER_COLS);
454 for (row = 0; row < stock_n_rows; row++) {
455 type = prefs_folder_column_get_column
456 (folder_col.stock_list_view, row);
457 state[row].type = type;
458 state[row].visible = FALSE;
461 pos = row;
462 for (row = 0; row < shown_n_rows; row++) {
463 type = prefs_folder_column_get_column
464 (folder_col.shown_list_view, row);
465 state[pos + row].type = type;
466 state[pos + row].visible = TRUE;
469 prefs_folder_column_set_config(state);
470 main_window_set_folder_column();
473 static void prefs_folder_column_add(void)
475 GtkListStore *stock_store, *shown_store;
476 GtkTreeIter stock_sel, shown_sel, shown_add;
477 gboolean shown_sel_valid;
478 gchar *name;
479 FolderColumnType type;
481 stock_store = GTK_LIST_STORE(gtk_tree_view_get_model
482 (GTK_TREE_VIEW(folder_col.stock_list_view)));
483 shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
484 (GTK_TREE_VIEW(folder_col.shown_list_view)));
486 if (!gtk_tree_selection_get_selected
487 (gtk_tree_view_get_selection
488 (GTK_TREE_VIEW(folder_col.stock_list_view)),
489 NULL,
490 &stock_sel))
491 return;
493 shown_sel_valid = gtk_tree_selection_get_selected
494 (gtk_tree_view_get_selection
495 (GTK_TREE_VIEW(folder_col.shown_list_view)),
496 NULL,
497 &shown_sel);
499 gtk_tree_model_get(GTK_TREE_MODEL(stock_store), &stock_sel,
500 SUMCOL_TYPE, &type,
501 -1);
503 gtk_list_store_remove(stock_store, &stock_sel);
505 gtk_list_store_insert_after(shown_store, &shown_add,
506 shown_sel_valid ? &shown_sel : NULL);
508 name = gettext(col_name[type]);
510 gtk_list_store_set(shown_store, &shown_add,
511 SUMCOL_NAME, name,
512 SUMCOL_TYPE, type,
513 -1);
515 gtk_tree_selection_select_iter(gtk_tree_view_get_selection
516 (GTK_TREE_VIEW(folder_col.shown_list_view)),
517 &shown_add);
518 prefs_folder_column_shown_set_active(TRUE);
519 prefs_folder_column_stock_set_active(FALSE);
522 static void prefs_folder_column_remove(void)
524 GtkListStore *stock_store, *shown_store;
525 GtkTreeIter shown_sel, stock_sel, stock_add;
526 gboolean stock_sel_valid;
527 gchar *name;
528 FolderColumnType type;
530 stock_store = GTK_LIST_STORE(gtk_tree_view_get_model
531 (GTK_TREE_VIEW(folder_col.stock_list_view)));
532 shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
533 (GTK_TREE_VIEW(folder_col.shown_list_view)));
535 if (!gtk_tree_selection_get_selected
536 (gtk_tree_view_get_selection
537 (GTK_TREE_VIEW(folder_col.shown_list_view)),
538 NULL,
539 &shown_sel))
540 return;
542 stock_sel_valid = gtk_tree_selection_get_selected
543 (gtk_tree_view_get_selection
544 (GTK_TREE_VIEW(folder_col.stock_list_view)),
545 NULL,
546 &stock_sel);
548 gtk_tree_model_get(GTK_TREE_MODEL(shown_store), &shown_sel,
549 SUMCOL_TYPE, &type,
550 -1);
552 gtk_list_store_remove(shown_store, &shown_sel);
554 gtk_list_store_insert_after(stock_store, &stock_add,
555 stock_sel_valid ? &stock_sel : NULL);
557 name = gettext(col_name[type]);
559 gtk_list_store_set(stock_store, &stock_add,
560 SUMCOL_NAME, name,
561 SUMCOL_TYPE, type,
562 -1);
564 gtk_tree_selection_select_iter(gtk_tree_view_get_selection
565 (GTK_TREE_VIEW(folder_col.stock_list_view)),
566 &stock_add);
567 prefs_folder_column_shown_set_active(FALSE);
568 prefs_folder_column_stock_set_active(TRUE);
571 static void prefs_folder_column_up(void)
573 GtkTreePath *prev, *sel;
574 GtkTreeIter isel;
575 GtkListStore *shown_store;
576 GtkTreeIter iprev;
578 if (!gtk_tree_selection_get_selected
579 (gtk_tree_view_get_selection
580 (GTK_TREE_VIEW(folder_col.shown_list_view)),
581 NULL,
582 &isel))
583 return;
585 shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
586 (GTK_TREE_VIEW(folder_col.shown_list_view)));
588 sel = gtk_tree_model_get_path(GTK_TREE_MODEL(shown_store),
589 &isel);
590 if (!sel)
591 return;
593 prev = gtk_tree_path_copy(sel);
594 if (!gtk_tree_path_prev(prev)) {
595 gtk_tree_path_free(prev);
596 gtk_tree_path_free(sel);
597 return;
600 gtk_tree_model_get_iter(GTK_TREE_MODEL(shown_store),
601 &iprev, prev);
602 gtk_tree_path_free(sel);
603 gtk_tree_path_free(prev);
605 gtk_list_store_swap(shown_store, &iprev, &isel);
606 prefs_folder_column_shown_set_btn_sensitivity();
609 static void prefs_folder_column_down(void)
611 GtkListStore *shown_store;
612 GtkTreeIter next, sel;
614 if (!gtk_tree_selection_get_selected
615 (gtk_tree_view_get_selection
616 (GTK_TREE_VIEW(folder_col.shown_list_view)),
617 NULL,
618 &sel))
619 return;
621 shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
622 (GTK_TREE_VIEW(folder_col.shown_list_view)));
624 next = sel;
625 if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(shown_store), &next))
626 return;
628 gtk_list_store_swap(shown_store, &next, &sel);
629 prefs_folder_column_shown_set_btn_sensitivity();
632 static void prefs_folder_column_set_to_default(void)
634 prefs_folder_column_set_dialog(default_state);
635 prefs_folder_column_shown_set_active(FALSE);
636 prefs_folder_column_stock_set_active(FALSE);
639 static void prefs_folder_column_ok(void)
641 if (!folder_col.finished) {
642 folder_col.finished = TRUE;
643 prefs_folder_column_set_view();
647 static void prefs_folder_column_cancel(void)
649 folder_col.finished = TRUE;
652 static gint prefs_folder_column_delete_event(GtkWidget *widget,
653 GdkEventAny *event,
654 gpointer data)
656 folder_col.finished = TRUE;
657 return TRUE;
660 static gboolean prefs_folder_column_key_pressed(GtkWidget *widget,
661 GdkEventKey *event,
662 gpointer data)
664 if (event && event->keyval == GDK_KEY_Escape)
665 folder_col.finished = TRUE;
666 return FALSE;
669 static GtkListStore *prefs_folder_column_create_store(void)
671 return gtk_list_store_new(N_SUMCOL_COLUMNS,
672 G_TYPE_STRING,
673 G_TYPE_INT,
674 -1);
677 static void prefs_folder_column_insert_column(GtkListStore *store,
678 gint row,
679 const gchar *name,
680 FolderColumnType type)
682 GtkTreeIter iter;
684 if (row >= 0) {
685 if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store),
686 &iter, NULL, row))
687 row = -1;
689 if (row < 0) {
690 /* add new */
691 gtk_list_store_append(store, &iter);
692 gtk_list_store_set(store, &iter,
693 SUMCOL_NAME, name,
694 SUMCOL_TYPE, type,
695 -1);
696 return;
697 } else {
698 /* change existing */
699 gtk_list_store_set(store, &iter,
700 SUMCOL_NAME, name,
701 SUMCOL_TYPE, type,
702 -1);
707 *\brief Return the columnn type for a row
709 static FolderColumnType prefs_folder_column_get_column(GtkWidget *list, gint row)
711 GtkTreeView *list_view = GTK_TREE_VIEW(list);
712 GtkTreeModel *model = gtk_tree_view_get_model(list_view);
713 GtkTreeIter iter;
714 FolderColumnType result;
716 if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, row))
717 return -1;
719 gtk_tree_model_get(model, &iter,
720 SUMCOL_TYPE, &result,
721 -1);
723 return result;
726 static GtkWidget *prefs_folder_column_list_view_create(const gchar *name)
728 GtkWidget *list_view;
729 GtkTreeSelection *selector;
730 GtkTreeModel *model;
732 model = GTK_TREE_MODEL(prefs_folder_column_create_store());
733 list_view = gtk_tree_view_new_with_model(model);
734 g_object_unref(G_OBJECT(model));
736 selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
737 gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
739 prefs_filtering_create_list_view_columns(GTK_WIDGET(list_view), name);
741 gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(list_view),
742 GDK_BUTTON1_MASK,
743 row_targets,
744 G_N_ELEMENTS(row_targets),
745 GDK_ACTION_MOVE);
747 gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(list_view),
748 row_targets,
749 G_N_ELEMENTS(row_targets),
750 GDK_ACTION_MOVE);
752 g_signal_connect(G_OBJECT(list_view), "drag_data_get",
753 G_CALLBACK(drag_data_get),
754 model);
756 g_signal_connect(G_OBJECT(list_view), "drag_data_received",
757 G_CALLBACK(drag_data_received),
758 model);
760 return list_view;
763 static void prefs_filtering_create_list_view_columns(GtkWidget *list_view,
764 const gchar *name)
766 GtkTreeViewColumn *column;
767 GtkCellRenderer *renderer;
769 renderer = gtk_cell_renderer_text_new();
770 column = gtk_tree_view_column_new_with_attributes
771 (name, renderer, "text", SUMCOL_NAME, NULL);
772 gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
775 static void drag_data_get(GtkTreeView *tree_view, GdkDragContext *context,
776 GtkSelectionData *data, guint info,
777 guint time, GtkTreeModel *model)
779 GtkTreeIter iter;
780 FolderColumnType type;
781 GtkTreeModel *source_model;
783 if (info != TARGET_INFO_SUMCOL)
784 return;
786 if (!gtk_tree_selection_get_selected
787 (gtk_tree_view_get_selection(tree_view),
788 &source_model, &iter))
789 return;
791 gtk_tree_model_get(source_model, &iter,
792 SUMCOL_TYPE, &type,
793 -1);
795 /* send the type */
796 gtk_selection_data_set(data, gtk_selection_data_get_target(data), 8,
797 (gchar *) &type, sizeof type);
800 static void drag_data_received(GtkTreeView *tree_view, GdkDragContext *context,
801 gint x, gint y, GtkSelectionData *data,
802 guint info, guint time, GtkTreeModel *model)
804 GtkWidget *source;
805 GtkTreePath *dst = NULL, *sel = NULL;
806 GtkTreeIter isel, idst;
807 GtkTreeViewDropPosition pos;
808 FolderColumnType type;
809 GtkTreeModel *sel_model;
810 gchar *name;
812 source = gtk_drag_get_source_widget(context);
814 if (source == GTK_WIDGET(tree_view)) {
817 * Same widget: re-order
820 if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(tree_view),
821 NULL, &isel)) {
822 sel = gtk_tree_model_get_path(model, &isel);
823 gtk_tree_view_get_dest_row_at_pos(tree_view, x, y,
824 &dst, &pos);
826 /* NOTE: dst is invalid if selection beyond last row, in that
827 * case move beyond last one (XXX_move_before(..., NULL)) */
829 if (dst)
830 gtk_tree_model_get_iter(model, &idst, dst);
831 else
832 gtk_list_store_move_before(GTK_LIST_STORE(model),
833 &isel,
834 NULL);
836 /* we do not drag if no valid dst and sel, and when
837 * dst and sel are the same (moving after or before
838 * itself doesn't change order...) */
839 if ((dst && sel) && gtk_tree_path_compare(sel, dst) != 0) {
840 if (pos == GTK_TREE_VIEW_DROP_BEFORE
841 || pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
842 gtk_list_store_move_before(GTK_LIST_STORE(model),
843 &isel,
844 &idst);
845 else
846 gtk_list_store_move_after(GTK_LIST_STORE(model),
847 &isel,
848 &idst);
850 gtk_tree_path_free(dst);
851 gtk_tree_path_free(sel);
853 gtk_drag_finish(context, TRUE, FALSE, time);
855 } else if (source == folder_col.stock_list_view
856 || source == folder_col.shown_list_view) {
859 * Other widget: change and update
862 /* get source information and remove */
863 if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(
864 GTK_TREE_VIEW(source)),
865 &sel_model, &isel)) {
866 type = *((gint *) gtk_selection_data_get_data(data));
867 name = gettext(col_name[type]);
868 gtk_list_store_remove(GTK_LIST_STORE(sel_model), &isel);
870 /* get insertion position */
871 gtk_tree_view_get_dest_row_at_pos(tree_view, x, y, &dst, &pos);
873 /* NOTE: dst is invalid if insertion point beyond last row,
874 * just append to list in that case (XXX_store_append()) */
876 if (dst) {
877 gtk_tree_model_get_iter(model, &idst, dst);
879 if (pos == GTK_TREE_VIEW_DROP_BEFORE
880 || pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
881 gtk_list_store_insert_before(GTK_LIST_STORE(model),
882 &isel,
883 &idst);
884 else
885 gtk_list_store_insert_after(GTK_LIST_STORE(model),
886 &isel,
887 &idst);
888 } else
889 gtk_list_store_append(GTK_LIST_STORE(model),
890 &isel);
892 gtk_list_store_set(GTK_LIST_STORE(model), &isel,
893 SUMCOL_NAME, name,
894 SUMCOL_TYPE, type, -1);
895 gtk_tree_path_free(dst);
897 gtk_drag_finish(context, TRUE, FALSE, time);
900 prefs_folder_column_shown_set_active(FALSE);
901 prefs_folder_column_stock_set_active(FALSE);
903 /* XXXX: should we call gtk_drag_finish() for other code paths? */
906 static void prefs_folder_column_shown_set_btn_sensitivity(void)
908 GtkTreeModel *model = GTK_TREE_MODEL(gtk_tree_view_get_model(
909 GTK_TREE_VIEW(folder_col.shown_list_view)));
910 GtkTreeSelection *selection = gtk_tree_view_get_selection(
911 GTK_TREE_VIEW(folder_col.shown_list_view));
912 GtkTreeIter iter;
913 GtkTreePath *path;
915 if(!gtk_tree_selection_get_selected(selection, NULL, &iter)) {
916 gtk_widget_set_sensitive(folder_col.remove_btn, FALSE);
917 gtk_widget_set_sensitive(folder_col.up_btn, FALSE);
918 gtk_widget_set_sensitive(folder_col.down_btn, FALSE);
919 return;
922 path = gtk_tree_model_get_path(model, &iter);
924 gtk_widget_set_sensitive(folder_col.up_btn, gtk_tree_path_prev(path));
925 gtk_widget_set_sensitive(folder_col.down_btn,
926 gtk_tree_model_iter_next(model, &iter));
927 gtk_tree_path_free(path);
930 static void prefs_folder_column_shown_set_active(const gboolean active)
932 GtkTreeSelection *selection = NULL;
934 gtk_widget_set_sensitive(folder_col.remove_btn, active);
936 if(active == FALSE) {
937 selection = gtk_tree_view_get_selection(
938 GTK_TREE_VIEW(folder_col.shown_list_view));
939 gtk_tree_selection_unselect_all(selection);
941 gtk_widget_set_sensitive(folder_col.up_btn, FALSE);
942 gtk_widget_set_sensitive(folder_col.down_btn, FALSE);
943 } else {
944 prefs_folder_column_shown_set_btn_sensitivity();
948 static void prefs_folder_column_stock_set_active(const gboolean active)
950 GtkTreeSelection *selection = NULL;
952 gtk_widget_set_sensitive(folder_col.add_btn, active);
954 if(active == FALSE) {
955 selection = gtk_tree_view_get_selection(
956 GTK_TREE_VIEW(folder_col.stock_list_view));
957 gtk_tree_selection_unselect_all(selection);
961 static void prefs_folder_column_stock_sel_changed(void)
963 GtkTreeSelection *selection = gtk_tree_view_get_selection(
964 GTK_TREE_VIEW(folder_col.stock_list_view));
965 prefs_folder_column_stock_set_active(
966 (selection != NULL) ? TRUE : FALSE);
967 prefs_folder_column_shown_set_active(
968 (selection != NULL) ? FALSE : TRUE);
971 static void prefs_folder_column_shown_sel_changed(void)
973 GtkTreeSelection *selection = gtk_tree_view_get_selection(
974 GTK_TREE_VIEW(folder_col.shown_list_view));
975 prefs_folder_column_shown_set_active(
976 (selection != NULL) ? TRUE : FALSE);
977 prefs_folder_column_stock_set_active(
978 (selection != NULL) ? FALSE : TRUE);