2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2004 Hiroyuki Yamamoto & The Sylpheed-Claws Team
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.
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.
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.
30 #include <glib/gi18n.h>
32 #include <gdk/gdkkeysyms.h>
34 #include "prefs_common.h"
35 #include "prefs_gtk.h"
36 #include "prefs_summary_column.h"
38 #include "gtk/gtkutils.h"
39 #include "gtk/prefswindow.h"
41 #include "manage_window.h"
43 typedef struct _SummariesPage
49 GtkWidget *chkbtn_transhdr;
50 GtkWidget *chkbtn_folder_unread;
51 GtkWidget *spinbtn_ng_abbrev_len;
52 GtkWidget *chkbtn_swapfrom;
53 GtkWidget *chkbtn_useaddrbook;
54 GtkWidget *chkbtn_threadsubj;
55 GtkWidget *button_datefmt;
56 GtkWidget *entry_datefmt;
65 static void date_format_ok_btn_clicked (GtkButton *button,
67 static void date_format_cancel_btn_clicked (GtkButton *button,
69 static gboolean date_format_key_pressed (GtkWidget *keywidget,
72 static gboolean date_format_on_delete (GtkWidget *dialogwidget,
75 static void date_format_entry_on_change (GtkEditable *editable,
77 static void date_format_select_row (GtkTreeView *list_view,
79 GtkTreeViewColumn *column,
80 GtkWidget *date_format);
82 static GtkWidget *date_format_create(GtkButton *button, void *data)
84 static GtkWidget *datefmt_win = NULL;
87 GtkWidget *scrolledwindow1;
88 GtkWidget *datefmt_list_view;
93 GtkWidget *confirm_area;
95 GtkWidget *cancel_btn;
96 GtkWidget *datefmt_entry;
126 const gint TIME_FORMAT_ELEMS =
127 sizeof time_format / sizeof time_format[0];
129 GtkCellRenderer *renderer;
130 GtkTreeViewColumn *column;
131 GtkTreeSelection *selection;
133 time_format[0].txt = _("the full abbreviated weekday name");
134 time_format[1].txt = _("the full weekday name");
135 time_format[2].txt = _("the abbreviated month name");
136 time_format[3].txt = _("the full month name");
137 time_format[4].txt = _("the preferred date and time for the current locale");
138 time_format[5].txt = _("the century number (year/100)");
139 time_format[6].txt = _("the day of the month as a decimal number");
140 time_format[7].txt = _("the hour as a decimal number using a 24-hour clock");
141 time_format[8].txt = _("the hour as a decimal number using a 12-hour clock");
142 time_format[9].txt = _("the day of the year as a decimal number");
143 time_format[10].txt = _("the month as a decimal number");
144 time_format[11].txt = _("the minute as a decimal number");
145 time_format[12].txt = _("either AM or PM");
146 time_format[13].txt = _("the second as a decimal number");
147 time_format[14].txt = _("the day of the week as a decimal number");
148 time_format[15].txt = _("the preferred date for the current locale");
149 time_format[16].txt = _("the last two digits of a year");
150 time_format[17].txt = _("the year as a decimal number");
151 time_format[18].txt = _("the time zone or name or abbreviation");
153 if (datefmt_win) return datefmt_win;
155 store = gtk_list_store_new(N_DATEFMT_COLUMNS,
160 for (i = 0; i < TIME_FORMAT_ELEMS; i++) {
163 gtk_list_store_append(store, &iter);
164 gtk_list_store_set(store, &iter,
165 DATEFMT_FMT, time_format[i].fmt,
166 DATEFMT_TXT, time_format[i].txt,
170 datefmt_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
171 gtk_container_set_border_width(GTK_CONTAINER(datefmt_win), 8);
172 gtk_window_set_title(GTK_WINDOW(datefmt_win), _("Date format"));
173 gtk_window_set_position(GTK_WINDOW(datefmt_win), GTK_WIN_POS_CENTER);
174 gtk_widget_set_size_request(datefmt_win, 440, 280);
176 vbox1 = gtk_vbox_new(FALSE, 10);
177 gtk_widget_show(vbox1);
178 gtk_container_add(GTK_CONTAINER(datefmt_win), vbox1);
180 scrolledwindow1 = gtk_scrolled_window_new(NULL, NULL);
181 gtk_scrolled_window_set_policy
182 (GTK_SCROLLED_WINDOW(scrolledwindow1),
183 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
184 gtk_widget_show(scrolledwindow1);
185 gtk_box_pack_start(GTK_BOX(vbox1), scrolledwindow1, TRUE, TRUE, 0);
187 datefmt_list_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
188 g_object_unref(G_OBJECT(store));
189 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(datefmt_list_view),
190 prefs_common.enable_rules_hint);
191 gtk_widget_show(datefmt_list_view);
192 gtk_container_add(GTK_CONTAINER(scrolledwindow1), datefmt_list_view);
194 renderer = gtk_cell_renderer_text_new();
195 column = gtk_tree_view_column_new_with_attributes
196 (_("Specifier"), renderer, "text", DATEFMT_FMT,
198 gtk_tree_view_append_column(GTK_TREE_VIEW(datefmt_list_view), column);
200 renderer = gtk_cell_renderer_text_new();
201 column = gtk_tree_view_column_new_with_attributes
202 (_("Description"), renderer, "text", DATEFMT_TXT,
204 gtk_tree_view_append_column(GTK_TREE_VIEW(datefmt_list_view), column);
206 /* gtk_clist_set_column_width(GTK_CLIST(datefmt_clist), 0, 80); */
207 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(datefmt_list_view));
208 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
210 g_signal_connect(G_OBJECT(datefmt_list_view), "row_activated",
211 G_CALLBACK(date_format_select_row),
214 table = gtk_table_new(2, 2, FALSE);
215 gtk_widget_show(table);
216 gtk_box_pack_start(GTK_BOX(vbox1), table, FALSE, FALSE, 0);
217 gtk_table_set_row_spacings(GTK_TABLE(table), 4);
218 gtk_table_set_col_spacings(GTK_TABLE(table), 8);
220 label1 = gtk_label_new(_("Date format"));
221 gtk_widget_show(label1);
222 gtk_table_attach(GTK_TABLE(table), label1, 0, 1, 0, 1,
224 gtk_label_set_justify(GTK_LABEL(label1), GTK_JUSTIFY_LEFT);
225 gtk_misc_set_alignment(GTK_MISC(label1), 0, 0.5);
227 datefmt_entry = gtk_entry_new();
228 gtk_entry_set_max_length(GTK_ENTRY(datefmt_entry), 256);
229 gtk_widget_show(datefmt_entry);
230 gtk_table_attach(GTK_TABLE(table), datefmt_entry, 1, 2, 0, 1,
231 (GTK_EXPAND | GTK_FILL), 0, 0, 0);
233 /* we need the "sample" entry box; add it as data so callbacks can
234 * get the entry box */
235 g_object_set_data(G_OBJECT(datefmt_win), "datefmt_sample",
238 label2 = gtk_label_new(_("Example"));
239 gtk_widget_show(label2);
240 gtk_table_attach(GTK_TABLE(table), label2, 0, 1, 1, 2,
242 gtk_label_set_justify(GTK_LABEL(label2), GTK_JUSTIFY_LEFT);
243 gtk_misc_set_alignment(GTK_MISC(label2), 0, 0.5);
245 label3 = gtk_label_new("");
246 gtk_widget_show(label3);
247 gtk_table_attach(GTK_TABLE(table), label3, 1, 2, 1, 2,
248 (GTK_EXPAND | GTK_FILL), 0, 0, 0);
249 gtk_label_set_justify(GTK_LABEL(label3), GTK_JUSTIFY_LEFT);
250 gtk_misc_set_alignment(GTK_MISC(label3), 0, 0.5);
252 gtkut_stock_button_set_create(&confirm_area, &ok_btn, GTK_STOCK_OK,
253 &cancel_btn, GTK_STOCK_CANCEL, NULL, NULL);
255 gtk_box_pack_start(GTK_BOX(vbox1), confirm_area, FALSE, FALSE, 0);
256 gtk_widget_show(confirm_area);
257 gtk_widget_grab_default(ok_btn);
259 /* set the current format */
260 gtk_entry_set_text(GTK_ENTRY(datefmt_entry), prefs_common.date_format);
261 date_format_entry_on_change(GTK_EDITABLE(datefmt_entry),
264 g_signal_connect(G_OBJECT(ok_btn), "clicked",
265 G_CALLBACK(date_format_ok_btn_clicked),
267 g_signal_connect(G_OBJECT(cancel_btn), "clicked",
268 G_CALLBACK(date_format_cancel_btn_clicked),
270 g_signal_connect(G_OBJECT(datefmt_win), "key_press_event",
271 G_CALLBACK(date_format_key_pressed),
273 g_signal_connect(G_OBJECT(datefmt_win), "delete_event",
274 G_CALLBACK(date_format_on_delete),
276 g_signal_connect(G_OBJECT(datefmt_entry), "changed",
277 G_CALLBACK(date_format_entry_on_change),
280 gtk_window_set_position(GTK_WINDOW(datefmt_win), GTK_WIN_POS_CENTER);
281 gtk_window_set_modal(GTK_WINDOW(datefmt_win), TRUE);
283 gtk_widget_show(datefmt_win);
284 manage_window_set_transient(GTK_WINDOW(datefmt_win));
286 gtk_widget_grab_focus(ok_btn);
291 void prefs_summaries_create_widget(PrefsPage *_page, GtkWindow *window,
294 SummariesPage *prefs_summaries = (SummariesPage *) _page;
297 GtkWidget *chkbtn_transhdr;
298 GtkWidget *chkbtn_folder_unread;
300 GtkWidget *label_ng_abbrev;
301 GtkWidget *spinbtn_ng_abbrev_len;
302 GtkObject *spinbtn_ng_abbrev_len_adj;
303 GtkWidget *frame_summary;
305 GtkWidget *chkbtn_swapfrom;
306 GtkWidget *chkbtn_useaddrbook;
307 GtkWidget *chkbtn_threadsubj;
309 GtkWidget *label_datefmt;
310 GtkWidget *button_datefmt;
311 GtkWidget *entry_datefmt;
312 GtkWidget *button_dispitem;
314 vbox1 = gtk_vbox_new (FALSE, VSPACING);
315 gtk_widget_show (vbox1);
316 gtk_container_set_border_width (GTK_CONTAINER (vbox1), VBOX_BORDER);
318 vbox2 = gtk_vbox_new (FALSE, 0);
319 gtk_widget_show (vbox2);
320 gtk_box_pack_start (GTK_BOX (vbox1), vbox2, FALSE, TRUE, 0);
323 (vbox2, chkbtn_transhdr,
324 _("Translate header name (such as `From:', `Subject:')"));
326 PACK_CHECK_BUTTON (vbox2, chkbtn_folder_unread,
327 _("Display unread number next to folder name"));
329 PACK_VSPACER(vbox2, vbox3, VSPACING_NARROW_2);
331 hbox1 = gtk_hbox_new (FALSE, 8);
332 gtk_widget_show (hbox1);
333 gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, TRUE, 0);
335 label_ng_abbrev = gtk_label_new
336 (_("Abbreviate newsgroup names longer than"));
337 gtk_widget_show (label_ng_abbrev);
338 gtk_box_pack_start (GTK_BOX (hbox1), label_ng_abbrev, FALSE, FALSE, 0);
340 spinbtn_ng_abbrev_len_adj = gtk_adjustment_new (16, 0, 999, 1, 10, 10);
341 spinbtn_ng_abbrev_len = gtk_spin_button_new
342 (GTK_ADJUSTMENT (spinbtn_ng_abbrev_len_adj), 1, 0);
343 gtk_widget_show (spinbtn_ng_abbrev_len);
344 gtk_box_pack_start (GTK_BOX (hbox1), spinbtn_ng_abbrev_len,
346 gtk_widget_set_size_request (spinbtn_ng_abbrev_len, 56, -1);
347 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbtn_ng_abbrev_len),
350 label_ng_abbrev = gtk_label_new
352 gtk_widget_show (label_ng_abbrev);
353 gtk_box_pack_start (GTK_BOX (hbox1), label_ng_abbrev, FALSE, FALSE, 0);
355 /* ---- Summary ---- */
357 PACK_FRAME(vbox1, frame_summary, _("Summary View"));
359 vbox2 = gtk_vbox_new (FALSE, 0);
360 gtk_widget_show (vbox2);
361 gtk_container_add (GTK_CONTAINER (frame_summary), vbox2);
362 gtk_container_set_border_width (GTK_CONTAINER (vbox2), 8);
365 (vbox2, chkbtn_swapfrom,
366 _("Display recipient in `From' column if sender is yourself"));
368 (vbox2, chkbtn_useaddrbook,
369 _("Display sender using address book"));
371 (vbox2, chkbtn_threadsubj,
372 _("Thread using subject in addition to standard headers"));
374 PACK_VSPACER(vbox2, vbox3, VSPACING_NARROW_2);
376 hbox1 = gtk_hbox_new (FALSE, 8);
377 gtk_widget_show (hbox1);
378 gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, TRUE, 0);
380 label_datefmt = gtk_label_new (_("Date format"));
381 gtk_widget_show (label_datefmt);
382 gtk_box_pack_start (GTK_BOX (hbox1), label_datefmt, FALSE, FALSE, 0);
384 entry_datefmt = gtk_entry_new ();
385 gtk_widget_show (entry_datefmt);
386 gtk_box_pack_start (GTK_BOX (hbox1), entry_datefmt, TRUE, TRUE, 0);
388 button_datefmt = gtk_button_new_with_label (" ... ");
390 gtk_widget_show (button_datefmt);
391 gtk_box_pack_start (GTK_BOX (hbox1), button_datefmt, FALSE, FALSE, 0);
392 g_signal_connect (G_OBJECT (button_datefmt), "clicked",
393 G_CALLBACK (date_format_create), NULL);
395 PACK_VSPACER(vbox2, vbox3, VSPACING_NARROW);
397 hbox1 = gtk_hbox_new (FALSE, 8);
398 gtk_widget_show (hbox1);
399 gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, TRUE, 0);
401 button_dispitem = gtk_button_new_with_label
402 (_(" Set displayed items in summary... "));
403 gtk_widget_show (button_dispitem);
404 gtk_box_pack_start (GTK_BOX (hbox1), button_dispitem, FALSE, TRUE, 0);
405 g_signal_connect (G_OBJECT (button_dispitem), "clicked",
406 G_CALLBACK (prefs_summary_column_open),
409 prefs_summaries->window = GTK_WIDGET(window);
411 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_transhdr),
412 prefs_common.trans_hdr);
413 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_folder_unread),
414 prefs_common.display_folder_unread);
415 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_swapfrom),
416 prefs_common.swap_from);
417 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_useaddrbook),
418 prefs_common.use_addr_book);
419 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_threadsubj),
420 prefs_common.thread_by_subject);
421 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbtn_ng_abbrev_len),
422 prefs_common.ng_abbrev_len);
423 gtk_entry_set_text(GTK_ENTRY(entry_datefmt),
424 prefs_common.date_format?prefs_common.date_format:"");
426 prefs_summaries->chkbtn_transhdr = chkbtn_transhdr;
427 prefs_summaries->chkbtn_folder_unread = chkbtn_folder_unread;
428 prefs_summaries->spinbtn_ng_abbrev_len = spinbtn_ng_abbrev_len;
429 prefs_summaries->chkbtn_swapfrom = chkbtn_swapfrom;
430 prefs_summaries->chkbtn_useaddrbook = chkbtn_useaddrbook;
431 prefs_summaries->chkbtn_threadsubj = chkbtn_threadsubj;
432 prefs_summaries->entry_datefmt = entry_datefmt;
434 prefs_summaries->page.widget = vbox1;
437 void prefs_summaries_save(PrefsPage *_page)
439 SummariesPage *page = (SummariesPage *) _page;
441 prefs_common.trans_hdr = gtk_toggle_button_get_active(
442 GTK_TOGGLE_BUTTON(page->chkbtn_transhdr));
443 prefs_common.display_folder_unread = gtk_toggle_button_get_active(
444 GTK_TOGGLE_BUTTON(page->chkbtn_folder_unread));
445 prefs_common.swap_from = gtk_toggle_button_get_active(
446 GTK_TOGGLE_BUTTON(page->chkbtn_swapfrom));
447 prefs_common.use_addr_book = gtk_toggle_button_get_active(
448 GTK_TOGGLE_BUTTON(page->chkbtn_useaddrbook));
449 prefs_common.thread_by_subject = gtk_toggle_button_get_active(
450 GTK_TOGGLE_BUTTON(page->chkbtn_threadsubj));
451 prefs_common.ng_abbrev_len = gtk_spin_button_get_value_as_int(
452 GTK_SPIN_BUTTON(page->spinbtn_ng_abbrev_len));
454 g_free(prefs_common.date_format);
455 prefs_common.date_format = gtk_editable_get_chars(
456 GTK_EDITABLE(page->entry_datefmt), 0, -1);
459 static void prefs_summaries_destroy_widget(PrefsPage *_page)
463 SummariesPage *prefs_summaries;
465 void prefs_summaries_init(void)
468 static gchar *path[3];
470 path[0] = _("Display");
471 path[1] = _("Summaries");
474 page = g_new0(SummariesPage, 1);
475 page->page.path = path;
476 page->page.create_widget = prefs_summaries_create_widget;
477 page->page.destroy_widget = prefs_summaries_destroy_widget;
478 page->page.save_page = prefs_summaries_save;
479 page->page.weight = 60.0;
480 prefs_gtk_register_page((PrefsPage *) page);
481 prefs_summaries = page;
484 void prefs_summaries_done(void)
486 prefs_gtk_unregister_page((PrefsPage *) prefs_summaries);
487 g_free(prefs_summaries);
490 static void date_format_ok_btn_clicked(GtkButton *button, GtkWidget **widget)
492 GtkWidget *datefmt_sample = NULL;
495 g_return_if_fail(widget != NULL);
496 g_return_if_fail(*widget != NULL);
497 g_return_if_fail(prefs_summaries->entry_datefmt != NULL);
499 datefmt_sample = GTK_WIDGET(g_object_get_data
500 (G_OBJECT(*widget), "datefmt_sample"));
501 g_return_if_fail(datefmt_sample != NULL);
503 text = gtk_editable_get_chars(GTK_EDITABLE(datefmt_sample), 0, -1);
504 g_free(prefs_common.date_format);
505 prefs_common.date_format = text;
506 gtk_entry_set_text(GTK_ENTRY(prefs_summaries->entry_datefmt), text);
508 gtk_widget_destroy(*widget);
512 static void date_format_cancel_btn_clicked(GtkButton *button,
515 g_return_if_fail(widget != NULL);
516 g_return_if_fail(*widget != NULL);
518 gtk_widget_destroy(*widget);
522 static gboolean date_format_key_pressed(GtkWidget *keywidget, GdkEventKey *event,
525 if (event && event->keyval == GDK_Escape)
526 date_format_cancel_btn_clicked(NULL, widget);
530 static gboolean date_format_on_delete(GtkWidget *dialogwidget,
531 GdkEventAny *event, GtkWidget **widget)
533 g_return_val_if_fail(widget != NULL, FALSE);
534 g_return_val_if_fail(*widget != NULL, FALSE);
540 static void date_format_entry_on_change(GtkEditable *editable,
548 cur_time = time(NULL);
549 cal_time = localtime(&cur_time);
551 text = gtk_editable_get_chars(editable, 0, -1);
553 strftime(buffer, sizeof buffer, text, cal_time);
556 text = conv_codeset_strdup(buffer,
557 conv_get_locale_charset_str(),
560 text = g_strdup(buffer);
562 gtk_label_set_text(example, text);
567 static void date_format_select_row(GtkTreeView *list_view,
569 GtkTreeViewColumn *column,
570 GtkWidget *date_format)
574 const gchar *old_format;
576 GtkWidget *datefmt_sample;
580 g_return_if_fail(date_format != NULL);
582 /* only on double click */
583 datefmt_sample = GTK_WIDGET(g_object_get_data(G_OBJECT(date_format),
586 g_return_if_fail(datefmt_sample != NULL);
588 model = gtk_tree_view_get_model(list_view);
590 /* get format from list */
591 if (!gtk_tree_model_get_iter(model, &iter, path))
594 gtk_tree_model_get(model, &iter, DATEFMT_FMT, &format, -1);
596 cur_pos = gtk_editable_get_position(GTK_EDITABLE(datefmt_sample));
597 old_format = gtk_entry_get_text(GTK_ENTRY(datefmt_sample));
599 /* insert the format into the text entry */
600 new_format = g_malloc(strlen(old_format) + 3);
602 strncpy(new_format, old_format, cur_pos);
603 new_format[cur_pos] = '\0';
604 strcat(new_format, format);
605 strcat(new_format, &old_format[cur_pos]);
607 gtk_entry_set_text(GTK_ENTRY(datefmt_sample), new_format);
608 gtk_editable_set_position(GTK_EDITABLE(datefmt_sample), cur_pos + 2);