22acacfc96d7624dd2b95220b0ef5faa74e934a5
[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 #endif
41
42 typedef enum {
43         DATETIME_FORMAT_12H,
44         DATETIME_FORMAT_24H,
45         DATETIME_FORMAT_LOCALE,
46 } DatetimeFormat;
47
48 #define HILDON2_GCONF_FORMAT_DIR "/apps/clock"
49 #define HILDON2_GCONF_FORMAT_KEY HILDON2_GCONF_FORMAT_DIR "/time-format"
50
51 /* 'private'/'protected' functions */
52 static void   modest_datetime_formatter_class_init (ModestDatetimeFormatterClass *klass);
53 static void   modest_datetime_formatter_finalize   (GObject *obj);
54 static void   modest_datetime_formatter_instance_init (ModestDatetimeFormatter *obj);
55
56 typedef struct _ModestDatetimeFormatterPrivate ModestDatetimeFormatterPrivate;
57 struct _ModestDatetimeFormatterPrivate {
58         DatetimeFormat current_format;
59 #ifdef MODEST_TOOLKIT_HILDON2
60         guint gconf_handler;
61 #endif
62 };
63
64 #define MODEST_DATETIME_FORMATTER_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
65                                                                                    MODEST_TYPE_DATETIME_FORMATTER, \
66                                                                                    ModestDatetimeFormatterPrivate))
67
68 enum {
69         FORMAT_CHANGED_SIGNAL,
70         LAST_SIGNAL
71 };
72
73 /* globals */
74 static GObjectClass *parent_class = NULL;
75
76 static guint signals[LAST_SIGNAL] = {0};
77
78 GType
79 modest_datetime_formatter_get_type (void)
80 {
81         static GType my_type = 0;
82
83         if (!my_type) {
84                 static const GTypeInfo my_info = {
85                         sizeof(ModestDatetimeFormatterClass),
86                         NULL,   /* base init */
87                         NULL,   /* base finalize */
88                         (GClassInitFunc) modest_datetime_formatter_class_init,
89                         NULL,   /* class finalize */
90                         NULL,   /* class data */
91                         sizeof(ModestDatetimeFormatter),
92                         0,      /* n_preallocs */
93                         (GInstanceInitFunc) modest_datetime_formatter_instance_init,
94                         NULL
95                 };
96
97                 my_type = g_type_register_static (G_TYPE_OBJECT,
98                                                   "ModestDatetimeFormatter",
99                                                   &my_info, 0);
100         }
101         return my_type;
102 }
103
104 static void
105 modest_datetime_formatter_class_init (ModestDatetimeFormatterClass *klass)
106 {
107         GObjectClass *gobject_class;
108         gobject_class = (GObjectClass *) klass;
109
110         parent_class = g_type_class_peek_parent (klass);
111         gobject_class->finalize = modest_datetime_formatter_finalize;
112
113         g_type_class_add_private (gobject_class,
114                                   sizeof(ModestDatetimeFormatterPrivate));
115
116         signals[FORMAT_CHANGED_SIGNAL] =
117                 g_signal_new ("format_changed",
118                               G_TYPE_FROM_CLASS (gobject_class),
119                               G_SIGNAL_RUN_FIRST,
120                               G_STRUCT_OFFSET (ModestDatetimeFormatterClass, format_changed),
121                               NULL, NULL,
122                               g_cclosure_marshal_VOID__VOID,
123                               G_TYPE_NONE, 0);
124 }
125
126 #ifdef MODEST_TOOLKIT_HILDON2
127 static void
128 update_format (ModestDatetimeFormatter *obj)
129 {
130         GConfClient *gconf;
131         GError *err = NULL;
132         gboolean gconf_value;
133         ModestDatetimeFormatterPrivate *priv;
134
135         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (obj);
136
137         gconf = gconf_client_get_default ();
138         gconf_value = gconf_client_get_bool (gconf, HILDON2_GCONF_FORMAT_KEY,
139                                              &err);
140
141         if (err != NULL) {
142                 g_warning ("Error reading time format in gconf %s", err->message);
143                 g_error_free (err);
144         } else {
145                 priv->current_format = gconf_value?DATETIME_FORMAT_24H:DATETIME_FORMAT_12H;
146         }
147 }
148
149 static void
150 clock_format_changed (GConfClient *gconf,
151                       guint cnxn_id,
152                       GConfEntry *entry,
153                       gpointer userdata)
154 {
155         ModestDatetimeFormatter *self = (ModestDatetimeFormatter *) userdata;
156
157         update_format (self);
158         g_signal_emit (G_OBJECT (self), signals[FORMAT_CHANGED_SIGNAL], 0);
159 }
160 #endif
161
162 static void
163 init_format (ModestDatetimeFormatter *obj)
164 {
165         ModestDatetimeFormatterPrivate *priv;
166
167         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (obj);
168
169         priv->current_format = DATETIME_FORMAT_LOCALE;
170
171 #ifdef MODEST_TOOLKIT_HILDON2
172         GConfClient *gconf;
173         GError *err = NULL;
174
175         gconf = gconf_client_get_default ();
176         gconf_client_add_dir (gconf, HILDON2_GCONF_FORMAT_DIR,
177                               GCONF_CLIENT_PRELOAD_ONELEVEL,
178                               &err);
179         priv->gconf_handler = gconf_client_notify_add (gconf, HILDON2_GCONF_FORMAT_KEY,
180                                                        clock_format_changed, (gpointer) obj,
181                                                        NULL, &err);
182
183         if (err != NULL) {
184                 g_warning ("Error listening to time format in gconf %s", err->message);
185                 g_error_free (err);
186         }
187         update_format (obj);
188 #endif
189 }
190
191 static void
192 modest_datetime_formatter_instance_init (ModestDatetimeFormatter *obj)
193 {
194         init_format (obj);
195 }
196
197 static void   
198 modest_datetime_formatter_finalize   (GObject *obj)
199 {
200 #ifdef MODEST_TOOLKIT_HILDON2
201         ModestDatetimeFormatterPrivate *priv;
202         GConfClient *gconf;
203
204         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (obj);
205         gconf = gconf_client_get_default ();
206         gconf_client_notify_remove (gconf,
207                                     priv->gconf_handler);
208         priv->gconf_handler = 0;
209         gconf_client_remove_dir (gconf, HILDON2_GCONF_FORMAT_DIR,
210                                  NULL);
211 #endif
212         G_OBJECT_CLASS (parent_class)->finalize (obj);
213 }
214
215 ModestDatetimeFormatter*
216 modest_datetime_formatter_new (void)
217 {
218         return g_object_new (MODEST_TYPE_DATETIME_FORMATTER, NULL);
219 }
220
221 const gchar *
222 modest_datetime_formatter_format_date (ModestDatetimeFormatter *self,
223                                        time_t date)
224 {
225 #define DATE_BUF_SIZE 64 
226
227         static gchar date_buf[DATE_BUF_SIZE];
228         ModestDatetimeFormatterPrivate *priv;
229         const gchar *format_string = NULL;
230
231         g_return_val_if_fail (MODEST_IS_DATETIME_FORMATTER (self), NULL);
232         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (self);
233
234         switch (priv->current_format) {
235         case DATETIME_FORMAT_12H:
236         case DATETIME_FORMAT_24H:
237                 format_string = _HL("wdgt_va_date");
238                 break;
239         case DATETIME_FORMAT_LOCALE:
240                 format_string = "%x";
241                 break;
242         }
243         modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, format_string, date);
244
245         return date_buf;
246 }
247
248 const gchar *
249 modest_datetime_formatter_format_time (ModestDatetimeFormatter *self,
250                                        time_t date)
251 {
252 #define DATE_BUF_SIZE 64 
253
254         static gchar date_buf[DATE_BUF_SIZE];
255         ModestDatetimeFormatterPrivate *priv;
256         const gchar *format_string = NULL;
257         gboolean is_pm;
258         struct tm localtime_tm = {0, };
259
260         g_return_val_if_fail (MODEST_IS_DATETIME_FORMATTER (self), NULL);
261         priv = MODEST_DATETIME_FORMATTER_GET_PRIVATE (self);
262 #ifdef MODEST_USE_LIBTIME
263         time_get_local_ex (date, &localtime_tm);
264 #else
265         time_t date_copy;
266         date_copy = date;
267         localtime_r (&date_copy, &localtime_tm);
268 #endif
269         is_pm = (localtime_tm.tm_hour/12) % 2;
270
271         switch (priv->current_format) {
272         case DATETIME_FORMAT_12H:
273                 format_string = is_pm?_HL("wdgt_va_12h_time_pm"):_HL("wdgt_va_12h_time_am");
274                 break;
275         case DATETIME_FORMAT_24H:
276                 format_string = _HL("wdgt_va_24h_time");
277                 break;
278         case DATETIME_FORMAT_LOCALE:
279                 format_string = "%X";
280                 break;
281         }
282         modest_text_utils_strftime (date_buf, DATE_BUF_SIZE, format_string, date);
283
284         return date_buf;
285 }
286
287 const gchar *
288 modest_datetime_formatter_display_long_datetime (ModestDatetimeFormatter *self,
289                                                  time_t date)
290 {
291
292 #define DATE_BUF_DOUBLE_SIZE 128 
293
294         static gchar date_buf[DATE_BUF_DOUBLE_SIZE];
295         
296         snprintf (date_buf, DATE_BUF_DOUBLE_SIZE, 
297                   "%s %s", modest_datetime_formatter_format_date (self, date), 
298                   modest_datetime_formatter_format_time (self, date));
299
300         return date_buf;
301 }
302
303 const gchar *
304 modest_datetime_formatter_display_datetime (ModestDatetimeFormatter *self,
305                                             time_t date)
306 {
307
308         struct tm today_localtime_tm = {0, };
309         struct tm date_localtime_tm = {0, };
310         time_t today;
311
312         today = time (NULL);
313 #ifdef MODEST_USE_LIBTIME
314         time_get_local_ex (today, &today_localtime_tm);
315         time_get_local_ex (date, &date_localtime_tm);
316 #else
317         time_t date_copy;
318         date_copy = today;
319         localtime_r (&date_copy, &today_localtime_tm);
320         date_copy = date;
321         localtime_r (&date_copy, &date_localtime_tm);
322 #endif
323
324         if (today_localtime_tm.tm_mday == date_localtime_tm.tm_mday &&
325             today_localtime_tm.tm_mon == date_localtime_tm.tm_mon &&
326             today_localtime_tm.tm_year == date_localtime_tm.tm_year)
327                 return modest_datetime_formatter_format_time (self, date);
328         else
329                 return modest_datetime_formatter_format_date (self, date);
330 }