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