[empathy] Adium: Convert NSDateFormatter to strftime



commit 67929359fee3036b7af9485854f009ce15b83f9d
Author: Xavier Claessens <xclaesse gmail com>
Date:   Sun May 22 10:41:16 2011 +0200

    Adium: Convert NSDateFormatter to strftime

 libempathy-gtk/empathy-theme-adium.c |  155 ++++++++++++++++++++++++++++++++--
 1 files changed, 149 insertions(+), 6 deletions(-)
---
diff --git a/libempathy-gtk/empathy-theme-adium.c b/libempathy-gtk/empathy-theme-adium.c
index b62b017..b0bd09a 100644
--- a/libempathy-gtk/empathy-theme-adium.c
+++ b/libempathy-gtk/empathy-theme-adium.c
@@ -81,6 +81,8 @@ struct _EmpathyAdiumData {
 	GHashTable *info;
 	guint version;
 	gboolean custom_template;
+	/* gchar* -> gchar* both owned */
+	GHashTable *date_format_cache;
 
 	/* HTML bits */
 	const gchar *template_html;
@@ -407,6 +409,142 @@ static gchar *colors[] = {
 	"yellowgreen",
 };
 
+static const gchar *
+nsdate_to_strftime (EmpathyAdiumData *data, const gchar *nsdate)
+{
+	/* Convert from NSDateFormatter (http://www.stepcase.com/blog/2008/12/02/format-string-for-the-iphone-nsdateformatter/)
+	 * to strftime supported by g_date_time_format.
+	 * FIXME: table is incomplete, doc of g_date_time_format has a table of
+	 *        supported tags.
+	 * FIXME: g_date_time_format in GLib 2.28 does 0 padding by default, but
+	 *        in 2.29.x we have to explictely request padding with %0x */
+	static const gchar *convert_table[] = {
+		"a", "%p", // AM/PM
+		"A", NULL, // 0~86399999 (Millisecond of Day)
+
+		"cccc", "%A", // Sunday/Monday/Tuesday/Wednesday/Thursday/Friday/Saturday
+		"ccc", "%a", // Sun/Mon/Tue/Wed/Thu/Fri/Sat
+		"cc", "%u", // 1~7 (Day of Week)
+		"c", "%u", // 1~7 (Day of Week)
+
+		"dd", "%d", // 1~31 (0 padded Day of Month)
+		"d", "%d", // 1~31 (0 padded Day of Month)
+		"D", "%j", // 1~366 (0 padded Day of Year)
+
+		"e", "%u", // 1~7 (0 padded Day of Week)
+		"EEEE", "%A", // Sunday/Monday/Tuesday/Wednesday/Thursday/Friday/Saturday
+		"EEE", "%a", // Sun/Mon/Tue/Wed/Thu/Fri/Sat
+		"EE", "%a", // Sun/Mon/Tue/Wed/Thu/Fri/Sat
+		"E", "%a", // Sun/Mon/Tue/Wed/Thu/Fri/Sat
+
+		"F", NULL, // 1~5 (0 padded Week of Month, first day of week = Monday)
+
+		"g", NULL, // Julian Day Number (number of days since 4713 BC January 1)
+		"GGGG", NULL, // Before Christ/Anno Domini
+		"GGG", NULL, // BC/AD (Era Designator Abbreviated)
+		"GG", NULL, // BC/AD (Era Designator Abbreviated)
+		"G", NULL, // BC/AD (Era Designator Abbreviated)
+
+		"h", "%I", // 1~12 (0 padded Hour (12hr))
+		"H", "%H", // 0~23 (0 padded Hour (24hr))
+
+		"k", NULL, // 1~24 (0 padded Hour (24hr)
+		"K", NULL, // 0~11 (0 padded Hour (12hr))
+
+		"LLLL", "%B", // January/February/March/April/May/June/July/August/September/October/November/December
+		"LLL", "%b", // Jan/Feb/Mar/Apr/May/Jun/Jul/Aug/Sep/Oct/Nov/Dec
+		"LL", "%m", // 1~12 (0 padded Month)
+		"L", "%m", // 1~12 (0 padded Month)
+
+		"m", "%M", // 0~59 (0 padded Minute)
+		"MMMM", "%B", // January/February/March/April/May/June/July/August/September/October/November/December
+		"MMM", "%b", // Jan/Feb/Mar/Apr/May/Jun/Jul/Aug/Sep/Oct/Nov/Dec
+		"MM", "%m", // 1~12 (0 padded Month)
+		"M", "%m", // 1~12 (0 padded Month)
+
+		"qqqq", NULL, // 1st quarter/2nd quarter/3rd quarter/4th quarter
+		"qqq", NULL, // Q1/Q2/Q3/Q4
+		"qq", NULL, // 1~4 (0 padded Quarter)
+		"q", NULL, // 1~4 (0 padded Quarter)
+		"QQQQ", NULL, // 1st quarter/2nd quarter/3rd quarter/4th quarter
+		"QQQ", NULL, // Q1/Q2/Q3/Q4
+		"QQ", NULL, // 1~4 (0 padded Quarter)
+		"Q", NULL, // 1~4 (0 padded Quarter)
+
+		"s", "%S", // 0~59 (0 padded Second)
+		"S", NULL, // (rounded Sub-Second)
+
+		"u", "%Y", // (0 padded Year)
+
+		"vvvv", "%Z", // (General GMT Timezone Name)
+		"vvv", "%Z", // (General GMT Timezone Abbreviation)
+		"vv", "%Z", // (General GMT Timezone Abbreviation)
+		"v", "%Z", // (General GMT Timezone Abbreviation)
+
+		"w", "%W", // 1~53 (0 padded Week of Year, 1st day of week = Sunday, NB, 1st week of year starts from the last Sunday of last year)
+		"W", NULL, // 1~5 (0 padded Week of Month, 1st day of week = Sunday)
+
+		"yyyy", "%Y", // (Full Year)
+		"yyy", "%y", // (2 Digits Year)
+		"yy", "%y", // (2 Digits Year)
+		"y", "%Y", // (Full Year)
+		"YYYY", NULL, // (Full Year, starting from the Sunday of the 1st week of year)
+		"YYY", NULL, // (2 Digits Year, starting from the Sunday of the 1st week of year)
+		"YY", NULL, // (2 Digits Year, starting from the Sunday of the 1st week of year)
+		"Y", NULL, // (Full Year, starting from the Sunday of the 1st week of year)
+
+		"zzzz", NULL, // (Specific GMT Timezone Name)
+		"zzz", NULL, // (Specific GMT Timezone Abbreviation)
+		"zz", NULL, // (Specific GMT Timezone Abbreviation)
+		"z", NULL, // (Specific GMT Timezone Abbreviation)
+		"Z", "%z", // +0000 (RFC 822 Timezone)
+	};
+	const gchar *str;
+	GString *string;
+	guint i, j;
+
+	if (nsdate == NULL) {
+		return NULL;
+	}
+
+	str = g_hash_table_lookup (data->date_format_cache, nsdate);
+	if (str != NULL) {
+		return str;
+	}
+
+	/* Copy nsdate into string, replacing occurences of NSDateFormatter tags
+	 * by corresponding strftime tag. */
+	string = g_string_sized_new (strlen (nsdate));
+	for (i = 0; nsdate[i] != '\0'; i++) {
+		gboolean found = FALSE;
+
+		/* even indexes are NSDateFormatter tag, odd indexes are the
+		 * corresponding strftime tag */
+		for (j = 0; j < G_N_ELEMENTS (convert_table); j += 2) {
+			if (g_str_has_prefix (nsdate + i, convert_table[j])) {
+				found = TRUE;
+				break;
+			}
+		}
+		if (found) {
+			/* If we don't have a replacement, just ignore that tag */
+			if (convert_table[j + 1] != NULL) {
+				g_string_append (string, convert_table[j + 1]);
+			}
+			i += strlen (convert_table[j]) - 1;
+		} else {
+			g_string_append_c (string, nsdate[i]);
+		}
+	}
+
+	DEBUG ("Date format converted '%s' â?? '%s'", nsdate, string->str);
+
+	/* The cache takes ownership of string->str */
+	g_hash_table_insert (data->date_format_cache, g_strdup (nsdate), string->str);
+	return g_string_free (string, FALSE);
+}
+
+
 static void
 theme_adium_append_html (EmpathyThemeAdium *theme,
 			 const gchar       *func,
@@ -420,6 +558,7 @@ theme_adium_append_html (EmpathyThemeAdium *theme,
 		         gint64             timestamp,
 		         gboolean           is_backlog)
 {
+	EmpathyThemeAdiumPriv *priv = GET_PRIV (theme);
 	GString     *string;
 	const gchar *cur = NULL;
 	gchar       *script;
@@ -477,16 +616,17 @@ theme_adium_append_html (EmpathyThemeAdium *theme,
 			replace = message;
 		} else if (theme_adium_match (&cur, "%time%") ||
 			   theme_adium_match_with_format (&cur, "%time{", &format)) {
-			/* FIXME: format is not exactly strftime.
-			 * See NSDateFormatter spec:
-			 * http://www.stepcase.com/blog/2008/12/02/format-string-for-the-iphone-nsdateformatter/
-			 */
+			const gchar *strftime_format;
+
+			strftime_format = nsdate_to_strftime (priv->data, format);
 			if (is_backlog) {
 				dup_replace = empathy_time_to_string_local (timestamp,
-					format ? format : EMPATHY_TIME_DATE_FORMAT_DISPLAY_SHORT);
+					strftime_format ? strftime_format :
+					EMPATHY_TIME_DATE_FORMAT_DISPLAY_SHORT);
 			} else {
 				dup_replace = empathy_time_to_string_local (timestamp,
-					format ? format : EMPATHY_TIME_FORMAT_DISPLAY_SHORT);
+					strftime_format ? strftime_format :
+					EMPATHY_TIME_FORMAT_DISPLAY_SHORT);
 			}
 			replace = dup_replace;
 		} else if (theme_adium_match (&cur, "%shortTime%")) {
@@ -1700,6 +1840,8 @@ empathy_adium_data_new_with_info (const gchar *path, GHashTable *info)
 	data->info = g_hash_table_ref (info);
 	data->version = adium_info_get_version (info);
 	data->strings_to_free = g_ptr_array_new_with_free_func (g_free);
+	data->date_format_cache = g_hash_table_new_full (g_str_hash,
+		g_str_equal, g_free, g_free);
 
 	DEBUG ("Loading theme at %s", path);
 
@@ -1853,6 +1995,7 @@ empathy_adium_data_unref (EmpathyAdiumData *data)
 		g_free (data->default_outgoing_avatar_filename);
 		g_hash_table_unref (data->info);
 		g_ptr_array_unref (data->strings_to_free);
+		tp_clear_pointer (&data->date_format_cache, g_hash_table_unref);
 
 		g_slice_free (EmpathyAdiumData, data);
 	}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]