db50dc1c280fbca8d6dbf7dcd8e8a93d2dcf9c55
[modest] / src / modest-datetime-formatter.c
1 /* Copyright (c) 2008, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <config.h>
31 #include <modest-datetime-formatter.h>
32 #ifdef MODEST_TOOLKIT_HILDON2
33 #include <gconf/gconf-client.h>
34 #include <gtk/gtkmarshal.h>
35 #endif
36 #include <glib/gi18n.h>
37 #include "modest-text-utils.h"
38 #ifdef MODEST_USE_LIBTIME
39 #include <clockd/libtime.h>
40 #include <libosso.h>
41 #include <modest-platform.h>
42 #endif
43
44 typedef enum {
45         DATETIME_FORMAT_12H,
46         DATETIME_FORMAT_24H,
47         DATETIME_FORMAT_LOCALE,
48 } DatetimeFormat;
49
50 #define HILDON2_GCONF_FORMAT_DIR "/apps/clock"
51 #define HILDON2_GCONF_FORMAT_KEY HILDON2_GCONF_FORMAT_DIR "/time-format"
52
53 /* 'private'/'protected' functions */
54 static void   modest_datetime_formatter_class_init (ModestDatetimeFormatterClass *klass);
55 static void   modest_datetime_formatter_finalize   (GObject *obj);
56 static void   modest_datetime_formatter_instance_init (ModestDatetimeFormatter *obj);
57
58 typedef struct _ModestDatetimeFormatterPrivate ModestDatetimeFormatterPrivate;
59 struct _ModestDatetimeFormatterPrivate {
60         DatetimeFormat current_format;
61 #ifdef MODEST_TOOLKIT_HILDON2
62         guint gconf_handler;
63 #endif
64 };
65
66 #define MODEST_DATETIME_FORMATTER_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
67                                                                                    MODEST_TYPE_DATETIME_FORMATTER, \
68                                                                                    ModestDatetimeFormatterPrivate))
69
70 enum {
71         FORMAT_CHANGED_SIGNAL,
72         LAST_SIGNAL
73 };
74
75 /* globals */
76 static GObjectClass *parent_class = NULL;
77
78 static guint signals[LAST_SIGNAL] = {0};
79
80 GType
81 modest_datetime_formatter_get_type (void)
82 {
83         static GType my_type = 0;
84
85         if (!my_type) {
86                 static const GTypeInfo my_info = {
87                         sizeof(ModestDatetimeFormatterClass),
88                         NULL,   /* base init */
89                         NULL,   /* base finalize */
90                         (GClassInitFunc) modest_datetime_formatter_class_init,
91                         NULL,   /* class finalize */
92                         NULL,   /* class data */
93                         sizeof(ModestDatetimeFormatter),
94                         0,      /* n_preallocs */
95                         (GInstanceInitFunc) modest_datetime_formatter_instance_init,
96                         NULL
97                 };
98
99                 my_type = g_type_register_static (G_TYPE_OBJECT,
100                                                   "ModestDatetimeFormatter",
101                                                   &my_info, 0);
102         }
103         return my_type;
104 }
105
106 static void
107 modest_datetime_formatter_class_init (ModestDatetimeFormatterClass *klass)
108 {
109         GObjectClass *gobject_class;
110         gobject_class = (GObjectClass *) klass;
111
112         parent_class = g_type_class_peek_parent (klass);
113         gobject_class->finalize = modest_datetime_formatter_finalize;
114
115         g_type_class_add_private (gobject_class,
116                                   sizeof(ModestDatetimeFormatterPrivate));
117
118         signals[FORMAT_CHANGED_SIGNAL] =
119                 g_signal_new ("format_changed",
120                               G_TYPE_FROM_CLASS (gobject_class),
121                               G_SIGNAL_RUN_FIRST,
122                               G_STRUCT_OFFSET (ModestDatetimeFormatterClass, format_changed),
123                               NULL, NULL,
124                               g_cclosure_marshal_VOID__VOID,
125                               G_TYPE_NONE, 0);
126 }
127
128 #ifdef MODEST_TOOLKIT_HILDON2
129 static void
130 update_format (ModestDatetimeFormatter *obj)
131 {
132         GConfClient *gconf;
133         GError *err = NULL;
134         gboolean gconf_value;
135         ModestDatetimeFormatterPrivate *priv;
136
137         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (obj);
138
139         gconf = gconf_client_get_default ();
140         gconf_value = gconf_client_get_bool (gconf, HILDON2_GCONF_FORMAT_KEY,
141                                              &err);
142
143         if (err != NULL) {
144                 g_warning ("Error reading time format in gconf %s", err->message);
145                 g_error_free (err);
146         } else {
147                 priv->current_format = gconf_value?DATETIME_FORMAT_24H:DATETIME_FORMAT_12H;
148         }
149 }
150
151 static void
152 clock_format_changed (GConfClient *gconf,
153                       guint cnxn_id,
154                       GConfEntry *entry,
155                       gpointer userdata)
156 {
157         ModestDatetimeFormatter *self = (ModestDatetimeFormatter *) userdata;
158
159         update_format (self);
160         g_signal_emit (G_OBJECT (self), signals[FORMAT_CHANGED_SIGNAL], 0);
161 }
162 #endif
163
164 #ifdef MODEST_USE_LIBTIME
165 static void 
166 time_changed_cb (gpointer userdata)
167 {
168         time_get_synced ();
169         g_signal_emit (G_OBJECT (userdata), signals[FORMAT_CHANGED_SIGNAL], 0);
170 }
171 #endif
172
173 static void
174 init_format (ModestDatetimeFormatter *obj)
175 {
176         ModestDatetimeFormatterPrivate *priv;
177
178         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (obj);
179
180         priv->current_format = DATETIME_FORMAT_LOCALE;
181
182 #ifdef MODEST_TOOLKIT_HILDON2
183         GConfClient *gconf;
184         GError *err = NULL;
185
186         gconf = gconf_client_get_default ();
187         gconf_client_add_dir (gconf, HILDON2_GCONF_FORMAT_DIR,
188                               GCONF_CLIENT_PRELOAD_ONELEVEL,
189                               &err);
190         priv->gconf_handler = gconf_client_notify_add (gconf, HILDON2_GCONF_FORMAT_KEY,
191                                                        clock_format_changed, (gpointer) obj,
192                                                        NULL, &err);
193
194         if (err != NULL) {
195                 g_warning ("Error listening to time format in gconf %s", err->message);
196                 g_error_free (err);
197         }
198
199         update_format (obj);
200 #endif
201
202 #ifdef MODEST_USE_LIBTIME
203         osso_time_set_notification_cb (modest_platform_get_osso_context (),
204                                        time_changed_cb,
205                                        obj);
206         time_get_synced ();
207 #endif
208
209 }
210
211 static void
212 modest_datetime_formatter_instance_init (ModestDatetimeFormatter *obj)
213 {
214         init_format (obj);
215 }
216
217 static void   
218 modest_datetime_formatter_finalize   (GObject *obj)
219 {
220 #ifdef MODEST_TOOLKIT_HILDON2
221         ModestDatetimeFormatterPrivate *priv;
222         GConfClient *gconf;
223
224         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (obj);
225         gconf = gconf_client_get_default ();
226         gconf_client_notify_remove (gconf,
227                                     priv->gconf_handler);
228         priv->gconf_handler = 0;
229         gconf_client_remove_dir (gconf, HILDON2_GCONF_FORMAT_DIR,
230                                  NULL);
231
232         /* Disconnect notification */
233 #ifdef MODEST_USE_LIBTIME
234         osso_time_set_notification_cb (modest_platform_get_osso_context (), NULL, NULL);
235 #endif
236 #endif
237         G_OBJECT_CLASS (parent_class)->finalize (obj);
238 }
239
240 ModestDatetimeFormatter*
241 modest_datetime_formatter_new (void)
242 {
243         return g_object_new (MODEST_TYPE_DATETIME_FORMATTER, NULL);
244 }
245
246 const gchar *
247 modest_datetime_formatter_format_date (ModestDatetimeFormatter *self,
248                                        time_t date)
249 {
250 #define DATE_BUF_SIZE 64 
251
252         static gchar date_buf[DATE_BUF_SIZE];
253         ModestDatetimeFormatterPrivate *priv;
254         const gchar *format_string = NULL;
255
256         g_return_val_if_fail (MODEST_IS_DATETIME_FORMATTER (self), NULL);
257         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (self);
258
259         switch (priv->current_format) {
260         case DATETIME_FORMAT_12H:
261         case DATETIME_FORMAT_24H:
262                 format_string = _HL("wdgt_va_date");
263                 break;
264         case DATETIME_FORMAT_LOCALE:
265                 format_string = "%x";
266                 break;
267         }
268         modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, format_string, date);
269
270         return date_buf;
271 }
272
273 const gchar *
274 modest_datetime_formatter_format_time (ModestDatetimeFormatter *self,
275                                        time_t date)
276 {
277 #define DATE_BUF_SIZE 64 
278
279         static gchar date_buf[DATE_BUF_SIZE];
280         ModestDatetimeFormatterPrivate *priv;
281         const gchar *format_string = NULL;
282         gboolean is_pm;
283         struct tm localtime_tm = {0, };
284
285         g_return_val_if_fail (MODEST_IS_DATETIME_FORMATTER (self), NULL);
286         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (self);
287 #ifdef MODEST_USE_LIBTIME
288         time_get_local_ex (date, &localtime_tm);
289 #else
290         time_t date_copy;
291         date_copy = date;
292         localtime_r (&date_copy, &localtime_tm);
293 #endif
294         is_pm = (localtime_tm.tm_hour/12) % 2;
295
296         switch (priv->current_format) {
297         case DATETIME_FORMAT_12H:
298                 format_string = is_pm?_HL("wdgt_va_12h_time_pm"):_HL("wdgt_va_12h_time_am");
299                 break;
300         case DATETIME_FORMAT_24H:
301                 format_string = _HL("wdgt_va_24h_time");
302                 break;
303         case DATETIME_FORMAT_LOCALE:
304                 format_string = "%X";
305                 break;
306         }
307         modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, format_string, date);
308
309         return date_buf;
310 }
311
312 const gchar *
313 modest_datetime_formatter_display_long_datetime (ModestDatetimeFormatter *self,
314                                                  time_t date)
315 {
316
317 #define DATE_BUF_DOUBLE_SIZE 128 
318
319         static gchar date_buf[DATE_BUF_DOUBLE_SIZE];
320         
321         snprintf (date_buf, DATE_BUF_DOUBLE_SIZE, 
322                   "%s %s", modest_datetime_formatter_format_date (self, date), 
323                   modest_datetime_formatter_format_time (self, date));
324
325         return date_buf;
326 }
327
328 const gchar *
329 modest_datetime_formatter_display_datetime (ModestDatetimeFormatter *self,
330                                             time_t date)
331 {
332
333         struct tm today_localtime_tm = {0, };
334         struct tm date_localtime_tm = {0, };
335         time_t today;
336
337         today = time (NULL);
338 #ifdef MODEST_USE_LIBTIME
339         time_get_local_ex (today, &today_localtime_tm);
340         time_get_local_ex (date, &date_localtime_tm);
341 #else
342         time_t date_copy;
343         date_copy = today;
344         localtime_r (&date_copy, &today_localtime_tm);
345         date_copy = date;
346         localtime_r (&date_copy, &date_localtime_tm);
347 #endif
348
349         if (today_localtime_tm.tm_mday == date_localtime_tm.tm_mday &&
350             today_localtime_tm.tm_mon == date_localtime_tm.tm_mon &&
351             today_localtime_tm.tm_year == date_localtime_tm.tm_year)
352                 return modest_datetime_formatter_format_time (self, date);
353         else
354                 return modest_datetime_formatter_format_date (self, date);
355 }