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