1 /*
2  * EDateTimeList - list of calendar dates/times with GtkTreeModel interface.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, see <http://www.gnu.org/licenses/>.
15  *
16  *
17  * Authors:
18  *		Hans Petter Jansson  <hpj@ximian.com>
19  *
20  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
21  *
22  */
23 
24 #include "evolution-config.h"
25 
26 #include "comp-util.h"
27 
28 #include "e-date-time-list.h"
29 
30 #include <string.h>
31 #include <libecal/libecal.h>
32 
33 /* XXX Was it really necessary to implement a custom GtkTreeModel for a
34  *     one-column list store?  There's no mention of why this was done. */
35 
36 #define G_LIST(x)                        ((GList *) x)
37 #define E_DATE_TIME_LIST_IS_SORTED(list) \
38 	(E_DATE_TIME_LIST (list)->sort_column_id != -2)
39 #define IS_VALID_ITER(dt_list, iter) \
40 	(iter != NULL && iter->user_data != NULL && \
41 	dt_list->priv->stamp == iter->stamp)
42 
43 struct _EDateTimeListPrivate {
44 	gint     stamp;
45 	GList   *list;
46 
47 	guint    columns_dirty : 1;
48 
49 	gboolean use_24_hour_format;
50 	ICalTimezone *zone;
51 };
52 
53 enum {
54 	PROP_0,
55 	PROP_USE_24_HOUR_FORMAT,
56 	PROP_TIMEZONE
57 };
58 
59 static GType column_types[E_DATE_TIME_LIST_NUM_COLUMNS];
60 
61 static void e_date_time_list_tree_model_init (GtkTreeModelIface *iface);
62 
G_DEFINE_TYPE_WITH_CODE(EDateTimeList,e_date_time_list,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,e_date_time_list_tree_model_init))63 G_DEFINE_TYPE_WITH_CODE (
64 	EDateTimeList, e_date_time_list, G_TYPE_OBJECT,
65 	G_IMPLEMENT_INTERFACE (
66 		GTK_TYPE_TREE_MODEL, e_date_time_list_tree_model_init))
67 
68 static gint
69 compare_datetime (const ICalTime *itt1,
70                   const ICalTime *itt2)
71 {
72 	return i_cal_time_compare ((ICalTime *) itt1, (ICalTime *) itt2);
73 }
74 
75 static void
all_rows_deleted(EDateTimeList * date_time_list)76 all_rows_deleted (EDateTimeList *date_time_list)
77 {
78 	GtkTreePath *path;
79 	gint         i;
80 
81 	if (!date_time_list->priv->list)
82 		return;
83 
84 	path = gtk_tree_path_new ();
85 	i = g_list_length (date_time_list->priv->list);
86 	gtk_tree_path_append_index (path, i);
87 
88 	for (; i >= 0; i--) {
89 		gtk_tree_model_row_deleted (GTK_TREE_MODEL (date_time_list), path);
90 		gtk_tree_path_prev (path);
91 	}
92 
93 	gtk_tree_path_free (path);
94 }
95 
96 static void
row_deleted(EDateTimeList * date_time_list,gint n)97 row_deleted (EDateTimeList *date_time_list,
98              gint n)
99 {
100 	GtkTreePath *path;
101 
102 	path = gtk_tree_path_new ();
103 	gtk_tree_path_append_index (path, n);
104 	gtk_tree_model_row_deleted (GTK_TREE_MODEL (date_time_list), path);
105 	gtk_tree_path_free (path);
106 }
107 
108 static void
row_added(EDateTimeList * date_time_list,gint n)109 row_added (EDateTimeList *date_time_list,
110            gint n)
111 {
112 	GtkTreePath *path;
113 	GtkTreeIter  iter;
114 
115 	path = gtk_tree_path_new ();
116 	gtk_tree_path_append_index (path, n);
117 
118 	if (gtk_tree_model_get_iter (GTK_TREE_MODEL (date_time_list), &iter, path))
119 		gtk_tree_model_row_inserted (GTK_TREE_MODEL (date_time_list), path, &iter);
120 
121 	gtk_tree_path_free (path);
122 }
123 
124 static void
row_updated(EDateTimeList * date_time_list,gint n)125 row_updated (EDateTimeList *date_time_list,
126              gint n)
127 {
128 	GtkTreePath *path;
129 	GtkTreeIter  iter;
130 
131 	path = gtk_tree_path_new ();
132 	gtk_tree_path_append_index (path, n);
133 
134 	if (gtk_tree_model_get_iter (GTK_TREE_MODEL (date_time_list), &iter, path))
135 		gtk_tree_model_row_changed (GTK_TREE_MODEL (date_time_list), path, &iter);
136 
137 	gtk_tree_path_free (path);
138 }
139 
140 /* Builds a static string out of an exception date */
141 static gchar *
get_exception_string(EDateTimeList * date_time_list,ICalTime * itt)142 get_exception_string (EDateTimeList *date_time_list,
143 		      ICalTime *itt)
144 {
145 	static gchar buf[256];
146 	ICalTime *tt;
147 	ICalTimezone *zone;
148 
149 	zone = e_date_time_list_get_timezone (date_time_list);
150 
151 	if (zone)
152 		tt = i_cal_time_convert_to_zone (itt, zone);
153 	else
154 		tt = g_object_ref (itt);
155 
156 	cal_comp_util_format_itt (tt, buf, sizeof (buf));
157 
158 	g_clear_object (&tt);
159 
160 	return buf;
161 }
162 
163 static void
date_time_list_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)164 date_time_list_set_property (GObject *object,
165                              guint property_id,
166                              const GValue *value,
167                              GParamSpec *pspec)
168 {
169 	switch (property_id) {
170 		case PROP_USE_24_HOUR_FORMAT:
171 			e_date_time_list_set_use_24_hour_format (
172 				E_DATE_TIME_LIST (object),
173 				g_value_get_boolean (value));
174 			return;
175 
176 		case PROP_TIMEZONE:
177 			e_date_time_list_set_timezone (
178 				E_DATE_TIME_LIST (object),
179 				g_value_get_pointer (value));
180 			return;
181 	}
182 
183 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
184 }
185 
186 static void
date_time_list_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)187 date_time_list_get_property (GObject *object,
188                              guint property_id,
189                              GValue *value,
190                              GParamSpec *pspec)
191 {
192 	switch (property_id) {
193 		case PROP_USE_24_HOUR_FORMAT:
194 			g_value_set_boolean (
195 				value,
196 				e_date_time_list_get_use_24_hour_format (
197 				E_DATE_TIME_LIST (object)));
198 			return;
199 
200 		case PROP_TIMEZONE:
201 			g_value_set_pointer (
202 				value, e_date_time_list_get_timezone (
203 				E_DATE_TIME_LIST (object)));
204 			return;
205 	}
206 
207 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
208 }
209 
210 static void
date_time_list_finalize(GObject * object)211 date_time_list_finalize (GObject *object)
212 {
213 	EDateTimeList *date_time_list = E_DATE_TIME_LIST (object);
214 
215 	g_clear_object (&date_time_list->priv->zone);
216 
217 	g_list_free_full (date_time_list->priv->list, g_object_unref);
218 	date_time_list->priv->list = NULL;
219 
220 	/* Chain up to parent's method. */
221 	G_OBJECT_CLASS (e_date_time_list_parent_class)->finalize (object);
222 }
223 
224 static GtkTreeModelFlags
date_time_list_get_flags(GtkTreeModel * tree_model)225 date_time_list_get_flags (GtkTreeModel *tree_model)
226 {
227 	g_return_val_if_fail (E_IS_DATE_TIME_LIST (tree_model), 0);
228 
229 	return GTK_TREE_MODEL_LIST_ONLY;
230 }
231 
232 static gint
date_time_list_get_n_columns(GtkTreeModel * tree_model)233 date_time_list_get_n_columns (GtkTreeModel *tree_model)
234 {
235 	EDateTimeList *date_time_list = (EDateTimeList *) tree_model;
236 
237 	g_return_val_if_fail (E_IS_DATE_TIME_LIST (tree_model), 0);
238 
239 	date_time_list->priv->columns_dirty = TRUE;
240 	return E_DATE_TIME_LIST_NUM_COLUMNS;
241 }
242 
243 static GType
date_time_list_get_column_type(GtkTreeModel * tree_model,gint index)244 date_time_list_get_column_type (GtkTreeModel *tree_model,
245                                 gint index)
246 {
247 	EDateTimeList *date_time_list = (EDateTimeList *) tree_model;
248 
249 	g_return_val_if_fail (E_IS_DATE_TIME_LIST (tree_model), G_TYPE_INVALID);
250 	g_return_val_if_fail (index < E_DATE_TIME_LIST_NUM_COLUMNS &&
251 			      index >= 0, G_TYPE_INVALID);
252 
253 	date_time_list->priv->columns_dirty = TRUE;
254 	return column_types[index];
255 }
256 
257 static gboolean
date_time_list_get_iter(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreePath * path)258 date_time_list_get_iter (GtkTreeModel *tree_model,
259                          GtkTreeIter *iter,
260                          GtkTreePath *path)
261 {
262 	EDateTimeList *date_time_list = (EDateTimeList *) tree_model;
263 	GList         *l;
264 	gint           i;
265 
266 	g_return_val_if_fail (E_IS_DATE_TIME_LIST (tree_model), FALSE);
267 	g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
268 
269 	if (!date_time_list->priv->list)
270 		return FALSE;
271 
272 	date_time_list->priv->columns_dirty = TRUE;
273 
274 	i = gtk_tree_path_get_indices (path)[0];
275 	l = g_list_nth (date_time_list->priv->list, i);
276 	if (!l)
277 		return FALSE;
278 
279 	iter->user_data = l;
280 	iter->stamp = date_time_list->priv->stamp;
281 	return TRUE;
282 }
283 
284 static GtkTreePath *
date_time_list_get_path(GtkTreeModel * tree_model,GtkTreeIter * iter)285 date_time_list_get_path (GtkTreeModel *tree_model,
286                          GtkTreeIter *iter)
287 {
288 	EDateTimeList *date_time_list = (EDateTimeList *) tree_model;
289 	GtkTreePath   *retval;
290 	GList         *l;
291 
292 	g_return_val_if_fail (E_IS_DATE_TIME_LIST (tree_model), NULL);
293 	g_return_val_if_fail (iter->stamp == E_DATE_TIME_LIST (tree_model)->priv->stamp, NULL);
294 
295 	l = iter->user_data;
296 	retval = gtk_tree_path_new ();
297 	gtk_tree_path_append_index (retval, g_list_position (date_time_list->priv->list, l));
298 	return retval;
299 }
300 
301 static void
date_time_list_get_value(GtkTreeModel * tree_model,GtkTreeIter * iter,gint column,GValue * value)302 date_time_list_get_value (GtkTreeModel *tree_model,
303                           GtkTreeIter *iter,
304                           gint column,
305                           GValue *value)
306 {
307 	EDateTimeList *date_time_list = E_DATE_TIME_LIST (tree_model);
308 	ICalTime *itt;
309 	GList *link;
310 	const gchar *str;
311 
312 	g_return_if_fail (E_IS_DATE_TIME_LIST (tree_model));
313 	g_return_if_fail (column < E_DATE_TIME_LIST_NUM_COLUMNS);
314 	g_return_if_fail (E_DATE_TIME_LIST (tree_model)->priv->stamp == iter->stamp);
315 	g_return_if_fail (IS_VALID_ITER (date_time_list, iter));
316 
317 	g_value_init (value, column_types[column]);
318 
319 	if (!date_time_list->priv->list)
320 		return;
321 
322 	link = iter->user_data;
323 	itt = link->data;
324 
325 	if (!itt)
326 		return;
327 
328 	switch (column) {
329 		case E_DATE_TIME_LIST_COLUMN_DESCRIPTION:
330 			str = get_exception_string (date_time_list, itt);
331 			g_value_set_string (value, str);
332 			break;
333 	}
334 }
335 
336 static gboolean
date_time_list_iter_next(GtkTreeModel * tree_model,GtkTreeIter * iter)337 date_time_list_iter_next (GtkTreeModel *tree_model,
338                           GtkTreeIter *iter)
339 {
340 	GList *l;
341 
342 	g_return_val_if_fail (E_IS_DATE_TIME_LIST (tree_model), FALSE);
343 	g_return_val_if_fail (IS_VALID_ITER (E_DATE_TIME_LIST (tree_model), iter), FALSE);
344 
345 	if (!E_DATE_TIME_LIST (tree_model)->priv->list)
346 		return FALSE;
347 
348 	l = iter->user_data;
349 	l = g_list_next (l);
350 	if (l) {
351 		iter->user_data = l;
352 		return TRUE;
353 	}
354 
355 	return FALSE;
356 }
357 
358 static gboolean
date_time_list_iter_children(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent)359 date_time_list_iter_children (GtkTreeModel *tree_model,
360                               GtkTreeIter *iter,
361                               GtkTreeIter *parent)
362 {
363 	EDateTimeList *date_time_list = E_DATE_TIME_LIST (tree_model);
364 
365 	/* this is a list, nodes have no children */
366 	if (parent)
367 		return FALSE;
368 
369 	/* but if parent == NULL we return the list itself as children of the
370 	 * "root" */
371 
372 	if (!date_time_list->priv->list)
373 		return FALSE;
374 
375 	iter->stamp = E_DATE_TIME_LIST (tree_model)->priv->stamp;
376 	iter->user_data = date_time_list->priv->list;
377 	return TRUE;
378 }
379 
380 static gboolean
date_time_list_iter_has_child(GtkTreeModel * tree_model,GtkTreeIter * iter)381 date_time_list_iter_has_child (GtkTreeModel *tree_model,
382                                GtkTreeIter *iter)
383 {
384 	g_return_val_if_fail (IS_VALID_ITER (E_DATE_TIME_LIST (tree_model), iter), FALSE);
385 	return FALSE;
386 }
387 
388 static gint
date_time_list_iter_n_children(GtkTreeModel * tree_model,GtkTreeIter * iter)389 date_time_list_iter_n_children (GtkTreeModel *tree_model,
390                                 GtkTreeIter *iter)
391 {
392 	EDateTimeList *date_time_list = E_DATE_TIME_LIST (tree_model);
393 
394 	g_return_val_if_fail (E_IS_DATE_TIME_LIST (tree_model), -1);
395 
396 	if (iter == NULL)
397 		return g_list_length (date_time_list->priv->list);
398 
399 	g_return_val_if_fail (E_DATE_TIME_LIST (tree_model)->priv->stamp == iter->stamp, -1);
400 	return 0;
401 }
402 
403 static gboolean
date_time_list_iter_nth_child(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * parent,gint n)404 date_time_list_iter_nth_child (GtkTreeModel *tree_model,
405                                GtkTreeIter *iter,
406                                GtkTreeIter *parent,
407                                gint n)
408 {
409 	EDateTimeList *date_time_list = E_DATE_TIME_LIST (tree_model);
410 
411 	g_return_val_if_fail (E_IS_DATE_TIME_LIST (tree_model), FALSE);
412 
413 	if (parent)
414 		return FALSE;
415 
416 	if (date_time_list->priv->list) {
417 		GList *l;
418 
419 		l = g_list_nth (date_time_list->priv->list, n);
420 		if (!l)
421 			return FALSE;
422 
423 		iter->stamp = date_time_list->priv->stamp;
424 		iter->user_data = l;
425 		return TRUE;
426 	}
427 
428 	return FALSE;
429 }
430 
431 static gboolean
date_time_list_iter_parent(GtkTreeModel * tree_model,GtkTreeIter * iter,GtkTreeIter * child)432 date_time_list_iter_parent (GtkTreeModel *tree_model,
433                             GtkTreeIter *iter,
434                             GtkTreeIter *child)
435 {
436 	return FALSE;
437 }
438 
439 static void
e_date_time_list_class_init(EDateTimeListClass * class)440 e_date_time_list_class_init (EDateTimeListClass *class)
441 {
442 	GObjectClass *object_class;
443 
444 	g_type_class_add_private (class, sizeof (EDateTimeListPrivate));
445 
446 	object_class = G_OBJECT_CLASS (class);
447 	object_class->set_property = date_time_list_set_property;
448 	object_class->get_property = date_time_list_get_property;
449 	object_class->finalize = date_time_list_finalize;
450 
451 	g_object_class_install_property (
452 		object_class,
453 		PROP_USE_24_HOUR_FORMAT,
454 		g_param_spec_boolean (
455 			"use-24-hour-format",
456 			"Use 24-hour Format",
457 			NULL,
458 			FALSE,
459 			G_PARAM_READWRITE));
460 
461 	g_object_class_install_property (
462 		object_class,
463 		PROP_TIMEZONE,
464 		g_param_spec_pointer (
465 			"timezone",
466 			"Time Zone",
467 			NULL,
468 			G_PARAM_READWRITE));
469 
470 	column_types[E_DATE_TIME_LIST_COLUMN_DESCRIPTION] = G_TYPE_STRING;
471 }
472 
473 static void
e_date_time_list_init(EDateTimeList * date_time_list)474 e_date_time_list_init (EDateTimeList *date_time_list)
475 {
476 	date_time_list->priv = G_TYPE_INSTANCE_GET_PRIVATE (date_time_list, E_TYPE_DATE_TIME_LIST, EDateTimeListPrivate);
477 
478 	date_time_list->priv->stamp = g_random_int ();
479 	date_time_list->priv->columns_dirty = FALSE;
480 	date_time_list->priv->list = NULL;
481 }
482 
483 static void
e_date_time_list_tree_model_init(GtkTreeModelIface * iface)484 e_date_time_list_tree_model_init (GtkTreeModelIface *iface)
485 {
486 	iface->get_flags = date_time_list_get_flags;
487 	iface->get_n_columns = date_time_list_get_n_columns;
488 	iface->get_column_type = date_time_list_get_column_type;
489 	iface->get_iter = date_time_list_get_iter;
490 	iface->get_path = date_time_list_get_path;
491 	iface->get_value = date_time_list_get_value;
492 	iface->iter_next = date_time_list_iter_next;
493 	iface->iter_children = date_time_list_iter_children;
494 	iface->iter_has_child = date_time_list_iter_has_child;
495 	iface->iter_n_children = date_time_list_iter_n_children;
496 	iface->iter_nth_child = date_time_list_iter_nth_child;
497 	iface->iter_parent = date_time_list_iter_parent;
498 }
499 
500 EDateTimeList *
e_date_time_list_new(void)501 e_date_time_list_new (void)
502 {
503 	return g_object_new (E_TYPE_DATE_TIME_LIST, NULL);
504 }
505 
506 ICalTime *
e_date_time_list_get_date_time(EDateTimeList * date_time_list,GtkTreeIter * iter)507 e_date_time_list_get_date_time (EDateTimeList *date_time_list,
508                                 GtkTreeIter *iter)
509 {
510 	g_return_val_if_fail (IS_VALID_ITER (date_time_list, iter), NULL);
511 
512 	return G_LIST (iter->user_data)->data;
513 }
514 
515 void
e_date_time_list_set_date_time(EDateTimeList * date_time_list,GtkTreeIter * iter,const ICalTime * itt)516 e_date_time_list_set_date_time (EDateTimeList *date_time_list,
517                                 GtkTreeIter *iter,
518                                 const ICalTime *itt)
519 {
520 	ICalTime *itt_old;
521 
522 	g_return_if_fail (IS_VALID_ITER (date_time_list, iter));
523 
524 	itt_old = G_LIST (iter->user_data)->data;
525 	g_clear_object (&itt_old);
526 	G_LIST (iter->user_data)->data = i_cal_time_clone (itt);
527 	row_updated (date_time_list,
528 		g_list_position (date_time_list->priv->list, G_LIST (iter->user_data)));
529 }
530 
531 gboolean
e_date_time_list_get_use_24_hour_format(EDateTimeList * date_time_list)532 e_date_time_list_get_use_24_hour_format (EDateTimeList *date_time_list)
533 {
534 	g_return_val_if_fail (E_IS_DATE_TIME_LIST (date_time_list), FALSE);
535 
536 	return date_time_list->priv->use_24_hour_format;
537 }
538 
539 void
e_date_time_list_set_use_24_hour_format(EDateTimeList * date_time_list,gboolean use_24_hour_format)540 e_date_time_list_set_use_24_hour_format (EDateTimeList *date_time_list,
541                                          gboolean use_24_hour_format)
542 {
543 	g_return_if_fail (E_IS_DATE_TIME_LIST (date_time_list));
544 
545 	if (date_time_list->priv->use_24_hour_format == use_24_hour_format)
546 		return;
547 
548 	date_time_list->priv->use_24_hour_format = use_24_hour_format;
549 
550 	g_object_notify (G_OBJECT (date_time_list), "use-24-hour-format");
551 }
552 
553 ICalTimezone *
e_date_time_list_get_timezone(EDateTimeList * date_time_list)554 e_date_time_list_get_timezone (EDateTimeList *date_time_list)
555 {
556 	g_return_val_if_fail (E_IS_DATE_TIME_LIST (date_time_list), NULL);
557 
558 	return date_time_list->priv->zone;
559 }
560 
561 void
e_date_time_list_set_timezone(EDateTimeList * date_time_list,const ICalTimezone * zone)562 e_date_time_list_set_timezone (EDateTimeList *date_time_list,
563 			       const ICalTimezone *zone)
564 {
565 	g_return_if_fail (E_IS_DATE_TIME_LIST (date_time_list));
566 
567 	if (date_time_list->priv->zone == zone)
568 		return;
569 
570 	g_clear_object (&date_time_list->priv->zone);
571 	if (zone)
572 		date_time_list->priv->zone = g_object_ref ((ICalTimezone *) zone);
573 
574 	g_object_notify (G_OBJECT (date_time_list), "timezone");
575 }
576 
577 void
e_date_time_list_append(EDateTimeList * date_time_list,GtkTreeIter * iter,const ICalTime * itt)578 e_date_time_list_append (EDateTimeList *date_time_list,
579                          GtkTreeIter *iter,
580                          const ICalTime *itt)
581 {
582 	g_return_if_fail (itt != NULL);
583 	g_return_if_fail (i_cal_time_is_valid_time ((ICalTime *) itt));
584 
585 	if (g_list_find_custom (date_time_list->priv->list, itt, (GCompareFunc) compare_datetime) == NULL) {
586 		date_time_list->priv->list = g_list_append (date_time_list->priv->list, i_cal_time_clone (itt));
587 		row_added (date_time_list, g_list_length (date_time_list->priv->list) - 1);
588 	}
589 
590 	if (iter) {
591 		iter->user_data = g_list_last (date_time_list->priv->list);
592 		iter->stamp = date_time_list->priv->stamp;
593 	}
594 }
595 
596 void
e_date_time_list_remove(EDateTimeList * date_time_list,GtkTreeIter * iter)597 e_date_time_list_remove (EDateTimeList *date_time_list,
598                          GtkTreeIter *iter)
599 {
600 	ICalTime *itt;
601 	gint n;
602 
603 	g_return_if_fail (IS_VALID_ITER (date_time_list, iter));
604 
605 	n = g_list_position (date_time_list->priv->list, G_LIST (iter->user_data));
606 	itt = G_LIST (iter->user_data)->data;
607 	g_clear_object (&itt);
608 	date_time_list->priv->list = g_list_delete_link (
609 		date_time_list->priv->list, G_LIST (iter->user_data));
610 	row_deleted (date_time_list, n);
611 }
612 
613 void
e_date_time_list_clear(EDateTimeList * date_time_list)614 e_date_time_list_clear (EDateTimeList *date_time_list)
615 {
616 	all_rows_deleted (date_time_list);
617 
618 	g_list_free_full (date_time_list->priv->list, g_object_unref);
619 	date_time_list->priv->list = NULL;
620 }
621