From 50302d03b3ce145b165db2ddef4e92ad190cbef9 Mon Sep 17 00:00:00 2001 From: Milan Crha Date: Tue, 4 Aug 2009 15:04:02 +0200 Subject: [PATCH] Bug #205137 - Configurable date formats in components --- addressbook/gui/widgets/e-addressbook-view.c | 11 +- calendar/gui/dialogs/cal-prefs-dialog.c | 7 + calendar/gui/dialogs/cal-prefs-dialog.glade | 79 + calendar/gui/e-cal-list-view.c | 6 + calendar/gui/e-calendar-table.c | 5 + calendar/gui/e-calendar-view.c | 8 +- calendar/gui/e-cell-date-edit-text.c | 9 +- calendar/gui/e-memo-table.c | 5 + e-util/Makefile.am | 2 + e-util/e-datetime-format.c | 571 +++++ e-util/e-datetime-format.h | 46 + mail/em-format-html-display.c | 29 +- mail/em-format-html.c | 32 +- mail/mail-config.glade | 1963 ++++++++++++------ mail/message-list.c | 8 +- modules/addressbook/autocompletion-config.c | 5 +- modules/mail/em-mailer-prefs.c | 7 + po/POTFILES.in | 1 + widgets/table/e-cell-date.c | 79 +- widgets/table/e-cell-date.h | 1 + 20 files changed, 2078 insertions(+), 796 deletions(-) create mode 100644 e-util/e-datetime-format.c create mode 100644 e-util/e-datetime-format.h diff --git a/addressbook/gui/widgets/e-addressbook-view.c b/addressbook/gui/widgets/e-addressbook-view.c index 601e7f9546..c606530594 100644 --- a/addressbook/gui/widgets/e-addressbook-view.c +++ b/addressbook/gui/widgets/e-addressbook-view.c @@ -26,6 +26,7 @@ #include #include #include
+#include
#include #include #include @@ -267,19 +268,27 @@ static void addressbook_view_create_table_view (EAddressbookView *view) { ETableModel *adapter; + ETableExtras *extras; + ECell *cell; ETable *table; GtkWidget *widget; gchar *etspecfile; adapter = eab_table_adapter_new (view->priv->model); + extras = e_table_extras_new (); + + /* Set proper format component for a default 'date' cell renderer. */ + cell = e_table_extras_get_cell (extras, "date"); + e_cell_date_set_format_component (E_CELL_DATE (cell), "addressbook"); + /* Here we create the table. We give it the three pieces of the table we've created, the header, the model, and the initial layout. It does the rest. */ etspecfile = g_build_filename ( EVOLUTION_ETSPECDIR, "e-addressbook-view.etspec", NULL); widget = e_table_scrolled_new_from_spec_file ( - adapter, NULL, etspecfile, NULL); + adapter, extras, etspecfile, NULL); table = E_TABLE (E_TABLE_SCROLLED (widget)->table); g_free (etspecfile); diff --git a/calendar/gui/dialogs/cal-prefs-dialog.c b/calendar/gui/dialogs/cal-prefs-dialog.c index 8f22c98569..1ed8409bd4 100644 --- a/calendar/gui/dialogs/cal-prefs-dialog.c +++ b/calendar/gui/dialogs/cal-prefs-dialog.c @@ -32,6 +32,7 @@ #include "cal-prefs-dialog.h" #include #include +#include #include #include #include @@ -581,6 +582,7 @@ calendar_prefs_dialog_construct (CalendarPrefsDialog *prefs, gint i; GtkWidget *toplevel; GtkWidget *widget; + GtkWidget *table; GSList *l; gchar *gladefile; @@ -769,6 +771,11 @@ calendar_prefs_dialog_construct (CalendarPrefsDialog *prefs, toplevel = e_config_create_widget ((EConfig *)ec); gtk_container_add (GTK_CONTAINER (prefs), toplevel); + /* date/time format */ + table = glade_xml_get_widget (gui, "datetime_format_table"); + e_datetime_format_add_setup_widget (table, 0, "calendar", "table", DTFormatKindDateTime, _("Time and date:")); + e_datetime_format_add_setup_widget (table, 1, "calendar", "table", DTFormatKindDate, _("Date only:")); + show_config (prefs); /* FIXME: weakref? */ setup_changes (prefs); diff --git a/calendar/gui/dialogs/cal-prefs-dialog.glade b/calendar/gui/dialogs/cal-prefs-dialog.glade index 63e9e6092f..984e509b64 100644 --- a/calendar/gui/dialogs/cal-prefs-dialog.glade +++ b/calendar/gui/dialogs/cal-prefs-dialog.glade @@ -1024,6 +1024,85 @@ Days 3 + + + + True + <span weight="bold">Date/Time Format</span> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + False + 12 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 1 + 3 + False + 0 + 0 + + + 0 + True + True + + + + + 0 + True + True + + 1 diff --git a/calendar/gui/e-cal-list-view.c b/calendar/gui/e-cal-list-view.c index 5cf64aebf7..1f9ca3fdcc 100644 --- a/calendar/gui/e-cal-list-view.c +++ b/calendar/gui/e-cal-list-view.c @@ -41,6 +41,7 @@ #include
#include
#include
+#include
#include #include
#include @@ -269,6 +270,11 @@ setup_e_table (ECalListView *cal_list_view) e_table_extras_add_compare (extras, "date-compare", date_compare_cb); + + /* set proper format component for a default 'date' cell renderer */ + cell = e_table_extras_get_cell (extras, "date"); + e_cell_date_set_format_component (E_CELL_DATE (cell), "calendar"); + /* Create table view */ etspecfile = g_build_filename (EVOLUTION_ETSPECDIR, diff --git a/calendar/gui/e-calendar-table.c b/calendar/gui/e-calendar-table.c index a61477d081..a904b34d42 100644 --- a/calendar/gui/e-calendar-table.c +++ b/calendar/gui/e-calendar-table.c @@ -41,6 +41,7 @@ #include
#include
#include
+#include
#include #include #include
@@ -826,6 +827,10 @@ calendar_table_constructed (GObject *object) e_table_extras_add_pixbuf(extras, "complete", pixbuf); g_object_unref(pixbuf); + /* set proper format component for a default 'date' cell renderer */ + cell = e_table_extras_get_cell (extras, "date"); + e_cell_date_set_format_component (E_CELL_DATE (cell), "calendar"); + /* Create the table */ etspecfile = g_build_filename ( diff --git a/calendar/gui/e-calendar-view.c b/calendar/gui/e-calendar-view.c index 0b7c52fd00..3575c11eda 100644 --- a/calendar/gui/e-calendar-view.c +++ b/calendar/gui/e-calendar-view.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -2044,16 +2045,11 @@ tooltip_grab (GtkWidget *tooltip, GdkEventKey *event, ECalendarView *view) static gchar * get_label (struct icaltimetype *tt, icaltimezone *f_zone, icaltimezone *t_zone) { - gchar buffer[1000]; struct tm tmp_tm; tmp_tm = icaltimetype_to_tm_with_zone (tt, f_zone, t_zone); - e_time_format_date_and_time (&tmp_tm, - calendar_config_get_24_hour_format (), - FALSE, FALSE, - buffer, 1000); - return g_strdup (buffer); + return e_datetime_format_format_tm ("calendar", "table", DTFormatKindDateTime, &tmp_tm); } void diff --git a/calendar/gui/e-cell-date-edit-text.c b/calendar/gui/e-cell-date-edit-text.c index c99d62d4e9..97dee085ea 100644 --- a/calendar/gui/e-cell-date-edit-text.c +++ b/calendar/gui/e-cell-date-edit-text.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "e-cell-date-edit-text.h" @@ -117,7 +118,6 @@ cell_date_edit_text_get_text (ECellText *cell, gboolean use_24_hour_format; icaltimezone *timezone; struct tm tmp_tm; - gchar buffer[64]; if (!dv) return g_strdup (""); @@ -131,10 +131,9 @@ cell_date_edit_text_get_text (ECellText *cell, it will be set to the current timezone. See set_value(). */ tmp_tm = icaltimetype_to_tm_with_zone (&dv->tt, dv->zone, timezone); - e_time_format_date_and_time (&tmp_tm, use_24_hour_format, - !dv->tt.is_date, FALSE, - buffer, sizeof (buffer)); - return g_strdup (buffer); + return e_datetime_format_format_tm ( + "calendar", "table", dv->tt.is_date ? + DTFormatKindDate : DTFormatKindDateTime, &tmp_tm); } static void diff --git a/calendar/gui/e-memo-table.c b/calendar/gui/e-memo-table.c index e23f82108b..d89ca044e4 100644 --- a/calendar/gui/e-memo-table.c +++ b/calendar/gui/e-memo-table.c @@ -41,6 +41,7 @@ #include
#include
#include
+#include
#include #include #include
@@ -606,6 +607,10 @@ memo_table_constructed (GObject *object) e_table_extras_add_cell (extras, "icon", cell); e_table_extras_add_pixbuf (extras, "icon", icon_pixbufs[0]); + /* set proper format component for a default 'date' cell renderer */ + cell = e_table_extras_get_cell (extras, "date"); + e_cell_date_set_format_component (E_CELL_DATE (cell), "calendar"); + /* Create the table */ etspecfile = g_build_filename ( diff --git a/e-util/Makefile.am b/e-util/Makefile.am index f9d468f886..558d899d94 100644 --- a/e-util/Makefile.am +++ b/e-util/Makefile.am @@ -45,6 +45,7 @@ eutilinclude_HEADERS = \ e-charset.h \ e-config.h \ e-cursor.h \ + e-datetime-format.h \ e-dialog-utils.h \ e-dialog-widgets.h \ e-error.h \ @@ -88,6 +89,7 @@ libeutil_la_SOURCES = \ e-charset.c \ e-config.c \ e-cursor.c \ + e-datetime-format.c \ e-dialog-utils.c \ e-dialog-widgets.c \ e-error.c \ diff --git a/e-util/e-datetime-format.c b/e-util/e-datetime-format.c new file mode 100644 index 0000000000..c6900ff8ca --- /dev/null +++ b/e-util/e-datetime-format.c @@ -0,0 +1,571 @@ +/* + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Copyright (C) 1999-2009 Novell, Inc. (www.novell.com) + * + */ + +#include +#include +#include + +#include "e-datetime-format.h" +#include "e-util.h" + +#define KEYS_FILENAME "datetime-formats" +#define KEYS_GROUPNAME "formats" + +#ifdef G_OS_WIN32 +/* The localtime() in Microsoft's C library *is* thread-safe */ +#define localtime_r(timep, result) (localtime (timep) ? memcpy ((result), localtime (timep), sizeof (*(result))) : 0) +#endif + +static GHashTable *key2fmt = NULL; + +static GKeyFile *setup_keyfile = NULL; /* used on the combo */ +static gint setup_keyfile_instances = 0; + +static void +save_keyfile (GKeyFile *keyfile) +{ + gchar *contents; + gchar *filename; + gsize length; + GError *error = NULL; + + g_return_if_fail (keyfile != NULL); + + filename = g_build_filename (e_get_user_data_dir (), KEYS_FILENAME, NULL); + contents = g_key_file_to_data (keyfile, &length, NULL); + + g_file_set_contents (filename, contents, length, &error); + + if (error != NULL) { + g_warning ("%s", error->message); + g_error_free (error); + } + + g_free (contents); + g_free (filename); +} + +static void +ensure_loaded (void) +{ + GKeyFile *keyfile; + gchar *str, **keys; + gint i; + + if (key2fmt) + return; + + key2fmt = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + keyfile = g_key_file_new (); + + str = g_build_filename (e_get_user_data_dir (), KEYS_FILENAME, NULL); + g_key_file_load_from_file (keyfile, str, G_KEY_FILE_NONE, NULL); + g_free (str); + + keys = g_key_file_get_keys (keyfile, KEYS_GROUPNAME, NULL, NULL); + + if (keys) { + for (i = 0; keys [i]; i++) { + str = g_key_file_get_string (keyfile, KEYS_GROUPNAME, keys [i], NULL); + if (str) + g_hash_table_insert (key2fmt, g_strdup (keys [i]), str); + } + + g_strfreev (keys); + } + + g_key_file_free (keyfile); +} + +static const gchar * +get_default_format (DTFormatKind kind, const gchar *key) +{ + const gchar *res = NULL; + + ensure_loaded (); + + switch (kind) { + case DTFormatKindDate: + res = g_hash_table_lookup (key2fmt, "Default-Date"); + if (!res) + res = "%x"; + break; + case DTFormatKindTime: + res = g_hash_table_lookup (key2fmt, "Default-Time"); + if (!res) + res = "%X"; + break; + case DTFormatKindDateTime: + res = g_hash_table_lookup (key2fmt, "Default-DateTime"); + if (!res && key && g_str_has_prefix (key, "mail-table")) + res = "%ad %H:%M"; + if (!res) + res = "%x %X"; /* %c is also possible, but it doesn't play well with time zone identifiers */ + break; + case DTFormatKindShortDate: + res = g_hash_table_lookup (key2fmt, "Default-ShortDate"); + if (!res) + res = "%A, %B %d"; + break; + } + + if (!res) + res = "%x %X"; + + return res; +} + +static const gchar * +get_format_internal (const gchar *key, DTFormatKind kind) +{ + const gchar *res; + + ensure_loaded (); + + g_return_val_if_fail (key != NULL, NULL); + g_return_val_if_fail (key2fmt != NULL, NULL); + + res = g_hash_table_lookup (key2fmt, key); + if (!res) + res = get_default_format (kind, key); + + return res; +} + +static void +set_format_internal (const gchar *key, const gchar *fmt, GKeyFile *keyfile) +{ + ensure_loaded (); + + g_return_if_fail (key != NULL); + g_return_if_fail (key2fmt != NULL); + g_return_if_fail (keyfile != NULL); + + if (!fmt || !*fmt) { + g_hash_table_remove (key2fmt, key); + g_key_file_remove_key (keyfile, KEYS_GROUPNAME, key, NULL); + } else { + g_hash_table_insert (key2fmt, g_strdup (key), g_strdup (fmt)); + g_key_file_set_string (keyfile, KEYS_GROUPNAME, key, fmt); + } +} + +static gchar * +format_relative_date (time_t tvalue, time_t ttoday, const struct tm *value, const struct tm *today) +{ + gchar *res = g_strdup (get_default_format (DTFormatKindDate, NULL)); + + g_return_val_if_fail (value != NULL, res); + g_return_val_if_fail (today != NULL, res); + + /* if it's more than a week, use the default date format */ + if (ttoday - tvalue > 7 * 24 * 60 * 60 || + tvalue - ttoday > 7 * 24 * 60 * 60) + return res; + + g_free (res); + + if (value->tm_year == today->tm_year && + value->tm_mon == today->tm_mon && + value->tm_mday == today->tm_mday) { + res = g_strdup (_("Today")); + } else { + gint diff = (gint) (tvalue - ttoday); + gint since_midnight = today->tm_sec + (60 * today->tm_min) + (60 * 60 * today->tm_hour); + gboolean future = (diff > 0); + + if (!future) + diff *= -1; + + diff = (diff - since_midnight) / (24 * 60 * 60); + if (diff <= 1) { + if (future) + res = g_strdup (_("Tomorrow")); + else + res = g_strdup (_("Yesterday")); + } else { + if (future) + res = g_strdup_printf (_("%d days from now"), diff); + else + res = g_strdup_printf (_("%d days ago"), diff); + } + } + + return res; +} + +static gchar * +format_internal (const gchar *key, DTFormatKind kind, time_t tvalue, struct tm *tm_value) +{ + const gchar *fmt; + gchar buff[129]; + GString *use_fmt = NULL; + gint i, last = 0; + struct tm today, value; + time_t ttoday; + + tzset(); + if (!tm_value) { + localtime_r (&tvalue, &value); + tm_value = &value; + } else { + /* recalculate tvalue to local (system) timezone */ + tvalue = mktime (tm_value); + localtime_r (&tvalue, &value); + } + + fmt = get_format_internal (key, kind); + for (i = 0; fmt [i]; i++) { + if (fmt [i] == '%') { + if (fmt [i + 1] == '%') { + i++; + } else if (fmt [i + 1] == 'a' && fmt [i + 2] == 'd' && (fmt [i + 3] == 0 || !g_ascii_isalpha (fmt [i + 3]))) { + gchar *ad; + + /* "%ad" for abbreviated date */ + if (!use_fmt) { + use_fmt = g_string_new (""); + + ttoday = time (NULL); + localtime_r (&ttoday, &today); + } + + g_string_append_len (use_fmt, fmt + last, i - last); + last = i + 3; + i += 2; + + ad = format_relative_date (tvalue, ttoday, &value, &today); + if (ad) + g_string_append (use_fmt, ad); + else if (g_ascii_isspace (fmt [i + 3])) + i++; + + g_free (ad); + } + } + } + + if (use_fmt && last < i) { + g_string_append_len (use_fmt, fmt + last, i - last); + } + + e_utf8_strftime_fix_am_pm (buff, sizeof (buff) - 1, use_fmt ? use_fmt->str : fmt, tm_value); + + if (use_fmt) + g_string_free (use_fmt, TRUE); + + return g_strstrip (g_strdup (buff)); +} + +static void +fill_combo_formats (GtkWidget *combo, const gchar *key, DTFormatKind kind) +{ + const gchar *date_items [] = { + N_ ("Use locale default"), + "%m/%d/%y", /* American style */ + "%m/%d/%Y", /* American style, full year */ + "%d.%m.%y", /* non-American style */ + "%d.%m.%Y", /* non-American style, full year */ + "%ad", /* abbreviated date, like "Today" */ + NULL + }; + + const gchar *time_items [] = { + N_ ("Use locale default"), + "%I:%M:%S %p", /* 12hours style */ + "%I:%M %p", /* 12hours style, without seconds */ + "%H:%M:%S", /* 24hours style */ + "%H:%M", /* 24hours style, without seconds */ + NULL + }; + + const gchar *datetime_items [] = { + N_ ("Use locale default"), + "%m/%d/%y %I:%M:%S %p", /* American style */ + "%m/%d/%Y %I:%M:%S %p", /* American style, full year */ + "%m/%d/%y %I:%M %p", /* American style, without seconds */ + "%m/%d/%Y %I:%M %p", /* American style, without seconds, full year */ + "%ad %I:%M:%S %p", /* %ad is an abbreviated date, like "Today" */ + "%ad %I:%M %p", /* %ad is an abbreviated date, like "Today", without seconds */ + "%d.%m.%y %H:%M:%S", /* non-American style */ + "%d.%m.%Y %H:%M:%S", /* non-American style, full year */ + "%d.%m.%y %H:%M", /* non-American style, without seconds */ + "%d.%m.%Y %H:%M", /* non-American style, without seconds, full year */ + "%ad %H:%M:%S", + "%ad %H:%M", /* without seconds */ + NULL + }; + + const gchar *shortdate_items [] = { + "%A, %B %d", + "%A, %d %B", + "%a, %b %d", + "%a, %d %b", + NULL + }; + + const gchar **items = NULL; + int i, idx = 0; + const gchar *fmt; + + g_return_if_fail (GTK_IS_COMBO_BOX_ENTRY (combo)); + + switch (kind) { + case DTFormatKindDate: + items = date_items; + break; + case DTFormatKindTime: + items = time_items; + break; + case DTFormatKindDateTime: + items = datetime_items; + break; + case DTFormatKindShortDate: + items = shortdate_items; + break; + } + + g_return_if_fail (items != NULL); + + fmt = get_format_internal (key, kind); + + for (i = 0; items [i]; i++) { + if (i == 0) { + gtk_combo_box_append_text ((GtkComboBox *) combo, _(items[i])); + } else { + gtk_combo_box_append_text ((GtkComboBox *) combo, items[i]); + if (!idx && fmt && g_str_equal (fmt, items[i])) + idx = i; + } + } + + if (idx == 0 && fmt && !g_str_equal (fmt, get_default_format (kind, key))) { + gtk_combo_box_append_text ((GtkComboBox *) combo, fmt); + idx = i; + } + + gtk_combo_box_set_active ((GtkComboBox *) combo, idx); +} + +static void +update_preview_widget (GtkWidget *combo) +{ + GtkWidget *preview; + const gchar *key; + gchar *value; + time_t now; + + g_return_if_fail (combo != NULL); + g_return_if_fail (GTK_IS_COMBO_BOX_ENTRY (combo)); + + preview = g_object_get_data (G_OBJECT (combo), "preview-label"); + g_return_if_fail (preview != NULL); + g_return_if_fail (GTK_IS_LABEL (preview)); + + key = g_object_get_data (G_OBJECT (combo), "format-key"); + g_return_if_fail (key != NULL); + + time (&now); + + value = format_internal (key, GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "format-kind")), now, NULL); + gtk_label_set_text (GTK_LABEL (preview), value ? value : ""); + g_free (value); +} + +static void +format_combo_changed_cb (GtkWidget *combo, gpointer user_data) +{ + const gchar *key; + DTFormatKind kind; + GKeyFile *keyfile; + + g_return_if_fail (combo != NULL); + g_return_if_fail (GTK_IS_COMBO_BOX_ENTRY (combo)); + + key = g_object_get_data (G_OBJECT (combo), "format-key"); + g_return_if_fail (key != NULL); + + kind = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (combo), "format-kind")); + keyfile = g_object_get_data (G_OBJECT (combo), "setup-key-file"); + + if (kind != DTFormatKindShortDate && gtk_combo_box_get_active (GTK_COMBO_BOX (combo)) == 0) { + /* use locale default */ + set_format_internal (key, NULL, keyfile); + } else { + gchar *text; + + text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (combo)); + set_format_internal (key, text, keyfile); + g_free (text); + } + + update_preview_widget (combo); + + /* save on every change only because 'unref_setup_keyfile' is never called :( + how about in kill-bonobo? */ + save_keyfile (keyfile); +} + +static gchar * +gen_key (const gchar *component, const gchar *part, DTFormatKind kind) +{ + const gchar *kind_str = NULL; + + g_return_val_if_fail (component != NULL, NULL); + g_return_val_if_fail (*component != 0, NULL); + + + switch (kind) { + case DTFormatKindDate: + kind_str = "Date"; + break; + case DTFormatKindTime: + kind_str = "Time"; + break; + case DTFormatKindDateTime: + kind_str = "DateTime"; + break; + case DTFormatKindShortDate: + kind_str = "ShortDate"; + break; + } + + return g_strconcat (component, (part && *part) ? "-" : "", part && *part ? part : "", "-", kind_str, NULL); +} + +static void +unref_setup_keyfile (gpointer ptr) +{ + g_return_if_fail (ptr == setup_keyfile); + g_return_if_fail (setup_keyfile != NULL); + g_return_if_fail (setup_keyfile_instances > 0); + + /* this is never called :( */ + setup_keyfile_instances--; + if (setup_keyfile_instances == 0) { + save_keyfile (setup_keyfile); + g_key_file_free (setup_keyfile); + setup_keyfile = NULL; + } +} + +/** + * e_datetime_format_add_setup_widget: + * @table: Where to attach widgets. Requires 3 columns. + * @row: On which row to attach. + * @component: Component identifier for the format. Cannot be empty nor NULL. + * @part: Part in the component, can be NULL or empty string. + * @kind: Kind of the format for the component/part. + * @caption: Caption for the widget, can be NULL, then the "Format:" is used. + * + * Adds a setup widget for a component and part. The table should have 3 columns. + * All the work related to loading and saving the value is done automatically, + * on user's changes. + **/ +void +e_datetime_format_add_setup_widget (GtkWidget *table, gint row, const gchar *component, const gchar *part, DTFormatKind kind, const gchar *caption) +{ + GtkWidget *label, *combo, *preview, *align; + gchar *key; + + g_return_if_fail (table != NULL); + g_return_if_fail (row >= 0); + g_return_if_fail (component != NULL); + g_return_if_fail (*component != 0); + + key = gen_key (component, part, kind); + + label = gtk_label_new_with_mnemonic (caption ? caption : _("Format:")); + combo = gtk_combo_box_entry_new_text (); + + fill_combo_formats (combo, key, kind); + gtk_label_set_mnemonic_widget ((GtkLabel *)label, combo); + + align = gtk_alignment_new (0.0, 0.5, 0.0, 0.0); + gtk_container_add (GTK_CONTAINER (align), combo); + + gtk_table_attach ((GtkTable *) table, label, 0, 1, row, row + 1, 0, 0, 2, 0); + gtk_table_attach ((GtkTable *) table, align, 1, 2, row, row + 1, 0, 0, 2, 0); + + preview = gtk_label_new (""); + gtk_misc_set_alignment (GTK_MISC (preview), 0.0, 0.5); + gtk_label_set_ellipsize (GTK_LABEL (preview), PANGO_ELLIPSIZE_END); + gtk_table_attach ((GtkTable *) table, preview, 2, 3, row, row + 1, GTK_EXPAND | GTK_FILL, 0, 2, 0); + + if (!setup_keyfile) { + gchar *filename; + + filename = g_build_filename (e_get_user_data_dir (), KEYS_FILENAME, NULL); + setup_keyfile = g_key_file_new (); + g_key_file_load_from_file (setup_keyfile, filename, G_KEY_FILE_NONE, NULL); + g_free (filename); + + setup_keyfile_instances = 1; + } else { + setup_keyfile_instances++; + } + + g_object_set_data (G_OBJECT (combo), "preview-label", preview); + g_object_set_data (G_OBJECT (combo), "format-kind", GINT_TO_POINTER (kind)); + g_object_set_data_full (G_OBJECT (combo), "format-key", key, g_free); + g_object_set_data_full (G_OBJECT (combo), "setup-key-file", setup_keyfile, unref_setup_keyfile); + g_signal_connect (combo, "changed", G_CALLBACK (format_combo_changed_cb), NULL); + + update_preview_widget (combo); + + gtk_widget_show_all (table); +} + +gchar * +e_datetime_format_format (const gchar *component, const gchar *part, DTFormatKind kind, time_t value) +{ + gchar *key, *res; + + g_return_val_if_fail (component != NULL, NULL); + g_return_val_if_fail (*component != 0, NULL); + + key = gen_key (component, part, kind); + g_return_val_if_fail (key != NULL, NULL); + + res = format_internal (key, kind, value, NULL); + + g_free (key); + + return res; +} + +gchar * +e_datetime_format_format_tm (const gchar *component, const gchar *part, DTFormatKind kind, struct tm *tm_time) +{ + gchar *key, *res; + + g_return_val_if_fail (component != NULL, NULL); + g_return_val_if_fail (*component != 0, NULL); + g_return_val_if_fail (tm_time != NULL, NULL); + + key = gen_key (component, part, kind); + g_return_val_if_fail (key != NULL, NULL); + + res = format_internal (key, kind, 0, tm_time); + + g_free (key); + + return res; +} diff --git a/e-util/e-datetime-format.h b/e-util/e-datetime-format.h new file mode 100644 index 0000000000..80f7d18826 --- /dev/null +++ b/e-util/e-datetime-format.h @@ -0,0 +1,46 @@ +/* + * + * Customizable date/time formatting in Evolution + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see + * + * + * Copyright (C) 1999-2009 Novell, Inc. (www.novell.com) + * + */ + +#ifndef __E_DATETIME_FORMAT__ +#define __E_DATETIME_FORMAT__ + +#include +#include +#include + +G_BEGIN_DECLS + +typedef enum _DTFormatKind { + DTFormatKindDate, + DTFormatKindTime, + DTFormatKindDateTime, + DTFormatKindShortDate +} DTFormatKind; + +void e_datetime_format_add_setup_widget (GtkWidget *table, gint row, const gchar *component, const gchar *part, DTFormatKind kind, const gchar *caption); + +gchar *e_datetime_format_format (const gchar *component, const gchar *part, DTFormatKind kind, time_t value); +gchar *e_datetime_format_format_tm (const gchar *component, const gchar *part, DTFormatKind kind, struct tm *tm_time); + +G_END_DECLS + +#endif diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c index a15b0d671f..70b8547972 100644 --- a/mail/em-format-html-display.c +++ b/mail/em-format-html-display.c @@ -63,6 +63,7 @@ #include #include +#include "e-util/e-datetime-format.h" #include #include @@ -81,16 +82,6 @@ #include "widgets/misc/e-attachment-button.h" #include "widgets/misc/e-attachment-view.h" -#ifdef G_OS_WIN32 -/* Undefine the similar macro from ,it doesn't check if - * localtime() returns NULL. - */ -#undef localtime_r - -/* The localtime() in Microsoft's C library is MT-safe */ -#define localtime_r(tp,tmp) (localtime(tp)?(*(tmp)=*localtime(tp),(tmp)):0) -#endif - #define d(x) #define EM_FORMAT_HTML_DISPLAY_GET_PRIVATE(obj) \ @@ -768,9 +759,7 @@ efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMF { const gchar *flag, *comp, *due; time_t date; - gchar due_date[128]; - struct tm due_tm; - gchar *iconpath; + gchar *iconpath, *due_date_str; if (emf->folder == NULL || emf->uid == NULL || (flag = camel_folder_get_message_user_tag(emf->folder, emf->uid, "follow-up")) == NULL @@ -801,10 +790,10 @@ efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMF camel_stream_printf(stream, "
"); if (comp && comp[0]) { - date = camel_header_decode_date(comp, NULL); - localtime_r(&date, &due_tm); - e_utf8_strftime_fix_am_pm(due_date, sizeof (due_date), _("Completed on %B %d, %Y, %l:%M %p"), &due_tm); - camel_stream_printf(stream, "%s, %s", flag, due_date); + date = camel_header_decode_date (comp, NULL); + due_date_str = e_datetime_format_format ("mail", "header", DTFormatKindDateTime, date); + camel_stream_printf (stream, "%s, %s %s", flag, _("Completed on"), due_date_str ? due_date_str : "???"); + g_free (due_date_str); } else if ((due = camel_folder_get_message_user_tag(emf->folder, emf->uid, "due-by")) != NULL && due[0]) { time_t now; @@ -813,9 +802,9 @@ efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMF if (now > date) camel_stream_printf(stream, "%s ", _("Overdue:")); - localtime_r(&date, &due_tm); - e_utf8_strftime_fix_am_pm(due_date, sizeof (due_date), _("by %B %d, %Y, %l:%M %p"), &due_tm); - camel_stream_printf(stream, "%s %s", flag, due_date); + due_date_str = e_datetime_format_format ("mail", "header", DTFormatKindDateTime, date); + /* To Translators: the "by" is part of the string, like "Follow-up by Tuesday, January 13, 2009" */ + camel_stream_printf (stream, "%s %s %s", flag, _("by"), due_date_str ? due_date_str : "???"); } else { camel_stream_printf(stream, "%s", flag); } diff --git a/mail/em-format-html.c b/mail/em-format-html.c index fa713282c1..b9657a1fd9 100644 --- a/mail/em-format-html.c +++ b/mail/em-format-html.c @@ -43,6 +43,7 @@ #include /* for e_utf8_strftime, what about e_time_format_time? */ #include +#include "e-util/e-datetime-format.h" #include "e-util/e-icon-factory.h" #include "e-util/e-util-private.h" #include "e-util/e-util.h" @@ -2321,14 +2322,16 @@ efh_format_header(EMFormat *emf, CamelStream *stream, CamelMedium *part, struct gint msg_offset, local_tz; time_t msg_date; struct tm local; + gchar *date_str; txt = header->value; while (*txt == ' ' || *txt == '\t') txt++; - /* Show the local timezone equivalent in brackets if the sender is remote */ msg_date = camel_header_decode_date(txt, &msg_offset); - e_localtime_with_offset(msg_date, &local, &local_tz); + e_localtime_with_offset (msg_date, &local, &local_tz); + + date_str = e_datetime_format_format ("mail", "header", DTFormatKindDateTime, msg_date); /* Convert message offset to minutes (e.g. -0400 --> -240) */ msg_offset = ((msg_offset / 100) * 60) + (msg_offset % 100); @@ -2336,25 +2339,18 @@ efh_format_header(EMFormat *emf, CamelStream *stream, CamelMedium *part, struct msg_offset -= local_tz / 60; if (msg_offset) { - gchar buf[256], *html; + gchar *html; - msg_offset += (local.tm_hour * 60) + local.tm_min; - if (msg_offset >= (24 * 60) || msg_offset < 0) { - /* translators: strftime format for local time equivalent in Date header display, with day */ - gchar *msg = g_strdup_printf("%s", _(" (%a, %R %Z)")); - e_utf8_strftime(buf, sizeof(buf), msg, &local); - g_free(msg); - } else { - /* translators: strftime format for local time equivalent in Date header display, without day */ - gchar *msg = g_strdup_printf("%s", _(" (%R %Z)")); - e_utf8_strftime(buf, sizeof(buf), msg, &local); - g_free(msg); - } + html = camel_text_to_html (txt, efh->text_html_flags, 0); + txt = value = g_strdup_printf ("%s (%s)", date_str, html); + + g_free (html); + g_free (date_str); - html = camel_text_to_html(txt, efh->text_html_flags, 0); - txt = value = g_strdup_printf("%s %s", html, buf); - g_free(html); flags |= EM_FORMAT_HTML_HEADER_HTML; + } else { + /* date_str will be freed at the end */ + txt = value = date_str; } flags |= EM_FORMAT_HEADER_BOLD; diff --git a/mail/mail-config.glade b/mail/mail-config.glade index b6e61b87f7..a0b61bf6bd 100644 --- a/mail/mail-config.glade +++ b/mail/mail-config.glade @@ -3215,685 +3215,1290 @@ For example: "Work" or "Personal" True a b - - - False - False - 1 - - - - - 0 - - - - - Confirm _when expunging a folder - True - True - False - True - True - - - False - False - 1 - - - - - - - 1 - - - - - 1 - - - - - False - False - 2 - - - - - - - True - General - True - center - - - False - tab - - - - - True - 12 - 12 - - - True - 0 - <span weight="bold">General</span> - True - - - False - False - 0 - - - - - True - 12 - - - True - - - False - False - 0 - - - - - True - 6 - - - _Show image animations - True - True - False - True - True - - - False - False - 0 - - - - - _Prompt on sending HTML mail to contacts that do not want them - True - True - False - True - True - - - False - False - 1 - - - - - False - False - 1 - - - - - False - False - 1 - - - - - True - 6 - - - True - 0 - <span weight="bold">Loading Images</span> - True - - - False - False - 0 - - - - - True - 12 - - - True - - - False - False - 0 - - - - - True - 6 - - - _Never load images from the Internet - True - True - False - True - True - - - False - False - 0 - - - - - _Load images in messages from contacts - True - True - False - True - True - radImagesNever - - - False - False - 1 - - - - - _Always load images from the Internet - True - True - False - True - True - radImagesNever - - - False - False - 2 - - - - - False - False - 1 - - - - - False - False - 1 - - - - - False - False - 2 - - - - - 1 - - - - - True - HTML Messages - True - center - - - 1 - False - tab - - - - - True - 12 - 6 - - - True - 0 - <span weight="bold">Labels</span> - True - - - False - False - 0 - - - - - True - 12 - - - - - - 1 - - - - - 2 - - - - - True - Labels - True - center - - - 2 - False - tab - - - - - True - 12 - 6 - - - True - 3 - - - True - - - True - <b>Sender Photograph</b> - True - - - False - False - 0 - - - - - False - False - 0 - - - - - True - - - True - - - _Show the photograph of sender in the message preview - True - True - False - True - True - - - False - False - 10 - 0 - - - - - False - False - 0 - - - - - True - - - S_earch for sender photograph only in local address books - True - True - False - True - True - - - False - False - 10 - 0 - - - - - False - False - 1 - - - - - False - False - 1 - - - - - False - False - 0 - - - - - True - 0 - <span weight="bold">Displayed Message _Headers</span> - True - True - txtHeaders - - - False - False - 1 - - - - - True - 12 - - - True - - - False - False - 0 - - - - - True - 12 - - - True - True - - - False - False - 0 - - - - - True - True - automatic - automatic - in - - - True - True - False - - Mail Headers Table - - - - - - 1 - - - - - 1 - - - - - True - 6 - - - gtk-add - True - False - True - False - True - - - False - False - 0 - - - - - gtk-remove - True - True - False - True - - - False - False - 1 - - - - - False - False - 2 - - - - - 2 - - - - - 3 - - - - - True - Headers - True - - - 3 - False - tab - - - - - True - 12 - 6 - - - True - - - True - 0 - <span weight="bold">General</span> - True - - - False - False - 0 - - - - - True - 12 - 9 - 3 - - - True - 6 - - - True - _Default junk plugin: - True - default_junk_plugin - - - False - False - 6 - 0 - - - - - True - create_combo_text_widget - - - False - False - 1 - - - - - 7 - 8 - GTK_FILL - - - - - Check incoming _messages for junk - True - True - False - Checks incoming mail messages to be Junk - True - True - - - GTK_FILL - - 4 - - - - - True - 3 - - - True - gtk-info - 4 - - - False - False - 0 - - - - - True - True - - - False - False - 1 - - - - - 8 - 9 - GTK_FILL - 15 - - - - - True - 4 - - - Delete junk messages on e_xit - True - True - False - True - True - - - False - False - 0 - - - - - True - a + False + True + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + True + Confirm _when expunging a folder + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + 0 + 1 + 0 + 1 + + + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + False + + + + + False + True + + + + + + True + General + True + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + 12 + True + False + 12 + + + + True + <span weight="bold">General</span> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + False + 12 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + False + 6 + + + + True + True + _Show image animations + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + _Prompt on sending HTML mail to contacts that do not want them + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + 0 + False + False + + + + + 0 + False + False + + + + + + True + False + 6 + + + + True + <span weight="bold">Loading Images</span> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + False + 12 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + False + 6 + + + + True + True + _Never load images from the Internet + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + _Load images in messages from contacts + True + GTK_RELIEF_NORMAL + True + False + False + True + radImagesNever + + + 0 + False + False + + + + + + True + True + _Always load images from the Internet + True + GTK_RELIEF_NORMAL + True + False + False + True + radImagesNever + + + 0 + False + False + + + + + 0 + False + False + + + + + 0 + False + False + + + + + 0 + False + False + + + + + False + True + + + + + + True + HTML Messages + True + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + 12 + True + False + 6 + + + + True + <span weight="bold">Labels</span> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + False + 12 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + False + 0 + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + False + False + True + False + False + False + + + + + 0 + True + True + + + + + + True + Note: Underscore in the label name is used as mnemonic identifier in menu. + False + False + GTK_JUSTIFY_CENTER + True + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 10 + False + False + + + + + 0 + True + True + + + + + + True + False + 2 + + + + True + True + gtk-add + True + GTK_RELIEF_NORMAL + False + + + 0 + False + False + + + + + + True + True + gtk-edit + True + GTK_RELIEF_NORMAL + True + + + 0 + False + False + + + + + + True + True + gtk-remove + True + GTK_RELIEF_NORMAL + True + + + 0 + False + False + + + + + + + + + 6 + False + False + + + + + 0 + True + True + + + + + 0 + True + True + + + + + False + True + + + + + + True + Labels + True + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + 12 + True + False + 6 + + + + True + False + 3 + + + + True + False + 0 + + + + True + <b>Sender Photograph</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 0 + False + False + + + + + + True + False + 0 + + + + True + False + 0 + + + + True + True + _Show the photograph of sender in the message preview + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 10 + False + False + + + + + 0 + False + False + + + + + + True + False + 0 + + + + True + True + S_earch for sender photograph only in local address books + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 10 + False + False + + + + + 0 + False + False + + + + + 0 + False + False + + + + + 0 + False + False + + + + + + True + <span weight="bold">Displayed Message _Headers</span> + True + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + txtHeaders + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + False + 12 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + False + 12 + + + + True + True + True + True + 0 + + True + * + False + + + 0 + False + False + + + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + False + True + False + False + False + + Mail Headers Table + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + False + 6 + + + + True + False + True + gtk-add + True + GTK_RELIEF_NORMAL + True + + + 0 + False + False + + + + + + True + True + gtk-remove + True + GTK_RELIEF_NORMAL + True + + + 0 + False + False + + + + + 0 + False + False + + + + + 0 + True + True + + + + + + True + False + 0 + + + + True + <span weight="bold">Date/Time Format</span> + True + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + txtHeaders + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + False + 0 + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 6 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 1 + 3 + False + 0 + 0 + + + 0 + True + True + + + + + 0 + True + True + + + + + 0 + False + True + + + + + False + True + + + + + + True + Headers + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + tab + + + + + + 12 + True + False + 6 + + + + True + False + 0 + + + + True + <span weight="bold">General</span> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + 12 + True + 9 + 1 + False + 3 + 0 + + + + True + False + 6 + + + + True + _Default junk plugin: + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + default_junk_plugin + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 6 + False + False + + + + + + True + create_combo_text_widget + 0 + 0 + Fri, 23 Mar 2007 09:28:55 GMT + + + 0 + False + False + + + + + 0 + 1 + 7 + 8 + fill + + + + + + True + Checks incoming mail messages to be Junk + True + Check incoming _messages for junk + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 1 + 0 + 1 + 4 + fill + + + + + + + True + False + 3 + + + + True + 4 + gtk-info + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + + False + True + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 0 + 1 + 8 + 9 + 15 + fill + + + + + + True + False + 4 + + + + True + True + Delete junk messages on e_xit + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + a b diff --git a/mail/message-list.c b/mail/message-list.c index b80431d5ff..7e0fb9b4c2 100644 --- a/mail/message-list.c +++ b/mail/message-list.c @@ -1811,7 +1811,8 @@ static ECell * create_composite_cell (gint col) images [i] = states_pixmaps [i + 6].pixbuf; cell_attach = e_cell_toggle_new (0, 2, images); - cell_date = e_cell_date_new(NULL, GTK_JUSTIFY_RIGHT); + cell_date = e_cell_date_new (NULL, GTK_JUSTIFY_RIGHT); + e_cell_date_set_format_component (E_CELL_DATE (cell_date), "mail"); g_object_set (G_OBJECT (cell_date), "bold_column", COL_UNREAD, "color_column", COL_COLOUR, @@ -1894,6 +1895,7 @@ message_list_create_extras (void) /* date cell */ cell = e_cell_date_new (NULL, GTK_JUSTIFY_LEFT); + e_cell_date_set_format_component (E_CELL_DATE (cell), "mail"); g_object_set (G_OBJECT (cell), "bold_column", COL_UNREAD, "color_column", COL_COLOUR, @@ -1927,6 +1929,10 @@ message_list_create_extras (void) cell = create_composite_cell (COL_TO); e_table_extras_add_cell (extras, "render_composite_to", cell); + /* set proper format component for a default 'date' cell renderer */ + cell = e_table_extras_get_cell (extras, "date"); + e_cell_date_set_format_component (E_CELL_DATE (cell), "mail"); + return extras; } diff --git a/modules/addressbook/autocompletion-config.c b/modules/addressbook/autocompletion-config.c index 370c1a1e7e..1ce9e707fa 100644 --- a/modules/addressbook/autocompletion-config.c +++ b/modules/addressbook/autocompletion-config.c @@ -30,6 +30,7 @@ #include #include +#include "e-util/e-datetime-format.h" #include "widgets/misc/e-preferences-window.h" static void @@ -129,9 +130,9 @@ autocompletion_config_init (EShell *shell) e_preferences_window_add_page ( E_PREFERENCES_WINDOW (preferences_window), - "autocompletion", + "contacts", "preferences-autocompletion", - _("Autocompletion"), + _("Contacts"), scrolled_window, 200); } diff --git a/modules/mail/em-mailer-prefs.c b/modules/mail/em-mailer-prefs.c index d9ec9e751b..e2c956e0ff 100644 --- a/modules/mail/em-mailer-prefs.c +++ b/modules/mail/em-mailer-prefs.c @@ -41,6 +41,7 @@ #include "libedataserverui/e-cell-renderer-color.h" #include "e-util/e-binding.h" +#include "e-util/e-datetime-format.h" #include "e-util/e-util-private.h" #include "widgets/misc/e-charset-combo-box.h" @@ -811,6 +812,7 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs, GHashTable *default_header_hash; GtkWidget *toplevel; GtkWidget *container; + GtkWidget *table; GtkWidget *widget; GtkTreeSelection *selection; GtkCellRenderer *renderer; @@ -1133,6 +1135,11 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs, g_slist_free (header_add_list); + /* date/time format */ + table = glade_xml_get_widget (gui, "datetime_format_table"); + e_datetime_format_add_setup_widget (table, 0, "mail", "header", DTFormatKindDateTime, _("Date header:")); + e_datetime_format_add_setup_widget (table, 1, "mail", "table", DTFormatKindDateTime, _("Table column:")); + /* Junk prefs */ widget = glade_xml_get_widget (gui, "chkCheckIncomingMail"); e_mutual_binding_new ( diff --git a/po/POTFILES.in b/po/POTFILES.in index 3e9daf0bea..f89170e0af 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -147,6 +147,7 @@ data/evolution.desktop.in.in data/evolution.keys.in.in e-util/e-categories-config.c e-util/e-charset.c +e-util/e-datetime-format.c e-util/e-dialog-utils.c e-util/e-error.c e-util/e-logger.c diff --git a/widgets/table/e-cell-date.c b/widgets/table/e-cell-date.c index d9dcbbea3b..ca1d842526 100644 --- a/widgets/table/e-cell-date.c +++ b/widgets/table/e-cell-date.c @@ -30,84 +30,28 @@ #include #include "e-util/e-util.h" #include "e-util/e-unicode.h" +#include "e-util/e-datetime-format.h" #include "e-cell-date.h" G_DEFINE_TYPE (ECellDate, e_cell_date, E_CELL_TEXT_TYPE) -#ifdef G_OS_WIN32 -/* The localtime() in Microsoft's C library *is* thread-safe */ -#define localtime_r(timep, result) (localtime (timep) ? memcpy ((result), localtime (timep), sizeof (*(result))) : 0) -#endif - static gchar * ecd_get_text(ECellText *cell, ETableModel *model, gint col, gint row) { time_t date = GPOINTER_TO_INT (e_table_model_value_at(model, col, row)); - time_t nowdate = time(NULL); - time_t yesdate; - struct tm then, now, yesterday; - gchar buf[100]; - gchar *temp; - gboolean done = FALSE; + const gchar *fmt_component, *fmt_part = NULL; if (date == 0) { return g_strdup (_("?")); } - tzset (); - localtime_r (&date, &then); - localtime_r (&nowdate, &now); - - if (nowdate - date < 60 * 60 * 8 && nowdate > date) { - e_utf8_strftime_fix_am_pm (buf, 100, _("%l:%M %p"), &then); - done = TRUE; - } - - if (!done) { - if (then.tm_mday == now.tm_mday && - then.tm_mon == now.tm_mon && - then.tm_year == now.tm_year) { - e_utf8_strftime_fix_am_pm (buf, 100, _("Today %l:%M %p"), &then); - done = TRUE; - } - } - if (!done) { - yesdate = nowdate - 60 * 60 * 24; - localtime_r (&yesdate, &yesterday); - if (then.tm_mday == yesterday.tm_mday && - then.tm_mon == yesterday.tm_mon && - then.tm_year == yesterday.tm_year) { - e_utf8_strftime_fix_am_pm (buf, 100, _("Yesterday %l:%M %p"), &then); - done = TRUE; - } - } - if (!done) { - gint i; - for (i = 2; i < 7; i++) { - yesdate = nowdate - 60 * 60 * 24 * i; - localtime_r (&yesdate, &yesterday); - if (then.tm_mday == yesterday.tm_mday && - then.tm_mon == yesterday.tm_mon && - then.tm_year == yesterday.tm_year) { - e_utf8_strftime_fix_am_pm (buf, 100, _("%a %l:%M %p"), &then); - done = TRUE; - break; - } - } - } - if (!done) { - if (then.tm_year == now.tm_year) { - e_utf8_strftime_fix_am_pm (buf, 100, _("%b %d %l:%M %p"), &then); - } else { - e_utf8_strftime_fix_am_pm (buf, 100, _("%b %d %Y"), &then); - } - } - temp = buf; - while ((temp = strstr (temp, " "))) { - memmove (temp, temp + 1, strlen (temp)); - } - return g_strstrip (g_strdup (buf)); + fmt_component = g_object_get_data ((GObject *) cell, "fmt-component"); + if (!fmt_component || !*fmt_component) + fmt_component = "Default"; + else + fmt_part = "table"; + return e_datetime_format_format (fmt_component, fmt_part, DTFormatKindDateTime, date); } static void @@ -165,3 +109,10 @@ e_cell_date_new (const gchar *fontname, GtkJustification justify) return (ECell *) ecd; } +void +e_cell_date_set_format_component (ECellDate *ecd, const gchar *fmt_component) +{ + g_return_if_fail (ecd != NULL); + + g_object_set_data_full ((GObject *)ecd, "fmt-component", g_strdup (fmt_component), g_free); +} diff --git a/widgets/table/e-cell-date.h b/widgets/table/e-cell-date.h index 968e387198..ec23bd61ad 100644 --- a/widgets/table/e-cell-date.h +++ b/widgets/table/e-cell-date.h @@ -44,6 +44,7 @@ typedef struct { GType e_cell_date_get_type (void); ECell *e_cell_date_new (const gchar *fontname, GtkJustification justify); +void e_cell_date_set_format_component (ECellDate *ecd, const gchar *fmt_component); G_END_DECLS