3 * Evolution calendar - Utilities for tagging ECalendar widgets
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 * Damon Chaplin <damon@ximian.com>
20 * Federico Mena-Quintero <federico@ximian.com>
22 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
26 #include "evolution-config.h"
28 #include "shell/e-shell.h"
29 #include "calendar-config.h"
30 #include "comp-util.h"
31 #include "e-cal-data-model-subscriber.h"
32 #include "tag-calendar.h"
34 struct _ETagCalendarPrivate
36 ECalendar
*calendar
; /* weak-referenced */
37 ECalendarItem
*calitem
; /* weak-referenced */
38 ECalDataModel
*data_model
; /* not referenced, due to circular dependency */
39 gboolean recur_events_italic
;
41 GHashTable
*objects
; /* ObjectInfo ~> 1 (unused) */
42 GHashTable
*dates
; /* julian date ~> DateInfo */
44 guint32 range_start_julian
;
45 guint32 range_end_julian
;
51 PROP_RECUR_EVENTS_ITALIC
54 static void e_tag_calendar_cal_data_model_subscriber_init (ECalDataModelSubscriberInterface
*iface
);
56 G_DEFINE_TYPE_WITH_CODE (ETagCalendar
, e_tag_calendar
, G_TYPE_OBJECT
,
57 G_IMPLEMENT_INTERFACE (E_TYPE_CAL_DATA_MODEL_SUBSCRIBER
, e_tag_calendar_cal_data_model_subscriber_init
))
62 gboolean is_transparent
; /* neither of the two means is_single */
63 gboolean is_recurring
;
75 object_info_hash (gconstpointer v
)
77 const ObjectInfo
*oinfo
= v
;
82 return g_direct_hash (oinfo
->client
) ^ e_cal_component_id_hash (oinfo
->id
);
85 /* component-related equality, for hash tables */
87 object_info_equal (gconstpointer v1
,
90 const ObjectInfo
*oinfo1
= v1
;
91 const ObjectInfo
*oinfo2
= v2
;
96 if (!oinfo1
|| !oinfo2
)
99 return oinfo1
->client
== oinfo2
->client
&&
100 e_cal_component_id_equal (oinfo1
->id
, oinfo2
->id
);
103 /* date-related equality, for drawing changes */
105 object_info_data_equal (ObjectInfo
*o1
,
114 return (o1
->is_transparent
? 1: 0) == (o2
->is_transparent
? 1 : 0) &&
115 (o1
->start_julian
? 1: 0) == (o2
->is_recurring
? 1 : 0) &&
116 (o1
->start_julian
== o2
->start_julian
) &&
117 (o1
->end_julian
== o2
->end_julian
);
121 object_info_new (ECalClient
*client
,
122 ECalComponentId
*id
, /* will be consumed */
123 gboolean is_transparent
,
124 gboolean is_recurring
,
125 guint32 start_julian
,
130 g_return_val_if_fail (client
!= NULL
, NULL
);
131 g_return_val_if_fail (id
!= NULL
, NULL
);
133 oinfo
= g_new0 (ObjectInfo
, 1);
134 oinfo
->client
= client
;
136 oinfo
->is_transparent
= is_transparent
;
137 oinfo
->is_recurring
= is_recurring
;
138 oinfo
->start_julian
= start_julian
;
139 oinfo
->end_julian
= end_julian
;
145 object_info_free (gpointer ptr
)
147 ObjectInfo
*oinfo
= ptr
;
150 e_cal_component_free_id (oinfo
->id
);
158 return g_new0 (DateInfo
, 1);
162 date_info_free (gpointer ptr
)
164 DateInfo
*dinfo
= ptr
;
171 date_info_update (DateInfo
*dinfo
,
175 gint nn
= inc
? +1 : -1;
176 gboolean ui_changed
= FALSE
;
178 g_return_val_if_fail (dinfo
!= NULL
, FALSE
);
179 g_return_val_if_fail (oinfo
!= NULL
, FALSE
);
181 if (oinfo
->is_transparent
) {
182 dinfo
->n_transparent
+= nn
;
183 ui_changed
= ui_changed
|| (inc
&& dinfo
->n_transparent
== 1) || (!inc
&& dinfo
->n_transparent
== 0);
184 } else if (oinfo
->is_recurring
) {
185 dinfo
->n_recurring
+= nn
;
186 ui_changed
= ui_changed
|| (inc
&& dinfo
->n_recurring
== 1) || (!inc
&& dinfo
->n_recurring
== 0);
188 dinfo
->n_single
+= nn
;
189 ui_changed
= ui_changed
|| (inc
&& dinfo
->n_single
== 1) || (!inc
&& dinfo
->n_single
== 0);
196 date_info_get_style (DateInfo
*dinfo
,
197 gboolean recur_events_italic
)
201 g_return_val_if_fail (dinfo
!= NULL
, 0);
203 if (dinfo
->n_transparent
> 0 ||
204 (recur_events_italic
&& dinfo
->n_recurring
> 0))
205 style
|= E_CALENDAR_ITEM_MARK_ITALIC
;
207 if (dinfo
->n_single
> 0 ||
208 (!recur_events_italic
&& dinfo
->n_recurring
> 0))
209 style
|= E_CALENDAR_ITEM_MARK_BOLD
;
215 encode_ymd_to_julian (gint year
,
221 g_date_clear (&dt
, 1);
222 g_date_set_dmy (&dt
, day
, month
, year
);
224 return g_date_get_julian (&dt
);
228 encode_timet_to_julian (time_t t
,
230 const icaltimezone
*zone
)
232 struct icaltimetype tt
;
237 tt
= icaltime_from_timet_with_zone (t
, is_date
, zone
);
239 if (!icaltime_is_valid_time (tt
) || icaltime_is_null_time (tt
))
242 return encode_ymd_to_julian (tt
.year
, tt
.month
, tt
.day
);
246 decode_julian (guint32 julian
,
253 g_date_clear (&dt
, 1);
254 g_date_set_julian (&dt
, julian
);
256 *year
= g_date_get_year (&dt
);
257 *month
= g_date_get_month (&dt
);
258 *day
= g_date_get_day (&dt
);
262 tag_calendar_date_cb (gpointer key
,
266 ETagCalendar
*tag_calendar
= user_data
;
267 DateInfo
*dinfo
= value
;
268 gint year
, month
, day
;
270 decode_julian (GPOINTER_TO_UINT (key
), &year
, &month
, &day
);
272 e_calendar_item_mark_day (tag_calendar
->priv
->calitem
, year
, month
- 1, day
,
273 date_info_get_style (dinfo
, tag_calendar
->priv
->recur_events_italic
), FALSE
);
277 e_tag_calendar_remark_days (ETagCalendar
*tag_calendar
)
279 g_return_if_fail (E_IS_TAG_CALENDAR (tag_calendar
));
280 g_return_if_fail (tag_calendar
->priv
->calitem
!= NULL
);
282 e_calendar_item_clear_marks (tag_calendar
->priv
->calitem
);
284 g_hash_table_foreach (tag_calendar
->priv
->dates
, tag_calendar_date_cb
, tag_calendar
);
288 e_tag_calendar_date_to_timet (gint year
,
291 const icaltimezone
*with_zone
)
296 date
= g_date_new_dmy (day
, month
, year
);
297 g_return_val_if_fail (date
!= NULL
, (time_t) -1);
299 tt
= cal_comp_gdate_to_timet (date
, with_zone
);
307 e_tag_calendar_date_range_changed_cb (ETagCalendar
*tag_calendar
)
309 gint start_year
, start_month
, start_day
, end_year
, end_month
, end_day
;
310 time_t range_start
, range_end
;
312 g_return_if_fail (E_IS_TAG_CALENDAR (tag_calendar
));
314 if (!tag_calendar
->priv
->data_model
||
315 !tag_calendar
->priv
->calitem
)
318 g_return_if_fail (E_IS_CALENDAR_ITEM (tag_calendar
->priv
->calitem
));
320 /* This can fail on start, when the ECalendarItem wasn't updated (drawn) yet */
321 if (!e_calendar_item_get_date_range (tag_calendar
->priv
->calitem
,
322 &start_year
, &start_month
, &start_day
, &end_year
, &end_month
, &end_day
))
328 range_start
= e_tag_calendar_date_to_timet (start_year
, start_month
, start_day
, NULL
);
329 range_end
= e_tag_calendar_date_to_timet (end_year
, end_month
, end_day
, NULL
);
331 tag_calendar
->priv
->range_start_julian
= encode_ymd_to_julian (start_year
, start_month
, start_day
);
332 tag_calendar
->priv
->range_end_julian
= encode_ymd_to_julian (end_year
, end_month
, end_day
);
334 /* Range change causes removal of marks in the calendar */
335 e_tag_calendar_remark_days (tag_calendar
);
337 e_cal_data_model_subscribe (tag_calendar
->priv
->data_model
,
338 E_CAL_DATA_MODEL_SUBSCRIBER (tag_calendar
),
339 range_start
, range_end
);
343 e_tag_calendar_query_tooltip_cb (ECalendar
*calendar
,
346 gboolean keayboard_mode
,
348 ETagCalendar
*tag_calendar
)
351 gint32 julian
, events
;
355 g_return_val_if_fail (E_IS_CALENDAR (calendar
), FALSE
);
356 g_return_val_if_fail (E_IS_TAG_CALENDAR (tag_calendar
), FALSE
);
357 g_return_val_if_fail (GTK_IS_TOOLTIP (tooltip
), FALSE
);
359 if (!e_calendar_item_convert_position_to_date (e_calendar_get_item (calendar
), x
, y
, &date
))
362 julian
= encode_ymd_to_julian (g_date_get_year (&date
), g_date_get_month (&date
), g_date_get_day (&date
));
363 date_info
= g_hash_table_lookup (tag_calendar
->priv
->dates
, GINT_TO_POINTER (julian
));
368 events
= date_info
->n_transparent
+ date_info
->n_recurring
+ date_info
->n_single
;
373 msg
= g_strdup_printf (g_dngettext (GETTEXT_PACKAGE
, "%d event", "%d events", events
), events
);
375 gtk_tooltip_set_text (tooltip
, msg
);
383 get_component_julian_range (ECalClient
*client
,
385 guint32
*start_julian
,
388 time_t instance_start
= 0, instance_end
= 0;
389 gboolean start_is_date
= FALSE
, end_is_date
= FALSE
;
390 const icaltimezone
*zone
;
392 g_return_if_fail (client
!= NULL
);
393 g_return_if_fail (comp
!= NULL
);
395 zone
= calendar_config_get_icaltimezone ();
397 cal_comp_get_instance_times (client
, e_cal_component_get_icalcomponent (comp
),
398 zone
, &instance_start
, &start_is_date
, &instance_end
, &end_is_date
, NULL
);
400 *start_julian
= encode_timet_to_julian (instance_start
, start_is_date
, zone
);
401 *end_julian
= encode_timet_to_julian (instance_end
- (instance_end
== instance_start
? 0 : 1), end_is_date
, zone
);
405 e_tag_calendar_update_by_oinfo (ETagCalendar
*tag_calendar
,
409 ECalendarItem
*calitem
;
410 guint32 dt
, start_julian
, end_julian
;
413 g_return_if_fail (tag_calendar
->priv
->calitem
!= NULL
);
415 calitem
= tag_calendar
->priv
->calitem
;
416 g_return_if_fail (calitem
!= NULL
);
421 start_julian
= oinfo
->start_julian
;
422 end_julian
= oinfo
->end_julian
;
425 if (start_julian
< tag_calendar
->priv
->range_start_julian
)
426 start_julian
= tag_calendar
->priv
->range_start_julian
;
428 if (end_julian
> tag_calendar
->priv
->range_end_julian
)
429 end_julian
= tag_calendar
->priv
->range_end_julian
;
432 for (dt
= start_julian
; dt
<= end_julian
; dt
++) {
433 dinfo
= g_hash_table_lookup (tag_calendar
->priv
->dates
, GUINT_TO_POINTER (dt
));
439 dinfo
= date_info_new ();
440 g_hash_table_insert (tag_calendar
->priv
->dates
, GUINT_TO_POINTER (dt
), dinfo
);
443 if (date_info_update (dinfo
, oinfo
, inc
)) {
444 gint year
, month
, day
;
447 decode_julian (dt
, &year
, &month
, &day
);
448 style
= date_info_get_style (dinfo
, tag_calendar
->priv
->recur_events_italic
);
450 e_calendar_item_mark_day (calitem
, year
, month
- 1, day
, style
, FALSE
);
453 g_hash_table_remove (tag_calendar
->priv
->dates
, GUINT_TO_POINTER (dt
));
459 e_tag_calendar_update_component_dates (ETagCalendar
*tag_calendar
,
460 ObjectInfo
*old_oinfo
,
461 ObjectInfo
*new_oinfo
)
463 g_return_if_fail (tag_calendar
->priv
->calitem
!= NULL
);
465 e_tag_calendar_update_by_oinfo (tag_calendar
, old_oinfo
, FALSE
);
466 e_tag_calendar_update_by_oinfo (tag_calendar
, new_oinfo
, TRUE
);
470 e_tag_calendar_data_subscriber_component_added (ECalDataModelSubscriber
*subscriber
,
474 ETagCalendar
*tag_calendar
;
475 ECalComponentTransparency transparency
;
476 guint32 start_julian
= 0, end_julian
= 0;
479 g_return_if_fail (E_IS_TAG_CALENDAR (subscriber
));
481 tag_calendar
= E_TAG_CALENDAR (subscriber
);
483 get_component_julian_range (client
, comp
, &start_julian
, &end_julian
);
484 if (start_julian
== 0 || end_julian
== 0)
487 e_cal_component_get_transparency (comp
, &transparency
);
489 oinfo
= object_info_new (client
, e_cal_component_get_id (comp
),
490 transparency
== E_CAL_COMPONENT_TRANSP_TRANSPARENT
,
491 e_cal_component_is_instance (comp
),
492 start_julian
, end_julian
);
494 e_tag_calendar_update_component_dates (tag_calendar
, NULL
, oinfo
);
496 g_hash_table_insert (tag_calendar
->priv
->objects
, oinfo
, GINT_TO_POINTER (0));
500 e_tag_calendar_data_subscriber_component_modified (ECalDataModelSubscriber
*subscriber
,
504 ETagCalendar
*tag_calendar
;
505 ECalComponentTransparency transparency
;
506 guint32 start_julian
= 0, end_julian
= 0;
507 gpointer orig_key
, orig_value
;
508 ObjectInfo
*old_oinfo
= NULL
, *new_oinfo
;
510 g_return_if_fail (E_IS_TAG_CALENDAR (subscriber
));
512 tag_calendar
= E_TAG_CALENDAR (subscriber
);
514 get_component_julian_range (client
, comp
, &start_julian
, &end_julian
);
515 if (start_julian
== 0 || end_julian
== 0)
518 e_cal_component_get_transparency (comp
, &transparency
);
520 new_oinfo
= object_info_new (client
, e_cal_component_get_id (comp
),
521 transparency
== E_CAL_COMPONENT_TRANSP_TRANSPARENT
,
522 e_cal_component_is_instance (comp
),
523 start_julian
, end_julian
);
525 if (!g_hash_table_lookup_extended (tag_calendar
->priv
->objects
, new_oinfo
, &orig_key
, &orig_value
)) {
526 object_info_free (new_oinfo
);
530 old_oinfo
= orig_key
;
532 if (object_info_data_equal (old_oinfo
, new_oinfo
)) {
533 object_info_free (new_oinfo
);
537 e_tag_calendar_update_component_dates (tag_calendar
, old_oinfo
, new_oinfo
);
539 /* it also frees old_oinfo */
540 g_hash_table_insert (tag_calendar
->priv
->objects
, new_oinfo
, GINT_TO_POINTER (0));
544 e_tag_calendar_data_subscriber_component_removed (ECalDataModelSubscriber
*subscriber
,
549 ETagCalendar
*tag_calendar
;
551 gpointer orig_key
, orig_value
;
552 ObjectInfo fake_oinfo
, *old_oinfo
;
554 g_return_if_fail (E_IS_TAG_CALENDAR (subscriber
));
556 tag_calendar
= E_TAG_CALENDAR (subscriber
);
558 id
.uid
= (gchar
*) uid
;
559 id
.rid
= (gchar
*) rid
;
561 /* only these two values are used for GHashTable compare */
562 fake_oinfo
.client
= client
;
565 if (!g_hash_table_lookup_extended (tag_calendar
->priv
->objects
, &fake_oinfo
, &orig_key
, &orig_value
))
568 old_oinfo
= orig_key
;
570 e_tag_calendar_update_component_dates (tag_calendar
, old_oinfo
, NULL
);
572 g_hash_table_remove (tag_calendar
->priv
->objects
, old_oinfo
);
576 e_tag_calendar_data_subscriber_freeze (ECalDataModelSubscriber
*subscriber
)
578 /* Ignore freezes here */
582 e_tag_calendar_data_subscriber_thaw (ECalDataModelSubscriber
*subscriber
)
584 /* Ignore freezes here */
588 e_tag_calendar_set_calendar (ETagCalendar
*tag_calendar
,
591 g_return_if_fail (E_IS_TAG_CALENDAR (tag_calendar
));
592 g_return_if_fail (E_IS_CALENDAR (calendar
));
593 g_return_if_fail (e_calendar_get_item (calendar
) != NULL
);
594 g_return_if_fail (tag_calendar
->priv
->calendar
== NULL
);
596 tag_calendar
->priv
->calendar
= calendar
;
597 tag_calendar
->priv
->calitem
= e_calendar_get_item (calendar
);
599 g_object_weak_ref (G_OBJECT (tag_calendar
->priv
->calendar
),
600 (GWeakNotify
) g_nullify_pointer
, &tag_calendar
->priv
->calendar
);
601 g_object_weak_ref (G_OBJECT (tag_calendar
->priv
->calitem
),
602 (GWeakNotify
) g_nullify_pointer
, &tag_calendar
->priv
->calitem
);
606 e_tag_calendar_set_property (GObject
*object
,
611 switch (property_id
) {
613 e_tag_calendar_set_calendar (
614 E_TAG_CALENDAR (object
),
615 g_value_get_object (value
));
618 case PROP_RECUR_EVENTS_ITALIC
:
619 e_tag_calendar_set_recur_events_italic (
620 E_TAG_CALENDAR (object
),
621 g_value_get_boolean (value
));
625 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
629 e_tag_calendar_get_property (GObject
*object
,
634 switch (property_id
) {
636 g_value_set_object (value
,
637 e_tag_calendar_get_calendar (E_TAG_CALENDAR (object
)));
640 case PROP_RECUR_EVENTS_ITALIC
:
641 g_value_set_boolean (value
,
642 e_tag_calendar_get_recur_events_italic (E_TAG_CALENDAR (object
)));
646 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
650 e_tag_calendar_constructed (GObject
*object
)
652 ETagCalendar
*tag_calendar
= E_TAG_CALENDAR (object
);
655 /* Chain up to parent's constructed() method. */
656 G_OBJECT_CLASS (e_tag_calendar_parent_class
)->constructed (object
);
658 g_return_if_fail (tag_calendar
->priv
->calendar
!= NULL
);
659 g_return_if_fail (tag_calendar
->priv
->calitem
!= NULL
);
661 g_signal_connect_swapped (tag_calendar
->priv
->calitem
, "date-range-changed",
662 G_CALLBACK (e_tag_calendar_date_range_changed_cb
), tag_calendar
);
664 g_signal_connect (tag_calendar
->priv
->calendar
, "query-tooltip",
665 G_CALLBACK (e_tag_calendar_query_tooltip_cb
), tag_calendar
);
667 gtk_widget_set_has_tooltip (GTK_WIDGET (tag_calendar
->priv
->calendar
), TRUE
);
669 settings
= e_util_ref_settings ("org.gnome.evolution.calendar");
672 settings
, "recur-events-italic",
673 tag_calendar
, "recur-events-italic",
674 G_SETTINGS_BIND_DEFAULT
| G_SETTINGS_BIND_NO_SENSITIVITY
);
676 g_object_unref (settings
);
680 e_tag_calendar_dispose (GObject
*object
)
682 ETagCalendar
*tag_calendar
= E_TAG_CALENDAR (object
);
684 if (tag_calendar
->priv
->calendar
!= NULL
) {
685 g_signal_handlers_disconnect_by_func (e_calendar_get_item (tag_calendar
->priv
->calendar
),
686 G_CALLBACK (e_tag_calendar_date_range_changed_cb
), tag_calendar
);
687 g_signal_handlers_disconnect_by_func (tag_calendar
->priv
->calendar
,
688 G_CALLBACK (e_tag_calendar_query_tooltip_cb
), tag_calendar
);
689 g_object_weak_unref (G_OBJECT (tag_calendar
->priv
->calendar
),
690 (GWeakNotify
) g_nullify_pointer
, &tag_calendar
->priv
->calendar
);
691 tag_calendar
->priv
->calendar
= NULL
;
694 if (tag_calendar
->priv
->calitem
!= NULL
) {
695 g_object_weak_unref (G_OBJECT (tag_calendar
->priv
->calitem
),
696 (GWeakNotify
) g_nullify_pointer
, &tag_calendar
->priv
->calitem
);
697 tag_calendar
->priv
->calitem
= NULL
;
700 if (tag_calendar
->priv
->data_model
)
701 e_tag_calendar_unsubscribe (tag_calendar
, tag_calendar
->priv
->data_model
);
703 /* Chain up to parent's dispose() method. */
704 G_OBJECT_CLASS (e_tag_calendar_parent_class
)->dispose (object
);
708 e_tag_calendar_finalize (GObject
*object
)
710 ETagCalendar
*tag_calendar
= E_TAG_CALENDAR (object
);
712 g_warn_if_fail (tag_calendar
->priv
->data_model
== NULL
);
714 g_hash_table_destroy (tag_calendar
->priv
->objects
);
715 g_hash_table_destroy (tag_calendar
->priv
->dates
);
717 /* Chain up to parent's finalize() method. */
718 G_OBJECT_CLASS (e_tag_calendar_parent_class
)->finalize (object
);
722 e_tag_calendar_class_init (ETagCalendarClass
*class)
724 GObjectClass
*object_class
;
726 g_type_class_add_private (class, sizeof (ETagCalendarPrivate
));
728 object_class
= G_OBJECT_CLASS (class);
729 object_class
->set_property
= e_tag_calendar_set_property
;
730 object_class
->get_property
= e_tag_calendar_get_property
;
731 object_class
->constructed
= e_tag_calendar_constructed
;
732 object_class
->dispose
= e_tag_calendar_dispose
;
733 object_class
->finalize
= e_tag_calendar_finalize
;
735 g_object_class_install_property (
738 g_param_spec_object (
744 G_PARAM_CONSTRUCT_ONLY
));
746 g_object_class_install_property (
748 PROP_RECUR_EVENTS_ITALIC
,
749 g_param_spec_boolean (
750 "recur-events-italic",
751 "Recur Events Italic",
758 e_tag_calendar_cal_data_model_subscriber_init (ECalDataModelSubscriberInterface
*iface
)
760 iface
->component_added
= e_tag_calendar_data_subscriber_component_added
;
761 iface
->component_modified
= e_tag_calendar_data_subscriber_component_modified
;
762 iface
->component_removed
= e_tag_calendar_data_subscriber_component_removed
;
763 iface
->freeze
= e_tag_calendar_data_subscriber_freeze
;
764 iface
->thaw
= e_tag_calendar_data_subscriber_thaw
;
768 e_tag_calendar_init (ETagCalendar
*tag_calendar
)
770 tag_calendar
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (tag_calendar
, E_TYPE_TAG_CALENDAR
, ETagCalendarPrivate
);
772 tag_calendar
->priv
->objects
= g_hash_table_new_full (
778 tag_calendar
->priv
->dates
= g_hash_table_new_full (
786 e_tag_calendar_new (ECalendar
*calendar
)
788 return g_object_new (E_TYPE_TAG_CALENDAR
, "calendar", calendar
, NULL
);
792 e_tag_calendar_get_calendar (ETagCalendar
*tag_calendar
)
794 g_return_val_if_fail (E_IS_TAG_CALENDAR (tag_calendar
), NULL
);
796 return tag_calendar
->priv
->calendar
;
800 e_tag_calendar_get_recur_events_italic (ETagCalendar
*tag_calendar
)
802 g_return_val_if_fail (E_IS_TAG_CALENDAR (tag_calendar
), FALSE
);
804 return tag_calendar
->priv
->recur_events_italic
;
808 e_tag_calendar_set_recur_events_italic (ETagCalendar
*tag_calendar
,
809 gboolean recur_events_italic
)
811 g_return_if_fail (E_IS_TAG_CALENDAR (tag_calendar
));
813 if ((tag_calendar
->priv
->recur_events_italic
? 1 : 0) == (recur_events_italic
? 1 : 0))
816 tag_calendar
->priv
->recur_events_italic
= recur_events_italic
;
818 g_object_notify (G_OBJECT (tag_calendar
), "recur-events-italic");
820 e_tag_calendar_remark_days (tag_calendar
);
824 e_tag_calendar_subscribe (ETagCalendar
*tag_calendar
,
825 ECalDataModel
*data_model
)
827 g_return_if_fail (E_IS_TAG_CALENDAR (tag_calendar
));
828 g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model
));
829 g_return_if_fail (tag_calendar
->priv
->data_model
!= data_model
);
831 /* if the reference is held by the priv->data_model, then
832 an unsubscribe may cause free of the tag_calendar */
833 g_object_ref (tag_calendar
);
835 if (tag_calendar
->priv
->data_model
)
836 e_tag_calendar_unsubscribe (tag_calendar
, tag_calendar
->priv
->data_model
);
838 tag_calendar
->priv
->data_model
= data_model
;
839 e_tag_calendar_date_range_changed_cb (tag_calendar
);
841 g_object_unref (tag_calendar
);
845 e_tag_calendar_unsubscribe (ETagCalendar
*tag_calendar
,
846 ECalDataModel
*data_model
)
848 g_return_if_fail (E_IS_TAG_CALENDAR (tag_calendar
));
849 g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model
));
850 g_return_if_fail (tag_calendar
->priv
->data_model
== data_model
);
852 e_cal_data_model_unsubscribe (data_model
, E_CAL_DATA_MODEL_SUBSCRIBER (tag_calendar
));
853 tag_calendar
->priv
->data_model
= NULL
;
855 /* calitem can be NULL during dispose of an ECalBaseShellContents */
856 if (tag_calendar
->priv
->calitem
)
857 e_calendar_item_clear_marks (tag_calendar
->priv
->calitem
);
859 g_hash_table_remove_all (tag_calendar
->priv
->objects
);
860 g_hash_table_remove_all (tag_calendar
->priv
->dates
);
863 struct calendar_tag_closure
{
864 ECalendarItem
*calitem
;
869 gboolean skip_transparent_events
;
870 gboolean recur_events_italic
;
873 /* Clears all the tags in a calendar and fills a closure structure with the
874 * necessary information for iterating over occurrences. Returns FALSE if
875 * the calendar has no dates shown. */
877 prepare_tag (ECalendar
*ecal
,
878 struct calendar_tag_closure
*closure
,
880 gboolean clear_first
)
882 gint start_year
, start_month
, start_day
;
883 gint end_year
, end_month
, end_day
;
884 struct icaltimetype start_tt
= icaltime_null_time ();
885 struct icaltimetype end_tt
= icaltime_null_time ();
888 e_calendar_item_clear_marks (e_calendar_get_item (ecal
));
890 if (!e_calendar_item_get_date_range (
891 e_calendar_get_item (ecal
),
892 &start_year
, &start_month
, &start_day
,
893 &end_year
, &end_month
, &end_day
))
896 start_tt
.year
= start_year
;
897 start_tt
.month
= start_month
+ 1;
898 start_tt
.day
= start_day
;
900 end_tt
.year
= end_year
;
901 end_tt
.month
= end_month
+ 1;
902 end_tt
.day
= end_day
;
904 icaltime_adjust (&end_tt
, 1, 0, 0, 0);
906 closure
->calitem
= e_calendar_get_item (ecal
);
909 closure
->zone
= zone
;
911 closure
->zone
= calendar_config_get_icaltimezone ();
913 closure
->start_time
=
914 icaltime_as_timet_with_zone (start_tt
, closure
->zone
);
916 icaltime_as_timet_with_zone (end_tt
, closure
->zone
);
921 /* Marks the specified range in an ECalendar;
922 * called from e_cal_generate_instances() */
924 tag_calendar_cb (ECalComponent
*comp
,
927 struct calendar_tag_closure
*closure
)
929 struct icaltimetype start_tt
, end_tt
;
930 ECalComponentTransparency transparency
;
933 /* If we are skipping TRANSPARENT events, return if the event is
935 e_cal_component_get_transparency (comp
, &transparency
);
936 if (transparency
== E_CAL_COMPONENT_TRANSP_TRANSPARENT
) {
937 if (closure
->skip_transparent_events
)
940 style
= E_CALENDAR_ITEM_MARK_ITALIC
;
941 } else if (closure
->recur_events_italic
&& e_cal_component_is_instance (comp
)) {
942 style
= E_CALENDAR_ITEM_MARK_ITALIC
;
944 style
= E_CALENDAR_ITEM_MARK_BOLD
;
947 start_tt
= icaltime_from_timet_with_zone (istart
, FALSE
, closure
->zone
);
948 end_tt
= icaltime_from_timet_with_zone (iend
- 1, FALSE
, closure
->zone
);
950 e_calendar_item_mark_days (
952 start_tt
.year
, start_tt
.month
- 1, start_tt
.day
,
953 end_tt
.year
, end_tt
.month
- 1, end_tt
.day
,
959 /* Resolves TZIDs for the recurrence generator, for when the comp is not on
960 * the server. We need to try to use builtin timezones first, as they may not
961 * be added to the server yet. */
962 static icaltimezone
*
963 resolve_tzid_cb (const gchar
*tzid
,
966 icaltimezone
*zone
= NULL
;
968 /* Try to find the builtin timezone first. */
969 zone
= icaltimezone_get_builtin_timezone_from_tzid (tzid
);
972 /* FIXME: Handle errors. */
973 GError
*error
= NULL
;
975 e_cal_client_get_timezone_sync (
976 client
, tzid
, &zone
, NULL
, &error
);
980 "%s: Failed to get timezone '%s': %s",
981 G_STRFUNC
, tzid
, error
->message
);
982 g_error_free (error
);
990 * tag_calendar_by_comp:
991 * @ecal: Calendar widget to tag.
992 * @comp: A calendar component object.
993 * @clear_first: Whether the #ECalendar should be cleared of any marks first.
995 * Tags an #ECalendar widget with any occurrences of a specific calendar
996 * component that occur within the calendar's current time range.
997 * Note that TRANSPARENT events are also tagged here.
999 * If comp_is_on_server is FALSE, it will try to resolve TZIDs using builtin
1000 * timezones first, before querying the server, since the timezones may not
1001 * have been added to the calendar on the server yet.
1004 tag_calendar_by_comp (ECalendar
*ecal
,
1005 ECalComponent
*comp
,
1007 icaltimezone
*display_zone
,
1008 gboolean clear_first
,
1009 gboolean comp_is_on_server
,
1010 gboolean can_recur_events_italic
,
1011 GCancellable
*cancellable
)
1013 GSettings
*settings
;
1014 struct calendar_tag_closure closure
;
1016 g_return_if_fail (E_IS_CALENDAR (ecal
));
1017 g_return_if_fail (E_IS_CAL_COMPONENT (comp
));
1019 /* If the ECalendar isn't visible, we just return. */
1020 if (!gtk_widget_get_visible (GTK_WIDGET (ecal
)))
1023 if (!prepare_tag (ecal
, &closure
, display_zone
, clear_first
))
1026 settings
= e_util_ref_settings ("org.gnome.evolution.calendar");
1028 closure
.skip_transparent_events
= FALSE
;
1029 closure
.recur_events_italic
=
1030 can_recur_events_italic
&&
1031 g_settings_get_boolean (settings
, "recur-events-italic");
1033 g_object_unref (settings
);
1035 if (comp_is_on_server
) {
1036 struct calendar_tag_closure
*alloced_closure
;
1038 alloced_closure
= g_new0 (struct calendar_tag_closure
, 1);
1040 *alloced_closure
= closure
;
1042 e_cal_client_generate_instances_for_object (
1043 client
, e_cal_component_get_icalcomponent (comp
),
1044 closure
.start_time
, closure
.end_time
, cancellable
,
1045 (ECalRecurInstanceFn
) tag_calendar_cb
,
1046 alloced_closure
, (GDestroyNotify
) g_free
);
1048 e_cal_recur_generate_instances (
1049 comp
, closure
.start_time
, closure
.end_time
,
1050 (ECalRecurInstanceFn
) tag_calendar_cb
,
1052 (ECalRecurResolveTimezoneFn
) resolve_tzid_cb
,
1053 client
, closure
.zone
);