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