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