1 /*
2  * Evolution calendar - Data model for ETable
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  *		Rodrigo Moya <rodrigo@ximian.com>
19  *
20  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
21  *
22  */
23 
24 #include "evolution-config.h"
25 
26 #include <string.h>
27 #include <glib/gi18n.h>
28 
29 #include <libebackend/libebackend.h>
30 
31 #include <e-util/e-util.h>
32 #include <e-util/e-util-enumtypes.h>
33 
34 #include "comp-util.h"
35 #include "e-cal-data-model-subscriber.h"
36 #include "e-cal-dialogs.h"
37 #include "e-cal-ops.h"
38 #include "itip-utils.h"
39 #include "misc.h"
40 
41 #include "e-cal-model.h"
42 
43 struct _ECalModelComponentPrivate {
44 	GString *categories_str;
45 	gint icon_index;
46 };
47 
48 #define E_CAL_MODEL_GET_PRIVATE(obj) \
49 	(G_TYPE_INSTANCE_GET_PRIVATE \
50 	((obj), E_TYPE_CAL_MODEL, ECalModelPrivate))
51 
52 #define E_CAL_MODEL_COMPONENT_GET_PRIVATE(obj) \
53 	(G_TYPE_INSTANCE_GET_PRIVATE \
54 	((obj), E_TYPE_CAL_MODEL_COMPONENT, ECalModelComponentPrivate))
55 
56 struct _ECalModelPrivate {
57 	ECalDataModel *data_model;
58 	ESourceRegistry *registry;
59 	EShell *shell;
60 	EClientCache *client_cache;
61 
62 	/* The default source uid of an ECalClient */
63 	gchar *default_source_uid;
64 
65 	/* Array for storing the objects. Each element is of type ECalModelComponent */
66 	GPtrArray *objects;
67 
68 	ICalComponentKind kind;
69 	ICalTimezone *zone;
70 
71 	/* The time range to display */
72 	time_t start;
73 	time_t end;
74 
75 	/* The search regular expression */
76 	gchar *search_sexp;
77 
78 	/* The default category */
79 	gchar *default_category;
80 
81 	/* Whether we display dates in 24-hour format. */
82         gboolean use_24_hour_format;
83 
84 	/* Whether to compress weekends into one cell. */
85 	gboolean compress_weekend;
86 
87 	/* First day of the week */
88 	GDateWeekday week_start_day;
89 
90 	/* Work days.  Indices are based on GDateWeekday.
91 	 * The first element (G_DATE_BAD_WEEKDAY) is unused. */
92 	gboolean work_days[G_DATE_SUNDAY + 1];
93 
94 	/* Work day timespan */
95 	gint work_day_start_hour;
96 	gint work_day_start_minute;
97 	gint work_day_end_hour;
98 	gint work_day_end_minute;
99 	gint work_day_start_mon;
100 	gint work_day_end_mon;
101 	gint work_day_start_tue;
102 	gint work_day_end_tue;
103 	gint work_day_start_wed;
104 	gint work_day_end_wed;
105 	gint work_day_start_thu;
106 	gint work_day_end_thu;
107 	gint work_day_start_fri;
108 	gint work_day_end_fri;
109 	gint work_day_start_sat;
110 	gint work_day_end_sat;
111 	gint work_day_start_sun;
112 	gint work_day_end_sun;
113 
114 	/* callback, to retrieve start time for newly added rows by click-to-add */
115 	ECalModelDefaultTimeFunc get_default_time;
116 	gpointer get_default_time_user_data;
117 
118 	/* Default reminder for events */
119 	gboolean use_default_reminder;
120 	gint default_reminder_interval;
121 	EDurationType default_reminder_units;
122 
123 	/* Ask user to confirm before deleting components. */
124 	gboolean confirm_delete;
125 };
126 
127 typedef struct {
128 	const gchar *color;
129 	GList *uids;
130 } AssignedColorData;
131 
132 static const gchar *cal_model_get_color_for_component (ECalModel *model, ECalModelComponent *comp_data);
133 
134 enum {
135 	PROP_0,
136 	PROP_CLIENT_CACHE,
137 	PROP_COMPRESS_WEEKEND,
138 	PROP_CONFIRM_DELETE,
139 	PROP_DATA_MODEL,
140 	PROP_DEFAULT_REMINDER_INTERVAL,
141 	PROP_DEFAULT_REMINDER_UNITS,
142 	PROP_DEFAULT_SOURCE_UID,
143 	PROP_REGISTRY,
144 	PROP_SHELL,
145 	PROP_TIMEZONE,
146 	PROP_USE_24_HOUR_FORMAT,
147 	PROP_USE_DEFAULT_REMINDER,
148 	PROP_WEEK_START_DAY,
149 	PROP_WORK_DAY_MONDAY,
150 	PROP_WORK_DAY_TUESDAY,
151 	PROP_WORK_DAY_WEDNESDAY,
152 	PROP_WORK_DAY_THURSDAY,
153 	PROP_WORK_DAY_FRIDAY,
154 	PROP_WORK_DAY_SATURDAY,
155 	PROP_WORK_DAY_SUNDAY,
156 	PROP_WORK_DAY_END_HOUR,
157 	PROP_WORK_DAY_END_MINUTE,
158 	PROP_WORK_DAY_START_HOUR,
159 	PROP_WORK_DAY_START_MINUTE,
160 	PROP_WORK_DAY_START_MON,
161 	PROP_WORK_DAY_END_MON,
162 	PROP_WORK_DAY_START_TUE,
163 	PROP_WORK_DAY_END_TUE,
164 	PROP_WORK_DAY_START_WED,
165 	PROP_WORK_DAY_END_WED,
166 	PROP_WORK_DAY_START_THU,
167 	PROP_WORK_DAY_END_THU,
168 	PROP_WORK_DAY_START_FRI,
169 	PROP_WORK_DAY_END_FRI,
170 	PROP_WORK_DAY_START_SAT,
171 	PROP_WORK_DAY_END_SAT,
172 	PROP_WORK_DAY_START_SUN,
173 	PROP_WORK_DAY_END_SUN
174 };
175 
176 enum {
177 	TIME_RANGE_CHANGED,
178 	ROW_APPENDED,
179 	COMPS_DELETED,
180 	TIMEZONE_CHANGED,
181 	OBJECT_CREATED,
182 	LAST_SIGNAL
183 };
184 
185 /* Forward Declarations */
186 static void e_cal_model_table_model_init (ETableModelInterface *iface);
187 static void e_cal_model_cal_data_model_subscriber_init (ECalDataModelSubscriberInterface *iface);
188 
189 static guint signals[LAST_SIGNAL];
190 
G_DEFINE_ABSTRACT_TYPE_WITH_CODE(ECalModel,e_cal_model,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE,NULL)G_IMPLEMENT_INTERFACE (E_TYPE_TABLE_MODEL,e_cal_model_table_model_init)G_IMPLEMENT_INTERFACE (E_TYPE_CAL_DATA_MODEL_SUBSCRIBER,e_cal_model_cal_data_model_subscriber_init))191 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ECalModel, e_cal_model, G_TYPE_OBJECT,
192 	G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL)
193 	G_IMPLEMENT_INTERFACE (E_TYPE_TABLE_MODEL, e_cal_model_table_model_init)
194 	G_IMPLEMENT_INTERFACE (E_TYPE_CAL_DATA_MODEL_SUBSCRIBER, e_cal_model_cal_data_model_subscriber_init))
195 
196 G_DEFINE_TYPE (ECalModelComponent, e_cal_model_component, G_TYPE_OBJECT)
197 
198 static void
199 e_cal_model_component_set_icalcomponent (ECalModelComponent *comp_data,
200 					 ECalModel *model,
201 					 ICalComponent *icomp)
202 {
203 	if (model != NULL)
204 		g_return_if_fail (E_IS_CAL_MODEL (model));
205 	g_return_if_fail (comp_data != NULL);
206 
207 	g_clear_object (&comp_data->icalcomp);
208 	comp_data->icalcomp = icomp;
209 
210 	if (comp_data->priv->categories_str)
211 		g_string_free (comp_data->priv->categories_str, TRUE);
212 	comp_data->priv->categories_str = NULL;
213 	comp_data->priv->icon_index = -1;
214 
215 	g_clear_pointer (&comp_data->dtstart, e_cell_date_edit_value_free);
216 	g_clear_pointer (&comp_data->dtend, e_cell_date_edit_value_free);
217 	g_clear_pointer (&comp_data->due, e_cell_date_edit_value_free);
218 	g_clear_pointer (&comp_data->completed, e_cell_date_edit_value_free);
219 	g_clear_pointer (&comp_data->created, e_cell_date_edit_value_free);
220 	g_clear_pointer (&comp_data->lastmodified, e_cell_date_edit_value_free);
221 	g_clear_pointer (&comp_data->color, g_free);
222 
223 	if (comp_data->icalcomp && model)
224 		e_cal_model_set_instance_times (comp_data, model->priv->zone);
225 }
226 
227 static void
e_cal_model_component_finalize(GObject * object)228 e_cal_model_component_finalize (GObject *object)
229 {
230 	ECalModelComponent *comp_data = E_CAL_MODEL_COMPONENT (object);
231 
232 	g_clear_object (&comp_data->client);
233 
234 	e_cal_model_component_set_icalcomponent (comp_data, NULL, NULL);
235 
236 	/* Chain up to parent's finalize() method. */
237 	G_OBJECT_CLASS (e_cal_model_component_parent_class)->finalize (object);
238 }
239 
240 /* Class initialization function for the calendar component object */
241 static void
e_cal_model_component_class_init(ECalModelComponentClass * class)242 e_cal_model_component_class_init (ECalModelComponentClass *class)
243 {
244 	GObjectClass *object_class;
245 
246 	object_class = (GObjectClass *) class;
247 	g_type_class_add_private (class, sizeof (ECalModelComponentPrivate));
248 
249 	object_class->finalize = e_cal_model_component_finalize;
250 }
251 
252 static void
e_cal_model_component_init(ECalModelComponent * comp)253 e_cal_model_component_init (ECalModelComponent *comp)
254 {
255 	comp->priv = E_CAL_MODEL_COMPONENT_GET_PRIVATE (comp);
256 	comp->priv->icon_index = -1;
257 	comp->is_new_component = FALSE;
258 }
259 
260 static gpointer
get_categories(ECalModelComponent * comp_data)261 get_categories (ECalModelComponent *comp_data)
262 {
263 	if (!comp_data->priv->categories_str) {
264 		ICalProperty *prop;
265 
266 		comp_data->priv->categories_str = g_string_new ("");
267 
268 		for (prop = i_cal_component_get_first_property (comp_data->icalcomp, I_CAL_CATEGORIES_PROPERTY);
269 		     prop;
270 		     g_object_unref (prop), prop = i_cal_component_get_next_property (comp_data->icalcomp, I_CAL_CATEGORIES_PROPERTY)) {
271 			const gchar *categories = i_cal_property_get_categories (prop);
272 			if (!categories)
273 				continue;
274 
275 			if (comp_data->priv->categories_str->len)
276 				g_string_append_c (comp_data->priv->categories_str, ',');
277 			g_string_append (comp_data->priv->categories_str, categories);
278 		}
279 	}
280 
281 	return g_strdup (comp_data->priv->categories_str->str);
282 }
283 
284 static gchar *
get_classification(ECalModelComponent * comp_data)285 get_classification (ECalModelComponent *comp_data)
286 {
287 	ICalProperty *prop;
288 	ICalProperty_Class class_prop;
289 
290 	prop = i_cal_component_get_first_property (comp_data->icalcomp, I_CAL_CLASS_PROPERTY);
291 
292 	if (!prop)
293 		return _("Public");
294 
295 	class_prop = i_cal_property_get_class (prop);
296 
297 	g_clear_object (&prop);
298 
299 	switch (class_prop) {
300 	case I_CAL_CLASS_PUBLIC:
301 		return _("Public");
302 	case I_CAL_CLASS_PRIVATE:
303 		return _("Private");
304 	case I_CAL_CLASS_CONFIDENTIAL:
305 		return _("Confidential");
306 	default:
307 		return _("Unknown");
308 	}
309 }
310 
311 static const gchar *
get_color(ECalModel * model,ECalModelComponent * comp_data)312 get_color (ECalModel *model,
313            ECalModelComponent *comp_data)
314 {
315 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
316 
317 	return e_cal_model_get_color_for_component (model, comp_data);
318 }
319 
320 static gpointer
get_description(ECalModelComponent * comp_data)321 get_description (ECalModelComponent *comp_data)
322 {
323 	ICalProperty *prop;
324 	GString *str = NULL;
325 
326 	for (prop = i_cal_component_get_first_property (comp_data->icalcomp, I_CAL_DESCRIPTION_PROPERTY);
327 	     prop;
328 	     g_object_unref (prop), prop = i_cal_component_get_next_property (comp_data->icalcomp, I_CAL_DESCRIPTION_PROPERTY)) {
329 		if (!str)
330 			str = g_string_new (NULL);
331 		g_string_append (str, i_cal_property_get_description (prop));
332 	}
333 
334 	return str ? g_string_free (str, FALSE) : g_strdup ("");
335 }
336 
337 static ECellDateEditValue *
get_dtstart(ECalModel * model,ECalModelComponent * comp_data)338 get_dtstart (ECalModel *model,
339              ECalModelComponent *comp_data)
340 {
341 	if (!comp_data->dtstart) {
342 		comp_data->dtstart = e_cal_model_util_get_datetime_value (model, comp_data,
343 			I_CAL_DTSTART_PROPERTY, i_cal_property_get_dtstart);
344 	}
345 
346 	return e_cell_date_edit_value_copy (comp_data->dtstart);
347 }
348 
349 static ECellDateEditValue *
get_datetime_from_utc(ECalModel * model,ECalModelComponent * comp_data,ICalPropertyKind propkind,ICalTime * (* get_value)(ICalProperty * prop),ECellDateEditValue ** buffer)350 get_datetime_from_utc (ECalModel *model,
351                        ECalModelComponent *comp_data,
352                        ICalPropertyKind propkind,
353                        ICalTime * (*get_value) (ICalProperty *prop),
354 		       ECellDateEditValue **buffer)
355 {
356 	g_return_val_if_fail (buffer != NULL, NULL);
357 
358 	if (!*buffer) {
359 		ECalModelPrivate *priv;
360 		ICalTime *tt_value;
361 		ICalProperty *prop;
362 
363 		priv = model->priv;
364 
365 		prop = i_cal_component_get_first_property (comp_data->icalcomp, propkind);
366 		if (!prop)
367 			return NULL;
368 
369 		tt_value = get_value (prop);
370 
371 		/* these are always in UTC, thus convert to default zone, if any and done */
372 		if (priv->zone)
373 			i_cal_time_convert_timezone (tt_value, i_cal_timezone_get_utc_timezone (), priv->zone);
374 
375 		g_object_unref (prop);
376 
377 		if (!i_cal_time_is_valid_time (tt_value) || i_cal_time_is_null_time (tt_value)) {
378 			g_clear_object (&tt_value);
379 			return NULL;
380 		}
381 
382 		*buffer = e_cell_date_edit_value_new_take (tt_value, NULL);
383 	}
384 
385 	return e_cell_date_edit_value_copy (*buffer);
386 }
387 
388 static gpointer
get_summary(ECalModelComponent * comp_data)389 get_summary (ECalModelComponent *comp_data)
390 {
391 	ICalProperty *prop;
392 	gchar *res = NULL;
393 
394 	prop = i_cal_component_get_first_property (comp_data->icalcomp, I_CAL_SUMMARY_PROPERTY);
395 	if (prop)
396 		res = g_strdup (i_cal_property_get_summary (prop));
397 
398 	g_clear_object (&prop);
399 
400 	if (!res)
401 		res = g_strdup ("");
402 
403 	e_cal_model_until_sanitize_text_value (res, -1);
404 
405 	return res;
406 }
407 
408 static gchar *
get_uid(ECalModelComponent * comp_data)409 get_uid (ECalModelComponent *comp_data)
410 {
411 	return (gchar *) i_cal_component_get_uid (comp_data->icalcomp);
412 }
413 
414 static gchar *
get_source_description(ESourceRegistry * registry,ECalModelComponent * comp_data)415 get_source_description (ESourceRegistry *registry,
416 			ECalModelComponent *comp_data)
417 {
418 	if (!registry || !comp_data || !comp_data->client)
419 		return NULL;
420 
421 	return e_util_get_source_full_name (registry, e_client_get_source (E_CLIENT (comp_data->client)));
422 }
423 
424 static void
set_categories(ECalModelComponent * comp_data,const gchar * value)425 set_categories (ECalModelComponent *comp_data,
426                 const gchar *value)
427 {
428 	ICalProperty *prop;
429 
430 	/* remove all categories first */
431 	e_cal_util_component_remove_property_by_kind (comp_data->icalcomp, I_CAL_CATEGORIES_PROPERTY, TRUE);
432 
433 	if (comp_data->priv->categories_str)
434 		g_string_free (comp_data->priv->categories_str, TRUE);
435 	comp_data->priv->categories_str = NULL;
436 
437 	/* then set a new value; no need to populate categories_str,
438 	 * it'll be populated on demand (in the get_categories() function)
439 	*/
440 	if (value && *value) {
441 		prop = i_cal_property_new_categories (value);
442 		i_cal_component_take_property (comp_data->icalcomp, prop);
443 	}
444 }
445 
446 static void
set_classification(ECalModelComponent * comp_data,const gchar * value)447 set_classification (ECalModelComponent *comp_data,
448                     const gchar *value)
449 {
450 	ICalProperty *prop;
451 
452 	prop = i_cal_component_get_first_property (comp_data->icalcomp, I_CAL_CLASS_PROPERTY);
453 	if (!value || !(*value)) {
454 		if (prop) {
455 			i_cal_component_remove_property (comp_data->icalcomp, prop);
456 			g_clear_object (&prop);
457 		}
458 	} else {
459 		ICalProperty_Class ical_class;
460 
461 		if (!g_ascii_strcasecmp (value, "PUBLIC"))
462 			ical_class = I_CAL_CLASS_PUBLIC;
463 		else if (!g_ascii_strcasecmp (value, "PRIVATE"))
464 			ical_class = I_CAL_CLASS_PRIVATE;
465 		else if (!g_ascii_strcasecmp (value, "CONFIDENTIAL"))
466 			ical_class = I_CAL_CLASS_CONFIDENTIAL;
467 		else
468 			ical_class = I_CAL_CLASS_NONE;
469 
470 		if (!prop) {
471 			prop = i_cal_property_new_class (ical_class);
472 			i_cal_component_take_property (comp_data->icalcomp, prop);
473 		} else {
474 			i_cal_property_set_class (prop, ical_class);
475 			g_clear_object (&prop);
476 		}
477 	}
478 }
479 
480 static void
set_description(ECalModelComponent * comp_data,const gchar * value)481 set_description (ECalModelComponent *comp_data,
482                  const gchar *value)
483 {
484 	ICalProperty *prop;
485 
486 	/* remove old description(s) */
487 	e_cal_util_component_remove_property_by_kind (comp_data->icalcomp, I_CAL_DESCRIPTION_PROPERTY, TRUE);
488 
489 	/* now add the new description */
490 	if (!value || !(*value))
491 		return;
492 
493 	prop = i_cal_property_new_description (value);
494 	i_cal_component_take_property (comp_data->icalcomp, prop);
495 }
496 
497 static void
set_dtstart(ECalModel * model,ECalModelComponent * comp_data,gconstpointer value)498 set_dtstart (ECalModel *model,
499              ECalModelComponent *comp_data,
500              gconstpointer value)
501 {
502 	e_cal_model_update_comp_time (
503 		model, comp_data, value,
504 		I_CAL_DTSTART_PROPERTY,
505 		i_cal_property_set_dtstart,
506 		i_cal_property_new_dtstart);
507 }
508 
509 static void
set_summary(ECalModelComponent * comp_data,const gchar * value)510 set_summary (ECalModelComponent *comp_data,
511              const gchar *value)
512 {
513 	ICalProperty *prop;
514 
515 	prop = i_cal_component_get_first_property (comp_data->icalcomp, I_CAL_SUMMARY_PROPERTY);
516 
517 	if (string_is_empty (value)) {
518 		if (prop) {
519 			i_cal_component_remove_property (comp_data->icalcomp, prop);
520 			g_clear_object (&prop);
521 		}
522 	} else {
523 		if (prop) {
524 			i_cal_property_set_summary (prop, value);
525 			g_clear_object (&prop);
526 		} else {
527 			prop = i_cal_property_new_summary (value);
528 			i_cal_component_take_property (comp_data->icalcomp, prop);
529 		}
530 	}
531 }
532 
533 static void
datetime_to_zone(ECalClient * client,ICalTime * tt,ICalTimezone * tt_zone,const gchar * tzid)534 datetime_to_zone (ECalClient *client,
535 		  ICalTime *tt,
536 		  ICalTimezone *tt_zone,
537                   const gchar *tzid)
538 {
539 	ICalTimezone *from, *to;
540 	const gchar *tt_tzid = NULL;
541 
542 	g_return_if_fail (tt != NULL);
543 
544 	if (tt_zone)
545 		tt_tzid = i_cal_timezone_get_tzid (tt_zone);
546 
547 	if (tt_tzid == NULL || tzid == NULL ||
548 	    tt_tzid == tzid || g_str_equal (tt_tzid, tzid))
549 		return;
550 
551 	from = tt_zone;
552 	to = i_cal_timezone_get_builtin_timezone_from_tzid (tzid);
553 	if (!to) {
554 		/* do not abort on failure here, maybe the zone is not available there */
555 		if (!e_cal_client_get_timezone_sync (client, tzid, &to, NULL, NULL))
556 			to = NULL;
557 	}
558 
559 	i_cal_time_convert_timezone (tt, from, to);
560 }
561 
562 static void
cal_model_set_data_model(ECalModel * model,ECalDataModel * data_model)563 cal_model_set_data_model (ECalModel *model,
564 			  ECalDataModel *data_model)
565 {
566 	g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model));
567 	g_return_if_fail (model->priv->data_model == NULL);
568 
569 	/* Be aware of a circular dependency, once this @model is subscribed to
570 	   the @data_model, then the @data_model increases reference count
571 	   of the @model.
572 	*/
573 	model->priv->data_model = g_object_ref (data_model);
574 }
575 
576 static void
cal_model_set_registry(ECalModel * model,ESourceRegistry * registry)577 cal_model_set_registry (ECalModel *model,
578                         ESourceRegistry *registry)
579 {
580 	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
581 	g_return_if_fail (model->priv->registry == NULL);
582 
583 	model->priv->registry = g_object_ref (registry);
584 }
585 
586 static void
cal_model_set_shell(ECalModel * model,EShell * shell)587 cal_model_set_shell (ECalModel *model,
588 		     EShell *shell)
589 {
590 	EClientCache *client_cache;
591 
592 	g_return_if_fail (E_IS_SHELL (shell));
593 	g_return_if_fail (model->priv->shell == NULL);
594 
595 	model->priv->shell = g_object_ref (shell);
596 
597 	client_cache = e_shell_get_client_cache (shell);
598 
599 	g_return_if_fail (E_IS_CLIENT_CACHE (client_cache));
600 	g_return_if_fail (model->priv->client_cache == NULL);
601 
602 	model->priv->client_cache = g_object_ref (client_cache);
603 }
604 
605 static void
cal_model_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)606 cal_model_set_property (GObject *object,
607                         guint property_id,
608                         const GValue *value,
609                         GParamSpec *pspec)
610 {
611 	switch (property_id) {
612 		case PROP_COMPRESS_WEEKEND:
613 			e_cal_model_set_compress_weekend (
614 				E_CAL_MODEL (object),
615 				g_value_get_boolean (value));
616 			return;
617 
618 		case PROP_CONFIRM_DELETE:
619 			e_cal_model_set_confirm_delete (
620 				E_CAL_MODEL (object),
621 				g_value_get_boolean (value));
622 			return;
623 
624 		case PROP_DATA_MODEL:
625 			cal_model_set_data_model (
626 				E_CAL_MODEL (object),
627 				g_value_get_object (value));
628 			return;
629 
630 		case PROP_DEFAULT_SOURCE_UID:
631 			e_cal_model_set_default_source_uid (
632 				E_CAL_MODEL (object),
633 				g_value_get_string (value));
634 			return;
635 
636 		case PROP_DEFAULT_REMINDER_INTERVAL:
637 			e_cal_model_set_default_reminder_interval (
638 				E_CAL_MODEL (object),
639 				g_value_get_int (value));
640 			return;
641 
642 		case PROP_DEFAULT_REMINDER_UNITS:
643 			e_cal_model_set_default_reminder_units (
644 				E_CAL_MODEL (object),
645 				g_value_get_enum (value));
646 			return;
647 
648 		case PROP_REGISTRY:
649 			cal_model_set_registry (
650 				E_CAL_MODEL (object),
651 				g_value_get_object (value));
652 			return;
653 
654 		case PROP_SHELL:
655 			cal_model_set_shell (
656 				E_CAL_MODEL (object),
657 				g_value_get_object (value));
658 			return;
659 
660 		case PROP_TIMEZONE:
661 			e_cal_model_set_timezone (
662 				E_CAL_MODEL (object),
663 				g_value_get_object (value));
664 			return;
665 
666 		case PROP_USE_24_HOUR_FORMAT:
667 			e_cal_model_set_use_24_hour_format (
668 				E_CAL_MODEL (object),
669 				g_value_get_boolean (value));
670 			return;
671 
672 		case PROP_USE_DEFAULT_REMINDER:
673 			e_cal_model_set_use_default_reminder (
674 				E_CAL_MODEL (object),
675 				g_value_get_boolean (value));
676 			return;
677 
678 		case PROP_WEEK_START_DAY:
679 			e_cal_model_set_week_start_day (
680 				E_CAL_MODEL (object),
681 				g_value_get_enum (value));
682 			return;
683 
684 		case PROP_WORK_DAY_MONDAY:
685 			e_cal_model_set_work_day (
686 				E_CAL_MODEL (object),
687 				G_DATE_MONDAY,
688 				g_value_get_boolean (value));
689 			return;
690 
691 		case PROP_WORK_DAY_TUESDAY:
692 			e_cal_model_set_work_day (
693 				E_CAL_MODEL (object),
694 				G_DATE_TUESDAY,
695 				g_value_get_boolean (value));
696 			return;
697 
698 		case PROP_WORK_DAY_WEDNESDAY:
699 			e_cal_model_set_work_day (
700 				E_CAL_MODEL (object),
701 				G_DATE_WEDNESDAY,
702 				g_value_get_boolean (value));
703 			return;
704 
705 		case PROP_WORK_DAY_THURSDAY:
706 			e_cal_model_set_work_day (
707 				E_CAL_MODEL (object),
708 				G_DATE_THURSDAY,
709 				g_value_get_boolean (value));
710 			return;
711 
712 		case PROP_WORK_DAY_FRIDAY:
713 			e_cal_model_set_work_day (
714 				E_CAL_MODEL (object),
715 				G_DATE_FRIDAY,
716 				g_value_get_boolean (value));
717 			return;
718 
719 		case PROP_WORK_DAY_SATURDAY:
720 			e_cal_model_set_work_day (
721 				E_CAL_MODEL (object),
722 				G_DATE_SATURDAY,
723 				g_value_get_boolean (value));
724 			return;
725 
726 		case PROP_WORK_DAY_SUNDAY:
727 			e_cal_model_set_work_day (
728 				E_CAL_MODEL (object),
729 				G_DATE_SUNDAY,
730 				g_value_get_boolean (value));
731 			return;
732 
733 		case PROP_WORK_DAY_END_HOUR:
734 			e_cal_model_set_work_day_end_hour (
735 				E_CAL_MODEL (object),
736 				g_value_get_int (value));
737 			return;
738 
739 		case PROP_WORK_DAY_END_MINUTE:
740 			e_cal_model_set_work_day_end_minute (
741 				E_CAL_MODEL (object),
742 				g_value_get_int (value));
743 			return;
744 
745 		case PROP_WORK_DAY_START_HOUR:
746 			e_cal_model_set_work_day_start_hour (
747 				E_CAL_MODEL (object),
748 				g_value_get_int (value));
749 			return;
750 
751 		case PROP_WORK_DAY_START_MINUTE:
752 			e_cal_model_set_work_day_start_minute (
753 				E_CAL_MODEL (object),
754 				g_value_get_int (value));
755 			return;
756 
757 		case PROP_WORK_DAY_START_MON:
758 			e_cal_model_set_work_day_start_mon (
759 				E_CAL_MODEL (object),
760 				g_value_get_int (value));
761 			return;
762 
763 		case PROP_WORK_DAY_END_MON:
764 			e_cal_model_set_work_day_end_mon (
765 				E_CAL_MODEL (object),
766 				g_value_get_int (value));
767 			return;
768 
769 		case PROP_WORK_DAY_START_TUE:
770 			e_cal_model_set_work_day_start_tue (
771 				E_CAL_MODEL (object),
772 				g_value_get_int (value));
773 			return;
774 
775 		case PROP_WORK_DAY_END_TUE:
776 			e_cal_model_set_work_day_end_tue (
777 				E_CAL_MODEL (object),
778 				g_value_get_int (value));
779 			return;
780 
781 		case PROP_WORK_DAY_START_WED:
782 			e_cal_model_set_work_day_start_wed (
783 				E_CAL_MODEL (object),
784 				g_value_get_int (value));
785 			return;
786 
787 		case PROP_WORK_DAY_END_WED:
788 			e_cal_model_set_work_day_end_wed (
789 				E_CAL_MODEL (object),
790 				g_value_get_int (value));
791 			return;
792 
793 		case PROP_WORK_DAY_START_THU:
794 			e_cal_model_set_work_day_start_thu (
795 				E_CAL_MODEL (object),
796 				g_value_get_int (value));
797 			return;
798 
799 		case PROP_WORK_DAY_END_THU:
800 			e_cal_model_set_work_day_end_thu (
801 				E_CAL_MODEL (object),
802 				g_value_get_int (value));
803 			return;
804 
805 		case PROP_WORK_DAY_START_FRI:
806 			e_cal_model_set_work_day_start_fri (
807 				E_CAL_MODEL (object),
808 				g_value_get_int (value));
809 			return;
810 
811 		case PROP_WORK_DAY_END_FRI:
812 			e_cal_model_set_work_day_end_fri (
813 				E_CAL_MODEL (object),
814 				g_value_get_int (value));
815 			return;
816 
817 		case PROP_WORK_DAY_START_SAT:
818 			e_cal_model_set_work_day_start_sat (
819 				E_CAL_MODEL (object),
820 				g_value_get_int (value));
821 			return;
822 
823 		case PROP_WORK_DAY_END_SAT:
824 			e_cal_model_set_work_day_end_sat (
825 				E_CAL_MODEL (object),
826 				g_value_get_int (value));
827 			return;
828 
829 		case PROP_WORK_DAY_START_SUN:
830 			e_cal_model_set_work_day_start_sun (
831 				E_CAL_MODEL (object),
832 				g_value_get_int (value));
833 			return;
834 
835 		case PROP_WORK_DAY_END_SUN:
836 			e_cal_model_set_work_day_end_sun (
837 				E_CAL_MODEL (object),
838 				g_value_get_int (value));
839 			return;
840 	}
841 
842 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
843 }
844 
845 static void
cal_model_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)846 cal_model_get_property (GObject *object,
847                         guint property_id,
848                         GValue *value,
849                         GParamSpec *pspec)
850 {
851 	switch (property_id) {
852 		case PROP_CLIENT_CACHE:
853 			g_value_set_object (
854 				value,
855 				e_cal_model_get_client_cache (
856 				E_CAL_MODEL (object)));
857 			return;
858 
859 		case PROP_COMPRESS_WEEKEND:
860 			g_value_set_boolean (
861 				value,
862 				e_cal_model_get_compress_weekend (
863 				E_CAL_MODEL (object)));
864 			return;
865 
866 		case PROP_CONFIRM_DELETE:
867 			g_value_set_boolean (
868 				value,
869 				e_cal_model_get_confirm_delete (
870 				E_CAL_MODEL (object)));
871 			return;
872 
873 		case PROP_DATA_MODEL:
874 			g_value_set_object (
875 				value,
876 				e_cal_model_get_data_model (
877 				E_CAL_MODEL (object)));
878 			return;
879 
880 		case PROP_DEFAULT_SOURCE_UID:
881 			g_value_set_string (
882 				value,
883 				e_cal_model_get_default_source_uid (
884 				E_CAL_MODEL (object)));
885 			return;
886 
887 		case PROP_DEFAULT_REMINDER_INTERVAL:
888 			g_value_set_int (
889 				value,
890 				e_cal_model_get_default_reminder_interval (
891 				E_CAL_MODEL (object)));
892 			return;
893 
894 		case PROP_DEFAULT_REMINDER_UNITS:
895 			g_value_set_enum (
896 				value,
897 				e_cal_model_get_default_reminder_units (
898 				E_CAL_MODEL (object)));
899 			return;
900 
901 		case PROP_REGISTRY:
902 			g_value_set_object (
903 				value,
904 				e_cal_model_get_registry (
905 				E_CAL_MODEL (object)));
906 			return;
907 
908 		case PROP_SHELL:
909 			g_value_set_object (
910 				value,
911 				e_cal_model_get_shell (
912 				E_CAL_MODEL (object)));
913 			return;
914 
915 		case PROP_TIMEZONE:
916 			g_value_set_object (
917 				value,
918 				e_cal_model_get_timezone (
919 				E_CAL_MODEL (object)));
920 			return;
921 
922 		case PROP_USE_24_HOUR_FORMAT:
923 			g_value_set_boolean (
924 				value,
925 				e_cal_model_get_use_24_hour_format (
926 				E_CAL_MODEL (object)));
927 			return;
928 
929 		case PROP_USE_DEFAULT_REMINDER:
930 			g_value_set_boolean (
931 				value,
932 				e_cal_model_get_use_default_reminder (
933 				E_CAL_MODEL (object)));
934 			return;
935 
936 		case PROP_WEEK_START_DAY:
937 			g_value_set_enum (
938 				value,
939 				e_cal_model_get_week_start_day (
940 				E_CAL_MODEL (object)));
941 			return;
942 
943 		case PROP_WORK_DAY_MONDAY:
944 			g_value_set_boolean (
945 				value,
946 				e_cal_model_get_work_day (
947 				E_CAL_MODEL (object), G_DATE_MONDAY));
948 			return;
949 
950 		case PROP_WORK_DAY_TUESDAY:
951 			g_value_set_boolean (
952 				value,
953 				e_cal_model_get_work_day (
954 				E_CAL_MODEL (object), G_DATE_TUESDAY));
955 			return;
956 
957 		case PROP_WORK_DAY_WEDNESDAY:
958 			g_value_set_boolean (
959 				value,
960 				e_cal_model_get_work_day (
961 				E_CAL_MODEL (object), G_DATE_WEDNESDAY));
962 			return;
963 
964 		case PROP_WORK_DAY_THURSDAY:
965 			g_value_set_boolean (
966 				value,
967 				e_cal_model_get_work_day (
968 				E_CAL_MODEL (object), G_DATE_THURSDAY));
969 			return;
970 
971 		case PROP_WORK_DAY_FRIDAY:
972 			g_value_set_boolean (
973 				value,
974 				e_cal_model_get_work_day (
975 				E_CAL_MODEL (object), G_DATE_FRIDAY));
976 			return;
977 
978 		case PROP_WORK_DAY_SATURDAY:
979 			g_value_set_boolean (
980 				value,
981 				e_cal_model_get_work_day (
982 				E_CAL_MODEL (object), G_DATE_SATURDAY));
983 			return;
984 
985 		case PROP_WORK_DAY_SUNDAY:
986 			g_value_set_boolean (
987 				value,
988 				e_cal_model_get_work_day (
989 				E_CAL_MODEL (object), G_DATE_SUNDAY));
990 			return;
991 
992 		case PROP_WORK_DAY_END_HOUR:
993 			g_value_set_int (
994 				value,
995 				e_cal_model_get_work_day_end_hour (
996 				E_CAL_MODEL (object)));
997 			return;
998 
999 		case PROP_WORK_DAY_END_MINUTE:
1000 			g_value_set_int (
1001 				value,
1002 				e_cal_model_get_work_day_end_minute (
1003 				E_CAL_MODEL (object)));
1004 			return;
1005 
1006 		case PROP_WORK_DAY_START_HOUR:
1007 			g_value_set_int (
1008 				value,
1009 				e_cal_model_get_work_day_start_hour (
1010 				E_CAL_MODEL (object)));
1011 			return;
1012 
1013 		case PROP_WORK_DAY_START_MINUTE:
1014 			g_value_set_int (
1015 				value,
1016 				e_cal_model_get_work_day_start_minute (
1017 				E_CAL_MODEL (object)));
1018 			return;
1019 
1020 		case PROP_WORK_DAY_START_MON:
1021 			g_value_set_int (
1022 				value,
1023 				e_cal_model_get_work_day_start_mon (
1024 				E_CAL_MODEL (object)));
1025 			return;
1026 
1027 		case PROP_WORK_DAY_END_MON:
1028 			g_value_set_int (
1029 				value,
1030 				e_cal_model_get_work_day_end_mon (
1031 				E_CAL_MODEL (object)));
1032 			return;
1033 
1034 		case PROP_WORK_DAY_START_TUE:
1035 			g_value_set_int (
1036 				value,
1037 				e_cal_model_get_work_day_start_tue (
1038 				E_CAL_MODEL (object)));
1039 			return;
1040 
1041 		case PROP_WORK_DAY_END_TUE:
1042 			g_value_set_int (
1043 				value,
1044 				e_cal_model_get_work_day_end_tue (
1045 				E_CAL_MODEL (object)));
1046 			return;
1047 
1048 		case PROP_WORK_DAY_START_WED:
1049 			g_value_set_int (
1050 				value,
1051 				e_cal_model_get_work_day_start_wed (
1052 				E_CAL_MODEL (object)));
1053 			return;
1054 
1055 		case PROP_WORK_DAY_END_WED:
1056 			g_value_set_int (
1057 				value,
1058 				e_cal_model_get_work_day_end_wed (
1059 				E_CAL_MODEL (object)));
1060 			return;
1061 
1062 		case PROP_WORK_DAY_START_THU:
1063 			g_value_set_int (
1064 				value,
1065 				e_cal_model_get_work_day_start_thu (
1066 				E_CAL_MODEL (object)));
1067 			return;
1068 
1069 		case PROP_WORK_DAY_END_THU:
1070 			g_value_set_int (
1071 				value,
1072 				e_cal_model_get_work_day_end_thu (
1073 				E_CAL_MODEL (object)));
1074 			return;
1075 
1076 		case PROP_WORK_DAY_START_FRI:
1077 			g_value_set_int (
1078 				value,
1079 				e_cal_model_get_work_day_start_fri (
1080 				E_CAL_MODEL (object)));
1081 			return;
1082 
1083 		case PROP_WORK_DAY_END_FRI:
1084 			g_value_set_int (
1085 				value,
1086 				e_cal_model_get_work_day_end_fri (
1087 				E_CAL_MODEL (object)));
1088 			return;
1089 
1090 		case PROP_WORK_DAY_START_SAT:
1091 			g_value_set_int (
1092 				value,
1093 				e_cal_model_get_work_day_start_sat (
1094 				E_CAL_MODEL (object)));
1095 			return;
1096 
1097 		case PROP_WORK_DAY_END_SAT:
1098 			g_value_set_int (
1099 				value,
1100 				e_cal_model_get_work_day_end_sat (
1101 				E_CAL_MODEL (object)));
1102 			return;
1103 
1104 		case PROP_WORK_DAY_START_SUN:
1105 			g_value_set_int (
1106 				value,
1107 				e_cal_model_get_work_day_start_sun (
1108 				E_CAL_MODEL (object)));
1109 			return;
1110 
1111 		case PROP_WORK_DAY_END_SUN:
1112 			g_value_set_int (
1113 				value,
1114 				e_cal_model_get_work_day_end_sun (
1115 				E_CAL_MODEL (object)));
1116 			return;
1117 	}
1118 
1119 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1120 }
1121 
1122 static void
cal_model_constructed(GObject * object)1123 cal_model_constructed (GObject *object)
1124 {
1125 	e_extensible_load_extensions (E_EXTENSIBLE (object));
1126 
1127 	/* Chain up to parent's constructed() method. */
1128 	G_OBJECT_CLASS (e_cal_model_parent_class)->constructed (object);
1129 }
1130 
1131 static void
cal_model_dispose(GObject * object)1132 cal_model_dispose (GObject *object)
1133 {
1134 	ECalModelPrivate *priv;
1135 
1136 	priv = E_CAL_MODEL_GET_PRIVATE (object);
1137 
1138 	g_clear_object (&priv->data_model);
1139 	g_clear_object (&priv->registry);
1140 	g_clear_object (&priv->shell);
1141 	g_clear_object (&priv->client_cache);
1142 	g_clear_object (&priv->zone);
1143 
1144 	g_clear_pointer (&priv->default_source_uid, g_free);
1145 
1146 	/* Chain up to parent's dispose() method. */
1147 	G_OBJECT_CLASS (e_cal_model_parent_class)->dispose (object);
1148 }
1149 
1150 static void
cal_model_finalize(GObject * object)1151 cal_model_finalize (GObject *object)
1152 {
1153 	ECalModelPrivate *priv;
1154 	gint ii;
1155 
1156 	priv = E_CAL_MODEL_GET_PRIVATE (object);
1157 
1158 	g_free (priv->default_category);
1159 
1160 	for (ii = 0; ii < priv->objects->len; ii++) {
1161 		ECalModelComponent *comp_data;
1162 
1163 		comp_data = g_ptr_array_index (priv->objects, ii);
1164 		if (comp_data == NULL) {
1165 			g_warning ("comp_data is null\n");
1166 			continue;
1167 		}
1168 		g_object_unref (comp_data);
1169 	}
1170 	g_ptr_array_free (priv->objects, TRUE);
1171 
1172 	/* Chain up to parent's finalize() method. */
1173 	G_OBJECT_CLASS (e_cal_model_parent_class)->finalize (object);
1174 }
1175 
1176 static const gchar *
cal_model_get_color_for_component(ECalModel * model,ECalModelComponent * comp_data)1177 cal_model_get_color_for_component (ECalModel *model,
1178                                    ECalModelComponent *comp_data)
1179 {
1180 	ESource *source;
1181 	ESourceSelectable *extension;
1182 	const gchar *color_spec;
1183 	const gchar *extension_name;
1184 	const gchar *uid;
1185 	gint i, first_empty = 0;
1186 	ICalProperty *prop;
1187 
1188 	static AssignedColorData assigned_colors[] = {
1189 		{ "#BECEDD", NULL }, /* 190 206 221     Blue */
1190 		{ "#E2F0EF", NULL }, /* 226 240 239     Light Blue */
1191 		{ "#C6E2B7", NULL }, /* 198 226 183     Green */
1192 		{ "#E2F0D3", NULL }, /* 226 240 211     Light Green */
1193 		{ "#E2D4B7", NULL }, /* 226 212 183     Khaki */
1194 		{ "#EAEAC1", NULL }, /* 234 234 193     Light Khaki */
1195 		{ "#F0B8B7", NULL }, /* 240 184 183     Pink */
1196 		{ "#FED4D3", NULL }, /* 254 212 211     Light Pink */
1197 		{ "#E2C6E1", NULL }, /* 226 198 225     Purple */
1198 		{ "#F0E2EF", NULL }  /* 240 226 239     Light Purple */
1199 	};
1200 
1201 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
1202 
1203 	prop = i_cal_component_get_first_property (comp_data->icalcomp, I_CAL_COLOR_PROPERTY);
1204 	if (prop) {
1205 		GdkRGBA rgba;
1206 
1207 		color_spec = i_cal_property_get_color (prop);
1208 		if (color_spec && gdk_rgba_parse (&rgba, color_spec)) {
1209 			g_free (comp_data->color);
1210 			comp_data->color = g_strdup (color_spec);
1211 
1212 			g_object_unref (prop);
1213 
1214 			return comp_data->color;
1215 		}
1216 
1217 		g_object_unref (prop);
1218 	}
1219 
1220 	switch (e_cal_client_get_source_type (comp_data->client)) {
1221 		case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
1222 			extension_name = E_SOURCE_EXTENSION_CALENDAR;
1223 			break;
1224 		case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
1225 			extension_name = E_SOURCE_EXTENSION_TASK_LIST;
1226 			break;
1227 		case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
1228 			extension_name = E_SOURCE_EXTENSION_MEMO_LIST;
1229 			break;
1230 		default:
1231 			g_return_val_if_reached (NULL);
1232 	}
1233 
1234 	source = e_client_get_source (E_CLIENT (comp_data->client));
1235 	extension = e_source_get_extension (source, extension_name);
1236 	color_spec = e_source_selectable_get_color (extension);
1237 
1238 	if (color_spec != NULL) {
1239 		g_free (comp_data->color);
1240 		comp_data->color = g_strdup (color_spec);
1241 		return comp_data->color;
1242 	}
1243 
1244 	uid = e_source_get_uid (source);
1245 
1246 	for (i = 0; i < G_N_ELEMENTS (assigned_colors); i++) {
1247 		GList *l;
1248 
1249 		if (assigned_colors[i].uids == NULL) {
1250 			first_empty = i;
1251 			continue;
1252 		}
1253 
1254 		for (l = assigned_colors[i].uids; l != NULL; l = l->next)
1255 			if (g_strcmp0 (l->data, uid) == 0)
1256 				return assigned_colors[i].color;
1257 	}
1258 
1259 	/* return the first unused color */
1260 	assigned_colors[first_empty].uids = g_list_append (
1261 		assigned_colors[first_empty].uids, g_strdup (uid));
1262 
1263 	return assigned_colors[first_empty].color;
1264 }
1265 
1266 static gint
cal_model_column_count(ETableModel * etm)1267 cal_model_column_count (ETableModel *etm)
1268 {
1269 	return E_CAL_MODEL_FIELD_LAST;
1270 }
1271 
1272 static gint
cal_model_row_count(ETableModel * etm)1273 cal_model_row_count (ETableModel *etm)
1274 {
1275 	ECalModelPrivate *priv;
1276 	ECalModel *model = (ECalModel *) etm;
1277 
1278 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
1279 
1280 	priv = model->priv;
1281 
1282 	return priv->objects->len;
1283 }
1284 
1285 static const gchar *
cal_model_kind_to_extension_name(ECalModel * model)1286 cal_model_kind_to_extension_name (ECalModel *model)
1287 {
1288 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
1289 
1290 	switch (model->priv->kind) {
1291 		case I_CAL_VEVENT_COMPONENT:
1292 			return E_SOURCE_EXTENSION_CALENDAR;
1293 		case I_CAL_VJOURNAL_COMPONENT:
1294 			return E_SOURCE_EXTENSION_MEMO_LIST;
1295 		case I_CAL_VTODO_COMPONENT:
1296 			return E_SOURCE_EXTENSION_TASK_LIST;
1297 		default:
1298 			g_warn_if_reached ();
1299 			break;
1300 	}
1301 
1302 	return NULL;
1303 }
1304 
1305 typedef struct {
1306 	ECalModel *model;
1307 	ETableModel *table_model;
1308 	GHashTable *values;
1309 	gboolean success;
1310 } CreateComponentData;
1311 
1312 static void
create_component_data_free(gpointer ptr)1313 create_component_data_free (gpointer ptr)
1314 {
1315 	CreateComponentData *ccd = ptr;
1316 
1317 	if (ccd) {
1318 		GHashTableIter iter;
1319 		gpointer key, value;
1320 
1321 		g_hash_table_iter_init (&iter, ccd->values);
1322 		while (g_hash_table_iter_next (&iter, &key, &value)) {
1323 			gint column = GPOINTER_TO_INT (key);
1324 
1325 			e_table_model_free_value (ccd->table_model, column, value);
1326 		}
1327 
1328 		if (ccd->success)
1329 			g_signal_emit (ccd->model, signals[ROW_APPENDED], 0);
1330 
1331 		g_clear_object (&ccd->model);
1332 		g_clear_object (&ccd->table_model);
1333 		g_hash_table_destroy (ccd->values);
1334 		g_slice_free (CreateComponentData, ccd);
1335 	}
1336 }
1337 
1338 static void
cal_model_create_component_from_values_thread(EAlertSinkThreadJobData * job_data,gpointer user_data,GCancellable * cancellable,GError ** error)1339 cal_model_create_component_from_values_thread (EAlertSinkThreadJobData *job_data,
1340 					       gpointer user_data,
1341 					       GCancellable *cancellable,
1342 					       GError **error)
1343 {
1344 	CreateComponentData *ccd = user_data;
1345 	EClientCache *client_cache;
1346 	ESourceRegistry *registry;
1347 	ESource *source;
1348 	EClient *client;
1349 	ECalModelComponent *comp_data;
1350 	ICalProperty *prop;
1351 	const gchar *source_uid;
1352 	gchar *display_name;
1353 	GError *local_error = NULL;
1354 
1355 	g_return_if_fail (ccd != NULL);
1356 
1357 	source_uid = e_cal_model_get_default_source_uid (ccd->model);
1358 	g_return_if_fail (source_uid != NULL);
1359 
1360 	client_cache = e_cal_model_get_client_cache (ccd->model);
1361 	registry = e_cal_model_get_registry (ccd->model);
1362 
1363 	source = e_source_registry_ref_source (registry, source_uid);
1364 	if (!source) {
1365 		g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
1366 			_("Source with UID “%s” not found"), source_uid);
1367 		e_alert_sink_thread_job_set_alert_arg_0 (job_data, source_uid);
1368 		return;
1369 	}
1370 
1371 	display_name = e_util_get_source_full_name (registry, source);
1372 	e_alert_sink_thread_job_set_alert_arg_0 (job_data, display_name);
1373 	g_free (display_name);
1374 
1375 	client = e_client_cache_get_client_sync (client_cache, source,
1376 		cal_model_kind_to_extension_name (ccd->model), (guint32) -1, cancellable, &local_error);
1377 	g_clear_object (&source);
1378 
1379 	if (!client) {
1380 		e_util_propagate_open_source_job_error (job_data,
1381 			cal_model_kind_to_extension_name (ccd->model), local_error, error);
1382 		return;
1383 	}
1384 
1385 	comp_data = g_object_new (E_TYPE_CAL_MODEL_COMPONENT, NULL);
1386 	comp_data->client = E_CAL_CLIENT (g_object_ref (client));
1387 	comp_data->icalcomp = e_cal_model_create_component_with_defaults_sync (ccd->model, comp_data->client, FALSE, cancellable, error);
1388 
1389 	if (comp_data->icalcomp) {
1390 		ECalModelClass *model_class;
1391 		gchar *uid = NULL;
1392 		gpointer dtstart;
1393 
1394 		/* set values for our fields */
1395 		set_categories (comp_data, e_cal_model_util_get_value (ccd->values, E_CAL_MODEL_FIELD_CATEGORIES));
1396 		set_classification (comp_data, e_cal_model_util_get_value (ccd->values, E_CAL_MODEL_FIELD_CLASSIFICATION));
1397 		set_description (comp_data, e_cal_model_util_get_value (ccd->values, E_CAL_MODEL_FIELD_DESCRIPTION));
1398 		set_summary (comp_data, e_cal_model_util_get_value (ccd->values, E_CAL_MODEL_FIELD_SUMMARY));
1399 
1400 		dtstart = e_cal_model_util_get_value (ccd->values, E_CAL_MODEL_FIELD_DTSTART);
1401 		if (dtstart) {
1402 			set_dtstart (ccd->model, comp_data, dtstart);
1403 		} else if (ccd->model->priv->get_default_time) {
1404 			time_t tt = ccd->model->priv->get_default_time (ccd->model, ccd->model->priv->get_default_time_user_data);
1405 
1406 			if (tt > 0) {
1407 				/* Store Memo DTSTART as date, not as date-time */
1408 				ICalTime *itt = i_cal_time_new_from_timet_with_zone (tt,
1409 					i_cal_component_isa (comp_data->icalcomp) == I_CAL_VJOURNAL_COMPONENT, e_cal_model_get_timezone (ccd->model));
1410 
1411 				prop = i_cal_component_get_first_property (comp_data->icalcomp, I_CAL_DTSTART_PROPERTY);
1412 
1413 				if (prop) {
1414 					i_cal_property_set_dtstart (prop, itt);
1415 					g_object_unref (prop);
1416 				} else {
1417 					prop = i_cal_property_new_dtstart (itt);
1418 					i_cal_component_take_property (comp_data->icalcomp, prop);
1419 				}
1420 			}
1421 		}
1422 
1423 		/* call the class' method for filling the component */
1424 		model_class = E_CAL_MODEL_GET_CLASS (ccd->model);
1425 		if (model_class->fill_component_from_values != NULL) {
1426 			model_class->fill_component_from_values (ccd->model, comp_data, ccd->values);
1427 		}
1428 
1429 		prop = i_cal_component_get_first_property (comp_data->icalcomp, I_CAL_CLASS_PROPERTY);
1430 		if (!prop || i_cal_property_get_class (prop) == I_CAL_CLASS_NONE) {
1431 			ICalProperty_Class ical_class = I_CAL_CLASS_PUBLIC;
1432 			GSettings *settings;
1433 
1434 			settings = e_util_ref_settings ("org.gnome.evolution.calendar");
1435 			if (g_settings_get_boolean (settings, "classify-private"))
1436 				ical_class = I_CAL_CLASS_PRIVATE;
1437 			g_object_unref (settings);
1438 
1439 			if (!prop) {
1440 				prop = i_cal_property_new_class (ical_class);
1441 				i_cal_component_take_property (comp_data->icalcomp, prop);
1442 			} else {
1443 				i_cal_property_set_class (prop, ical_class);
1444 				g_object_unref (prop);
1445 			}
1446 		} else {
1447 			g_clear_object (&prop);
1448 		}
1449 
1450 		ccd->success = e_cal_client_create_object_sync (comp_data->client, comp_data->icalcomp, E_CAL_OPERATION_FLAG_NONE, &uid, cancellable, error);
1451 
1452 		g_free (uid);
1453 	}
1454 
1455 	g_object_unref (comp_data);
1456 	g_object_unref (client);
1457 }
1458 
1459 static void
cal_model_append_row(ETableModel * etm,ETableModel * source,gint row)1460 cal_model_append_row (ETableModel *etm,
1461                       ETableModel *source,
1462                       gint row)
1463 {
1464 	ECalModelClass *model_class;
1465 	ECalModel *model = (ECalModel *) etm;
1466 	GHashTable *values;
1467 	GCancellable *cancellable;
1468 	CreateComponentData *ccd;
1469 	const gchar *description;
1470 	const gchar *alert_ident;
1471 
1472 	g_return_if_fail (E_IS_CAL_MODEL (model));
1473 	g_return_if_fail (E_IS_TABLE_MODEL (source));
1474 
1475 	switch (e_cal_model_get_component_kind (model)) {
1476 		case I_CAL_VEVENT_COMPONENT:
1477 			description = _("Creating an event");
1478 			alert_ident = "calendar:failed-create-event";
1479 			break;
1480 		case I_CAL_VJOURNAL_COMPONENT:
1481 			description = _("Creating a memo");
1482 			alert_ident = "calendar:failed-create-memo";
1483 			break;
1484 		case I_CAL_VTODO_COMPONENT:
1485 			description = _("Creating a task");
1486 			alert_ident = "calendar:failed-create-task";
1487 			break;
1488 		default:
1489 			g_warn_if_reached ();
1490 			return;
1491 	}
1492 
1493 	values = g_hash_table_new (g_direct_hash, g_direct_equal);
1494 
1495 	/* store values for our fields */
1496 	e_cal_model_util_set_value (values, source, E_CAL_MODEL_FIELD_CATEGORIES, row);
1497 	e_cal_model_util_set_value (values, source, E_CAL_MODEL_FIELD_CLASSIFICATION, row);
1498 	e_cal_model_util_set_value (values, source, E_CAL_MODEL_FIELD_DESCRIPTION, row);
1499 	e_cal_model_util_set_value (values, source, E_CAL_MODEL_FIELD_SUMMARY, row);
1500 	e_cal_model_util_set_value (values, source, E_CAL_MODEL_FIELD_DTSTART, row);
1501 
1502 	/* call the class' method to store other values */
1503 	model_class = E_CAL_MODEL_GET_CLASS (model);
1504 	if (model_class->store_values_from_model != NULL) {
1505 		model_class->store_values_from_model (model, source, row, values);
1506 	}
1507 
1508 	ccd = g_slice_new0 (CreateComponentData);
1509 	ccd->model = g_object_ref (model);
1510 	ccd->table_model = g_object_ref (source);
1511 	ccd->values = values;
1512 	ccd->success = FALSE;
1513 
1514 	cancellable = e_cal_data_model_submit_thread_job (model->priv->data_model, description,
1515 		alert_ident, NULL, cal_model_create_component_from_values_thread,
1516 		ccd, create_component_data_free);
1517 
1518 	g_clear_object (&cancellable);
1519 }
1520 
1521 static gpointer
cal_model_value_at(ETableModel * etm,gint col,gint row)1522 cal_model_value_at (ETableModel *etm,
1523                     gint col,
1524                     gint row)
1525 {
1526 	ECalModelPrivate *priv;
1527 	ECalModelComponent *comp_data;
1528 	ECalModel *model = (ECalModel *) etm;
1529 	ESourceRegistry *registry;
1530 
1531 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
1532 
1533 	priv = model->priv;
1534 
1535 	registry = e_cal_model_get_registry (model);
1536 
1537 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, NULL);
1538 	g_return_val_if_fail (row >= 0 && row < priv->objects->len, NULL);
1539 
1540 	comp_data = g_ptr_array_index (priv->objects, row);
1541 	g_return_val_if_fail (comp_data != NULL, NULL);
1542 	g_return_val_if_fail (comp_data->icalcomp != NULL, NULL);
1543 
1544 	switch (col) {
1545 	case E_CAL_MODEL_FIELD_CATEGORIES :
1546 		return get_categories (comp_data);
1547 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1548 		return get_classification (comp_data);
1549 	case E_CAL_MODEL_FIELD_COLOR :
1550 		return (gpointer) get_color (model, comp_data);
1551 	case E_CAL_MODEL_FIELD_COMPONENT :
1552 		return comp_data->icalcomp;
1553 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1554 		return get_description (comp_data);
1555 	case E_CAL_MODEL_FIELD_DTSTART :
1556 		return (gpointer) get_dtstart (model, comp_data);
1557 	case E_CAL_MODEL_FIELD_CREATED :
1558 		return (gpointer) get_datetime_from_utc (
1559 			model, comp_data, I_CAL_CREATED_PROPERTY,
1560 			i_cal_property_get_created, &comp_data->created);
1561 	case E_CAL_MODEL_FIELD_LASTMODIFIED :
1562 	{
1563 		gpointer result = (gpointer) get_datetime_from_utc (
1564 			model, comp_data, I_CAL_LASTMODIFIED_PROPERTY,
1565 			i_cal_property_get_lastmodified, &comp_data->lastmodified);
1566 		if (!result && !e_cal_util_component_has_property (comp_data->icalcomp, I_CAL_METHOD_PROPERTY))
1567 			return get_datetime_from_utc (model, comp_data, I_CAL_DTSTAMP_PROPERTY, i_cal_property_get_dtstamp, &comp_data->lastmodified);
1568 
1569 		return result;
1570 
1571 	}
1572 	case E_CAL_MODEL_FIELD_HAS_ALARMS :
1573 		return GINT_TO_POINTER (e_cal_util_component_has_alarms (comp_data->icalcomp));
1574 	case E_CAL_MODEL_FIELD_ICON :
1575 	{
1576 		gint retval = comp_data->priv->icon_index;
1577 
1578 		if (retval >= 0)
1579 			return GINT_TO_POINTER (retval);
1580 
1581 		retval = 0;
1582 
1583 		if (i_cal_component_isa (comp_data->icalcomp) == I_CAL_VEVENT_COMPONENT) {
1584 			if (e_cal_util_component_has_attendee (comp_data->icalcomp))
1585 				retval = 1;
1586 			if (e_cal_util_component_has_recurrences (comp_data->icalcomp) ||
1587 			    e_cal_util_component_is_instance (comp_data->icalcomp))
1588 				retval = 2;
1589 		} else if (i_cal_component_isa (comp_data->icalcomp) == I_CAL_VJOURNAL_COMPONENT) {
1590 			if (e_cal_util_component_has_attendee (comp_data->icalcomp))
1591 				retval = 1;
1592 		} else {
1593 			ECalComponent *comp;
1594 
1595 			comp = e_cal_component_new_from_icalcomponent (i_cal_component_clone (comp_data->icalcomp));
1596 			if (comp) {
1597 				if (e_cal_component_has_recurrences (comp))
1598 					retval = 1;
1599 				else if (itip_organizer_is_user (registry, comp, comp_data->client))
1600 					retval = 3;
1601 				else {
1602 					GSList *attendees = NULL, *sl;
1603 
1604 					attendees = e_cal_component_get_attendees (comp);
1605 					for (sl = attendees; sl != NULL; sl = sl->next) {
1606 						ECalComponentAttendee *ca = sl->data;
1607 						const gchar *text;
1608 
1609 						text = itip_strip_mailto (e_cal_component_attendee_get_value (ca));
1610 						if (itip_address_is_user (registry, text)) {
1611 							if (e_cal_component_attendee_get_delegatedto (ca) != NULL)
1612 								retval = 3;
1613 							else
1614 								retval = 2;
1615 							break;
1616 						}
1617 					}
1618 
1619 					g_slist_free_full (attendees, e_cal_component_attendee_free);
1620 				}
1621 
1622 				g_object_unref (comp);
1623 			}
1624 		}
1625 
1626 		comp_data->priv->icon_index = retval;
1627 
1628 		return GINT_TO_POINTER (retval);
1629 	}
1630 	case E_CAL_MODEL_FIELD_SUMMARY :
1631 		return get_summary (comp_data);
1632 	case E_CAL_MODEL_FIELD_UID :
1633 		return get_uid (comp_data);
1634 	case E_CAL_MODEL_FIELD_SOURCE:
1635 		return get_source_description (registry, comp_data);
1636 	case E_CAL_MODEL_FIELD_CANCELLED:
1637 		return GINT_TO_POINTER (i_cal_component_get_status (comp_data->icalcomp) == I_CAL_STATUS_CANCELLED ? 1 : 0);
1638 	}
1639 
1640 	return (gpointer) "";
1641 }
1642 
1643 static void
cal_model_set_value_at(ETableModel * etm,gint col,gint row,gconstpointer value)1644 cal_model_set_value_at (ETableModel *etm,
1645                         gint col,
1646                         gint row,
1647                         gconstpointer value)
1648 {
1649 	ECalModelPrivate *priv;
1650 	ECalModelComponent *comp_data;
1651 	ECalModel *model = (ECalModel *) etm;
1652 	ECalObjModType mod = E_CAL_OBJ_MOD_ALL;
1653 
1654 	g_return_if_fail (E_IS_CAL_MODEL (model));
1655 
1656 	priv = model->priv;
1657 
1658 	g_return_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST);
1659 	g_return_if_fail (row >= 0 && row < priv->objects->len);
1660 
1661 	comp_data = g_ptr_array_index (priv->objects, row);
1662 	g_return_if_fail (comp_data != NULL);
1663 
1664 	if (!e_cal_dialogs_recur_icalcomp (comp_data->client, comp_data->icalcomp, &mod, NULL, FALSE))
1665 		return;
1666 
1667 	switch (col) {
1668 	case E_CAL_MODEL_FIELD_CATEGORIES :
1669 		set_categories (comp_data, value);
1670 		break;
1671 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1672 		set_classification (comp_data, value);
1673 		break;
1674 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1675 		set_description (comp_data, value);
1676 		break;
1677 	case E_CAL_MODEL_FIELD_DTSTART :
1678 		set_dtstart (model, comp_data, value);
1679 		break;
1680 	case E_CAL_MODEL_FIELD_SUMMARY :
1681 		set_summary (comp_data, value);
1682 		break;
1683 	}
1684 
1685 	e_cal_ops_modify_component (model, comp_data->client, comp_data->icalcomp, mod, E_CAL_OPS_SEND_FLAG_DONT_SEND);
1686 }
1687 
1688 static gboolean
cal_model_is_cell_editable(ETableModel * etm,gint col,gint row)1689 cal_model_is_cell_editable (ETableModel *etm,
1690                             gint col,
1691                             gint row)
1692 {
1693 	ECalModelPrivate *priv;
1694 	ECalModel *model = (ECalModel *) etm;
1695 
1696 	g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE);
1697 
1698 	priv = model->priv;
1699 
1700 	g_return_val_if_fail (col >= 0 && col <= E_CAL_MODEL_FIELD_LAST, FALSE);
1701 	g_return_val_if_fail (row >= -1 || (row >= 0 && row < priv->objects->len), FALSE);
1702 
1703 	if (!e_cal_model_test_row_editable (E_CAL_MODEL (etm), row))
1704 		return FALSE;
1705 
1706 	switch (col) {
1707 	case E_CAL_MODEL_FIELD_CATEGORIES :
1708 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1709 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1710 	case E_CAL_MODEL_FIELD_DTSTART :
1711 	case E_CAL_MODEL_FIELD_SUMMARY :
1712 		return TRUE;
1713 	}
1714 
1715 	return FALSE;
1716 }
1717 
1718 static gpointer
cal_model_duplicate_value(ETableModel * etm,gint col,gconstpointer value)1719 cal_model_duplicate_value (ETableModel *etm,
1720                            gint col,
1721                            gconstpointer value)
1722 {
1723 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, NULL);
1724 
1725 	switch (col) {
1726 	case E_CAL_MODEL_FIELD_CATEGORIES :
1727 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1728 	case E_CAL_MODEL_FIELD_SUMMARY :
1729 	case E_CAL_MODEL_FIELD_SOURCE:
1730 		return g_strdup (value);
1731 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1732 	case E_CAL_MODEL_FIELD_HAS_ALARMS :
1733 	case E_CAL_MODEL_FIELD_ICON :
1734 	case E_CAL_MODEL_FIELD_COLOR :
1735 	case E_CAL_MODEL_FIELD_CANCELLED:
1736 		return (gpointer) value;
1737 	case E_CAL_MODEL_FIELD_COMPONENT :
1738 		return i_cal_component_clone ((ICalComponent *) value);
1739 	case E_CAL_MODEL_FIELD_DTSTART :
1740 	case E_CAL_MODEL_FIELD_CREATED :
1741 	case E_CAL_MODEL_FIELD_LASTMODIFIED :
1742 		return e_cell_date_edit_value_copy (value);
1743 	}
1744 
1745 	return NULL;
1746 }
1747 
1748 static void
cal_model_free_value(ETableModel * etm,gint col,gpointer value)1749 cal_model_free_value (ETableModel *etm,
1750                       gint col,
1751                       gpointer value)
1752 {
1753 	g_return_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST);
1754 
1755 	switch (col) {
1756 	case E_CAL_MODEL_FIELD_CATEGORIES :
1757 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1758 	case E_CAL_MODEL_FIELD_SUMMARY :
1759 	case E_CAL_MODEL_FIELD_SOURCE:
1760 		g_free (value);
1761 		break;
1762 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1763 	case E_CAL_MODEL_FIELD_HAS_ALARMS :
1764 	case E_CAL_MODEL_FIELD_ICON :
1765 	case E_CAL_MODEL_FIELD_COLOR :
1766 	case E_CAL_MODEL_FIELD_CANCELLED:
1767 		break;
1768 	case E_CAL_MODEL_FIELD_DTSTART:
1769 	case E_CAL_MODEL_FIELD_CREATED :
1770 	case E_CAL_MODEL_FIELD_LASTMODIFIED :
1771 		if (value)
1772 			e_cell_date_edit_value_free (value);
1773 		break;
1774 	case E_CAL_MODEL_FIELD_COMPONENT :
1775 		if (value)
1776 			g_object_unref ((ICalComponent *) value);
1777 		break;
1778 	}
1779 }
1780 
1781 static gpointer
cal_model_initialize_value(ETableModel * etm,gint col)1782 cal_model_initialize_value (ETableModel *etm,
1783                             gint col)
1784 {
1785 	ECalModelPrivate *priv;
1786 	ECalModel *model = (ECalModel *) etm;
1787 
1788 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
1789 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, NULL);
1790 
1791 	priv = model->priv;
1792 
1793 	switch (col) {
1794 	case E_CAL_MODEL_FIELD_CATEGORIES :
1795 		return g_strdup (priv->default_category ? priv->default_category:"");
1796 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1797 	case E_CAL_MODEL_FIELD_SUMMARY :
1798 	case E_CAL_MODEL_FIELD_SOURCE:
1799 		return g_strdup ("");
1800 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1801 	case E_CAL_MODEL_FIELD_DTSTART :
1802 	case E_CAL_MODEL_FIELD_CREATED :
1803 	case E_CAL_MODEL_FIELD_LASTMODIFIED :
1804 	case E_CAL_MODEL_FIELD_HAS_ALARMS :
1805 	case E_CAL_MODEL_FIELD_ICON :
1806 	case E_CAL_MODEL_FIELD_COLOR :
1807 	case E_CAL_MODEL_FIELD_COMPONENT :
1808 	case E_CAL_MODEL_FIELD_CANCELLED:
1809 		return NULL;
1810 	}
1811 
1812 	return NULL;
1813 }
1814 
1815 static gboolean
cal_model_value_is_empty(ETableModel * etm,gint col,gconstpointer value)1816 cal_model_value_is_empty (ETableModel *etm,
1817                           gint col,
1818                           gconstpointer value)
1819 {
1820 	ECalModelPrivate *priv;
1821 	ECalModel *model = (ECalModel *) etm;
1822 
1823 	g_return_val_if_fail (E_IS_CAL_MODEL (model), TRUE);
1824 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, TRUE);
1825 
1826 	priv = model->priv;
1827 
1828 	switch (col) {
1829 	case E_CAL_MODEL_FIELD_CATEGORIES :
1830 		/* This could be a hack or not.  If the categories field only
1831 		 * contains the default category, then it possibly means that
1832 		 * the user has not entered anything at all in the click-to-add;
1833 		 * the category is in the value because we put it there in
1834 		 * ecm_initialize_value().
1835 		 */
1836 		if (priv->default_category && value && strcmp (priv->default_category, value) == 0)
1837 			return TRUE;
1838 		else
1839 			return string_is_empty (value);
1840 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1841 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1842 	case E_CAL_MODEL_FIELD_SUMMARY :
1843 	case E_CAL_MODEL_FIELD_SOURCE:
1844 		return string_is_empty (value);
1845 	case E_CAL_MODEL_FIELD_DTSTART :
1846 	case E_CAL_MODEL_FIELD_CREATED :
1847 	case E_CAL_MODEL_FIELD_LASTMODIFIED :
1848 		return value ? FALSE : TRUE;
1849 	case E_CAL_MODEL_FIELD_HAS_ALARMS :
1850 	case E_CAL_MODEL_FIELD_ICON :
1851 	case E_CAL_MODEL_FIELD_COLOR :
1852 	case E_CAL_MODEL_FIELD_COMPONENT :
1853 	case E_CAL_MODEL_FIELD_CANCELLED:
1854 		return TRUE;
1855 	}
1856 
1857 	return TRUE;
1858 }
1859 
1860 static gchar *
cal_model_value_to_string(ETableModel * etm,gint col,gconstpointer value)1861 cal_model_value_to_string (ETableModel *etm,
1862                            gint col,
1863                            gconstpointer value)
1864 {
1865 	g_return_val_if_fail (col >= 0 && col < E_CAL_MODEL_FIELD_LAST, g_strdup (""));
1866 
1867 	switch (col) {
1868 	case E_CAL_MODEL_FIELD_CATEGORIES :
1869 	case E_CAL_MODEL_FIELD_CLASSIFICATION :
1870 	case E_CAL_MODEL_FIELD_DESCRIPTION :
1871 	case E_CAL_MODEL_FIELD_SUMMARY :
1872 	case E_CAL_MODEL_FIELD_SOURCE:
1873 		return g_strdup (value);
1874 	case E_CAL_MODEL_FIELD_DTSTART :
1875 	case E_CAL_MODEL_FIELD_CREATED :
1876 	case E_CAL_MODEL_FIELD_LASTMODIFIED :
1877 		return e_cal_model_date_value_to_string (E_CAL_MODEL (etm), value);
1878 	case E_CAL_MODEL_FIELD_ICON :
1879 		if (GPOINTER_TO_INT (value) == 0)
1880 			return g_strdup (_("Normal"));
1881 		else if (GPOINTER_TO_INT (value) == 1)
1882 			return g_strdup (_("Recurring"));
1883 		else
1884 			return g_strdup (_("Assigned"));
1885 	case E_CAL_MODEL_FIELD_HAS_ALARMS :
1886 	case E_CAL_MODEL_FIELD_CANCELLED:
1887 		return g_strdup (value ? _("Yes") : _("No"));
1888 	case E_CAL_MODEL_FIELD_COLOR :
1889 	case E_CAL_MODEL_FIELD_COMPONENT :
1890 		return g_strdup ("");
1891 	}
1892 
1893 	return g_strdup ("");
1894 }
1895 
1896 static gint
e_cal_model_get_component_index(ECalModel * model,ECalClient * client,const ECalComponentId * id)1897 e_cal_model_get_component_index (ECalModel *model,
1898 				 ECalClient *client,
1899 				 const ECalComponentId *id)
1900 {
1901 	gint ii;
1902 
1903 	for (ii = 0; ii < model->priv->objects->len; ii++) {
1904 		ECalModelComponent *comp_data = g_ptr_array_index (model->priv->objects, ii);
1905 
1906 		if (comp_data) {
1907 			const gchar *uid;
1908 			gboolean has_rid = e_cal_component_id_get_rid (id) != NULL;
1909 
1910 			uid = i_cal_component_get_uid (comp_data->icalcomp);
1911 
1912 			if (uid && *uid) {
1913 				if ((!client || comp_data->client == client) && strcmp (uid, e_cal_component_id_get_uid (id)) == 0) {
1914 					if (has_rid) {
1915 						gchar *rid;
1916 
1917 						rid = e_cal_util_component_get_recurid_as_string (comp_data->icalcomp);
1918 
1919 						if (!(rid && *rid && strcmp (rid, e_cal_component_id_get_rid (id)) == 0)) {
1920 							g_free (rid);
1921 							continue;
1922 						}
1923 
1924 						g_free (rid);
1925 					}
1926 
1927 					return ii;
1928 				}
1929 			}
1930 		}
1931 	}
1932 
1933 	return -1;
1934 }
1935 
1936 static void
cal_model_data_subscriber_component_added_or_modified(ECalDataModelSubscriber * subscriber,ECalClient * client,ECalComponent * comp,gboolean is_added)1937 cal_model_data_subscriber_component_added_or_modified (ECalDataModelSubscriber *subscriber,
1938 						       ECalClient *client,
1939 						       ECalComponent *comp,
1940 						       gboolean is_added)
1941 {
1942 	ECalModel *model;
1943 	ECalModelComponent *comp_data;
1944 	ETableModel *table_model;
1945 	ECalComponentId *id;
1946 	ICalComponent *icomp;
1947 	gint index;
1948 
1949 	model = E_CAL_MODEL (subscriber);
1950 	table_model = E_TABLE_MODEL (model);
1951 
1952 	id = e_cal_component_get_id (comp);
1953 
1954 	/* The component should not exist, when it's claimed being added, thus, when it's the main
1955 	   component, remove any existing instances and add it from scratch. */
1956 	if (is_added && !e_cal_component_id_get_rid (id)) {
1957 		GSList *removed_comps = NULL;
1958 
1959 		for (index = 0; index < model->priv->objects->len; index++) {
1960 			comp_data = g_ptr_array_index (model->priv->objects, index);
1961 
1962 			if (comp_data && comp_data->client == client) {
1963 				const gchar *uid;
1964 
1965 				uid = i_cal_component_get_uid (comp_data->icalcomp);
1966 
1967 				if (uid && *uid && g_strcmp0 (uid, e_cal_component_id_get_uid (id)) == 0) {
1968 					e_table_model_pre_change (table_model);
1969 
1970 					g_ptr_array_remove_index (model->priv->objects, index);
1971 					removed_comps = g_slist_prepend (removed_comps, comp_data);
1972 					e_table_model_row_deleted (table_model, index);
1973 
1974 					index--;
1975 				}
1976 			}
1977 		}
1978 
1979 		g_signal_emit (model, signals[COMPS_DELETED], 0, removed_comps);
1980 
1981 		g_slist_free_full (removed_comps, g_object_unref);
1982 
1983 		index = -1;
1984 	} else {
1985 		index = e_cal_model_get_component_index (model, client, id);
1986 	}
1987 
1988 	e_cal_component_id_free (id);
1989 
1990 	if (index < 0 && !is_added)
1991 		return;
1992 
1993 	icomp = i_cal_component_clone (e_cal_component_get_icalcomponent (comp));
1994 
1995 	if (index < 0) {
1996 		e_table_model_pre_change (table_model);
1997 
1998 		comp_data = g_object_new (E_TYPE_CAL_MODEL_COMPONENT, NULL);
1999 		comp_data->is_new_component = FALSE;
2000 		comp_data->client = g_object_ref (client);
2001 		comp_data->icalcomp = icomp;
2002 		e_cal_model_set_instance_times (comp_data, model->priv->zone);
2003 		g_ptr_array_add (model->priv->objects, comp_data);
2004 
2005 		e_table_model_row_inserted (table_model, model->priv->objects->len - 1);
2006 	} else {
2007 		e_table_model_pre_change (table_model);
2008 
2009 		comp_data = g_ptr_array_index (model->priv->objects, index);
2010 		e_cal_model_component_set_icalcomponent (comp_data, model, icomp);
2011 
2012 		e_table_model_row_changed (table_model, index);
2013 	}
2014 }
2015 
2016 static void
e_cal_model_data_subscriber_component_added(ECalDataModelSubscriber * subscriber,ECalClient * client,ECalComponent * comp)2017 e_cal_model_data_subscriber_component_added (ECalDataModelSubscriber *subscriber,
2018 					     ECalClient *client,
2019 					     ECalComponent *comp)
2020 {
2021 	cal_model_data_subscriber_component_added_or_modified (subscriber, client, comp, TRUE);
2022 }
2023 
2024 static void
e_cal_model_data_subscriber_component_modified(ECalDataModelSubscriber * subscriber,ECalClient * client,ECalComponent * comp)2025 e_cal_model_data_subscriber_component_modified (ECalDataModelSubscriber *subscriber,
2026 						ECalClient *client,
2027 						ECalComponent *comp)
2028 {
2029 	cal_model_data_subscriber_component_added_or_modified (subscriber, client, comp, FALSE);
2030 }
2031 
2032 static void
e_cal_model_data_subscriber_component_removed(ECalDataModelSubscriber * subscriber,ECalClient * client,const gchar * uid,const gchar * rid)2033 e_cal_model_data_subscriber_component_removed (ECalDataModelSubscriber *subscriber,
2034 					       ECalClient *client,
2035 					       const gchar *uid,
2036 					       const gchar *rid)
2037 {
2038 	ECalModel *model;
2039 	ECalModelComponent *comp_data;
2040 	ETableModel *table_model;
2041 	ECalComponentId *id;
2042 	GSList *link;
2043 	gint index;
2044 
2045 	model = E_CAL_MODEL (subscriber);
2046 
2047 	id = e_cal_component_id_new (uid, rid);
2048 
2049 	index = e_cal_model_get_component_index (model, client, id);
2050 
2051 	e_cal_component_id_free (id);
2052 
2053 	if (index < 0)
2054 		return;
2055 
2056 	table_model = E_TABLE_MODEL (model);
2057 	e_table_model_pre_change (table_model);
2058 
2059 	comp_data = g_ptr_array_remove_index (model->priv->objects, index);
2060 	if (!comp_data) {
2061 		e_table_model_no_change (table_model);
2062 		return;
2063 	}
2064 
2065 	link = g_slist_append (NULL, comp_data);
2066 	g_signal_emit (model, signals[COMPS_DELETED], 0, link);
2067 
2068 	g_slist_free (link);
2069 	g_object_unref (comp_data);
2070 
2071 	e_table_model_row_deleted (table_model, index);
2072 }
2073 
2074 static void
e_cal_model_data_subscriber_freeze(ECalDataModelSubscriber * subscriber)2075 e_cal_model_data_subscriber_freeze (ECalDataModelSubscriber *subscriber)
2076 {
2077 	/* No freeze/thaw, the ETableModel doesn't notify about changes when frozen */
2078 
2079 	/* ETableModel *table_model = E_TABLE_MODEL (subscriber);
2080 	e_table_model_freeze (table_model); */
2081 }
2082 
2083 static void
e_cal_model_data_subscriber_thaw(ECalDataModelSubscriber * subscriber)2084 e_cal_model_data_subscriber_thaw (ECalDataModelSubscriber *subscriber)
2085 {
2086 	/* No freeze/thaw, the ETableModel doesn't notify about changes when frozen */
2087 
2088 	/* ETableModel *table_model = E_TABLE_MODEL (subscriber);
2089 	e_table_model_thaw (table_model); */
2090 }
2091 
2092 static void
e_cal_model_class_init(ECalModelClass * class)2093 e_cal_model_class_init (ECalModelClass *class)
2094 {
2095 	GObjectClass *object_class;
2096 
2097 	g_type_class_add_private (class, sizeof (ECalModelPrivate));
2098 
2099 	object_class = G_OBJECT_CLASS (class);
2100 	object_class->set_property = cal_model_set_property;
2101 	object_class->get_property = cal_model_get_property;
2102 	object_class->constructed = cal_model_constructed;
2103 	object_class->dispose = cal_model_dispose;
2104 	object_class->finalize = cal_model_finalize;
2105 
2106 	class->get_color_for_component = cal_model_get_color_for_component;
2107 
2108 	g_object_class_install_property (
2109 		object_class,
2110 		PROP_DATA_MODEL,
2111 		g_param_spec_object (
2112 			"data-model",
2113 			"Calendar Data Model",
2114 			NULL,
2115 			E_TYPE_CAL_DATA_MODEL,
2116 			G_PARAM_READWRITE |
2117 			G_PARAM_CONSTRUCT_ONLY));
2118 
2119 	g_object_class_install_property (
2120 		object_class,
2121 		PROP_CLIENT_CACHE,
2122 		g_param_spec_object (
2123 			"client-cache",
2124 			"Client Cache",
2125 			NULL,
2126 			E_TYPE_CLIENT_CACHE,
2127 			G_PARAM_READABLE));
2128 
2129 	g_object_class_install_property (
2130 		object_class,
2131 		PROP_COMPRESS_WEEKEND,
2132 		g_param_spec_boolean (
2133 			"compress-weekend",
2134 			"Compress Weekend",
2135 			NULL,
2136 			FALSE,
2137 			G_PARAM_READWRITE));
2138 
2139 	g_object_class_install_property (
2140 		object_class,
2141 		PROP_CONFIRM_DELETE,
2142 		g_param_spec_boolean (
2143 			"confirm-delete",
2144 			"Confirm Delete",
2145 			NULL,
2146 			TRUE,
2147 			G_PARAM_READWRITE));
2148 
2149 	g_object_class_install_property (
2150 		object_class,
2151 		PROP_DEFAULT_REMINDER_INTERVAL,
2152 		g_param_spec_int (
2153 			"default-reminder-interval",
2154 			"Default Reminder Interval",
2155 			NULL,
2156 			G_MININT,
2157 			G_MAXINT,
2158 			0,
2159 			G_PARAM_READWRITE));
2160 
2161 	g_object_class_install_property (
2162 		object_class,
2163 		PROP_DEFAULT_REMINDER_UNITS,
2164 		g_param_spec_enum (
2165 			"default-reminder-units",
2166 			"Default Reminder Units",
2167 			NULL,
2168 			E_TYPE_DURATION_TYPE,
2169 			E_DURATION_MINUTES,
2170 			G_PARAM_READWRITE));
2171 
2172 	g_object_class_install_property (
2173 		object_class,
2174 		PROP_DEFAULT_SOURCE_UID,
2175 		g_param_spec_string (
2176 			"default-source-uid",
2177 			"Default source UID of an ECalClient",
2178 			NULL,
2179 			NULL,
2180 			G_PARAM_READWRITE));
2181 
2182 	g_object_class_install_property (
2183 		object_class,
2184 		PROP_REGISTRY,
2185 		g_param_spec_object (
2186 			"registry",
2187 			"Registry",
2188 			"Data source registry",
2189 			E_TYPE_SOURCE_REGISTRY,
2190 			G_PARAM_READWRITE |
2191 			G_PARAM_CONSTRUCT_ONLY));
2192 
2193 	g_object_class_install_property (
2194 		object_class,
2195 		PROP_SHELL,
2196 		g_param_spec_object (
2197 			"shell",
2198 			"Shell",
2199 			"EShell",
2200 			E_TYPE_SHELL,
2201 			G_PARAM_READWRITE |
2202 			G_PARAM_CONSTRUCT_ONLY));
2203 
2204 	g_object_class_install_property (
2205 		object_class,
2206 		PROP_TIMEZONE,
2207 		g_param_spec_object (
2208 			"timezone",
2209 			"Time Zone",
2210 			NULL,
2211 			I_CAL_TYPE_TIMEZONE,
2212 			G_PARAM_READWRITE));
2213 
2214 	g_object_class_install_property (
2215 		object_class,
2216 		PROP_USE_24_HOUR_FORMAT,
2217 		g_param_spec_boolean (
2218 			"use-24-hour-format",
2219 			"Use 24-Hour Format",
2220 			NULL,
2221 			TRUE,
2222 			G_PARAM_READWRITE));
2223 
2224 	g_object_class_install_property (
2225 		object_class,
2226 		PROP_USE_DEFAULT_REMINDER,
2227 		g_param_spec_boolean (
2228 			"use-default-reminder",
2229 			"Use Default Reminder",
2230 			NULL,
2231 			FALSE,
2232 			G_PARAM_READWRITE));
2233 
2234 	g_object_class_install_property (
2235 		object_class,
2236 		PROP_WEEK_START_DAY,
2237 		g_param_spec_enum (
2238 			"week-start-day",
2239 			"Week Start Day",
2240 			NULL,
2241 			E_TYPE_DATE_WEEKDAY,
2242 			G_DATE_MONDAY,
2243 			G_PARAM_READWRITE |
2244 			G_PARAM_CONSTRUCT));
2245 
2246 	g_object_class_install_property (
2247 		object_class,
2248 		PROP_WORK_DAY_MONDAY,
2249 		g_param_spec_boolean (
2250 			"work-day-monday",
2251 			"Work Day: Monday",
2252 			"Whether Monday is a work day",
2253 			TRUE,
2254 			G_PARAM_READWRITE |
2255 			G_PARAM_CONSTRUCT |
2256 			G_PARAM_STATIC_STRINGS));
2257 
2258 	g_object_class_install_property (
2259 		object_class,
2260 		PROP_WORK_DAY_TUESDAY,
2261 		g_param_spec_boolean (
2262 			"work-day-tuesday",
2263 			"Work Day: Tuesday",
2264 			"Whether Tuesday is a work day",
2265 			TRUE,
2266 			G_PARAM_READWRITE |
2267 			G_PARAM_CONSTRUCT |
2268 			G_PARAM_STATIC_STRINGS));
2269 
2270 	g_object_class_install_property (
2271 		object_class,
2272 		PROP_WORK_DAY_WEDNESDAY,
2273 		g_param_spec_boolean (
2274 			"work-day-wednesday",
2275 			"Work Day: Wednesday",
2276 			"Whether Wednesday is a work day",
2277 			TRUE,
2278 			G_PARAM_READWRITE |
2279 			G_PARAM_CONSTRUCT |
2280 			G_PARAM_STATIC_STRINGS));
2281 
2282 	g_object_class_install_property (
2283 		object_class,
2284 		PROP_WORK_DAY_THURSDAY,
2285 		g_param_spec_boolean (
2286 			"work-day-thursday",
2287 			"Work Day: Thursday",
2288 			"Whether Thursday is a work day",
2289 			TRUE,
2290 			G_PARAM_READWRITE |
2291 			G_PARAM_CONSTRUCT |
2292 			G_PARAM_STATIC_STRINGS));
2293 
2294 	g_object_class_install_property (
2295 		object_class,
2296 		PROP_WORK_DAY_FRIDAY,
2297 		g_param_spec_boolean (
2298 			"work-day-friday",
2299 			"Work Day: Friday",
2300 			"Whether Friday is a work day",
2301 			TRUE,
2302 			G_PARAM_READWRITE |
2303 			G_PARAM_CONSTRUCT |
2304 			G_PARAM_STATIC_STRINGS));
2305 
2306 	g_object_class_install_property (
2307 		object_class,
2308 		PROP_WORK_DAY_SATURDAY,
2309 		g_param_spec_boolean (
2310 			"work-day-saturday",
2311 			"Work Day: Saturday",
2312 			"Whether Saturday is a work day",
2313 			TRUE,
2314 			G_PARAM_READWRITE |
2315 			G_PARAM_CONSTRUCT |
2316 			G_PARAM_STATIC_STRINGS));
2317 
2318 	g_object_class_install_property (
2319 		object_class,
2320 		PROP_WORK_DAY_SUNDAY,
2321 		g_param_spec_boolean (
2322 			"work-day-sunday",
2323 			"Work Day: Sunday",
2324 			"Whether Sunday is a work day",
2325 			TRUE,
2326 			G_PARAM_READWRITE |
2327 			G_PARAM_CONSTRUCT |
2328 			G_PARAM_STATIC_STRINGS));
2329 
2330 	g_object_class_install_property (
2331 		object_class,
2332 		PROP_WORK_DAY_END_HOUR,
2333 		g_param_spec_int (
2334 			"work-day-end-hour",
2335 			"Work Day End Hour",
2336 			NULL,
2337 			0,
2338 			23,
2339 			0,
2340 			G_PARAM_READWRITE));
2341 
2342 	g_object_class_install_property (
2343 		object_class,
2344 		PROP_WORK_DAY_END_MINUTE,
2345 		g_param_spec_int (
2346 			"work-day-end-minute",
2347 			"Work Day End Minute",
2348 			NULL,
2349 			0,
2350 			59,
2351 			0,
2352 			G_PARAM_READWRITE));
2353 
2354 	g_object_class_install_property (
2355 		object_class,
2356 		PROP_WORK_DAY_START_HOUR,
2357 		g_param_spec_int (
2358 			"work-day-start-hour",
2359 			"Work Day Start Hour",
2360 			NULL,
2361 			0,
2362 			23,
2363 			0,
2364 			G_PARAM_READWRITE));
2365 
2366 	g_object_class_install_property (
2367 		object_class,
2368 		PROP_WORK_DAY_START_MINUTE,
2369 		g_param_spec_int (
2370 			"work-day-start-minute",
2371 			"Work Day Start Minute",
2372 			NULL,
2373 			0,
2374 			59,
2375 			0,
2376 			G_PARAM_READWRITE));
2377 
2378 	g_object_class_install_property (
2379 		object_class,
2380 		PROP_WORK_DAY_START_MON,
2381 		g_param_spec_int (
2382 			"work-day-start-mon",
2383 			"Work Day Start for Monday",
2384 			NULL,
2385 			-1,
2386 			2359,
2387 			-1,
2388 			G_PARAM_READWRITE));
2389 
2390 	g_object_class_install_property (
2391 		object_class,
2392 		PROP_WORK_DAY_END_MON,
2393 		g_param_spec_int (
2394 			"work-day-end-mon",
2395 			"Work Day End for Monday",
2396 			NULL,
2397 			-1,
2398 			2359,
2399 			-1,
2400 			G_PARAM_READWRITE));
2401 
2402 	g_object_class_install_property (
2403 		object_class,
2404 		PROP_WORK_DAY_START_TUE,
2405 		g_param_spec_int (
2406 			"work-day-start-tue",
2407 			"Work Day Start for Tuesday",
2408 			NULL,
2409 			-1,
2410 			2359,
2411 			-1,
2412 			G_PARAM_READWRITE));
2413 
2414 	g_object_class_install_property (
2415 		object_class,
2416 		PROP_WORK_DAY_END_TUE,
2417 		g_param_spec_int (
2418 			"work-day-end-tue",
2419 			"Work Day End for Tuesday",
2420 			NULL,
2421 			-1,
2422 			2359,
2423 			-1,
2424 			G_PARAM_READWRITE));
2425 
2426 	g_object_class_install_property (
2427 		object_class,
2428 		PROP_WORK_DAY_START_WED,
2429 		g_param_spec_int (
2430 			"work-day-start-wed",
2431 			"Work Day Start for Wednesday",
2432 			NULL,
2433 			-1,
2434 			2359,
2435 			-1,
2436 			G_PARAM_READWRITE));
2437 
2438 	g_object_class_install_property (
2439 		object_class,
2440 		PROP_WORK_DAY_END_WED,
2441 		g_param_spec_int (
2442 			"work-day-end-wed",
2443 			"Work Day End for Wednesday",
2444 			NULL,
2445 			-1,
2446 			2359,
2447 			-1,
2448 			G_PARAM_READWRITE));
2449 
2450 	g_object_class_install_property (
2451 		object_class,
2452 		PROP_WORK_DAY_START_THU,
2453 		g_param_spec_int (
2454 			"work-day-start-thu",
2455 			"Work Day Start for Thursday",
2456 			NULL,
2457 			-1,
2458 			2359,
2459 			-1,
2460 			G_PARAM_READWRITE));
2461 
2462 	g_object_class_install_property (
2463 		object_class,
2464 		PROP_WORK_DAY_END_THU,
2465 		g_param_spec_int (
2466 			"work-day-end-thu",
2467 			"Work Day End for Thursday",
2468 			NULL,
2469 			-1,
2470 			2359,
2471 			-1,
2472 			G_PARAM_READWRITE));
2473 
2474 	g_object_class_install_property (
2475 		object_class,
2476 		PROP_WORK_DAY_START_FRI,
2477 		g_param_spec_int (
2478 			"work-day-start-fri",
2479 			"Work Day Start for Friday",
2480 			NULL,
2481 			-1,
2482 			2359,
2483 			-1,
2484 			G_PARAM_READWRITE));
2485 
2486 	g_object_class_install_property (
2487 		object_class,
2488 		PROP_WORK_DAY_END_FRI,
2489 		g_param_spec_int (
2490 			"work-day-end-fri",
2491 			"Work Day End for Friday",
2492 			NULL,
2493 			-1,
2494 			2359,
2495 			-1,
2496 			G_PARAM_READWRITE));
2497 
2498 	g_object_class_install_property (
2499 		object_class,
2500 		PROP_WORK_DAY_START_SAT,
2501 		g_param_spec_int (
2502 			"work-day-start-sat",
2503 			"Work Day Start for Saturday",
2504 			NULL,
2505 			-1,
2506 			2359,
2507 			-1,
2508 			G_PARAM_READWRITE));
2509 
2510 	g_object_class_install_property (
2511 		object_class,
2512 		PROP_WORK_DAY_END_SAT,
2513 		g_param_spec_int (
2514 			"work-day-end-sat",
2515 			"Work Day End for Saturday",
2516 			NULL,
2517 			-1,
2518 			2359,
2519 			-1,
2520 			G_PARAM_READWRITE));
2521 
2522 	g_object_class_install_property (
2523 		object_class,
2524 		PROP_WORK_DAY_START_SUN,
2525 		g_param_spec_int (
2526 			"work-day-start-sun",
2527 			"Work Day Start for Sunday",
2528 			NULL,
2529 			-1,
2530 			2359,
2531 			-1,
2532 			G_PARAM_READWRITE));
2533 
2534 	g_object_class_install_property (
2535 		object_class,
2536 		PROP_WORK_DAY_END_SUN,
2537 		g_param_spec_int (
2538 			"work-day-end-sun",
2539 			"Work Day End for Sunday",
2540 			NULL,
2541 			-1,
2542 			2359,
2543 			-1,
2544 			G_PARAM_READWRITE));
2545 
2546 	signals[TIME_RANGE_CHANGED] = g_signal_new (
2547 		"time_range_changed",
2548 		G_TYPE_FROM_CLASS (class),
2549 		G_SIGNAL_RUN_LAST,
2550 		G_STRUCT_OFFSET (ECalModelClass, time_range_changed),
2551 		NULL, NULL,
2552 		e_marshal_VOID__INT64_INT64,
2553 		G_TYPE_NONE, 2,
2554 		G_TYPE_INT64,
2555 		G_TYPE_INT64);
2556 
2557 	signals[ROW_APPENDED] = g_signal_new (
2558 		"row_appended",
2559 		G_TYPE_FROM_CLASS (class),
2560 		G_SIGNAL_RUN_LAST,
2561 		G_STRUCT_OFFSET (ECalModelClass, row_appended),
2562 		NULL, NULL,
2563 		g_cclosure_marshal_VOID__VOID,
2564 		G_TYPE_NONE, 0);
2565 
2566 	signals[COMPS_DELETED] = g_signal_new (
2567 		"comps_deleted",
2568 		G_TYPE_FROM_CLASS (class),
2569 		G_SIGNAL_RUN_LAST,
2570 		G_STRUCT_OFFSET (ECalModelClass, comps_deleted),
2571 		NULL, NULL,
2572 		g_cclosure_marshal_VOID__POINTER,
2573 		G_TYPE_NONE, 1,
2574 		G_TYPE_POINTER);
2575 
2576 	signals[TIMEZONE_CHANGED] = g_signal_new (
2577 		"timezone-changed",
2578 		G_TYPE_FROM_CLASS (class),
2579 		G_SIGNAL_RUN_LAST,
2580 		G_STRUCT_OFFSET (ECalModelClass, timezone_changed),
2581 		NULL, NULL,
2582 		e_marshal_VOID__OBJECT_OBJECT,
2583 		G_TYPE_NONE, 2,
2584 		I_CAL_TYPE_TIMEZONE,
2585 		I_CAL_TYPE_TIMEZONE);
2586 
2587 	signals[OBJECT_CREATED] = g_signal_new (
2588 		"object-created",
2589 		G_TYPE_FROM_CLASS (class),
2590 		G_SIGNAL_RUN_LAST,
2591 		G_STRUCT_OFFSET (ECalModelClass, object_created),
2592 		NULL, NULL,
2593 		g_cclosure_marshal_VOID__OBJECT,
2594 		G_TYPE_NONE, 1, E_TYPE_CAL_CLIENT);
2595 }
2596 
2597 static void
e_cal_model_table_model_init(ETableModelInterface * iface)2598 e_cal_model_table_model_init (ETableModelInterface *iface)
2599 {
2600 	iface->column_count = cal_model_column_count;
2601 	iface->row_count = cal_model_row_count;
2602 	iface->append_row = cal_model_append_row;
2603 
2604 	iface->value_at = cal_model_value_at;
2605 	iface->set_value_at = cal_model_set_value_at;
2606 	iface->is_cell_editable = cal_model_is_cell_editable;
2607 
2608 	iface->duplicate_value = cal_model_duplicate_value;
2609 	iface->free_value = cal_model_free_value;
2610 	iface->initialize_value = cal_model_initialize_value;
2611 	iface->value_is_empty = cal_model_value_is_empty;
2612 	iface->value_to_string = cal_model_value_to_string;
2613 }
2614 
2615 static void
e_cal_model_cal_data_model_subscriber_init(ECalDataModelSubscriberInterface * iface)2616 e_cal_model_cal_data_model_subscriber_init (ECalDataModelSubscriberInterface *iface)
2617 {
2618 	iface->component_added = e_cal_model_data_subscriber_component_added;
2619 	iface->component_modified = e_cal_model_data_subscriber_component_modified;
2620 	iface->component_removed = e_cal_model_data_subscriber_component_removed;
2621 	iface->freeze = e_cal_model_data_subscriber_freeze;
2622 	iface->thaw = e_cal_model_data_subscriber_thaw;
2623 }
2624 
2625 static void
e_cal_model_init(ECalModel * model)2626 e_cal_model_init (ECalModel *model)
2627 {
2628 	model->priv = E_CAL_MODEL_GET_PRIVATE (model);
2629 
2630 	/* match none by default */
2631 	model->priv->start = (time_t) -1;
2632 	model->priv->end = (time_t) -1;
2633 
2634 	model->priv->objects = g_ptr_array_new ();
2635 	model->priv->kind = I_CAL_NO_COMPONENT;
2636 
2637 	model->priv->use_24_hour_format = TRUE;
2638 }
2639 
2640 /* updates time in a component, and keeps the timezone used in it, if exists */
2641 void
e_cal_model_update_comp_time(ECalModel * model,ECalModelComponent * comp_data,gconstpointer time_value,ICalPropertyKind kind,void (* set_func)(ICalProperty * prop,ICalTime * v),ICalProperty * (* new_func)(ICalTime * v))2642 e_cal_model_update_comp_time (ECalModel *model,
2643                               ECalModelComponent *comp_data,
2644                               gconstpointer time_value,
2645                               ICalPropertyKind kind,
2646                               void (*set_func) (ICalProperty *prop,
2647                                                 ICalTime *v),
2648                               ICalProperty * (*new_func) (ICalTime *v))
2649 {
2650 	ECellDateEditValue *dv = (ECellDateEditValue *) time_value;
2651 	ICalProperty *prop;
2652 	ICalParameter *param;
2653 	ICalTimezone *model_zone;
2654 	ICalTime *tt;
2655 
2656 	g_return_if_fail (model != NULL);
2657 	g_return_if_fail (comp_data != NULL);
2658 	g_return_if_fail (set_func != NULL);
2659 	g_return_if_fail (new_func != NULL);
2660 
2661 	prop = i_cal_component_get_first_property (comp_data->icalcomp, kind);
2662 	if (prop)
2663 		param = i_cal_property_get_first_parameter (prop, I_CAL_TZID_PARAMETER);
2664 	else
2665 		param = NULL;
2666 
2667 	/* If we are setting the property to NULL (i.e. removing it), then
2668 	 * we remove it if it exists. */
2669 	if (!dv) {
2670 		if (prop) {
2671 			i_cal_component_remove_property (comp_data->icalcomp, prop);
2672 			g_object_unref (prop);
2673 		}
2674 
2675 		return;
2676 	}
2677 
2678 	model_zone = e_cal_model_get_timezone (model);
2679 	tt = e_cell_date_edit_value_get_time (dv);
2680 	datetime_to_zone (comp_data->client, tt, model_zone, param ? i_cal_parameter_get_tzid (param) : NULL);
2681 
2682 	if (prop) {
2683 		set_func (prop, tt);
2684 	} else {
2685 		prop = new_func (tt);
2686 		i_cal_component_take_property (comp_data->icalcomp, prop);
2687 
2688 		prop = i_cal_component_get_first_property (comp_data->icalcomp, kind);
2689 	}
2690 
2691 	if (param) {
2692 		const gchar *tzid = i_cal_parameter_get_tzid (param);
2693 
2694 		/* If the TZID is set to "UTC", we don't want to save the TZID. */
2695 		if (!tzid || !*tzid || !strcmp (tzid, "UTC")) {
2696 			i_cal_property_remove_parameter_by_kind (prop, I_CAL_TZID_PARAMETER);
2697 		}
2698 	} else if (model_zone) {
2699 		const gchar *tzid = i_cal_timezone_get_tzid (model_zone);
2700 
2701 		if (tzid && *tzid) {
2702 			param = i_cal_parameter_new_tzid (tzid);
2703 			i_cal_property_take_parameter (prop, param);
2704 		}
2705 	}
2706 
2707 	g_clear_object (&prop);
2708 }
2709 
2710 /**
2711  * e_cal_model_test_row_editable
2712  * @model: an #ECalModel
2713  * @row: Row of our interest. -1 is editable only when default client is
2714  * editable.
2715  *
2716  * Checks if component at @row is editable or not.  It doesn't check bounds
2717  * for @row.
2718  *
2719  * Returns: Whether @row is editable or not.
2720  **/
2721 gboolean
e_cal_model_test_row_editable(ECalModel * model,gint row)2722 e_cal_model_test_row_editable (ECalModel *model,
2723                                gint row)
2724 {
2725 	gboolean readonly = FALSE;
2726 	ECalClient *client = NULL;
2727 
2728 	if (row != -1) {
2729 		ECalModelComponent *comp_data;
2730 
2731 		comp_data = e_cal_model_get_component_at (model, row);
2732 
2733 		if (comp_data != NULL && comp_data->client != NULL)
2734 			client = g_object_ref (comp_data->client);
2735 
2736 		readonly = (client == NULL);
2737 	} else {
2738 		const gchar *source_uid;
2739 
2740 		source_uid = e_cal_model_get_default_source_uid (model);
2741 
2742 		/* if the source cannot be opened, then expect the client being writable;
2743 		   there will be shown an error if not, when saving changes anyway */
2744 		readonly = source_uid == NULL;
2745 
2746 		if (source_uid != NULL) {
2747 			ESourceRegistry *registry = e_cal_model_get_registry (model);
2748 			EClientCache *client_cache = e_cal_model_get_client_cache (model);
2749 			ESource *source;
2750 
2751 			source = e_source_registry_ref_source (registry, source_uid);
2752 			if (source) {
2753 				EClient *e_client;
2754 
2755 				e_client = e_client_cache_ref_cached_client (client_cache, source,
2756 					cal_model_kind_to_extension_name (model));
2757 				if (e_client) {
2758 					client = E_CAL_CLIENT (e_client);
2759 				} else {
2760 					const gchar *parent_uid = e_source_get_parent (source);
2761 
2762 					/* There are couple known to be always read-only */
2763 					readonly = g_strcmp0 (parent_uid, "webcal-stub") == 0 ||
2764 						   g_strcmp0 (parent_uid, "weather-stub") == 0 ||
2765 						   g_strcmp0 (parent_uid, "contacts-stub") == 0;
2766 				}
2767 			}
2768 
2769 			g_clear_object (&source);
2770 		}
2771 	}
2772 
2773 	if (!readonly && client)
2774 		readonly = e_client_is_readonly (E_CLIENT (client));
2775 
2776 	g_clear_object (&client);
2777 
2778 	return !readonly;
2779 }
2780 
2781 ESourceRegistry *
e_cal_model_get_registry(ECalModel * model)2782 e_cal_model_get_registry (ECalModel *model)
2783 {
2784 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
2785 
2786 	return model->priv->registry;
2787 }
2788 
2789 EShell *
e_cal_model_get_shell(ECalModel * model)2790 e_cal_model_get_shell (ECalModel *model)
2791 {
2792 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
2793 
2794 	return model->priv->shell;
2795 }
2796 
2797 ECalDataModel *
e_cal_model_get_data_model(ECalModel * model)2798 e_cal_model_get_data_model (ECalModel *model)
2799 {
2800 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
2801 
2802 	return model->priv->data_model;
2803 }
2804 
2805 EClientCache *
e_cal_model_get_client_cache(ECalModel * model)2806 e_cal_model_get_client_cache (ECalModel *model)
2807 {
2808 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
2809 
2810 	return model->priv->client_cache;
2811 }
2812 
2813 gboolean
e_cal_model_get_confirm_delete(ECalModel * model)2814 e_cal_model_get_confirm_delete (ECalModel *model)
2815 {
2816 	g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE);
2817 
2818 	return model->priv->confirm_delete;
2819 }
2820 
2821 void
e_cal_model_set_confirm_delete(ECalModel * model,gboolean confirm_delete)2822 e_cal_model_set_confirm_delete (ECalModel *model,
2823                                 gboolean confirm_delete)
2824 {
2825 	g_return_if_fail (E_IS_CAL_MODEL (model));
2826 
2827 	if (model->priv->confirm_delete == confirm_delete)
2828 		return;
2829 
2830 	model->priv->confirm_delete = confirm_delete;
2831 
2832 	g_object_notify (G_OBJECT (model), "confirm-delete");
2833 }
2834 
2835 ICalComponentKind
e_cal_model_get_component_kind(ECalModel * model)2836 e_cal_model_get_component_kind (ECalModel *model)
2837 {
2838 	g_return_val_if_fail (E_IS_CAL_MODEL (model), I_CAL_NO_COMPONENT);
2839 
2840 	return model->priv->kind;
2841 }
2842 
2843 void
e_cal_model_set_component_kind(ECalModel * model,ICalComponentKind kind)2844 e_cal_model_set_component_kind (ECalModel *model,
2845 				ICalComponentKind kind)
2846 {
2847 	g_return_if_fail (E_IS_CAL_MODEL (model));
2848 
2849 	model->priv->kind = kind;
2850 }
2851 
2852 ICalTimezone *
e_cal_model_get_timezone(ECalModel * model)2853 e_cal_model_get_timezone (ECalModel *model)
2854 {
2855 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
2856 
2857 	return model->priv->zone;
2858 }
2859 
2860 void
e_cal_model_set_timezone(ECalModel * model,const ICalTimezone * zone)2861 e_cal_model_set_timezone (ECalModel *model,
2862 			  const ICalTimezone *zone)
2863 {
2864 	ICalTimezone *old_zone;
2865 
2866 	g_return_if_fail (E_IS_CAL_MODEL (model));
2867 
2868 	if (model->priv->zone == zone)
2869 		return;
2870 
2871 	e_table_model_pre_change (E_TABLE_MODEL (model));
2872 	old_zone = model->priv->zone;
2873 	model->priv->zone = zone ? e_cal_util_copy_timezone (zone) : NULL;
2874 
2875 	/* the timezone affects the times shown for date fields,
2876 	 * so we need to redisplay everything */
2877 	e_table_model_changed (E_TABLE_MODEL (model));
2878 
2879 	g_object_notify (G_OBJECT (model), "timezone");
2880 	g_signal_emit (
2881 		model, signals[TIMEZONE_CHANGED], 0,
2882 		old_zone, model->priv->zone);
2883 
2884 	g_clear_object (&old_zone);
2885 }
2886 
2887 gboolean
e_cal_model_get_compress_weekend(ECalModel * model)2888 e_cal_model_get_compress_weekend (ECalModel *model)
2889 {
2890 	g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE);
2891 
2892 	return model->priv->compress_weekend;
2893 }
2894 
2895 void
e_cal_model_set_compress_weekend(ECalModel * model,gboolean compress_weekend)2896 e_cal_model_set_compress_weekend (ECalModel *model,
2897                                   gboolean compress_weekend)
2898 {
2899 	g_return_if_fail (E_IS_CAL_MODEL (model));
2900 
2901 	if (model->priv->compress_weekend == compress_weekend)
2902 		return;
2903 
2904 	model->priv->compress_weekend = compress_weekend;
2905 
2906 	g_object_notify (G_OBJECT (model), "compress-weekend");
2907 }
2908 
2909 void
e_cal_model_set_default_category(ECalModel * model,const gchar * default_category)2910 e_cal_model_set_default_category (ECalModel *model,
2911                                   const gchar *default_category)
2912 {
2913 	g_return_if_fail (E_IS_CAL_MODEL (model));
2914 
2915 	g_free (model->priv->default_category);
2916 	model->priv->default_category = g_strdup (default_category);
2917 }
2918 
2919 gint
e_cal_model_get_default_reminder_interval(ECalModel * model)2920 e_cal_model_get_default_reminder_interval (ECalModel *model)
2921 {
2922 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
2923 
2924 	return model->priv->default_reminder_interval;
2925 }
2926 
2927 void
e_cal_model_set_default_reminder_interval(ECalModel * model,gint default_reminder_interval)2928 e_cal_model_set_default_reminder_interval (ECalModel *model,
2929                                            gint default_reminder_interval)
2930 {
2931 	g_return_if_fail (E_IS_CAL_MODEL (model));
2932 
2933 	if (model->priv->default_reminder_interval == default_reminder_interval)
2934 		return;
2935 
2936 	model->priv->default_reminder_interval = default_reminder_interval;
2937 
2938 	g_object_notify (G_OBJECT (model), "default-reminder-interval");
2939 }
2940 
2941 EDurationType
e_cal_model_get_default_reminder_units(ECalModel * model)2942 e_cal_model_get_default_reminder_units (ECalModel *model)
2943 {
2944 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
2945 
2946 	return model->priv->default_reminder_units;
2947 }
2948 
2949 void
e_cal_model_set_default_reminder_units(ECalModel * model,EDurationType default_reminder_units)2950 e_cal_model_set_default_reminder_units (ECalModel *model,
2951                                         EDurationType default_reminder_units)
2952 {
2953 	g_return_if_fail (E_IS_CAL_MODEL (model));
2954 
2955 	if (model->priv->default_reminder_units == default_reminder_units)
2956 		return;
2957 
2958 	model->priv->default_reminder_units = default_reminder_units;
2959 
2960 	g_object_notify (G_OBJECT (model), "default-reminder-units");
2961 }
2962 
2963 gboolean
e_cal_model_get_use_24_hour_format(ECalModel * model)2964 e_cal_model_get_use_24_hour_format (ECalModel *model)
2965 {
2966 	g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE);
2967 
2968 	return model->priv->use_24_hour_format;
2969 }
2970 
2971 void
e_cal_model_set_use_24_hour_format(ECalModel * model,gboolean use_24_hour_format)2972 e_cal_model_set_use_24_hour_format (ECalModel *model,
2973                                     gboolean use_24_hour_format)
2974 {
2975 	g_return_if_fail (E_IS_CAL_MODEL (model));
2976 
2977 	if (model->priv->use_24_hour_format == use_24_hour_format)
2978 		return;
2979 
2980 	e_table_model_pre_change (E_TABLE_MODEL (model));
2981 	model->priv->use_24_hour_format = use_24_hour_format;
2982 
2983 	/* Get the views to redraw themselves. */
2984 	e_table_model_changed (E_TABLE_MODEL (model));
2985 
2986 	g_object_notify (G_OBJECT (model), "use-24-hour-format");
2987 }
2988 
2989 gboolean
e_cal_model_get_use_default_reminder(ECalModel * model)2990 e_cal_model_get_use_default_reminder (ECalModel *model)
2991 {
2992 	g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE);
2993 
2994 	return model->priv->use_default_reminder;
2995 }
2996 
2997 void
e_cal_model_set_use_default_reminder(ECalModel * model,gboolean use_default_reminder)2998 e_cal_model_set_use_default_reminder (ECalModel *model,
2999                                       gboolean use_default_reminder)
3000 {
3001 	g_return_if_fail (E_IS_CAL_MODEL (model));
3002 
3003 	if (model->priv->use_default_reminder == use_default_reminder)
3004 		return;
3005 
3006 	model->priv->use_default_reminder = use_default_reminder;
3007 
3008 	g_object_notify (G_OBJECT (model), "use-default-reminder");
3009 }
3010 
3011 GDateWeekday
e_cal_model_get_week_start_day(ECalModel * model)3012 e_cal_model_get_week_start_day (ECalModel *model)
3013 {
3014 	g_return_val_if_fail (E_IS_CAL_MODEL (model), G_DATE_BAD_WEEKDAY);
3015 
3016 	return model->priv->week_start_day;
3017 }
3018 
3019 void
e_cal_model_set_week_start_day(ECalModel * model,GDateWeekday week_start_day)3020 e_cal_model_set_week_start_day (ECalModel *model,
3021                                 GDateWeekday week_start_day)
3022 {
3023 	g_return_if_fail (E_IS_CAL_MODEL (model));
3024 	g_return_if_fail (g_date_valid_weekday (week_start_day));
3025 
3026 	if (model->priv->week_start_day == week_start_day)
3027 		return;
3028 
3029 	model->priv->week_start_day = week_start_day;
3030 
3031 	g_object_notify (G_OBJECT (model), "week-start-day");
3032 }
3033 
3034 gboolean
e_cal_model_get_work_day(ECalModel * model,GDateWeekday weekday)3035 e_cal_model_get_work_day (ECalModel *model,
3036                           GDateWeekday weekday)
3037 {
3038 	g_return_val_if_fail (E_IS_CAL_MODEL (model), FALSE);
3039 	g_return_val_if_fail (g_date_valid_weekday (weekday), FALSE);
3040 
3041 	return model->priv->work_days[weekday];
3042 }
3043 
3044 void
e_cal_model_set_work_day(ECalModel * model,GDateWeekday weekday,gboolean work_day)3045 e_cal_model_set_work_day (ECalModel *model,
3046                           GDateWeekday weekday,
3047                           gboolean work_day)
3048 {
3049 	const gchar *property_name = NULL;
3050 
3051 	g_return_if_fail (E_IS_CAL_MODEL (model));
3052 	g_return_if_fail (g_date_valid_weekday (weekday));
3053 
3054 	if (work_day == model->priv->work_days[weekday])
3055 		return;
3056 
3057 	model->priv->work_days[weekday] = work_day;
3058 
3059 	switch (weekday) {
3060 		case G_DATE_MONDAY:
3061 			property_name = "work-day-monday";
3062 			break;
3063 		case G_DATE_TUESDAY:
3064 			property_name = "work-day-tuesday";
3065 			break;
3066 		case G_DATE_WEDNESDAY:
3067 			property_name = "work-day-wednesday";
3068 			break;
3069 		case G_DATE_THURSDAY:
3070 			property_name = "work-day-thursday";
3071 			break;
3072 		case G_DATE_FRIDAY:
3073 			property_name = "work-day-friday";
3074 			break;
3075 		case G_DATE_SATURDAY:
3076 			property_name = "work-day-saturday";
3077 			break;
3078 		case G_DATE_SUNDAY:
3079 			property_name = "work-day-sunday";
3080 			break;
3081 		default:
3082 			g_warn_if_reached ();
3083 	}
3084 
3085 	g_object_notify (G_OBJECT (model), property_name);
3086 }
3087 
3088 /**
3089  * e_cal_model_get_work_day_first:
3090  * @model: an #ECalModel
3091  *
3092  * Returns the first work day with respect to #ECalModel:work-week-start.
3093  * If no work days are set, the function returns %G_DATE_BAD_WEEKDAY.
3094  *
3095  * Returns: first work day of the week, or %G_DATE_BAD_WEEKDAY
3096  **/
3097 GDateWeekday
e_cal_model_get_work_day_first(ECalModel * model)3098 e_cal_model_get_work_day_first (ECalModel *model)
3099 {
3100 	GDateWeekday weekday;
3101 	gint ii;
3102 
3103 	g_return_val_if_fail (E_IS_CAL_MODEL (model), G_DATE_BAD_WEEKDAY);
3104 
3105 	weekday = e_cal_model_get_week_start_day (model);
3106 
3107 	for (ii = 0; ii < 7; ii++) {
3108 		if (e_cal_model_get_work_day (model, weekday))
3109 			return weekday;
3110 		weekday = e_weekday_get_next (weekday);
3111 	}
3112 
3113 	return G_DATE_BAD_WEEKDAY;
3114 }
3115 
3116 /**
3117  * e_cal_model_get_work_day_last:
3118  * @model: an #ECalModel
3119  *
3120  * Returns the last work day with respect to #ECalModel:work-week-start.
3121  * If no work days are set, the function returns %G_DATE_BAD_WEEKDAY.
3122  *
3123  * Returns: last work day of the week, or %G_DATE_BAD_WEEKDAY
3124  **/
3125 GDateWeekday
e_cal_model_get_work_day_last(ECalModel * model)3126 e_cal_model_get_work_day_last (ECalModel *model)
3127 {
3128 	GDateWeekday weekday;
3129 	gint ii;
3130 
3131 	g_return_val_if_fail (E_IS_CAL_MODEL (model), G_DATE_BAD_WEEKDAY);
3132 
3133 	weekday = e_cal_model_get_week_start_day (model);
3134 
3135 	for (ii = 0; ii < 7; ii++) {
3136 		weekday = e_weekday_get_prev (weekday);
3137 		if (e_cal_model_get_work_day (model, weekday))
3138 			return weekday;
3139 	}
3140 
3141 	return G_DATE_BAD_WEEKDAY;
3142 }
3143 
3144 gint
e_cal_model_get_work_day_end_hour(ECalModel * model)3145 e_cal_model_get_work_day_end_hour (ECalModel *model)
3146 {
3147 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
3148 
3149 	return model->priv->work_day_end_hour;
3150 }
3151 
3152 void
e_cal_model_set_work_day_end_hour(ECalModel * model,gint work_day_end_hour)3153 e_cal_model_set_work_day_end_hour (ECalModel *model,
3154                                    gint work_day_end_hour)
3155 {
3156 	g_return_if_fail (E_IS_CAL_MODEL (model));
3157 
3158 	if (model->priv->work_day_end_hour == work_day_end_hour)
3159 		return;
3160 
3161 	model->priv->work_day_end_hour = work_day_end_hour;
3162 
3163 	g_object_notify (G_OBJECT (model), "work-day-end-hour");
3164 }
3165 
3166 gint
e_cal_model_get_work_day_end_minute(ECalModel * model)3167 e_cal_model_get_work_day_end_minute (ECalModel *model)
3168 {
3169 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
3170 
3171 	return model->priv->work_day_end_minute;
3172 }
3173 
3174 void
e_cal_model_set_work_day_end_minute(ECalModel * model,gint work_day_end_minute)3175 e_cal_model_set_work_day_end_minute (ECalModel *model,
3176                                    gint work_day_end_minute)
3177 {
3178 	g_return_if_fail (E_IS_CAL_MODEL (model));
3179 
3180 	if (model->priv->work_day_end_minute == work_day_end_minute)
3181 		return;
3182 
3183 	model->priv->work_day_end_minute = work_day_end_minute;
3184 
3185 	g_object_notify (G_OBJECT (model), "work-day-end-minute");
3186 }
3187 
3188 gint
e_cal_model_get_work_day_start_hour(ECalModel * model)3189 e_cal_model_get_work_day_start_hour (ECalModel *model)
3190 {
3191 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
3192 
3193 	return model->priv->work_day_start_hour;
3194 }
3195 
3196 void
e_cal_model_set_work_day_start_hour(ECalModel * model,gint work_day_start_hour)3197 e_cal_model_set_work_day_start_hour (ECalModel *model,
3198                                    gint work_day_start_hour)
3199 {
3200 	g_return_if_fail (E_IS_CAL_MODEL (model));
3201 
3202 	if (model->priv->work_day_start_hour == work_day_start_hour)
3203 		return;
3204 
3205 	model->priv->work_day_start_hour = work_day_start_hour;
3206 
3207 	g_object_notify (G_OBJECT (model), "work-day-start-hour");
3208 }
3209 
3210 gint
e_cal_model_get_work_day_start_minute(ECalModel * model)3211 e_cal_model_get_work_day_start_minute (ECalModel *model)
3212 {
3213 	g_return_val_if_fail (E_IS_CAL_MODEL (model), 0);
3214 
3215 	return model->priv->work_day_start_minute;
3216 }
3217 
3218 void
e_cal_model_set_work_day_start_minute(ECalModel * model,gint work_day_start_minute)3219 e_cal_model_set_work_day_start_minute (ECalModel *model,
3220                                    gint work_day_start_minute)
3221 {
3222 	g_return_if_fail (E_IS_CAL_MODEL (model));
3223 
3224 	if (model->priv->work_day_start_minute == work_day_start_minute)
3225 		return;
3226 
3227 	model->priv->work_day_start_minute = work_day_start_minute;
3228 
3229 	g_object_notify (G_OBJECT (model), "work-day-start-minute");
3230 }
3231 
3232 gint
e_cal_model_get_work_day_start_mon(ECalModel * model)3233 e_cal_model_get_work_day_start_mon (ECalModel *model)
3234 {
3235 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3236 
3237 	return model->priv->work_day_start_mon;
3238 }
3239 
3240 void
e_cal_model_set_work_day_start_mon(ECalModel * model,gint work_day_start)3241 e_cal_model_set_work_day_start_mon (ECalModel *model,
3242 				    gint work_day_start)
3243 {
3244 	g_return_if_fail (E_IS_CAL_MODEL (model));
3245 
3246 	if (model->priv->work_day_start_mon == work_day_start)
3247 		return;
3248 
3249 	model->priv->work_day_start_mon = work_day_start;
3250 
3251 	g_object_notify (G_OBJECT (model), "work-day-start-mon");
3252 }
3253 
3254 gint
e_cal_model_get_work_day_end_mon(ECalModel * model)3255 e_cal_model_get_work_day_end_mon (ECalModel *model)
3256 {
3257 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3258 
3259 	return model->priv->work_day_end_mon;
3260 }
3261 
3262 void
e_cal_model_set_work_day_end_mon(ECalModel * model,gint work_day_end)3263 e_cal_model_set_work_day_end_mon (ECalModel *model,
3264 				  gint work_day_end)
3265 {
3266 	g_return_if_fail (E_IS_CAL_MODEL (model));
3267 
3268 	if (model->priv->work_day_end_mon == work_day_end)
3269 		return;
3270 
3271 	model->priv->work_day_end_mon = work_day_end;
3272 
3273 	g_object_notify (G_OBJECT (model), "work-day-end-mon");
3274 }
3275 
3276 gint
e_cal_model_get_work_day_start_tue(ECalModel * model)3277 e_cal_model_get_work_day_start_tue (ECalModel *model)
3278 {
3279 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3280 
3281 	return model->priv->work_day_start_tue;
3282 }
3283 
3284 void
e_cal_model_set_work_day_start_tue(ECalModel * model,gint work_day_start)3285 e_cal_model_set_work_day_start_tue (ECalModel *model,
3286 				    gint work_day_start)
3287 {
3288 	g_return_if_fail (E_IS_CAL_MODEL (model));
3289 
3290 	if (model->priv->work_day_start_tue == work_day_start)
3291 		return;
3292 
3293 	model->priv->work_day_start_tue = work_day_start;
3294 
3295 	g_object_notify (G_OBJECT (model), "work-day-start-tue");
3296 }
3297 
3298 gint
e_cal_model_get_work_day_end_tue(ECalModel * model)3299 e_cal_model_get_work_day_end_tue (ECalModel *model)
3300 {
3301 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3302 
3303 	return model->priv->work_day_end_tue;
3304 }
3305 
3306 void
e_cal_model_set_work_day_end_tue(ECalModel * model,gint work_day_end)3307 e_cal_model_set_work_day_end_tue (ECalModel *model,
3308 				  gint work_day_end)
3309 {
3310 	g_return_if_fail (E_IS_CAL_MODEL (model));
3311 
3312 	if (model->priv->work_day_end_tue == work_day_end)
3313 		return;
3314 
3315 	model->priv->work_day_end_tue = work_day_end;
3316 
3317 	g_object_notify (G_OBJECT (model), "work-day-end-tue");
3318 }
3319 
3320 gint
e_cal_model_get_work_day_start_wed(ECalModel * model)3321 e_cal_model_get_work_day_start_wed (ECalModel *model)
3322 {
3323 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3324 
3325 	return model->priv->work_day_start_wed;
3326 }
3327 
3328 void
e_cal_model_set_work_day_start_wed(ECalModel * model,gint work_day_start)3329 e_cal_model_set_work_day_start_wed (ECalModel *model,
3330 				    gint work_day_start)
3331 {
3332 	g_return_if_fail (E_IS_CAL_MODEL (model));
3333 
3334 	if (model->priv->work_day_start_wed == work_day_start)
3335 		return;
3336 
3337 	model->priv->work_day_start_wed = work_day_start;
3338 
3339 	g_object_notify (G_OBJECT (model), "work-day-start-wed");
3340 }
3341 
3342 gint
e_cal_model_get_work_day_end_wed(ECalModel * model)3343 e_cal_model_get_work_day_end_wed (ECalModel *model)
3344 {
3345 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3346 
3347 	return model->priv->work_day_end_wed;
3348 }
3349 
3350 void
e_cal_model_set_work_day_end_wed(ECalModel * model,gint work_day_end)3351 e_cal_model_set_work_day_end_wed (ECalModel *model,
3352 				  gint work_day_end)
3353 {
3354 	g_return_if_fail (E_IS_CAL_MODEL (model));
3355 
3356 	if (model->priv->work_day_end_wed == work_day_end)
3357 		return;
3358 
3359 	model->priv->work_day_end_wed = work_day_end;
3360 
3361 	g_object_notify (G_OBJECT (model), "work-day-end-wed");
3362 }
3363 
3364 gint
e_cal_model_get_work_day_start_thu(ECalModel * model)3365 e_cal_model_get_work_day_start_thu (ECalModel *model)
3366 {
3367 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3368 
3369 	return model->priv->work_day_start_thu;
3370 }
3371 
3372 void
e_cal_model_set_work_day_start_thu(ECalModel * model,gint work_day_start)3373 e_cal_model_set_work_day_start_thu (ECalModel *model,
3374 				    gint work_day_start)
3375 {
3376 	g_return_if_fail (E_IS_CAL_MODEL (model));
3377 
3378 	if (model->priv->work_day_start_thu == work_day_start)
3379 		return;
3380 
3381 	model->priv->work_day_start_thu = work_day_start;
3382 
3383 	g_object_notify (G_OBJECT (model), "work-day-start-thu");
3384 }
3385 
3386 gint
e_cal_model_get_work_day_end_thu(ECalModel * model)3387 e_cal_model_get_work_day_end_thu (ECalModel *model)
3388 {
3389 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3390 
3391 	return model->priv->work_day_end_thu;
3392 }
3393 
3394 void
e_cal_model_set_work_day_end_thu(ECalModel * model,gint work_day_end)3395 e_cal_model_set_work_day_end_thu (ECalModel *model,
3396 				  gint work_day_end)
3397 {
3398 	g_return_if_fail (E_IS_CAL_MODEL (model));
3399 
3400 	if (model->priv->work_day_end_thu == work_day_end)
3401 		return;
3402 
3403 	model->priv->work_day_end_thu = work_day_end;
3404 
3405 	g_object_notify (G_OBJECT (model), "work-day-end-thu");
3406 }
3407 
3408 gint
e_cal_model_get_work_day_start_fri(ECalModel * model)3409 e_cal_model_get_work_day_start_fri (ECalModel *model)
3410 {
3411 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3412 
3413 	return model->priv->work_day_start_fri;
3414 }
3415 
3416 void
e_cal_model_set_work_day_start_fri(ECalModel * model,gint work_day_start)3417 e_cal_model_set_work_day_start_fri (ECalModel *model,
3418 				    gint work_day_start)
3419 {
3420 	g_return_if_fail (E_IS_CAL_MODEL (model));
3421 
3422 	if (model->priv->work_day_start_fri == work_day_start)
3423 		return;
3424 
3425 	model->priv->work_day_start_fri = work_day_start;
3426 
3427 	g_object_notify (G_OBJECT (model), "work-day-start-fri");
3428 }
3429 
3430 gint
e_cal_model_get_work_day_end_fri(ECalModel * model)3431 e_cal_model_get_work_day_end_fri (ECalModel *model)
3432 {
3433 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3434 
3435 	return model->priv->work_day_end_fri;
3436 }
3437 
3438 void
e_cal_model_set_work_day_end_fri(ECalModel * model,gint work_day_end)3439 e_cal_model_set_work_day_end_fri (ECalModel *model,
3440 				  gint work_day_end)
3441 {
3442 	g_return_if_fail (E_IS_CAL_MODEL (model));
3443 
3444 	if (model->priv->work_day_end_fri == work_day_end)
3445 		return;
3446 
3447 	model->priv->work_day_end_fri = work_day_end;
3448 
3449 	g_object_notify (G_OBJECT (model), "work-day-end-fri");
3450 }
3451 
3452 gint
e_cal_model_get_work_day_start_sat(ECalModel * model)3453 e_cal_model_get_work_day_start_sat (ECalModel *model)
3454 {
3455 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3456 
3457 	return model->priv->work_day_start_sat;
3458 }
3459 
3460 void
e_cal_model_set_work_day_start_sat(ECalModel * model,gint work_day_start)3461 e_cal_model_set_work_day_start_sat (ECalModel *model,
3462 				    gint work_day_start)
3463 {
3464 	g_return_if_fail (E_IS_CAL_MODEL (model));
3465 
3466 	if (model->priv->work_day_start_sat == work_day_start)
3467 		return;
3468 
3469 	model->priv->work_day_start_sat = work_day_start;
3470 
3471 	g_object_notify (G_OBJECT (model), "work-day-start-sat");
3472 }
3473 
3474 gint
e_cal_model_get_work_day_end_sat(ECalModel * model)3475 e_cal_model_get_work_day_end_sat (ECalModel *model)
3476 {
3477 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3478 
3479 	return model->priv->work_day_end_sat;
3480 }
3481 
3482 void
e_cal_model_set_work_day_end_sat(ECalModel * model,gint work_day_end)3483 e_cal_model_set_work_day_end_sat (ECalModel *model,
3484 				  gint work_day_end)
3485 {
3486 	g_return_if_fail (E_IS_CAL_MODEL (model));
3487 
3488 	if (model->priv->work_day_end_sat == work_day_end)
3489 		return;
3490 
3491 	model->priv->work_day_end_sat = work_day_end;
3492 
3493 	g_object_notify (G_OBJECT (model), "work-day-end-sat");
3494 }
3495 
3496 gint
e_cal_model_get_work_day_start_sun(ECalModel * model)3497 e_cal_model_get_work_day_start_sun (ECalModel *model)
3498 {
3499 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3500 
3501 	return model->priv->work_day_start_sun;
3502 }
3503 
3504 void
e_cal_model_set_work_day_start_sun(ECalModel * model,gint work_day_start)3505 e_cal_model_set_work_day_start_sun (ECalModel *model,
3506 				    gint work_day_start)
3507 {
3508 	g_return_if_fail (E_IS_CAL_MODEL (model));
3509 
3510 	if (model->priv->work_day_start_sun == work_day_start)
3511 		return;
3512 
3513 	model->priv->work_day_start_sun = work_day_start;
3514 
3515 	g_object_notify (G_OBJECT (model), "work-day-start-sun");
3516 }
3517 
3518 gint
e_cal_model_get_work_day_end_sun(ECalModel * model)3519 e_cal_model_get_work_day_end_sun (ECalModel *model)
3520 {
3521 	g_return_val_if_fail (E_IS_CAL_MODEL (model), -1);
3522 
3523 	return model->priv->work_day_end_sun;
3524 }
3525 
3526 void
e_cal_model_set_work_day_end_sun(ECalModel * model,gint work_day_end)3527 e_cal_model_set_work_day_end_sun (ECalModel *model,
3528 				  gint work_day_end)
3529 {
3530 	g_return_if_fail (E_IS_CAL_MODEL (model));
3531 
3532 	if (model->priv->work_day_end_sun == work_day_end)
3533 		return;
3534 
3535 	model->priv->work_day_end_sun = work_day_end;
3536 
3537 	g_object_notify (G_OBJECT (model), "work-day-end-sun");
3538 }
3539 
3540 void
e_cal_model_get_work_day_range_for(ECalModel * model,GDateWeekday weekday,gint * start_hour,gint * start_minute,gint * end_hour,gint * end_minute)3541 e_cal_model_get_work_day_range_for (ECalModel *model,
3542 				    GDateWeekday weekday,
3543 				    gint *start_hour,
3544 				    gint *start_minute,
3545 				    gint *end_hour,
3546 				    gint *end_minute)
3547 {
3548 	gint start_adept = -1, end_adept = -1;
3549 
3550 	g_return_if_fail (E_IS_CAL_MODEL (model));
3551 	g_return_if_fail (start_hour != NULL);
3552 	g_return_if_fail (start_minute != NULL);
3553 	g_return_if_fail (end_hour != NULL);
3554 	g_return_if_fail (end_minute != NULL);
3555 
3556 	switch (weekday) {
3557 		case G_DATE_MONDAY:
3558 			start_adept = e_cal_model_get_work_day_start_mon (model);
3559 			end_adept = e_cal_model_get_work_day_end_mon (model);
3560 			break;
3561 		case G_DATE_TUESDAY:
3562 			start_adept = e_cal_model_get_work_day_start_tue (model);
3563 			end_adept = e_cal_model_get_work_day_end_tue (model);
3564 			break;
3565 		case G_DATE_WEDNESDAY:
3566 			start_adept = e_cal_model_get_work_day_start_wed (model);
3567 			end_adept = e_cal_model_get_work_day_end_wed (model);
3568 			break;
3569 		case G_DATE_THURSDAY:
3570 			start_adept = e_cal_model_get_work_day_start_thu (model);
3571 			end_adept = e_cal_model_get_work_day_end_thu (model);
3572 			break;
3573 		case G_DATE_FRIDAY:
3574 			start_adept = e_cal_model_get_work_day_start_fri (model);
3575 			end_adept = e_cal_model_get_work_day_end_fri (model);
3576 			break;
3577 		case G_DATE_SATURDAY:
3578 			start_adept = e_cal_model_get_work_day_start_sat (model);
3579 			end_adept = e_cal_model_get_work_day_end_sat (model);
3580 			break;
3581 		case G_DATE_SUNDAY:
3582 			start_adept = e_cal_model_get_work_day_start_sun (model);
3583 			end_adept = e_cal_model_get_work_day_end_sun (model);
3584 			break;
3585 		default:
3586 			break;
3587 	}
3588 
3589 	if (start_adept > 0 && (start_adept / 100) >= 0 && (start_adept / 100) <= 23 &&
3590 	    (start_adept % 100) >= 0 && (start_adept % 100) <= 59) {
3591 		*start_hour = start_adept / 100;
3592 		*start_minute = start_adept % 100;
3593 	} else {
3594 		*start_hour = e_cal_model_get_work_day_start_hour (model);
3595 		*start_minute = e_cal_model_get_work_day_start_minute (model);
3596 	}
3597 
3598 	if (end_adept > 0 && (end_adept / 100) >= 0 && (end_adept / 100) <= 23 &&
3599 	    (end_adept % 100) >= 0 && (end_adept % 100) <= 59) {
3600 		*end_hour = end_adept / 100;
3601 		*end_minute = end_adept % 100;
3602 	} else {
3603 		*end_hour = e_cal_model_get_work_day_end_hour (model);
3604 		*end_minute = e_cal_model_get_work_day_end_minute (model);
3605 	}
3606 }
3607 
3608 const gchar *
e_cal_model_get_default_source_uid(ECalModel * model)3609 e_cal_model_get_default_source_uid (ECalModel *model)
3610 {
3611 	g_return_val_if_fail (model != NULL, NULL);
3612 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
3613 
3614 	if (model->priv->default_source_uid && !*model->priv->default_source_uid)
3615 		return NULL;
3616 
3617 	return model->priv->default_source_uid;
3618 }
3619 
3620 void
e_cal_model_set_default_source_uid(ECalModel * model,const gchar * source_uid)3621 e_cal_model_set_default_source_uid (ECalModel *model,
3622 				    const gchar *source_uid)
3623 {
3624 	g_return_if_fail (E_IS_CAL_MODEL (model));
3625 
3626 	if (g_strcmp0 (model->priv->default_source_uid, source_uid) == 0)
3627 		return;
3628 
3629 	g_free (model->priv->default_source_uid);
3630 	model->priv->default_source_uid = g_strdup (source_uid);
3631 
3632 	g_object_notify (G_OBJECT (model), "default-source-uid");
3633 }
3634 
3635 static ECalModelComponent *
search_by_id_and_client(ECalModelPrivate * priv,ECalClient * client,const ECalComponentId * id)3636 search_by_id_and_client (ECalModelPrivate *priv,
3637                          ECalClient *client,
3638                          const ECalComponentId *id)
3639 {
3640 	gint i;
3641 
3642 	for (i = 0; i < priv->objects->len; i++) {
3643 		ECalModelComponent *comp_data = g_ptr_array_index (priv->objects, i);
3644 
3645 		if (comp_data) {
3646 			const gchar *uid;
3647 			gchar *rid;
3648 			gboolean has_rid = e_cal_component_id_get_rid (id) != NULL;
3649 
3650 			uid = i_cal_component_get_uid (comp_data->icalcomp);
3651 			rid = e_cal_util_component_get_recurid_as_string (comp_data->icalcomp);
3652 
3653 			if (uid && *uid) {
3654 				if ((!client || comp_data->client == client) &&
3655 				    !g_strcmp0 (e_cal_component_id_get_uid (id), uid)) {
3656 					if (has_rid) {
3657 						if (!(rid && *rid && !g_strcmp0 (e_cal_component_id_get_rid (id), rid))) {
3658 							g_free (rid);
3659 							continue;
3660 						}
3661 					}
3662 					g_free (rid);
3663 					return comp_data;
3664 				}
3665 			}
3666 
3667 			g_free (rid);
3668 		}
3669 	}
3670 
3671 	return NULL;
3672 }
3673 
3674 void
e_cal_model_remove_all_objects(ECalModel * model)3675 e_cal_model_remove_all_objects (ECalModel *model)
3676 {
3677 	ECalModelComponent *comp_data;
3678 	ETableModel *table_model;
3679 	GSList *comps = NULL;
3680 	guint ii;
3681 
3682 	table_model = E_TABLE_MODEL (model);
3683 
3684 	for (ii = 0; ii < model->priv->objects->len; ii++) {
3685 		comp_data = g_ptr_array_index (model->priv->objects, ii);
3686 
3687 		if (comp_data)
3688 			comps = g_slist_prepend (comps, comp_data);
3689 	}
3690 
3691 	ii = model->priv->objects->len;
3692 
3693 	e_table_model_pre_change (table_model);
3694 	e_table_model_rows_deleted (table_model, 0, ii);
3695 
3696 	g_ptr_array_set_size (model->priv->objects, 0);
3697 
3698 	if (comps)
3699 		g_signal_emit (model, signals[COMPS_DELETED], 0, comps);
3700 
3701 	g_slist_free_full (comps, g_object_unref);
3702 }
3703 
3704 void
e_cal_model_get_time_range(ECalModel * model,time_t * start,time_t * end)3705 e_cal_model_get_time_range (ECalModel *model,
3706                             time_t *start,
3707                             time_t *end)
3708 {
3709 	ECalModelPrivate *priv;
3710 
3711 	g_return_if_fail (model != NULL);
3712 	g_return_if_fail (E_IS_CAL_MODEL (model));
3713 
3714 	priv = model->priv;
3715 
3716 	if (start)
3717 		*start = priv->start;
3718 
3719 	if (end)
3720 		*end = priv->end;
3721 }
3722 
3723 void
e_cal_model_set_time_range(ECalModel * model,time_t start,time_t end)3724 e_cal_model_set_time_range (ECalModel *model,
3725                             time_t start,
3726                             time_t end)
3727 {
3728 	ECalModelPrivate *priv;
3729 	ECalDataModelSubscriber *subscriber;
3730 
3731 	g_return_if_fail (model != NULL);
3732 	g_return_if_fail (E_IS_CAL_MODEL (model));
3733 	g_return_if_fail (start >= 0 && end >= 0);
3734 	g_return_if_fail (start <= end);
3735 
3736 	priv = model->priv;
3737 
3738 	if (start != (time_t) 0 && end != (time_t) 0) {
3739 		end = time_day_end_with_zone (end, priv->zone) - 1;
3740 	}
3741 
3742 	if (priv->start == start && priv->end == end)
3743 		return;
3744 
3745 	subscriber = E_CAL_DATA_MODEL_SUBSCRIBER (model);
3746 	priv->start = start;
3747 	priv->end = end;
3748 
3749 	g_signal_emit (model, signals[TIME_RANGE_CHANGED], 0, (gint64) start, (gint64) end);
3750 
3751 	e_cal_data_model_subscribe (model->priv->data_model, subscriber, start, end);
3752 }
3753 
3754 /**
3755  * e_cal_model_create_component_with_defaults_sync
3756  */
3757 ICalComponent *
e_cal_model_create_component_with_defaults_sync(ECalModel * model,ECalClient * client,gboolean all_day,GCancellable * cancellable,GError ** error)3758 e_cal_model_create_component_with_defaults_sync (ECalModel *model,
3759 						 ECalClient *client,
3760 						 gboolean all_day,
3761 						 GCancellable *cancellable,
3762 						 GError **error)
3763 {
3764 	ECalComponent *comp = NULL;
3765 	ICalComponent *icomp;
3766 
3767 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
3768 
3769 	if (client) {
3770 		switch (model->priv->kind) {
3771 		case I_CAL_VEVENT_COMPONENT :
3772 			comp = cal_comp_event_new_with_defaults_sync (
3773 				client, all_day,
3774 				e_cal_model_get_use_default_reminder (model),
3775 				e_cal_model_get_default_reminder_interval (model),
3776 				e_cal_model_get_default_reminder_units (model),
3777 				cancellable, error);
3778 			break;
3779 		case I_CAL_VTODO_COMPONENT :
3780 			comp = cal_comp_task_new_with_defaults_sync (client, cancellable, error);
3781 			break;
3782 		case I_CAL_VJOURNAL_COMPONENT :
3783 			comp = cal_comp_memo_new_with_defaults_sync (client, cancellable, error);
3784 			break;
3785 		default:
3786 			g_warn_if_reached ();
3787 			return NULL;
3788 		}
3789 	}
3790 
3791 	if (comp) {
3792 		icomp = i_cal_component_clone (e_cal_component_get_icalcomponent (comp));
3793 		g_object_unref (comp);
3794 	} else {
3795 		icomp = i_cal_component_new (model->priv->kind);
3796 	}
3797 
3798 	/* make sure the component has a UID */
3799 	if (!i_cal_component_get_uid (icomp)) {
3800 		gchar *uid;
3801 
3802 		uid = e_util_generate_uid ();
3803 		i_cal_component_set_uid (icomp, uid);
3804 
3805 		g_free (uid);
3806 	}
3807 
3808 	return icomp;
3809 }
3810 
3811 /**
3812  * Returns information about attendees in the component.
3813  * If there are no attendees, the function returns NULL.
3814  *
3815  * The information is like "Status: Accepted: X   Declined: Y  ...".
3816  *
3817  * Free returned pointer with g_free.
3818  **/
3819 gchar *
e_cal_model_get_attendees_status_info(ECalModel * model,ECalComponent * comp,ECalClient * cal_client)3820 e_cal_model_get_attendees_status_info (ECalModel *model,
3821                                        ECalComponent *comp,
3822                                        ECalClient *cal_client)
3823 {
3824 	struct _values {
3825 		ICalParameterPartstat status;
3826 		const gchar *caption;
3827 		gint count;
3828 	} values[] = {
3829 		{ I_CAL_PARTSTAT_ACCEPTED,    N_("Accepted"),     0 },
3830 		{ I_CAL_PARTSTAT_DECLINED,    N_("Declined"),     0 },
3831 		{ I_CAL_PARTSTAT_TENTATIVE,   N_("Tentative"),    0 },
3832 		{ I_CAL_PARTSTAT_DELEGATED,   N_("Delegated"),    0 },
3833 		{ I_CAL_PARTSTAT_NEEDSACTION, N_("Needs action"), 0 },
3834 		{ I_CAL_PARTSTAT_NONE,        N_("Other"),        0 },
3835 		{ I_CAL_PARTSTAT_X,           NULL,              -1 }
3836 	};
3837 
3838 	ESourceRegistry *registry;
3839 	GSList *attendees = NULL, *a;
3840 	gboolean have = FALSE;
3841 	gchar *res = NULL;
3842 	gint i;
3843 
3844 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
3845 
3846 	registry = e_cal_model_get_registry (model);
3847 
3848 	if (!comp || !e_cal_component_has_attendees (comp) ||
3849 	    !itip_organizer_is_user_ex (registry, comp, cal_client, TRUE))
3850 		return NULL;
3851 
3852 	attendees = e_cal_component_get_attendees (comp);
3853 
3854 	for (a = attendees; a; a = a->next) {
3855 		ECalComponentAttendee *att = a->data;
3856 
3857 		if (att && e_cal_component_attendee_get_cutype (att) == I_CAL_CUTYPE_INDIVIDUAL &&
3858 		    (e_cal_component_attendee_get_role (att) == I_CAL_ROLE_CHAIR ||
3859 		     e_cal_component_attendee_get_role (att) == I_CAL_ROLE_REQPARTICIPANT ||
3860 		     e_cal_component_attendee_get_role (att) == I_CAL_ROLE_OPTPARTICIPANT)) {
3861 			have = TRUE;
3862 
3863 			for (i = 0; values[i].count != -1; i++) {
3864 				if (e_cal_component_attendee_get_partstat (att) == values[i].status || values[i].status == I_CAL_PARTSTAT_NONE) {
3865 					values[i].count++;
3866 					break;
3867 				}
3868 			}
3869 		}
3870 	}
3871 
3872 	if (have) {
3873 		GString *str = g_string_new ("");
3874 
3875 		for (i = 0; values[i].count != -1; i++) {
3876 			if (values[i].count > 0) {
3877 				if (str->str && *str->str)
3878 					g_string_append (str, "   ");
3879 
3880 				g_string_append_printf (str, "%s: %d", _(values[i].caption), values[i].count);
3881 			}
3882 		}
3883 
3884 		g_string_prepend (str, ": ");
3885 
3886 		/* To Translators: 'Status' here means the state of the attendees, the resulting string will be in a form:
3887 		 * Status: Accepted: X   Declined: Y   ... */
3888 		g_string_prepend (str, _("Status"));
3889 
3890 		res = g_string_free (str, FALSE);
3891 	}
3892 
3893 	g_slist_free_full (attendees, e_cal_component_attendee_free);
3894 
3895 	return res;
3896 }
3897 
3898 /**
3899  * e_cal_model_get_color_for_component
3900  */
3901 const gchar *
e_cal_model_get_color_for_component(ECalModel * model,ECalModelComponent * comp_data)3902 e_cal_model_get_color_for_component (ECalModel *model,
3903                                      ECalModelComponent *comp_data)
3904 {
3905 	ECalModelClass *model_class;
3906 	const gchar *color = NULL;
3907 
3908 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
3909 	g_return_val_if_fail (comp_data != NULL, NULL);
3910 
3911 	model_class = (ECalModelClass *) G_OBJECT_GET_CLASS (model);
3912 	if (model_class->get_color_for_component != NULL)
3913 		color = model_class->get_color_for_component (model, comp_data);
3914 
3915 	if (!color)
3916 		color = cal_model_get_color_for_component (model, comp_data);
3917 
3918 	return color;
3919 }
3920 
3921 gboolean
e_cal_model_get_rgba_for_component(ECalModel * model,ECalModelComponent * comp_data,GdkRGBA * rgba)3922 e_cal_model_get_rgba_for_component (ECalModel *model,
3923 				    ECalModelComponent *comp_data,
3924 				    GdkRGBA *rgba)
3925 {
3926 	const gchar *color;
3927 
3928 	color = e_cal_model_get_color_for_component (model, comp_data);
3929 	if (!color)
3930 		return FALSE;
3931 
3932 	return gdk_rgba_parse (rgba, color);
3933 }
3934 
3935 /**
3936  * e_cal_model_get_rgb_color_for_component:
3937  *
3938  * Deprecated: 3.20: Use e_cal_model_get_rgba_for_component() instead
3939  */
3940 gboolean
e_cal_model_get_rgb_color_for_component(ECalModel * model,ECalModelComponent * comp_data,gdouble * red,gdouble * green,gdouble * blue)3941 e_cal_model_get_rgb_color_for_component (ECalModel *model,
3942                                          ECalModelComponent *comp_data,
3943                                          gdouble *red,
3944                                          gdouble *green,
3945                                          gdouble *blue)
3946 {
3947 	GdkRGBA rgba;
3948 
3949 	if (!e_cal_model_get_rgba_for_component (model, comp_data, &rgba))
3950 		return FALSE;
3951 
3952 	if (red)
3953 		*red = rgba.red;
3954 	if (green)
3955 		*green = rgba.green;
3956 	if (blue)
3957 		*blue = rgba.blue;
3958 
3959 	return TRUE;
3960 }
3961 
3962 /**
3963  * e_cal_model_get_component_at
3964  */
3965 ECalModelComponent *
e_cal_model_get_component_at(ECalModel * model,gint row)3966 e_cal_model_get_component_at (ECalModel *model,
3967                               gint row)
3968 {
3969 	ECalModelPrivate *priv;
3970 
3971 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
3972 
3973 	priv = model->priv;
3974 
3975 	g_return_val_if_fail (row >= 0 && row < priv->objects->len, NULL);
3976 
3977 	return g_ptr_array_index (priv->objects, row);
3978 }
3979 
3980 ECalModelComponent *
e_cal_model_get_component_for_client_and_uid(ECalModel * model,ECalClient * client,const ECalComponentId * id)3981 e_cal_model_get_component_for_client_and_uid (ECalModel *model,
3982 					      ECalClient *client,
3983 					      const ECalComponentId *id)
3984 {
3985 	ECalModelPrivate *priv;
3986 
3987 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
3988 
3989 	priv = model->priv;
3990 
3991 	return search_by_id_and_client (priv, client, id);
3992 }
3993 
3994 /**
3995  * e_cal_model_date_value_to_string
3996  */
3997 gchar *
e_cal_model_date_value_to_string(ECalModel * model,gconstpointer value)3998 e_cal_model_date_value_to_string (ECalModel *model,
3999                                   gconstpointer value)
4000 {
4001 	ECalModelPrivate *priv;
4002 	ECellDateEditValue *dv = (ECellDateEditValue *) value;
4003 	struct tm tmp_tm;
4004 	gchar buffer[64];
4005 
4006 	g_return_val_if_fail (E_IS_CAL_MODEL (model), g_strdup (""));
4007 
4008 	priv = model->priv;
4009 
4010 	if (!dv)
4011 		return g_strdup ("");
4012 
4013 	/* We currently convert all the dates to the current timezone. */
4014 	tmp_tm = e_cal_util_icaltime_to_tm_with_zone (e_cell_date_edit_value_get_time (dv), e_cell_date_edit_value_get_zone (dv), priv->zone);
4015 
4016 	memset (buffer, 0, sizeof (buffer));
4017 	e_time_format_date_and_time (&tmp_tm, priv->use_24_hour_format,
4018 				     TRUE, FALSE,
4019 				     buffer, sizeof (buffer));
4020 	return g_strdup (buffer);
4021 }
4022 
4023 typedef struct _GenerateInstacesData {
4024 	ECalModelGenerateInstancesData mdata;
4025 	ECalRecurInstanceCb cb;
4026 	ECalClient *client;
4027 	ICalTimezone *zone;
4028 } GenerateInstancesData;
4029 
4030 static gboolean
ecm_generate_instances_cb(ICalComponent * comp,ICalTime * instance_start,ICalTime * instance_end,gpointer user_data,GCancellable * cancellable,GError ** error)4031 ecm_generate_instances_cb (ICalComponent *comp,
4032 			   ICalTime *instance_start,
4033 			   ICalTime *instance_end,
4034 			   gpointer user_data,
4035 			   GCancellable *cancellable,
4036 			   GError **error)
4037 {
4038 	GenerateInstancesData *gid = user_data;
4039 	ICalTime *changed_instance_start = NULL, *changed_instance_end = NULL;
4040 	gboolean res;
4041 
4042 	g_return_val_if_fail (gid != NULL, FALSE);
4043 	g_return_val_if_fail (gid->mdata.comp_data != NULL, FALSE);
4044 
4045 	cal_comp_get_instance_times (gid->mdata.comp_data->client, comp,
4046 		gid->zone, &changed_instance_start, &changed_instance_end, cancellable);
4047 
4048 	res = gid->cb (comp, changed_instance_start, changed_instance_end, &gid->mdata, cancellable, error);
4049 
4050 	g_clear_object (&changed_instance_start);
4051 	g_clear_object (&changed_instance_end);
4052 
4053 	return res;
4054 }
4055 
4056 /**
4057  * e_cal_model_generate_instances_sync
4058  *
4059  * cb function is not called with cb_data, but with ECalModelGenerateInstancesData which contains cb_data
4060  */
4061 void
e_cal_model_generate_instances_sync(ECalModel * model,time_t start,time_t end,GCancellable * cancellable,ECalRecurInstanceCb cb,gpointer cb_data)4062 e_cal_model_generate_instances_sync (ECalModel *model,
4063                                      time_t start,
4064                                      time_t end,
4065 				     GCancellable *cancellable,
4066                                      ECalRecurInstanceCb cb,
4067                                      gpointer cb_data)
4068 {
4069 	GenerateInstancesData gid;
4070 	gint i, n;
4071 
4072 	g_return_if_fail (cb != NULL);
4073 
4074 	gid.mdata.cb_data = cb_data;
4075 	gid.cb = cb;
4076 	gid.zone = model->priv->zone;
4077 
4078 	n = e_table_model_row_count (E_TABLE_MODEL (model));
4079 	for (i = 0; i < n; i++) {
4080 		ECalModelComponent *comp_data = e_cal_model_get_component_at (model, i);
4081 
4082 		if (comp_data->instance_start < end && comp_data->instance_end > start) {
4083 			gid.mdata.comp_data = comp_data;
4084 
4085 			e_cal_client_generate_instances_for_object_sync (comp_data->client, comp_data->icalcomp, start, end,
4086 				cancellable, ecm_generate_instances_cb, &gid);
4087 		}
4088 	}
4089 }
4090 
4091 /**
4092  * e_cal_model_get_object_array
4093  */
4094 GPtrArray *
e_cal_model_get_object_array(ECalModel * model)4095 e_cal_model_get_object_array (ECalModel *model)
4096 {
4097 	g_return_val_if_fail (model != NULL, NULL);
4098 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
4099 	g_return_val_if_fail (model->priv != NULL, NULL);
4100 
4101 	return model->priv->objects;
4102 }
4103 
4104 void
e_cal_model_set_instance_times(ECalModelComponent * comp_data,const ICalTimezone * zone)4105 e_cal_model_set_instance_times (ECalModelComponent *comp_data,
4106 				const ICalTimezone *zone)
4107 {
4108 	ICalTime *instance_start = NULL, *instance_end = NULL;
4109 
4110 	if (i_cal_component_isa (comp_data->icalcomp) == I_CAL_VEVENT_COMPONENT) {
4111 		ICalTime *start_time, *end_time;
4112 
4113 		start_time = i_cal_component_get_dtstart (comp_data->icalcomp);
4114 		end_time = i_cal_component_get_dtend (comp_data->icalcomp);
4115 
4116 		if (i_cal_time_is_date (start_time) && i_cal_time_is_null_time (end_time)) {
4117 			/* If end_time is null and it's an all day event,
4118 			 * just make start_time = end_time so that end_time
4119 			 * will be a valid date
4120 			 */
4121 			g_clear_object (&end_time);
4122 			end_time = i_cal_time_clone (start_time);
4123 			i_cal_time_adjust (end_time, 1, 0, 0, 0);
4124 			i_cal_component_set_dtend (comp_data->icalcomp, end_time);
4125 		} else if (i_cal_time_is_date (start_time) && i_cal_time_is_date (end_time) &&
4126 			   (i_cal_time_compare_date_only (start_time, end_time) == 0)) {
4127 			/* If both DTSTART and DTEND are DATE values, and they are the
4128 			 * same day, we add 1 day to DTEND. This means that most
4129 			 * events created with the old Evolution behavior will still
4130 			 * work OK. */
4131 			i_cal_time_adjust (end_time, 1, 0, 0, 0);
4132 			i_cal_component_set_dtend (comp_data->icalcomp, end_time);
4133 		}
4134 
4135 		g_clear_object (&start_time);
4136 		g_clear_object (&end_time);
4137 	}
4138 
4139 	cal_comp_get_instance_times (comp_data->client, comp_data->icalcomp, zone,
4140 		&instance_start, &instance_end, NULL);
4141 
4142 	comp_data->instance_start = instance_start ? i_cal_time_as_timet_with_zone (instance_start,
4143 		i_cal_time_get_timezone (instance_start)) : comp_data->instance_start;
4144 	comp_data->instance_end = instance_end ? i_cal_time_as_timet_with_zone (instance_end,
4145 		i_cal_time_get_timezone (instance_end)) : comp_data->instance_end;
4146 
4147 	g_clear_object (&instance_start);
4148 	g_clear_object (&instance_end);
4149 }
4150 
4151 /**
4152  * e_cal_model_set_default_time_func:
4153  * This function will be used when creating new item from the "click-to-add",
4154  * when user didn't fill a start date there.
4155  **/
4156 void
e_cal_model_set_default_time_func(ECalModel * model,ECalModelDefaultTimeFunc func,gpointer user_data)4157 e_cal_model_set_default_time_func (ECalModel *model,
4158                                    ECalModelDefaultTimeFunc func,
4159                                    gpointer user_data)
4160 {
4161 	g_return_if_fail (E_IS_CAL_MODEL (model));
4162 
4163 	model->priv->get_default_time = func;
4164 	model->priv->get_default_time_user_data = user_data;
4165 }
4166 
4167 void
e_cal_model_modify_component(ECalModel * model,ECalModelComponent * comp_data,ECalObjModType mod)4168 e_cal_model_modify_component (ECalModel *model,
4169 			      ECalModelComponent *comp_data,
4170 			      ECalObjModType mod)
4171 {
4172 	g_return_if_fail (E_IS_CAL_MODEL (model));
4173 	g_return_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data));
4174 
4175 	e_cal_ops_modify_component (model, comp_data->client, comp_data->icalcomp, mod, E_CAL_OPS_SEND_FLAG_ASK);
4176 }
4177 
4178 void
e_cal_model_util_set_value(GHashTable * values,ETableModel * table_model,gint column,gint row)4179 e_cal_model_util_set_value (GHashTable *values,
4180 			    ETableModel *table_model,
4181 			    gint column,
4182 			    gint row)
4183 {
4184 	gpointer value;
4185 
4186 	g_return_if_fail (values != NULL);
4187 
4188 	value = e_table_model_value_at (table_model, column, row);
4189 
4190 	g_hash_table_insert (values, GINT_TO_POINTER (column),
4191 		e_table_model_duplicate_value (table_model, column, value));
4192 }
4193 
4194 gpointer
e_cal_model_util_get_value(GHashTable * values,gint column)4195 e_cal_model_util_get_value (GHashTable *values,
4196 			    gint column)
4197 {
4198 	g_return_val_if_fail (values != NULL, NULL);
4199 
4200 	return g_hash_table_lookup (values, GINT_TO_POINTER (column));
4201 }
4202 
4203 void
e_cal_model_emit_object_created(ECalModel * model,ECalClient * where)4204 e_cal_model_emit_object_created (ECalModel *model,
4205 				 ECalClient *where)
4206 {
4207 	g_return_if_fail (E_IS_CAL_MODEL (model));
4208 	g_return_if_fail (E_IS_CAL_CLIENT (where));
4209 
4210 	g_signal_emit (model, signals[OBJECT_CREATED], 0, where);
4211 }
4212 
4213 gpointer
e_cal_model_util_get_status(ECalModelComponent * comp_data)4214 e_cal_model_util_get_status (ECalModelComponent *comp_data)
4215 {
4216 	ICalProperty *prop;
4217 	const gchar *res = "";
4218 
4219 	g_return_val_if_fail (comp_data != NULL, (gpointer) "");
4220 
4221 	prop = i_cal_component_get_first_property (comp_data->icalcomp, I_CAL_STATUS_PROPERTY);
4222 	if (prop) {
4223 		ICalPropertyStatus status;
4224 
4225 		status = i_cal_property_get_status (prop);
4226 
4227 		g_object_unref (prop);
4228 
4229 		res = cal_comp_util_status_to_localized_string (i_cal_component_isa (comp_data->icalcomp), status);
4230 		if (!res)
4231 			res = "";
4232 	}
4233 
4234 	return (gpointer) res;
4235 }
4236 
4237 ICalPropertyStatus
e_cal_model_util_set_status(ECalModelComponent * comp_data,gconstpointer value)4238 e_cal_model_util_set_status (ECalModelComponent *comp_data,
4239 			     gconstpointer value)
4240 {
4241 	ICalProperty *prop;
4242 	ICalPropertyStatus status;
4243 	const gchar *str_value = value;
4244 
4245 	g_return_val_if_fail (comp_data != NULL, I_CAL_STATUS_NONE);
4246 
4247 	prop = i_cal_component_get_first_property (comp_data->icalcomp, I_CAL_STATUS_PROPERTY);
4248 
4249 	if (!str_value || !*str_value) {
4250 		if (prop) {
4251 			i_cal_component_remove_property (comp_data->icalcomp, prop);
4252 			g_object_unref (prop);
4253 		}
4254 
4255 		return I_CAL_STATUS_NONE;
4256 	}
4257 
4258 	status = cal_comp_util_localized_string_to_status (i_cal_component_isa (comp_data->icalcomp), str_value, NULL, NULL);
4259 
4260 	if (status == I_CAL_STATUS_NONE) {
4261 		if (prop) {
4262 			i_cal_component_remove_property (comp_data->icalcomp, prop);
4263 			g_object_unref (prop);
4264 		}
4265 	} else if (prop) {
4266 		i_cal_property_set_status (prop, status);
4267 		g_object_unref (prop);
4268 	} else {
4269 		prop = i_cal_property_new_status (status);
4270 		i_cal_component_take_property (comp_data->icalcomp, prop);
4271 	}
4272 
4273 	return status;
4274 }
4275 
4276 static const gchar *
get_cmp_cache_str(gpointer cmp_cache,const gchar * str)4277 get_cmp_cache_str (gpointer cmp_cache,
4278 		   const gchar *str)
4279 {
4280 	const gchar *value;
4281 
4282 	if (!cmp_cache || !str)
4283 		return str;
4284 
4285 	value = e_table_sorting_utils_lookup_cmp_cache (cmp_cache, str);
4286 	if (!value) {
4287 		gchar *ckey;
4288 
4289 		ckey = g_utf8_collate_key (str, -1);
4290 		e_table_sorting_utils_add_to_cmp_cache (cmp_cache, (gchar *) str, ckey);
4291 		value = ckey;
4292 	}
4293 
4294 	return value;
4295 }
4296 
4297 static gint
cmp_cache_strings(gconstpointer str_a,gconstpointer str_b,gpointer cmp_cache)4298 cmp_cache_strings (gconstpointer str_a,
4299 		   gconstpointer str_b,
4300 		   gpointer cmp_cache)
4301 {
4302 	if (!cmp_cache)
4303 		return g_utf8_collate (str_a, str_b);
4304 
4305 	str_b = get_cmp_cache_str (cmp_cache, str_b);
4306 
4307 	g_return_val_if_fail (str_a != NULL, 0);
4308 	g_return_val_if_fail (str_b != NULL, 0);
4309 
4310 	return g_strcmp0 (str_a, str_b);
4311 }
4312 
4313 gint
e_cal_model_util_status_compare_cb(gconstpointer a,gconstpointer b,gpointer cmp_cache)4314 e_cal_model_util_status_compare_cb (gconstpointer a,
4315 				    gconstpointer b,
4316 				    gpointer cmp_cache)
4317 {
4318 	const gchar *string_a = a;
4319 	const gchar *string_b = b;
4320 	gint status_a = -2;
4321 	gint status_b = -2;
4322 
4323 	if (!string_a || !*string_a) {
4324 		status_a = -1;
4325 	} else {
4326 		const gchar *cache_str = get_cmp_cache_str (cmp_cache, string_a);
4327 
4328 		status_a = cal_comp_util_localized_string_to_status (I_CAL_ANY_COMPONENT, cache_str, cmp_cache_strings, cmp_cache);
4329 
4330 		if (status_a == I_CAL_STATUS_NONE)
4331 			status_a = -1;
4332 	}
4333 
4334 	if (string_b == NULL || *string_b == '\0')
4335 		status_b = -1;
4336 	else {
4337 		const gchar *cache_str = get_cmp_cache_str (cmp_cache, string_b);
4338 
4339 		status_b = cal_comp_util_localized_string_to_status (I_CAL_ANY_COMPONENT, cache_str, cmp_cache_strings, cmp_cache);
4340 
4341 		if (status_b == I_CAL_STATUS_NONE)
4342 			status_b = -1;
4343 	}
4344 
4345 	return status_a - status_b;
4346 }
4347 
4348 ECellDateEditValue *
e_cal_model_util_get_datetime_value(ECalModel * model,ECalModelComponent * comp_data,ICalPropertyKind kind,ICalTime * (* get_time_func)(ICalProperty * prop))4349 e_cal_model_util_get_datetime_value (ECalModel *model,
4350 				     ECalModelComponent *comp_data,
4351 				     ICalPropertyKind kind,
4352 				     ICalTime * (*get_time_func) (ICalProperty *prop))
4353 {
4354 	ECellDateEditValue *value;
4355 	ICalProperty *prop;
4356 	ICalParameter *param = NULL;
4357 	ICalTimezone *zone = NULL;
4358 	ICalTime *tt;
4359 	const gchar *tzid;
4360 	gboolean is_date;
4361 
4362 	g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
4363 	g_return_val_if_fail (E_IS_CAL_MODEL_COMPONENT (comp_data), NULL);
4364 	g_return_val_if_fail (get_time_func != NULL, NULL);
4365 
4366 	prop = i_cal_component_get_first_property (comp_data->icalcomp, kind);
4367 	if (!prop)
4368 		return NULL;
4369 
4370 	tt = get_time_func (prop);
4371 
4372 	if (!tt || !i_cal_time_is_valid_time (tt) || i_cal_time_is_null_time (tt)) {
4373 		g_clear_object (&prop);
4374 		g_clear_object (&tt);
4375 
4376 		return NULL;
4377 	}
4378 
4379 	is_date = i_cal_time_is_date (tt);
4380 
4381 	if (!is_date) {
4382 		param = i_cal_property_get_first_parameter (prop, I_CAL_TZID_PARAMETER);
4383 		tzid = param ? i_cal_parameter_get_tzid (param) : NULL;
4384 
4385 		if (!tzid || !*tzid ||
4386 		    !e_cal_client_get_timezone_sync (comp_data->client, tzid, &zone, NULL, NULL))
4387 			zone = NULL;
4388 	}
4389 
4390 	if (e_cal_data_model_get_expand_recurrences (model->priv->data_model)) {
4391 		gboolean is_date = i_cal_time_is_date (tt);
4392 		time_t instance_tt = (time_t) 0;
4393 
4394 		if (kind == I_CAL_DTSTART_PROPERTY)
4395 			instance_tt = comp_data->instance_start;
4396 		else if (kind == I_CAL_DTEND_PROPERTY)
4397 			instance_tt = comp_data->instance_end;
4398 		else
4399 			g_warn_if_reached ();
4400 
4401 		if (zone) {
4402 			g_clear_object (&tt);
4403 			tt = i_cal_time_new_from_timet_with_zone (instance_tt, is_date, zone);
4404 		} else if (model->priv->zone) {
4405 			g_clear_object (&tt);
4406 			tt = i_cal_time_new_from_timet_with_zone (instance_tt, is_date, model->priv->zone);
4407 		}
4408 
4409 		if (kind == I_CAL_DTEND_PROPERTY && is_date) {
4410 			ICalProperty *dtstart;
4411 
4412 			dtstart = i_cal_component_get_first_property (comp_data->icalcomp, I_CAL_DTSTART_PROPERTY);
4413 
4414 			if (dtstart) {
4415 				ICalTime *tt_start;
4416 				ICalTimezone *start_zone = NULL;
4417 
4418 				tt_start = i_cal_property_get_dtstart (dtstart);
4419 
4420 				g_clear_object (&param);
4421 
4422 				if (!i_cal_time_is_date (tt_start)) {
4423 					param = i_cal_property_get_first_parameter (dtstart, I_CAL_TZID_PARAMETER);
4424 					tzid = param ? i_cal_parameter_get_tzid (param) : NULL;
4425 
4426 					if (!tzid || !*tzid ||
4427 					    !e_cal_client_get_timezone_sync (comp_data->client, tzid, &start_zone, NULL, NULL))
4428 						start_zone = NULL;
4429 				}
4430 
4431 				if (start_zone) {
4432 					g_clear_object (&tt_start);
4433 					tt_start = i_cal_time_new_from_timet_with_zone (comp_data->instance_start, is_date, start_zone);
4434 				} else {
4435 					g_clear_object (&tt_start);
4436 					tt_start = i_cal_time_new_from_timet_with_zone (comp_data->instance_start, is_date, model->priv->zone);
4437 				}
4438 
4439 				i_cal_time_adjust (tt_start, 1, 0, 0, 0);
4440 
4441 				/* Decrease by a day only if the DTSTART will still be before, or the same as, DTEND */
4442 				if (i_cal_time_compare (tt_start, tt) <= 0)
4443 					i_cal_time_adjust (tt, -1, 0, 0, 0);
4444 
4445 				g_clear_object (&tt_start);
4446 				g_clear_object (&dtstart);
4447 				g_clear_object (&param);
4448 			}
4449 		}
4450 	}
4451 
4452 	value = e_cell_date_edit_value_new_take (tt, zone ? e_cal_util_copy_timezone (zone) : NULL);
4453 
4454 	g_clear_object (&prop);
4455 	g_clear_object (&param);
4456 
4457 	return value;
4458 }
4459 
4460 /* Removes unneeded characters from the 'value'.
4461    It modifies the 'value' inline. */
4462 void
e_cal_model_until_sanitize_text_value(gchar * value,gint value_length)4463 e_cal_model_until_sanitize_text_value (gchar *value,
4464 				       gint value_length)
4465 {
4466 	if (value && (value_length > 0 || value_length == -1) && *value) {
4467 		gchar *ptr, *pos;
4468 
4469 		for (ptr = value, pos = value; (value_length > 0 || value_length == -1) && *ptr; ptr++, pos++) {
4470 			if (*ptr == '\r')
4471 				pos--;
4472 			else if (*ptr == '\n' || *ptr == '\t')
4473 				*pos = ' ';
4474 			else if (pos != ptr)
4475 				*pos = *ptr;
4476 
4477 			if (value_length != -1)
4478 				value_length--;
4479 		}
4480 
4481 		if (pos < ptr)
4482 			*pos = '\0';
4483 	}
4484 }
4485