aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2009-08-04 21:04:02 +0800
committerMilan Crha <mcrha@redhat.com>2009-08-04 21:04:02 +0800
commitb6313289303f2263649c70ea477e04aea4a994ec (patch)
tree36b4435a060aca6425e717b1b0ddd29efb8a0712
parentbc301a8c3784610a0c55c9fb5056ec63ca574f4d (diff)
downloadgsoc2013-evolution-b6313289303f2263649c70ea477e04aea4a994ec.tar
gsoc2013-evolution-b6313289303f2263649c70ea477e04aea4a994ec.tar.gz
gsoc2013-evolution-b6313289303f2263649c70ea477e04aea4a994ec.tar.bz2
gsoc2013-evolution-b6313289303f2263649c70ea477e04aea4a994ec.tar.lz
gsoc2013-evolution-b6313289303f2263649c70ea477e04aea4a994ec.tar.xz
gsoc2013-evolution-b6313289303f2263649c70ea477e04aea4a994ec.tar.zst
gsoc2013-evolution-b6313289303f2263649c70ea477e04aea4a994ec.zip
Bug #205137 - Configurable date formats in components
-rw-r--r--addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in4
-rw-r--r--addressbook/gui/component/autocompletion-config.c9
-rw-r--r--addressbook/gui/widgets/e-addressbook-view.c11
-rw-r--r--calendar/gui/dialogs/cal-prefs-dialog.c8
-rw-r--r--calendar/gui/dialogs/cal-prefs-dialog.glade79
-rw-r--r--calendar/gui/e-cal-list-view.c6
-rw-r--r--calendar/gui/e-calendar-table.c5
-rw-r--r--calendar/gui/e-calendar-view.c8
-rw-r--r--calendar/gui/e-cell-date-edit-text.c7
-rw-r--r--calendar/gui/e-memo-table.c5
-rw-r--r--e-util/Makefile.am2
-rw-r--r--e-util/e-datetime-format.c571
-rw-r--r--e-util/e-datetime-format.h46
-rw-r--r--mail/em-format-html-display.c29
-rw-r--r--mail/em-format-html.c34
-rw-r--r--mail/em-mailer-prefs.c8
-rw-r--r--mail/mail-config.glade93
-rw-r--r--mail/message-list.c8
-rw-r--r--po/POTFILES.in1
-rw-r--r--widgets/table/e-cell-date.c79
-rw-r--r--widgets/table/e-cell-date.h1
21 files changed, 893 insertions, 121 deletions
diff --git a/addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in b/addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in
index 823d5bd89f..4000f01526 100644
--- a/addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in
+++ b/addressbook/gui/component/GNOME_Evolution_Addressbook.server.in.in
@@ -115,10 +115,10 @@
</oaf_attribute>
<oaf_attribute name="evolution2:config_item:title" type="string"
- _value="Autocompletion"/>
+ _value="Contacts"/>
<oaf_attribute name="evolution2:config_item:description" type="string"
- _value="Configure autocomplete here"/>
+ _value="Configure contacts and autocompletion here"/>
<oaf_attribute name="evolution2:config_item:icon_name" type="string"
value="preferences-autocompletion"/>
diff --git a/addressbook/gui/component/autocompletion-config.c b/addressbook/gui/component/autocompletion-config.c
index 9773f5bd5b..ebb2381e1e 100644
--- a/addressbook/gui/component/autocompletion-config.c
+++ b/addressbook/gui/component/autocompletion-config.c
@@ -39,6 +39,8 @@
#include <gtk/gtk.h>
#include <glib/gi18n.h>
+#include "e-util/e-datetime-format.h"
+
typedef struct {
EvolutionConfigControl *config_control;
@@ -159,7 +161,7 @@ autocompletion_config_control_new (void)
{
AutocompletionConfig *ac;
CORBA_Environment ev;
- GtkWidget *scrolledwin, *vbox, *itembox, *w;
+ GtkWidget *scrolledwin, *vbox, *itembox, *w, *table;
ac = g_new0 (AutocompletionConfig, 1);
@@ -177,6 +179,11 @@ autocompletion_config_control_new (void)
g_signal_connect (w, "toggled", (GCallback)show_address_check_toggled_cb, ac);
gtk_box_pack_start (GTK_BOX (itembox), w, FALSE, FALSE, 0);
+ itembox = add_section (vbox, _("Date/Time Format"), FALSE);
+ table = gtk_table_new (1, 3, FALSE);
+ gtk_box_pack_start (GTK_BOX (itembox), table, TRUE, TRUE, 0);
+ e_datetime_format_add_setup_widget (table, 0, "addressbook", "table", DTFormatKindDateTime, _("Table column:"));
+
itembox = add_section (vbox, _("Look up in address books"), TRUE);
ac->source_list = e_source_list_new_for_gconf_default ("/apps/evolution/addressbook/sources");
diff --git a/addressbook/gui/widgets/e-addressbook-view.c b/addressbook/gui/widgets/e-addressbook-view.c
index 25e55666d4..283b25f89f 100644
--- a/addressbook/gui/widgets/e-addressbook-view.c
+++ b/addressbook/gui/widgets/e-addressbook-view.c
@@ -26,6 +26,7 @@
#include <glib/gi18n.h>
#include <table/e-table-scrolled.h>
#include <table/e-table-model.h>
+#include <table/e-cell-date.h>
#include <misc/e-gui-utils.h>
#include <widgets/menus/gal-view-factory-etable.h>
#include <filter/rule-editor.h>
@@ -1281,18 +1282,26 @@ static void
create_table_view (EABView *view)
{
ETableModel *adapter;
+ ETableExtras *extras;
+ ECell *cell;
GtkWidget *table;
gchar *etspecfile;
adapter = eab_table_adapter_new(view->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);
- table = e_table_scrolled_new_from_spec_file (adapter, NULL, etspecfile, NULL);
+ table = e_table_scrolled_new_from_spec_file (adapter, extras, etspecfile, NULL);
g_free (etspecfile);
view->object = G_OBJECT(adapter);
diff --git a/calendar/gui/dialogs/cal-prefs-dialog.c b/calendar/gui/dialogs/cal-prefs-dialog.c
index 2c19acaadd..2fc17202cc 100644
--- a/calendar/gui/dialogs/cal-prefs-dialog.c
+++ b/calendar/gui/dialogs/cal-prefs-dialog.c
@@ -31,6 +31,7 @@
#include "../calendar-config.h"
#include "cal-prefs-dialog.h"
#include <widgets/misc/e-dateedit.h>
+#include "e-util/e-datetime-format.h"
#include <e-util/e-dialog-widgets.h>
#include <e-util/e-util-private.h>
#include <glib/gi18n.h>
@@ -779,7 +780,7 @@ calendar_prefs_dialog_construct (CalendarPrefsDialog *prefs)
ECalConfig *ec;
ECalConfigTargetPrefs *target;
gint i;
- GtkWidget *toplevel;
+ GtkWidget *toplevel, *table;
GSList *l;
const gchar *working_day_names[] = {
"sun_button",
@@ -859,6 +860,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</property>
<property name="position">3</property>
</packing>
</child>
+
+ <child>
+ <widget class="GtkLabel" id="label65">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;span weight=&quot;bold&quot;&gt;Date/Time Format&lt;/span&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox27">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label66">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="datetime_format_table">
+ <property name="visible">True</property>
+ <property name="n_rows">1</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">0</property>
+ <property name="column_spacing">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="position">1</property>
diff --git a/calendar/gui/e-cal-list-view.c b/calendar/gui/e-cal-list-view.c
index 0081dc1340..1da7f16037 100644
--- a/calendar/gui/e-cal-list-view.c
+++ b/calendar/gui/e-cal-list-view.c
@@ -40,6 +40,7 @@
#include <table/e-cell-toggle.h>
#include <table/e-cell-text.h>
#include <table/e-cell-combo.h>
+#include <table/e-cell-date.h>
#include <misc/e-popup-menu.h>
#include <misc/e-cell-date-edit.h>
#include <e-util/e-categories-config.h>
@@ -256,6 +257,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 70f347bae3..284922c029 100644
--- a/calendar/gui/e-calendar-table.c
+++ b/calendar/gui/e-calendar-table.c
@@ -42,6 +42,7 @@
#include <table/e-cell-toggle.h>
#include <table/e-cell-text.h>
#include <table/e-cell-combo.h>
+#include <table/e-cell-date.h>
#include <e-util/e-dialog-utils.h>
#include <e-util/e-util-private.h>
#include <misc/e-cell-date-edit.h>
@@ -687,6 +688,10 @@ e_calendar_table_init (ECalendarTable *cal_table)
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 (EVOLUTION_ETSPECDIR,
diff --git a/calendar/gui/e-calendar-view.c b/calendar/gui/e-calendar-view.c
index cd42454d64..286db6b5f1 100644
--- a/calendar/gui/e-calendar-view.c
+++ b/calendar/gui/e-calendar-view.c
@@ -33,6 +33,7 @@
#include <libedataserver/e-time-utils.h>
#include <e-util/e-util.h>
#include <e-util/e-error.h>
+#include <e-util/e-datetime-format.h>
#include <e-util/e-dialog-utils.h>
#include <e-util/e-icon-factory.h>
#include <libecal/e-cal-time-util.h>
@@ -2222,16 +2223,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 64dd48ddf1..5836b8ac66 100644
--- a/calendar/gui/e-cell-date-edit-text.c
+++ b/calendar/gui/e-cell-date-edit-text.c
@@ -33,6 +33,7 @@
#include <libedataserver/e-time-utils.h>
#include <libedataserver/e-data-server-util.h>
#include <e-util/e-util.h>
+#include <e-util/e-datetime-format.h>
#include <libecal/e-cal-time-util.h>
#include "e-cell-date-edit-text.h"
@@ -63,7 +64,6 @@ ecd_get_text (ECellText *cell, ETableModel *model, gint col, gint row)
ECellDateEditText *ecd = E_CELL_DATE_EDIT_TEXT (cell);
ECellDateEditValue *dv = e_table_model_value_at (model, col, row);
struct tm tmp_tm;
- gchar buffer[64];
if (!dv)
return g_strdup ("");
@@ -74,10 +74,7 @@ ecd_get_text (ECellText *cell, ETableModel *model, gint col, gint row)
it will be set to the current timezone. See set_value(). */
tmp_tm = icaltimetype_to_tm_with_zone (&dv->tt, dv->zone, ecd->zone);
- e_time_format_date_and_time (&tmp_tm, ecd->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 47b3d4410c..50158899ac 100644
--- a/calendar/gui/e-memo-table.c
+++ b/calendar/gui/e-memo-table.c
@@ -41,6 +41,7 @@
#include <table/e-cell-toggle.h>
#include <table/e-cell-text.h>
#include <table/e-cell-combo.h>
+#include <table/e-cell-date.h>
#include <e-util/e-dialog-utils.h>
#include <widgets/misc/e-cell-date-edit.h>
#include <widgets/misc/e-cell-percent.h>
@@ -255,6 +256,10 @@ e_memo_table_init (EMemoTable *memo_table)
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 (EVOLUTION_ETSPECDIR,
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index d723e3b290..35d254b4eb 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -45,6 +45,7 @@ eutilinclude_HEADERS = \
e-config.h \
e-corba-utils.h \
e-cursor.h \
+ e-datetime-format.h \
e-dialog-utils.h \
e-dialog-widgets.h \
e-error.h \
@@ -85,6 +86,7 @@ libeutil_la_SOURCES = \
e-config.c \
e-corba-utils.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 <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2009 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#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 <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2009 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef __E_DATETIME_FORMAT__
+#define __E_DATETIME_FORMAT__
+
+#include <time.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+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 312e5a1fb5..003eb37f8c 100644
--- a/mail/em-format-html-display.c
+++ b/mail/em-format-html-display.c
@@ -63,6 +63,7 @@
#include <e-util/e-util-private.h>
#include <libedataserver/e-msgport.h>
+#include "e-util/e-datetime-format.h"
#include <e-util/e-dialog-utils.h>
#include <e-util/e-icon-factory.h>
@@ -82,16 +83,6 @@
#include "widgets/misc/e-attachment-button.h"
#include "widgets/misc/e-attachment-view.h"
-#ifdef G_OS_WIN32
-/* Undefine the similar macro from <pthread.h>,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)
struct _EMFormatHTMLDisplayPrivate {
@@ -953,9 +944,7 @@ static void efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePar
{
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
@@ -986,10 +975,10 @@ static void efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePar
camel_stream_printf(stream, "<td align=\"left\" width=\"100%%\">");
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;
@@ -998,9 +987,9 @@ static void efhd_message_prefix(EMFormat *emf, CamelStream *stream, CamelMimePar
if (now > date)
camel_stream_printf(stream, "<b>%s</b>&nbsp;", _("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 ec3427c88d..038ca4b61b 100644
--- a/mail/em-format-html.c
+++ b/mail/em-format-html.c
@@ -43,6 +43,7 @@
#include <libedataserver/e-data-server-util.h> /* for e_utf8_strftime, what about e_time_format_time? */
#include <libedataserver/e-time-utils.h>
+#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"
@@ -1750,14 +1751,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);
@@ -1765,25 +1768,18 @@ efh_format_header(EMFormat *emf, CamelStream *stream, CamelMedium *part, struct
msg_offset -= local_tz / 60;
if (msg_offset) {
- gchar buf[256], *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("<I>%s</I>", _(" (%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("<I>%s</I>", _(" (%R %Z)"));
- e_utf8_strftime(buf, sizeof(buf), msg, &local);
- g_free(msg);
- }
+ gchar *html;
+
+ html = camel_text_to_html (txt, efh->text_html_flags, 0);
+ txt = value = g_strdup_printf ("%s (<I>%s</I>)", 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/em-mailer-prefs.c b/mail/em-mailer-prefs.c
index 057b2d9210..7da40551a5 100644
--- a/mail/em-mailer-prefs.c
+++ b/mail/em-mailer-prefs.c
@@ -41,6 +41,7 @@
#include "libedataserverui/e-cell-renderer-color.h"
+#include "e-util/e-datetime-format.h"
#include "e-util/e-util-private.h"
#include "e-util/e-util-labels.h"
@@ -1147,7 +1148,7 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs)
{
GSList *header_config_list, *header_add_list, *p;
GHashTable *default_header_hash;
- GtkWidget *toplevel;
+ GtkWidget *toplevel, *table;
GtkTreeSelection *selection;
GtkCellRenderer *renderer;
GtkTreeIter iter;
@@ -1449,6 +1450,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 */
prefs->check_incoming = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui, "chkCheckIncomingMail"));
toggle_button_init (prefs, prefs->check_incoming, FALSE,
diff --git a/mail/mail-config.glade b/mail/mail-config.glade
index 586dc854b1..a97fbb8ab2 100644
--- a/mail/mail-config.glade
+++ b/mail/mail-config.glade
@@ -6583,6 +6583,99 @@ b</property>
<property name="fill">True</property>
</packing>
</child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox210">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label591">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;span weight=&quot;bold&quot;&gt;Date/Time Format&lt;/span&gt;</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">txtHeaders</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox245">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label592">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">6</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="datetime_format_table">
+ <property name="visible">True</property>
+ <property name="n_rows">1</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">0</property>
+ <property name="column_spacing">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="tab_expand">False</property>
diff --git a/mail/message-list.c b/mail/message-list.c
index 07143ca0e5..92c740bb9d 100644
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@ -1728,7 +1728,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,
@@ -1811,6 +1812,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,
@@ -1844,6 +1846,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/po/POTFILES.in b/po/POTFILES.in
index 68d2da00b5..f78e5cea14 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -179,6 +179,7 @@ composer/mail-composer.error.xml
data/evolution.desktop.in.in
data/evolution.keys.in.in
e-util/e-categories-config.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 6e95a1f5ea..a3989dcc46 100644
--- a/widgets/table/e-cell-date.c
+++ b/widgets/table/e-cell-date.c
@@ -29,85 +29,29 @@
#include <glib/gi18n.h>
#include "e-util/e-util.h"
+#include "e-util/e-datetime-format.h"
#include "misc/e-unicode.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