evolution-3.6.4/calendar/gui/e-cell-date-edit-text.c

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 }