Also queue resize on body
[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 /* We need this very nasty stuff because the call to
67    osso_time_set_notification_cb cannot be reverted and thus the
68    handler will be called always even though we try to set another
69    one */
70 #ifdef MODEST_USE_LIBTIME
71 static ModestDatetimeFormatter *global_self = NULL;
72 #endif
73
74 #define MODEST_DATETIME_FORMATTER_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
75                                                                                    MODEST_TYPE_DATETIME_FORMATTER, \
76                                                                                    ModestDatetimeFormatterPrivate))
77
78 enum {
79         FORMAT_CHANGED_SIGNAL,
80         LAST_SIGNAL
81 };
82
83 /* globals */
84 static GObjectClass *parent_class = NULL;
85
86 static guint signals[LAST_SIGNAL] = {0};
87
88 GType
89 modest_datetime_formatter_get_type (void)
90 {
91         static GType my_type = 0;
92
93         if (!my_type) {
94                 static const GTypeInfo my_info = {
95                         sizeof(ModestDatetimeFormatterClass),
96                         NULL,   /* base init */
97                         NULL,   /* base finalize */
98                         (GClassInitFunc) modest_datetime_formatter_class_init,
99                         NULL,   /* class finalize */
100                         NULL,   /* class data */
101                         sizeof(ModestDatetimeFormatter),
102                         0,      /* n_preallocs */
103                         (GInstanceInitFunc) modest_datetime_formatter_instance_init,
104                         NULL
105                 };
106
107                 my_type = g_type_register_static (G_TYPE_OBJECT,
108                                                   "ModestDatetimeFormatter",
109                                                   &my_info, 0);
110         }
111         return my_type;
112 }
113
114 static void
115 modest_datetime_formatter_class_init (ModestDatetimeFormatterClass *klass)
116 {
117         GObjectClass *gobject_class;
118         gobject_class = (GObjectClass *) klass;
119
120         parent_class = g_type_class_peek_parent (klass);
121         gobject_class->finalize = modest_datetime_formatter_finalize;
122
123         g_type_class_add_private (gobject_class,
124                                   sizeof(ModestDatetimeFormatterPrivate));
125
126         signals[FORMAT_CHANGED_SIGNAL] =
127                 g_signal_new ("format_changed",
128                               G_TYPE_FROM_CLASS (gobject_class),
129                               G_SIGNAL_RUN_FIRST,
130                               G_STRUCT_OFFSET (ModestDatetimeFormatterClass, format_changed),
131                               NULL, NULL,
132                               g_cclosure_marshal_VOID__VOID,
133                               G_TYPE_NONE, 0);
134 }
135
136 #ifdef MODEST_TOOLKIT_HILDON2
137 static void
138 update_format (ModestDatetimeFormatter *obj)
139 {
140         GConfClient *gconf;
141         GError *err = NULL;
142         gboolean gconf_value;
143         ModestDatetimeFormatterPrivate *priv;
144
145         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (obj);
146
147         gconf = gconf_client_get_default ();
148         gconf_value = gconf_client_get_bool (gconf, HILDON2_GCONF_FORMAT_KEY,
149                                              &err);
150
151         if (err != NULL) {
152                 g_warning ("Error reading time format in gconf %s", err->message);
153                 g_error_free (err);
154         } else {
155                 priv->current_format = gconf_value?DATETIME_FORMAT_24H:DATETIME_FORMAT_12H;
156         }
157 }
158
159 static void
160 clock_format_changed (GConfClient *gconf,
161                       guint cnxn_id,
162                       GConfEntry *entry,
163                       gpointer userdata)
164 {
165         ModestDatetimeFormatter *self = (ModestDatetimeFormatter *) userdata;
166
167         update_format (self);
168         g_signal_emit (G_OBJECT (self), signals[FORMAT_CHANGED_SIGNAL], 0);
169 }
170 #endif
171
172 #ifdef MODEST_USE_LIBTIME
173 static void
174 time_changed_cb (gpointer userdata)
175 {
176         if (global_self) {
177                 time_get_synced ();
178                 g_signal_emit (global_self, signals[FORMAT_CHANGED_SIGNAL], 0);
179         }
180 }
181 #endif
182
183 static void
184 init_format (ModestDatetimeFormatter *obj)
185 {
186         ModestDatetimeFormatterPrivate *priv;
187
188         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (obj);
189
190         priv->current_format = DATETIME_FORMAT_LOCALE;
191
192 #ifdef MODEST_TOOLKIT_HILDON2
193         GConfClient *gconf;
194         GError *err = NULL;
195
196         gconf = gconf_client_get_default ();
197         gconf_client_add_dir (gconf, HILDON2_GCONF_FORMAT_DIR,
198                               GCONF_CLIENT_PRELOAD_ONELEVEL,
199                               &err);
200         priv->gconf_handler = gconf_client_notify_add (gconf, HILDON2_GCONF_FORMAT_KEY,
201                                                        clock_format_changed, (gpointer) obj,
202                                                        NULL, &err);
203
204         if (err != NULL) {
205                 g_warning ("Error listening to time format in gconf %s", err->message);
206                 g_error_free (err);
207         }
208
209         update_format (obj);
210 #endif
211
212 #ifdef MODEST_USE_LIBTIME
213         if (OSSO_OK == osso_time_set_notification_cb (modest_platform_get_osso_context (),
214                                                       time_changed_cb,
215                                                       NULL))
216                 global_self = obj;
217         time_get_synced ();
218 #endif
219
220 }
221
222 static void
223 modest_datetime_formatter_instance_init (ModestDatetimeFormatter *obj)
224 {
225         init_format (obj);
226 }
227
228 static void   
229 modest_datetime_formatter_finalize   (GObject *obj)
230 {
231 #ifdef MODEST_TOOLKIT_HILDON2
232         ModestDatetimeFormatterPrivate *priv;
233         GConfClient *gconf;
234
235         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (obj);
236         gconf = gconf_client_get_default ();
237         gconf_client_notify_remove (gconf,
238                                     priv->gconf_handler);
239         priv->gconf_handler = 0;
240         gconf_client_remove_dir (gconf, HILDON2_GCONF_FORMAT_DIR,
241                                  NULL);
242
243         /* Disconnect notification */
244 #ifdef MODEST_USE_LIBTIME
245         if (OSSO_OK != osso_time_set_notification_cb (modest_platform_get_osso_context (),
246                                                       NULL, NULL))
247                 global_self = NULL;
248 #endif
249 #endif
250         G_OBJECT_CLASS (parent_class)->finalize (obj);
251 }
252
253 ModestDatetimeFormatter*
254 modest_datetime_formatter_new (void)
255 {
256         return g_object_new (MODEST_TYPE_DATETIME_FORMATTER, NULL);
257 }
258
259 const gchar *
260 modest_datetime_formatter_format_date (ModestDatetimeFormatter *self,
261                                        time_t date)
262 {
263 #define DATE_BUF_SIZE 64 
264
265         static gchar date_buf[DATE_BUF_SIZE];
266         ModestDatetimeFormatterPrivate *priv;
267         const gchar *format_string = NULL;
268
269         g_return_val_if_fail (MODEST_IS_DATETIME_FORMATTER (self), NULL);
270         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (self);
271
272         switch (priv->current_format) {
273         case DATETIME_FORMAT_12H:
274         case DATETIME_FORMAT_24H:
275                 format_string = _HL("wdgt_va_date");
276                 break;
277         case DATETIME_FORMAT_LOCALE:
278                 format_string = "%x";
279                 break;
280         }
281         modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, format_string, date);
282
283         return date_buf;
284 }
285
286 const gchar *
287 modest_datetime_formatter_format_time (ModestDatetimeFormatter *self,
288                                        time_t date)
289 {
290 #define DATE_BUF_SIZE 64 
291
292         static gchar date_buf[DATE_BUF_SIZE];
293         ModestDatetimeFormatterPrivate *priv;
294         const gchar *format_string = NULL;
295         gboolean is_pm;
296         struct tm localtime_tm = {0, };
297
298         g_return_val_if_fail (MODEST_IS_DATETIME_FORMATTER (self), NULL);
299         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (self);
300 #ifdef MODEST_USE_LIBTIME
301         time_get_local_ex (date, &localtime_tm);
302 #else
303         time_t date_copy;
304         date_copy = date;
305         localtime_r (&date_copy, &localtime_tm);
306 #endif
307         is_pm = (localtime_tm.tm_hour/12) % 2;
308
309         switch (priv->current_format) {
310         case DATETIME_FORMAT_12H:
311                 format_string = is_pm?_HL("wdgt_va_12h_time_pm"):_HL("wdgt_va_12h_time_am");
312                 break;
313         case DATETIME_FORMAT_24H:
314                 format_string = _HL("wdgt_va_24h_time");
315                 break;
316         case DATETIME_FORMAT_LOCALE:
317                 format_string = "%X";
318                 break;
319         }
320         modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, format_string, date);
321
322         return date_buf;
323 }
324
325 const gchar *
326 modest_datetime_formatter_display_long_datetime (ModestDatetimeFormatter *self,
327                                                  time_t date)
328 {
329
330 #define DATE_BUF_DOUBLE_SIZE 128 
331
332         static gchar date_buf[DATE_BUF_DOUBLE_SIZE];
333         
334         snprintf (date_buf, DATE_BUF_DOUBLE_SIZE, 
335                   "%s %s", modest_datetime_formatter_format_date (self, date), 
336                   modest_datetime_formatter_format_time (self, date));
337
338         return date_buf;
339 }
340
341 const gchar *
342 modest_datetime_formatter_display_datetime (ModestDatetimeFormatter *self,
343                                             time_t date)
344 {
345
346         struct tm today_localtime_tm = {0, };
347         struct tm date_localtime_tm = {0, };
348         time_t today;
349
350         today = time (NULL);
351 #ifdef MODEST_USE_LIBTIME
352         time_get_local_ex (today, &today_localtime_tm);
353         time_get_local_ex (date, &date_localtime_tm);
354 #else
355         time_t date_copy;
356         date_copy = today;
357         localtime_r (&date_copy, &today_localtime_tm);
358         date_copy = date;
359         localtime_r (&date_copy, &date_localtime_tm);
360 #endif
361
362         if (today_localtime_tm.tm_mday == date_localtime_tm.tm_mday &&
363             today_localtime_tm.tm_mon == date_localtime_tm.tm_mon &&
364             today_localtime_tm.tm_year == date_localtime_tm.tm_year)
365                 return modest_datetime_formatter_format_time (self, date);
366         else
367                 return modest_datetime_formatter_format_date (self, date);
368 }