No issues found
1 /*
2 * ECellDateEditText - a subclass of ECellText used to show and edit the text
3 * representation of the date, from a ECalComponentDateTime* model value.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) version 3.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with the program; if not, see <http://www.gnu.org/licenses/>
17 *
18 * Authors:
19 * Damon Chaplin <damon@ximian.com>
20 *
21 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <sys/time.h>
29 #include <time.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <glib/gi18n.h>
33 #include <libecal/libecal.h>
34
35 #include <e-util/e-util.h>
36 #include <e-util/e-datetime-format.h>
37
38 #include "e-cell-date-edit-text.h"
39
40 #define E_CELL_DATE_EDIT_TEXT_GET_PRIVATE(obj) \
41 (G_TYPE_INSTANCE_GET_PRIVATE \
42 ((obj), E_TYPE_CELL_DATE_EDIT_TEXT, ECellDateEditTextPrivate))
43
44 struct _ECellDateEditTextPrivate {
45
46 /* The timezone to display the date in. */
47 icaltimezone *timezone;
48
49 /* Whether to display in 24-hour format. */
50 gboolean use_24_hour_format;
51 };
52
53 enum {
54 PROP_0,
55 PROP_TIMEZONE,
56 PROP_USE_24_HOUR_FORMAT
57 };
58
59 G_DEFINE_TYPE (
60 ECellDateEditText,
61 e_cell_date_edit_text,
62 E_TYPE_CELL_TEXT)
63
64 static void
65 cell_date_edit_text_set_property (GObject *object,
66 guint property_id,
67 const GValue *value,
68 GParamSpec *pspec)
69 {
70 switch (property_id) {
71 case PROP_TIMEZONE:
72 e_cell_date_edit_text_set_timezone (
73 E_CELL_DATE_EDIT_TEXT (object),
74 g_value_get_pointer (value));
75 return;
76
77 case PROP_USE_24_HOUR_FORMAT:
78 e_cell_date_edit_text_set_use_24_hour_format (
79 E_CELL_DATE_EDIT_TEXT (object),
80 g_value_get_boolean (value));
81 return;
82 }
83
84 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
85 }
86
87 static void
88 cell_date_edit_text_get_property (GObject *object,
89 guint property_id,
90 GValue *value,
91 GParamSpec *pspec)
92 {
93 switch (property_id) {
94 case PROP_TIMEZONE:
95 g_value_set_pointer (
96 value,
97 e_cell_date_edit_text_get_timezone (
98 E_CELL_DATE_EDIT_TEXT (object)));
99 return;
100
101 case PROP_USE_24_HOUR_FORMAT:
102 g_value_set_boolean (
103 value,
104 e_cell_date_edit_text_get_use_24_hour_format (
105 E_CELL_DATE_EDIT_TEXT (object)));
106 return;
107 }
108
109 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
110 }
111
112 static gchar *
113 cell_date_edit_text_get_text (ECellText *cell,
114 ETableModel *model,
115 gint col,
116 gint row)
117 {
118 ECellDateEditText *ecd = E_CELL_DATE_EDIT_TEXT (cell);
119 ECellDateEditValue *dv = e_table_model_value_at (model, col, row);
120 icaltimezone *timezone;
121 struct tm tmp_tm;
122
123 if (!dv)
124 return g_strdup ("");
125
126 timezone = e_cell_date_edit_text_get_timezone (ecd);
127
128 /* Note that although the property may be in a different
129 * timezone, we convert it to the current timezone to display
130 * it in the table. If the user actually edits the value,
131 * it will be set to the current timezone. See set_value (). */
132 tmp_tm = icaltimetype_to_tm_with_zone (&dv->tt, dv->zone, timezone);
133
134 return e_datetime_format_format_tm (
135 "calendar", "table", dv->tt.is_date ?
136 DTFormatKindDate : DTFormatKindDateTime, &tmp_tm);
137 }
138
139 static void
140 cell_date_edit_text_free_text (ECellText *cell,
141 gchar *text)
142 {
143 g_free (text);
144 }
145
146 /* FIXME: We need to set the "transient_for" property for the dialog. */
147 static void
148 show_date_warning (ECellDateEditText *ecd)
149 {
150 GtkWidget *dialog;
151 gchar buffer[64], *format;
152 time_t t;
153 struct tm *tmp_tm;
154
155 t = time (NULL);
156 /* We are only using this as an example, so the timezone doesn't
157 * matter. */
158 tmp_tm = localtime (&t);
159
160 if (e_cell_date_edit_text_get_use_24_hour_format (ecd))
161 /* strftime format of a weekday, a date and a time, 24-hour. */
162 format = _("%a %m/%d/%Y %H:%M:%S");
163 else
164 /* strftime format of a weekday, a date and a time, 12-hour. */
165 format = _("%a %m/%d/%Y %I:%M:%S %p");
166
167 e_utf8_strftime (buffer, sizeof (buffer), format, tmp_tm);
168
169 dialog = gtk_message_dialog_new (
170 NULL, 0,
171 GTK_MESSAGE_ERROR,
172 GTK_BUTTONS_OK,
173 _("The date must be entered in the format: \n%s"),
174 buffer);
175 gtk_dialog_run (GTK_DIALOG (dialog));
176 gtk_widget_destroy (dialog);
177 }
178
179 static void
180 cell_date_edit_text_set_value (ECellText *cell,
181 ETableModel *model,
182 gint col,
183 gint row,
184 const gchar *text)
185 {
186 ECellDateEditText *ecd = E_CELL_DATE_EDIT_TEXT (cell);
187 ETimeParseStatus status;
188 struct tm tmp_tm;
189 ECellDateEditValue *value;
190 gboolean is_date = TRUE;
191
192 /* Try to parse just a date first. If the value is only a date, we
193 * use a DATE value. */
194 status = e_time_parse_date (text, &tmp_tm);
195 if (status == E_TIME_PARSE_INVALID) {
196 is_date = FALSE;
197 status = e_time_parse_date_and_time (text, &tmp_tm);
198
199 if (status == E_TIME_PARSE_INVALID) {
200 show_date_warning (ecd);
201 return;
202 }
203 }
204
205 if (status == E_TIME_PARSE_NONE) {
206 value = NULL;
207 } else {
208 ECellDateEditValue dv;
209
210 dv.tt = icaltime_null_time ();
211
212 dv.tt.year = tmp_tm.tm_year + 1900;
213 dv.tt.month = tmp_tm.tm_mon + 1;
214 dv.tt.day = tmp_tm.tm_mday;
215 dv.tt.hour = tmp_tm.tm_hour;
216 dv.tt.minute = tmp_tm.tm_min;
217 dv.tt.second = tmp_tm.tm_sec;
218 dv.tt.is_date = is_date;
219
220 /* FIXME: We assume it is being set to the current timezone.
221 * Is that OK? */
222 if (is_date) {
223 dv.zone = NULL;
224 } else {
225 dv.zone = e_cell_date_edit_text_get_timezone (ecd);
226 }
227
228 value = &dv;
229 }
230
231 e_table_model_set_value_at (model, col, row, value);
232 }
233
234 static void
235 e_cell_date_edit_text_class_init (ECellDateEditTextClass *class)
236 {
237 GObjectClass *object_class;
238 ECellTextClass *cell_text_class;
239
240 g_type_class_add_private (class, sizeof (ECellDateEditTextPrivate));
241
242 object_class = G_OBJECT_CLASS (class);
243 object_class->set_property = cell_date_edit_text_set_property;
244 object_class->get_property = cell_date_edit_text_get_property;
245
246 cell_text_class = E_CELL_TEXT_CLASS (class);
247 cell_text_class->get_text = cell_date_edit_text_get_text;
248 cell_text_class->free_text = cell_date_edit_text_free_text;
249 cell_text_class->set_value = cell_date_edit_text_set_value;
250
251 g_object_class_install_property (
252 object_class,
253 PROP_TIMEZONE,
254 g_param_spec_pointer (
255 "timezone",
256 "Time Zone",
257 NULL,
258 G_PARAM_READWRITE));
259
260 g_object_class_install_property (
261 object_class,
262 PROP_USE_24_HOUR_FORMAT,
263 g_param_spec_boolean (
264 "use-24-hour-format",
265 "Use 24-Hour Format",
266 NULL,
267 TRUE,
268 G_PARAM_READWRITE));
269 }
270
271 static void
272 e_cell_date_edit_text_init (ECellDateEditText *ecd)
273 {
274 ecd->priv = E_CELL_DATE_EDIT_TEXT_GET_PRIVATE (ecd);
275
276 ecd->priv->timezone = icaltimezone_get_utc_timezone ();
277 ecd->priv->use_24_hour_format = TRUE;
278 }
279
280 /**
281 * e_cell_date_edit_text_new:
282 *
283 * Creates a new ECell renderer that can be used to render and edit dates that
284 * that come from the model. The value returned from the model is
285 * interpreted as being a ECalComponentDateTime*.
286 *
287 * Returns: an ECell object that can be used to render dates.
288 */
289 ECell *
290 e_cell_date_edit_text_new (const gchar *fontname,
291 GtkJustification justify)
292 {
293 ECell *cell;
294
295 cell = g_object_new (E_TYPE_CELL_DATE_EDIT_TEXT, NULL);
296 e_cell_text_construct (E_CELL_TEXT (cell), fontname, justify);
297
298 return cell;
299 }
300
301 icaltimezone *
302 e_cell_date_edit_text_get_timezone (ECellDateEditText *ecd)
303 {
304 g_return_val_if_fail (E_IS_CELL_DATE_EDIT_TEXT (ecd), NULL);
305
306 return ecd->priv->timezone;
307 }
308
309 void
310 e_cell_date_edit_text_set_timezone (ECellDateEditText *ecd,
311 icaltimezone *timezone)
312 {
313 g_return_if_fail (E_IS_CELL_DATE_EDIT_TEXT (ecd));
314
315 if (ecd->priv->timezone == timezone)
316 return;
317
318 ecd->priv->timezone = timezone;
319
320 g_object_notify (G_OBJECT (ecd), "timezone");
321 }
322
323 gboolean
324 e_cell_date_edit_text_get_use_24_hour_format (ECellDateEditText *ecd)
325 {
326 g_return_val_if_fail (E_IS_CELL_DATE_EDIT_TEXT (ecd), FALSE);
327
328 return ecd->priv->use_24_hour_format;
329 }
330
331 void
332 e_cell_date_edit_text_set_use_24_hour_format (ECellDateEditText *ecd,
333 gboolean use_24_hour)
334 {
335 g_return_if_fail (E_IS_CELL_DATE_EDIT_TEXT (ecd));
336
337 if (ecd->priv->use_24_hour_format == use_24_hour)
338 return;
339
340 ecd->priv->use_24_hour_format = use_24_hour;
341
342 g_object_notify (G_OBJECT (ecd), "use-24-hour-format");
343 }
344
345 gint
346 e_cell_date_edit_compare_cb (gconstpointer a,
347 gconstpointer b,
348 gpointer cmp_cache)
349 {
350 ECellDateEditValue *dv1 = (ECellDateEditValue *) a;
351 ECellDateEditValue *dv2 = (ECellDateEditValue *) b;
352 struct icaltimetype tt;
353
354 /* First check if either is NULL. NULL dates sort last. */
355 if (!dv1 || !dv2) {
356 if (dv1 == dv2)
357 return 0;
358 else if (dv1)
359 return -1;
360 else
361 return 1;
362 }
363
364 /* Copy the 2nd value and convert it to the same timezone as the first. */
365 tt = dv2->tt;
366
367 icaltimezone_convert_time (&tt, dv2->zone, dv1->zone);
368
369 /* Now we can compare them. */
370 return icaltime_compare (dv1->tt, tt);
371 }