3bb6a9ab57dabc0dbf171177d4b5791fb6a48aa5
[claws.git] / src / prefs_summary_column.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2001 Hiroyuki Yamamoto
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 <gtk/gtkmain.h>
28 #include <gtk/gtkwindow.h>
29 #include <gtk/gtkvbox.h>
30 #include <gtk/gtkhbox.h>
31 #include <gtk/gtkclist.h>
32 #include <gtk/gtkbutton.h>
33 #include <gdk/gdkkeysyms.h>
34
35 #include "intl.h"
36 #include "prefs.h"
37 #include "prefs_common.h"
38 #include "prefs_summary_column.h"
39 #include "manage_window.h"
40 #include "summaryview.h"
41 #include "mainwindow.h"
42 #include "inc.h"
43 #include "gtkutils.h"
44 #include "utils.h"
45
46 static struct _SummaryColumnDialog
47 {
48         GtkWidget *window;
49
50         GtkWidget *stock_clist;
51         GtkWidget *shown_clist;
52
53         GtkWidget *add_btn;
54         GtkWidget *remove_btn;
55         GtkWidget *up_btn;
56         GtkWidget *down_btn;
57
58         GtkWidget *default_btn;
59
60         GtkWidget *ok_btn;
61         GtkWidget *cancel_btn;
62
63         gboolean finished;
64 } summary_col;
65
66 static const gchar *const col_name[N_SUMMARY_COLS] = {
67         N_("Mark"),             /* S_COL_MARK    */
68         N_("Unread"),           /* S_COL_UNREAD  */
69         N_("Attachment"),       /* S_COL_MIME    */
70         N_("Subject"),          /* S_COL_SUBJECT */
71         N_("From"),             /* S_COL_FROM    */
72         N_("Date"),             /* S_COL_DATE    */
73         N_("Size"),             /* S_COL_SIZE    */
74         N_("Number"),           /* S_COL_NUMBER  */
75         N_("Score")             /* S_COL_SCORE   */
76 };
77
78 static SummaryColumnState default_state[N_SUMMARY_COLS] = {
79         { S_COL_MARK   , TRUE  },
80         { S_COL_UNREAD , TRUE  },
81         { S_COL_MIME   , TRUE  },
82         { S_COL_SUBJECT, TRUE  },
83         { S_COL_FROM   , TRUE  },
84         { S_COL_DATE   , TRUE  },
85         { S_COL_SIZE   , TRUE  },
86         { S_COL_NUMBER , FALSE },
87         { S_COL_SCORE  , FALSE }
88 };
89
90 static void prefs_summary_column_create (void);
91
92 static void prefs_summary_column_set_dialog     (SummaryColumnState *state);
93 static void prefs_summary_column_set_view       (void);
94
95 /* callback functions */
96 static void prefs_summary_column_add    (void);
97 static void prefs_summary_column_remove (void);
98
99 static void prefs_summary_column_up     (void);
100 static void prefs_summary_column_down   (void);
101
102 static void prefs_summary_column_set_to_default (void);
103
104 static void prefs_summary_column_ok     (void);
105 static void prefs_summary_column_cancel (void);
106
107 static gint prefs_summary_column_delete_event   (GtkWidget      *widget,
108                                                  GdkEventAny    *event,
109                                                  gpointer        data);
110 static void prefs_summary_column_key_pressed    (GtkWidget      *widget,
111                                                  GdkEventKey    *event,
112                                                  gpointer        data);
113
114 void prefs_summary_column_open(void)
115 {
116         inc_lock();
117
118         if (!summary_col.window)
119                 prefs_summary_column_create();
120
121         manage_window_set_transient(GTK_WINDOW(summary_col.window));
122         gtk_widget_grab_focus(summary_col.ok_btn);
123
124         prefs_summary_column_set_dialog(NULL);
125
126         gtk_widget_show(summary_col.window);
127
128         summary_col.finished = FALSE;
129         while (summary_col.finished == FALSE)
130                 gtk_main_iteration();
131
132         gtk_widget_hide(summary_col.window);
133
134         inc_unlock();
135 }
136
137 static void prefs_summary_column_create(void)
138 {
139         GtkWidget *window;
140         GtkWidget *vbox;
141
142         GtkWidget *label_hbox;
143         GtkWidget *label;
144
145         GtkWidget *vbox1;
146
147         GtkWidget *hbox1;
148         GtkWidget *clist_hbox;
149         GtkWidget *scrolledwin;
150         GtkWidget *stock_clist;
151         GtkWidget *shown_clist;
152
153         GtkWidget *btn_vbox;
154         GtkWidget *btn_vbox1;
155         GtkWidget *add_btn;
156         GtkWidget *remove_btn;
157         GtkWidget *up_btn;
158         GtkWidget *down_btn;
159
160         GtkWidget *btn_hbox;
161         GtkWidget *default_btn;
162         GtkWidget *confirm_area;
163         GtkWidget *ok_btn;
164         GtkWidget *cancel_btn;
165
166         gchar *title[1];
167
168         debug_print(_("Creating summary column setting window...\n"));
169
170         window = gtk_window_new(GTK_WINDOW_DIALOG);
171         gtk_container_set_border_width(GTK_CONTAINER(window), 8);
172         gtk_window_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
173         gtk_window_set_modal(GTK_WINDOW(window), TRUE);
174         gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE);
175         gtk_window_set_title(GTK_WINDOW(window),
176                              _("Summary display item setting"));
177         gtk_signal_connect(GTK_OBJECT(window), "delete_event",
178                            GTK_SIGNAL_FUNC(prefs_summary_column_delete_event),
179                            NULL);
180         gtk_signal_connect(GTK_OBJECT(window), "key_press_event",
181                            GTK_SIGNAL_FUNC(prefs_summary_column_key_pressed),
182                            NULL);
183
184         vbox = gtk_vbox_new(FALSE, 6);
185         gtk_widget_show(vbox);
186         gtk_container_add(GTK_CONTAINER(window), vbox);
187
188         label_hbox = gtk_hbox_new(FALSE, 0);
189         gtk_widget_show(label_hbox);
190         gtk_box_pack_start(GTK_BOX(vbox), label_hbox, FALSE, FALSE, 4);
191
192         label = gtk_label_new
193                 (_("Select items to be displayed on the summary view. You can modify\n"
194                    "the order by using the Up / Down button, or dragging the items."));
195         gtk_widget_show(label);
196         gtk_box_pack_start(GTK_BOX(label_hbox), label, FALSE, FALSE, 4);
197         gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
198
199         vbox1 = gtk_vbox_new(FALSE, VSPACING);
200         gtk_widget_show(vbox1);
201         gtk_box_pack_start(GTK_BOX(vbox), vbox1, TRUE, TRUE, 0);
202         gtk_container_set_border_width(GTK_CONTAINER(vbox1), 2);
203
204         hbox1 = gtk_hbox_new(FALSE, 8);
205         gtk_widget_show(hbox1);
206         gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, TRUE, 0);
207
208         clist_hbox = gtk_hbox_new(FALSE, 8);
209         gtk_widget_show(clist_hbox);
210         gtk_box_pack_start(GTK_BOX(hbox1), clist_hbox, TRUE, TRUE, 0);
211
212         scrolledwin = gtk_scrolled_window_new(NULL, NULL);
213         gtk_widget_set_usize(scrolledwin, 180, 210);
214         gtk_widget_show(scrolledwin);
215         gtk_box_pack_start(GTK_BOX(clist_hbox), scrolledwin, TRUE, TRUE, 0);
216         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
217                                        GTK_POLICY_AUTOMATIC,
218                                        GTK_POLICY_AUTOMATIC);
219
220         title[0] = _("Available items");
221         stock_clist = gtk_clist_new_with_titles(1, title);
222         gtk_widget_show(stock_clist);
223         gtk_container_add(GTK_CONTAINER(scrolledwin), stock_clist);
224         gtk_clist_set_selection_mode(GTK_CLIST(stock_clist),
225                                      GTK_SELECTION_BROWSE);
226         GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(stock_clist)->column[0].button,
227                                GTK_CAN_FOCUS);
228
229         /* add/remove button */
230         btn_vbox = gtk_vbox_new(FALSE, 0);
231         gtk_widget_show(btn_vbox);
232         gtk_box_pack_start(GTK_BOX(hbox1), btn_vbox, FALSE, FALSE, 0);
233
234         btn_vbox1 = gtk_vbox_new(FALSE, 8);
235         gtk_widget_show(btn_vbox1);
236         gtk_box_pack_start(GTK_BOX(btn_vbox), btn_vbox1, TRUE, FALSE, 0);
237
238         add_btn = gtk_button_new_with_label(_("  ->  "));
239         gtk_widget_show(add_btn);
240         gtk_box_pack_start(GTK_BOX(btn_vbox1), add_btn, FALSE, FALSE, 0);
241
242         remove_btn = gtk_button_new_with_label(_("  <-  "));
243         gtk_widget_show(remove_btn);
244         gtk_box_pack_start(GTK_BOX(btn_vbox1), remove_btn, FALSE, FALSE, 0);
245
246         gtk_signal_connect(GTK_OBJECT(add_btn), "clicked",
247                            GTK_SIGNAL_FUNC(prefs_summary_column_add), NULL);
248         gtk_signal_connect(GTK_OBJECT(remove_btn), "clicked",
249                            GTK_SIGNAL_FUNC(prefs_summary_column_remove), NULL);
250
251         clist_hbox = gtk_hbox_new(FALSE, 8);
252         gtk_widget_show(clist_hbox);
253         gtk_box_pack_start(GTK_BOX(hbox1), clist_hbox, TRUE, TRUE, 0);
254
255         scrolledwin = gtk_scrolled_window_new(NULL, NULL);
256         gtk_widget_set_usize(scrolledwin, 180, 210);
257         gtk_widget_show(scrolledwin);
258         gtk_box_pack_start(GTK_BOX(clist_hbox), scrolledwin, TRUE, TRUE, 0);
259         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
260                                        GTK_POLICY_AUTOMATIC,
261                                        GTK_POLICY_AUTOMATIC);
262
263         title[0] = _("Displayed items");
264         shown_clist = gtk_clist_new_with_titles(1, title);
265         gtk_widget_show(shown_clist);
266         gtk_container_add(GTK_CONTAINER(scrolledwin), shown_clist);
267         gtk_clist_set_selection_mode(GTK_CLIST(shown_clist),
268                                      GTK_SELECTION_BROWSE);
269         gtk_clist_set_reorderable(GTK_CLIST(shown_clist), TRUE);
270         gtk_clist_set_use_drag_icons(GTK_CLIST(shown_clist), FALSE);
271         GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(shown_clist)->column[0].button,
272                                GTK_CAN_FOCUS);
273
274         /* up/down button */
275         btn_vbox = gtk_vbox_new(FALSE, 0);
276         gtk_widget_show(btn_vbox);
277         gtk_box_pack_start(GTK_BOX(hbox1), btn_vbox, FALSE, FALSE, 0);
278
279         btn_vbox1 = gtk_vbox_new(FALSE, 8);
280         gtk_widget_show(btn_vbox1);
281         gtk_box_pack_start(GTK_BOX(btn_vbox), btn_vbox1, TRUE, FALSE, 0);
282
283         up_btn = gtk_button_new_with_label(_("Up"));
284         gtk_widget_show(up_btn);
285         gtk_box_pack_start(GTK_BOX(btn_vbox1), up_btn, FALSE, FALSE, 0);
286
287         down_btn = gtk_button_new_with_label(_("Down"));
288         gtk_widget_show(down_btn);
289         gtk_box_pack_start(GTK_BOX(btn_vbox1), down_btn, FALSE, FALSE, 0);
290
291         gtk_signal_connect(GTK_OBJECT(up_btn), "clicked",
292                            GTK_SIGNAL_FUNC(prefs_summary_column_up), NULL);
293         gtk_signal_connect(GTK_OBJECT(down_btn), "clicked",
294                            GTK_SIGNAL_FUNC(prefs_summary_column_down), NULL);
295
296         btn_hbox = gtk_hbox_new(FALSE, 8);
297         gtk_widget_show(btn_hbox);
298         gtk_box_pack_end(GTK_BOX(vbox), btn_hbox, FALSE, FALSE, 0);
299
300         btn_vbox = gtk_vbox_new(FALSE, 0);
301         gtk_widget_show(btn_vbox);
302         gtk_box_pack_start(GTK_BOX(btn_hbox), btn_vbox, FALSE, FALSE, 0);
303
304         default_btn = gtk_button_new_with_label(_(" Revert to default "));
305         gtk_widget_show(default_btn);
306         gtk_box_pack_start(GTK_BOX(btn_vbox), default_btn, TRUE, FALSE, 0);
307         gtk_signal_connect(GTK_OBJECT(default_btn), "clicked",
308                            GTK_SIGNAL_FUNC(prefs_summary_column_set_to_default),
309                            NULL);
310
311         gtkut_button_set_create(&confirm_area, &ok_btn, _("OK"),
312                                 &cancel_btn, _("Cancel"), NULL, NULL);
313         gtk_widget_show(confirm_area);
314         gtk_box_pack_end(GTK_BOX(btn_hbox), confirm_area, FALSE, FALSE, 0);
315         gtk_widget_grab_default(ok_btn);
316
317         gtk_signal_connect(GTK_OBJECT(ok_btn), "clicked",
318                            GTK_SIGNAL_FUNC(prefs_summary_column_ok), NULL);
319         gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked",
320                            GTK_SIGNAL_FUNC(prefs_summary_column_cancel), NULL);
321
322         summary_col.window      = window;
323         summary_col.stock_clist = stock_clist;
324         summary_col.shown_clist = shown_clist;
325         summary_col.add_btn     = add_btn;
326         summary_col.remove_btn  = remove_btn;
327         summary_col.up_btn      = up_btn;
328         summary_col.down_btn    = down_btn;
329         summary_col.ok_btn      = ok_btn;
330         summary_col.cancel_btn  = cancel_btn;
331 }
332
333 SummaryColumnState *prefs_summary_column_get_config(void)
334 {
335         static SummaryColumnState state[N_SUMMARY_COLS];
336         SummaryColumnType type;
337         gint pos;
338
339         for (pos = 0; pos < N_SUMMARY_COLS; pos++)
340                 state[pos].type = -1;
341
342         for (type = 0; type < N_SUMMARY_COLS; type++) {
343                 pos = prefs_common.summary_col_pos[type];
344                 if (pos < 0 || pos >= N_SUMMARY_COLS ||
345                     state[pos].type != -1) {
346                         g_warning("Wrong column position\n");
347                         prefs_summary_column_set_config(default_state);
348                         return default_state;
349                 }
350
351                 state[pos].type = type;
352                 state[pos].visible = prefs_common.summary_col_visible[type];
353         }
354
355         return state;
356 }
357
358 void prefs_summary_column_set_config(SummaryColumnState *state)
359 {
360         SummaryColumnType type;
361         gint pos;
362
363         for (pos = 0; pos < N_SUMMARY_COLS; pos++) {
364                 type = state[pos].type;
365                 prefs_common.summary_col_visible[type] = state[pos].visible;
366                 prefs_common.summary_col_pos[type] = pos;
367         }
368 }
369
370 static void prefs_summary_column_set_dialog(SummaryColumnState *state)
371 {
372         GtkCList *stock_clist = GTK_CLIST(summary_col.stock_clist);
373         GtkCList *shown_clist = GTK_CLIST(summary_col.shown_clist);
374         gint pos;
375         SummaryColumnType type;
376         gchar *name;
377
378         gtk_clist_clear(stock_clist);
379         gtk_clist_clear(shown_clist);
380
381         if (!state)
382                 state = prefs_summary_column_get_config();
383
384         for (pos = 0; pos < N_SUMMARY_COLS; pos++) {
385                 gint row;
386                 type = state[pos].type;
387                 name = gettext(col_name[type]);
388
389                 if (state[pos].visible) {
390                         row = gtk_clist_append(shown_clist, (gchar **)&name);
391                         gtk_clist_set_row_data(shown_clist, row,
392                                                GINT_TO_POINTER(type));
393                 } else {
394                         row = gtk_clist_append(stock_clist, (gchar **)&name);
395                         gtk_clist_set_row_data(stock_clist, row,
396                                                GINT_TO_POINTER(type));
397                 }
398         }
399 }
400
401 static void prefs_summary_column_set_view(void)
402 {
403         GtkCList *stock_clist = GTK_CLIST(summary_col.stock_clist);
404         GtkCList *shown_clist = GTK_CLIST(summary_col.shown_clist);
405         SummaryColumnState state[N_SUMMARY_COLS];
406         SummaryColumnType type;
407         gint row, pos = 0;
408
409         g_return_if_fail
410                 (stock_clist->rows + shown_clist->rows == N_SUMMARY_COLS);
411
412         for (row = 0; row < stock_clist->rows; row++) {
413                 type = GPOINTER_TO_INT
414                         (gtk_clist_get_row_data(stock_clist, row));
415                 state[row].type = type;
416                 state[row].visible = FALSE;
417         }
418
419         pos = row;
420         for (row = 0; row < shown_clist->rows; row++) {
421                 type = GPOINTER_TO_INT
422                         (gtk_clist_get_row_data(shown_clist, row));
423                 state[pos + row].type = type;
424                 state[pos + row].visible = TRUE;
425         }
426
427         prefs_summary_column_set_config(state);
428         main_window_set_summary_column();
429 }
430
431 static void prefs_summary_column_add(void)
432 {
433         GtkCList *stock_clist = GTK_CLIST(summary_col.stock_clist);
434         GtkCList *shown_clist = GTK_CLIST(summary_col.shown_clist);
435         gint row;
436         SummaryColumnType type;
437         gchar *name;
438
439         if (!stock_clist->selection) return;
440
441         row = GPOINTER_TO_INT(stock_clist->selection->data);
442         type = GPOINTER_TO_INT(gtk_clist_get_row_data(stock_clist, row));
443         gtk_clist_remove(stock_clist, row);
444         if (stock_clist->rows == row)
445                 gtk_clist_select_row(stock_clist, row - 1, -1);
446
447         if (!shown_clist->selection)
448                 row = 0;
449         else
450                 row = GPOINTER_TO_INT(shown_clist->selection->data) + 1;
451
452         name = gettext(col_name[type]);
453         row = gtk_clist_insert(shown_clist, row, (gchar **)&name);
454         gtk_clist_set_row_data(shown_clist, row, GINT_TO_POINTER(type));
455         gtk_clist_select_row(shown_clist, row, -1);
456 }
457
458 static void prefs_summary_column_remove(void)
459 {
460         GtkCList *stock_clist = GTK_CLIST(summary_col.stock_clist);
461         GtkCList *shown_clist = GTK_CLIST(summary_col.shown_clist);
462         gint row;
463         SummaryColumnType type;
464         gchar *name;
465
466         if (!shown_clist->selection) return;
467
468         row = GPOINTER_TO_INT(shown_clist->selection->data);
469         type = GPOINTER_TO_INT(gtk_clist_get_row_data(shown_clist, row));
470         gtk_clist_remove(shown_clist, row);
471         if (shown_clist->rows == row)
472                 gtk_clist_select_row(shown_clist, row - 1, -1);
473
474         if (!stock_clist->selection)
475                 row = 0;
476         else
477                 row = GPOINTER_TO_INT(stock_clist->selection->data) + 1;
478
479         name = gettext(col_name[type]);
480         row = gtk_clist_insert(stock_clist, row, (gchar **)&name);
481         gtk_clist_set_row_data(stock_clist, row, GINT_TO_POINTER(type));
482         gtk_clist_select_row(stock_clist, row, -1);
483 }
484
485 static void prefs_summary_column_up(void)
486 {
487         GtkCList *clist = GTK_CLIST(summary_col.shown_clist);
488         gint row;
489
490         if (!clist->selection) return;
491
492         row = GPOINTER_TO_INT(clist->selection->data);
493         if (row > 0)
494                 gtk_clist_row_move(clist, row, row - 1);
495 }
496
497 static void prefs_summary_column_down(void)
498 {
499         GtkCList *clist = GTK_CLIST(summary_col.shown_clist);
500         gint row;
501
502         if (!clist->selection) return;
503
504         row = GPOINTER_TO_INT(clist->selection->data);
505         if (row >= 0 && row < clist->rows - 1)
506                 gtk_clist_row_move(clist, row, row + 1);
507 }
508
509 static void prefs_summary_column_set_to_default(void)
510 {
511         prefs_summary_column_set_dialog(default_state);
512 }
513
514 static void prefs_summary_column_ok(void)
515 {
516         if (!summary_col.finished) {
517                 summary_col.finished = TRUE;
518                 prefs_summary_column_set_view();
519         }
520 }
521
522 static void prefs_summary_column_cancel(void)
523 {
524         summary_col.finished = TRUE;
525 }
526
527 static gint prefs_summary_column_delete_event(GtkWidget *widget,
528                                               GdkEventAny *event,
529                                               gpointer data)
530 {
531         summary_col.finished = TRUE;
532         return TRUE;
533 }
534
535 static void prefs_summary_column_key_pressed(GtkWidget *widget,
536                                              GdkEventKey *event,
537                                              gpointer data)
538 {
539         if (event && event->keyval == GDK_Escape)
540                 summary_col.finished = TRUE;
541 }