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), TRUE);
190 gtk_widget_show(datefmt_list_view);
191 gtk_container_add(GTK_CONTAINER(scrolledwindow1), datefmt_list_view);
193 renderer = gtk_cell_renderer_text_new();
194 column = gtk_tree_view_column_new_with_attributes
195 (_("Specifier"), renderer, "text", DATEFMT_FMT,
197 gtk_tree_view_append_column(GTK_TREE_VIEW(datefmt_list_view), column);
199 renderer = gtk_cell_renderer_text_new();
200 column = gtk_tree_view_column_new_with_attributes
201 (_("Description"), renderer, "text", DATEFMT_TXT,
203 gtk_tree_view_append_column(GTK_TREE_VIEW(datefmt_list_view), column);
205 /* gtk_clist_set_column_width(GTK_CLIST(datefmt_clist), 0, 80); */
206 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(datefmt_list_view));
207 gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE);
209 g_signal_connect(G_OBJECT(datefmt_list_view), "row_activated",
210 G_CALLBACK(date_format_select_row),
213 table = gtk_table_new(2, 2, FALSE);
214 gtk_widget_show(table);
215 gtk_box_pack_start(GTK_BOX(vbox1), table, FALSE, FALSE, 0);
216 gtk_table_set_row_spacings(GTK_TABLE(table), 4);
217 gtk_table_set_col_spacings(GTK_TABLE(table), 8);
219 label1 = gtk_label_new(_("Date format"));
220 gtk_widget_show(label1);
221 gtk_table_attach(GTK_TABLE(table), label1, 0, 1, 0, 1,
223 gtk_label_set_justify(GTK_LABEL(label1), GTK_JUSTIFY_LEFT);
224 gtk_misc_set_alignment(GTK_MISC(label1), 0, 0.5);
226 datefmt_entry = gtk_entry_new();
227 gtk_entry_set_max_length(GTK_ENTRY(datefmt_entry), 256);
228 gtk_widget_show(datefmt_entry);
229 gtk_table_attach(GTK_TABLE(table), datefmt_entry, 1, 2, 0, 1,
230 (GTK_EXPAND | GTK_FILL), 0, 0, 0);
232 /* we need the "sample" entry box; add it as data so callbacks can
233 * get the entry box */
234 g_object_set_data(G_OBJECT(datefmt_win), "datefmt_sample",
237 label2 = gtk_label_new(_("Example"));
238 gtk_widget_show(label2);
239 gtk_table_attach(GTK_TABLE(table), label2, 0, 1, 1, 2,
241 gtk_label_set_justify(GTK_LABEL(label2), GTK_JUSTIFY_LEFT);
242 gtk_misc_set_alignment(GTK_MISC(label2), 0, 0.5);
244 label3 = gtk_label_new("");
245 gtk_widget_show(label3);
246 gtk_table_attach(GTK_TABLE(table), label3, 1, 2, 1, 2,
247 (GTK_EXPAND | GTK_FILL), 0, 0, 0);
248 gtk_label_set_justify(GTK_LABEL(label3), GTK_JUSTIFY_LEFT);
249 gtk_misc_set_alignment(GTK_MISC(label3), 0, 0.5);
251 gtkut_stock_button_set_create(&confirm_area, &ok_btn, GTK_STOCK_OK,
252 &cancel_btn, GTK_STOCK_CANCEL, NULL, NULL);
254 gtk_box_pack_start(GTK_BOX(vbox1), confirm_area, FALSE, FALSE, 0);
255 gtk_widget_show(confirm_area);
256 gtk_widget_grab_default(ok_btn);
258 /* set the current format */
259 gtk_entry_set_text(GTK_ENTRY(datefmt_entry), prefs_common.date_format);
260 date_format_entry_on_change(GTK_EDITABLE(datefmt_entry),
263 g_signal_connect(G_OBJECT(ok_btn), "clicked",
264 G_CALLBACK(date_format_ok_btn_clicked),
266 g_signal_connect(G_OBJECT(cancel_btn), "clicked",
267 G_CALLBACK(date_format_cancel_btn_clicked),
269 g_signal_connect(G_OBJECT(datefmt_win), "key_press_event",
270 G_CALLBACK(date_format_key_pressed),
272 g_signal_connect(G_OBJECT(datefmt_win), "delete_event",
273 G_CALLBACK(date_format_on_delete),
275 g_signal_connect(G_OBJECT(datefmt_entry), "changed",
276 G_CALLBACK(date_format_entry_on_change),
279 gtk_window_set_position(GTK_WINDOW(datefmt_win), GTK_WIN_POS_CENTER);
280 gtk_window_set_modal(GTK_WINDOW(datefmt_win), TRUE);
282 gtk_widget_show(datefmt_win);
283 manage_window_set_transient(GTK_WINDOW(datefmt_win));
285 gtk_widget_grab_focus(ok_btn);
290 void prefs_summaries_create_widget(PrefsPage *_page, GtkWindow *window,
293 SummariesPage *prefs_summaries = (SummariesPage *) _page;
296 GtkWidget *chkbtn_transhdr;
297 GtkWidget *chkbtn_folder_unread;
299 GtkWidget *label_ng_abbrev;
300 GtkWidget *spinbtn_ng_abbrev_len;
301 GtkObject *spinbtn_ng_abbrev_len_adj;
302 GtkWidget *frame_summary;
304 GtkWidget *chkbtn_swapfrom;
305 GtkWidget *chkbtn_useaddrbook;
306 GtkWidget *chkbtn_threadsubj;
308 GtkWidget *label_datefmt;
309 GtkWidget *button_datefmt;
310 GtkWidget *entry_datefmt;
311 GtkWidget *button_dispitem;
313 vbox1 = gtk_vbox_new (FALSE, VSPACING);
314 gtk_widget_show (vbox1);
315 gtk_container_set_border_width (GTK_CONTAINER (vbox1), VBOX_BORDER);
317 vbox2 = gtk_vbox_new (FALSE, 0);
318 gtk_widget_show (vbox2);
319 gtk_box_pack_start (GTK_BOX (vbox1), vbox2, FALSE, TRUE, 0);
322 (vbox2, chkbtn_transhdr,
323 _("Translate header name (such as `From:', `Subject:')"));
325 PACK_CHECK_BUTTON (vbox2, chkbtn_folder_unread,
326 _("Display unread number next to folder name"));
328 PACK_VSPACER(vbox2, vbox3, VSPACING_NARROW_2);
330 hbox1 = gtk_hbox_new (FALSE, 8);
331 gtk_widget_show (hbox1);
332 gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, TRUE, 0);
334 label_ng_abbrev = gtk_label_new
335 (_("Abbreviate newsgroup names longer than"));
336 gtk_widget_show (label_ng_abbrev);
337 gtk_box_pack_start (GTK_BOX (hbox1), label_ng_abbrev, FALSE, FALSE, 0);
339 spinbtn_ng_abbrev_len_adj = gtk_adjustment_new (16, 0, 999, 1, 10, 10);
340 spinbtn_ng_abbrev_len = gtk_spin_button_new
341 (GTK_ADJUSTMENT (spinbtn_ng_abbrev_len_adj), 1, 0);
342 gtk_widget_show (spinbtn_ng_abbrev_len);
343 gtk_box_pack_start (GTK_BOX (hbox1), spinbtn_ng_abbrev_len,
345 gtk_widget_set_size_request (spinbtn_ng_abbrev_len, 56, -1);
346 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbtn_ng_abbrev_len),
349 label_ng_abbrev = gtk_label_new
351 gtk_widget_show (label_ng_abbrev);
352 gtk_box_pack_start (GTK_BOX (hbox1), label_ng_abbrev, FALSE, FALSE, 0);
354 /* ---- Summary ---- */
356 PACK_FRAME(vbox1, frame_summary, _("Summary View"));
358 vbox2 = gtk_vbox_new (FALSE, 0);
359 gtk_widget_show (vbox2);
360 gtk_container_add (GTK_CONTAINER (frame_summary), vbox2);
361 gtk_container_set_border_width (GTK_CONTAINER (vbox2), 8);
364 (vbox2, chkbtn_swapfrom,
365 _("Display recipient in `From' column if sender is yourself"));
367 (vbox2, chkbtn_useaddrbook,
368 _("Display sender using address book"));
370 (vbox2, chkbtn_threadsubj,
371 _("Thread using subject in addition to standard headers"));
373 PACK_VSPACER(vbox2, vbox3, VSPACING_NARROW_2);
375 hbox1 = gtk_hbox_new (FALSE, 8);
376 gtk_widget_show (hbox1);
377 gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, TRUE, 0);
379 label_datefmt = gtk_label_new (_("Date format"));
380 gtk_widget_show (label_datefmt);
381 gtk_box_pack_start (GTK_BOX (hbox1), label_datefmt, FALSE, FALSE, 0);
383 entry_datefmt = gtk_entry_new ();
384 gtk_widget_show (entry_datefmt);
385 gtk_box_pack_start (GTK_BOX (hbox1), entry_datefmt, TRUE, TRUE, 0);
387 button_datefmt = gtk_button_new_with_label (" ... ");
389 gtk_widget_show (button_datefmt);
390 gtk_box_pack_start (GTK_BOX (hbox1), button_datefmt, FALSE, FALSE, 0);
391 g_signal_connect (G_OBJECT (button_datefmt), "clicked",
392 G_CALLBACK (date_format_create), NULL);
394 PACK_VSPACER(vbox2, vbox3, VSPACING_NARROW);
396 hbox1 = gtk_hbox_new (FALSE, 8);
397 gtk_widget_show (hbox1);
398 gtk_box_pack_start (GTK_BOX (vbox2), hbox1, FALSE, TRUE, 0);
400 button_dispitem = gtk_button_new_with_label
401 (_(" Set displayed items in summary... "));
402 gtk_widget_show (button_dispitem);
403 gtk_box_pack_start (GTK_BOX (hbox1), button_dispitem, FALSE, TRUE, 0);
404 g_signal_connect (G_OBJECT (button_dispitem), "clicked",
405 G_CALLBACK (prefs_summary_column_open),
408 prefs_summaries->window = GTK_WIDGET(window);
410 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_transhdr),
411 prefs_common.trans_hdr);
412 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_folder_unread),
413 prefs_common.display_folder_unread);
414 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_swapfrom),
415 prefs_common.swap_from);
416 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_useaddrbook),
417 prefs_common.use_addr_book);
418 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chkbtn_threadsubj),
419 prefs_common.thread_by_subject);
420 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbtn_ng_abbrev_len),
421 prefs_common.ng_abbrev_len);
422 gtk_entry_set_text(GTK_ENTRY(entry_datefmt),
423 prefs_common.date_format?prefs_common.date_format:"");
425 prefs_summaries->chkbtn_transhdr = chkbtn_transhdr;
426 prefs_summaries->chkbtn_folder_unread = chkbtn_folder_unread;
427 prefs_summaries->spinbtn_ng_abbrev_len = spinbtn_ng_abbrev_len;
428 prefs_summaries->chkbtn_swapfrom = chkbtn_swapfrom;
429 prefs_summaries->chkbtn_useaddrbook = chkbtn_useaddrbook;
430 prefs_summaries->chkbtn_threadsubj = chkbtn_threadsubj;
431 prefs_summaries->entry_datefmt = entry_datefmt;
433 prefs_summaries->page.widget = vbox1;
436 void prefs_summaries_save(PrefsPage *_page)
438 SummariesPage *page = (SummariesPage *) _page;
440 prefs_common.trans_hdr = gtk_toggle_button_get_active(
441 GTK_TOGGLE_BUTTON(page->chkbtn_transhdr));
442 prefs_common.display_folder_unread = gtk_toggle_button_get_active(
443 GTK_TOGGLE_BUTTON(page->chkbtn_folder_unread));
444 prefs_common.swap_from = gtk_toggle_button_get_active(
445 GTK_TOGGLE_BUTTON(page->chkbtn_swapfrom));
446 prefs_common.use_addr_book = gtk_toggle_button_get_active(
447 GTK_TOGGLE_BUTTON(page->chkbtn_useaddrbook));
448 prefs_common.thread_by_subject = gtk_toggle_button_get_active(
449 GTK_TOGGLE_BUTTON(page->chkbtn_threadsubj));
450 prefs_common.ng_abbrev_len = gtk_spin_button_get_value_as_int(
451 GTK_SPIN_BUTTON(page->spinbtn_ng_abbrev_len));
453 g_free(prefs_common.date_format);
454 prefs_common.date_format = gtk_editable_get_chars(
455 GTK_EDITABLE(page->entry_datefmt), 0, -1);
458 static void prefs_summaries_destroy_widget(PrefsPage *_page)
462 SummariesPage *prefs_summaries;
464 void prefs_summaries_init(void)
467 static gchar *path[3];
469 path[0] = _("Display");
470 path[1] = _("Summaries");
473 page = g_new0(SummariesPage, 1);
474 page->page.path = path;
475 page->page.create_widget = prefs_summaries_create_widget;
476 page->page.destroy_widget = prefs_summaries_destroy_widget;
477 page->page.save_page = prefs_summaries_save;
478 page->page.weight = 60.0;
479 prefs_gtk_register_page((PrefsPage *) page);
480 prefs_summaries = page;
483 void prefs_summaries_done(void)
485 prefs_gtk_unregister_page((PrefsPage *) prefs_summaries);
486 g_free(prefs_summaries);
489 static void date_format_ok_btn_clicked(GtkButton *button, GtkWidget **widget)
491 GtkWidget *datefmt_sample = NULL;
494 g_return_if_fail(widget != NULL);
495 g_return_if_fail(*widget != NULL);
496 g_return_if_fail(prefs_summaries->entry_datefmt != NULL);
498 datefmt_sample = GTK_WIDGET(g_object_get_data
499 (G_OBJECT(*widget), "datefmt_sample"));
500 g_return_if_fail(datefmt_sample != NULL);
502 text = gtk_editable_get_chars(GTK_EDITABLE(datefmt_sample), 0, -1);
503 g_free(prefs_common.date_format);
504 prefs_common.date_format = text;
505 gtk_entry_set_text(GTK_ENTRY(prefs_summaries->entry_datefmt), text);
507 gtk_widget_destroy(*widget);
511 static void date_format_cancel_btn_clicked(GtkButton *button,
514 g_return_if_fail(widget != NULL);
515 g_return_if_fail(*widget != NULL);
517 gtk_widget_destroy(*widget);
521 static gboolean date_format_key_pressed(GtkWidget *keywidget, GdkEventKey *event,
524 if (event && event->keyval == GDK_Escape)
525 date_format_cancel_btn_clicked(NULL, widget);
529 static gboolean date_format_on_delete(GtkWidget *dialogwidget,
530 GdkEventAny *event, GtkWidget **widget)
532 g_return_val_if_fail(widget != NULL, FALSE);
533 g_return_val_if_fail(*widget != NULL, FALSE);
539 static void date_format_entry_on_change(GtkEditable *editable,
547 cur_time = time(NULL);
548 cal_time = localtime(&cur_time);
550 text = gtk_editable_get_chars(editable, 0, -1);
552 strftime(buffer, sizeof buffer, text, cal_time);
555 text = conv_codeset_strdup(buffer,
556 conv_get_locale_charset_str(),
559 text = g_strdup(buffer);
561 gtk_label_set_text(example, text);
566 static void date_format_select_row(GtkTreeView *list_view,
568 GtkTreeViewColumn *column,
569 GtkWidget *date_format)
573 const gchar *old_format;
575 GtkWidget *datefmt_sample;
579 g_return_if_fail(date_format != NULL);
581 /* only on double click */
582 datefmt_sample = GTK_WIDGET(g_object_get_data(G_OBJECT(date_format),
585 g_return_if_fail(datefmt_sample != NULL);
587 model = gtk_tree_view_get_model(list_view);
589 /* get format from list */
590 if (!gtk_tree_model_get_iter(model, &iter, path))
593 gtk_tree_model_get(model, &iter, DATEFMT_FMT, &format, -1);
595 cur_pos = gtk_editable_get_position(GTK_EDITABLE(datefmt_sample));
596 old_format = gtk_entry_get_text(GTK_ENTRY(datefmt_sample));
598 /* insert the format into the text entry */
599 new_format = g_malloc(strlen(old_format) + 3);
601 strncpy(new_format, old_format, cur_pos);
602 new_format[cur_pos] = '\0';
603 strcat(new_format, format);
604 strcat(new_format, &old_format[cur_pos]);
606 gtk_entry_set_text(GTK_ENTRY(datefmt_sample), new_format);
607 gtk_editable_set_position(GTK_EDITABLE(datefmt_sample), cur_pos + 2);