diff --git a/contrib/evolution/e-cal-data-model-subscriber.c b/contrib/evolution/e-cal-data-model-subscriber.c deleted file mode 100644 index 328b58ac..00000000 --- a/contrib/evolution/e-cal-data-model-subscriber.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, see . - * - * Authors: Milan Crha - */ - -#include "e-cal-data-model-subscriber.h" - -G_DEFINE_INTERFACE (ECalDataModelSubscriber, e_cal_data_model_subscriber, G_TYPE_OBJECT) - -static void -e_cal_data_model_subscriber_default_init (ECalDataModelSubscriberInterface *iface) -{ -} - -/** - * e_cal_data_model_subscriber_component_added: - * @subscriber: an #ECalDataModelSubscriber - * @client: an #ECalClient, which notifies about the component addition - * @comp: an #ECalComponent which was added - * - * Notifies the @subscriber about an added component which belongs - * to the time range used by the @subscriber. - * - * Note: The @subscriber can be frozen during these calls, to be able - * to cumulate multiple changes and propagate them at once. - **/ -void -e_cal_data_model_subscriber_component_added (ECalDataModelSubscriber *subscriber, - ECalClient *client, - ECalComponent *comp) -{ - ECalDataModelSubscriberInterface *iface; - - g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber)); - g_return_if_fail (E_IS_CAL_COMPONENT (comp)); - - iface = E_CAL_DATA_MODEL_SUBSCRIBER_GET_INTERFACE (subscriber); - g_return_if_fail (iface->component_added != NULL); - - iface->component_added (subscriber, client, comp); -} - -/** - * e_cal_data_model_subscriber_component_modified: - * @subscriber: an #ECalDataModelSubscriber - * @client: an #ECalClient, which notifies about the component modification - * @comp: an #ECalComponent which was modified - * - * Notifies the @subscriber about a modified component which belongs - * to the time range used by the @subscriber. - * - * Note: The @subscriber can be frozen during these calls, to be able - * to cumulate multiple changes and propagate them at once. - **/ -void -e_cal_data_model_subscriber_component_modified (ECalDataModelSubscriber *subscriber, - ECalClient *client, - ECalComponent *comp) -{ - ECalDataModelSubscriberInterface *iface; - - g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber)); - g_return_if_fail (E_IS_CAL_COMPONENT (comp)); - - iface = E_CAL_DATA_MODEL_SUBSCRIBER_GET_INTERFACE (subscriber); - g_return_if_fail (iface->component_modified != NULL); - - iface->component_modified (subscriber, client, comp); -} - -/** - * e_cal_data_model_subscriber_component_removed: - * @subscriber: an #ECalDataModelSubscriber - * @client: an #ECalClient, which notifies about the component removal - * @uid: UID of a removed component - * @rid: RID of a removed component - * - * Notifies the @subscriber about a removed component identified - * by @uid and @rid. This component may or may not be within - * the time range specified by the @subscriber. - * - * Note: The @subscriber can be frozen during these calls, to be able - * to cumulate multiple changes and propagate them at once. - **/ -void -e_cal_data_model_subscriber_component_removed (ECalDataModelSubscriber *subscriber, - ECalClient *client, - const gchar *uid, - const gchar *rid) -{ - ECalDataModelSubscriberInterface *iface; - - g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber)); - - iface = E_CAL_DATA_MODEL_SUBSCRIBER_GET_INTERFACE (subscriber); - g_return_if_fail (iface->component_removed != NULL); - - iface->component_removed (subscriber, client, uid, rid); -} - -/** - * e_cal_data_model_subscriber_freeze: - * @subscriber: an #ECalDataModelSubscriber - * - * Tells the @subscriber that it'll be notified about multiple - * changes. Once all the notifications are done, - * a e_cal_data_model_subscriber_thaw() is called. - * - * Note: This function can be called multiple times/recursively, with - * the same count of the e_cal_data_model_subscriber_thaw(), thus - * count with it. - **/ -void -e_cal_data_model_subscriber_freeze (ECalDataModelSubscriber *subscriber) -{ - ECalDataModelSubscriberInterface *iface; - - g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber)); - - iface = E_CAL_DATA_MODEL_SUBSCRIBER_GET_INTERFACE (subscriber); - g_return_if_fail (iface->freeze != NULL); - - iface->freeze (subscriber); -} - -/** - * e_cal_data_model_subscriber_thaw: - * @subscriber: an #ECalDataModelSubscriber - * - * A pair function for e_cal_data_model_subscriber_freeze(), which notifies - * about the end of a content update. - **/ -void -e_cal_data_model_subscriber_thaw (ECalDataModelSubscriber *subscriber) -{ - ECalDataModelSubscriberInterface *iface; - - g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber)); - - iface = E_CAL_DATA_MODEL_SUBSCRIBER_GET_INTERFACE (subscriber); - g_return_if_fail (iface->thaw != NULL); - - iface->thaw (subscriber); -} diff --git a/contrib/evolution/e-cal-data-model-subscriber.h b/contrib/evolution/e-cal-data-model-subscriber.h deleted file mode 100644 index 8d76fb0f..00000000 --- a/contrib/evolution/e-cal-data-model-subscriber.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, see . - * - * Authors: Milan Crha - */ - -#ifndef E_CAL_DATA_MODEL_SUBSCRIBER_H -#define E_CAL_DATA_MODEL_SUBSCRIBER_H - -#include - -/* Standard GObject macros */ -#define E_TYPE_CAL_DATA_MODEL_SUBSCRIBER \ - (e_cal_data_model_subscriber_get_type ()) -#define E_CAL_DATA_MODEL_SUBSCRIBER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_CAL_DATA_MODEL_SUBSCRIBER, ECalDataModelSubscriber)) -#define E_CAL_DATA_MODEL_SUBSCRIBER_INTERFACE(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_CAL_DATA_MODEL_SUBSCRIBER, ECalDataModelSubscriberInterface)) -#define E_IS_CAL_DATA_MODEL_SUBSCRIBER(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_CAL_DATA_MODEL_SUBSCRIBER)) -#define E_IS_CAL_DATA_MODEL_SUBSCRIBER_INTERFACE(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_CAL_DATA_MODEL_SUBSCRIBER)) -#define E_CAL_DATA_MODEL_SUBSCRIBER_GET_INTERFACE(obj) \ - (G_TYPE_INSTANCE_GET_INTERFACE \ - ((obj), E_TYPE_CAL_DATA_MODEL_SUBSCRIBER, ECalDataModelSubscriberInterface)) - -G_BEGIN_DECLS - -typedef struct _ECalDataModelSubscriber ECalDataModelSubscriber; -typedef struct _ECalDataModelSubscriberInterface ECalDataModelSubscriberInterface; - -struct _ECalDataModelSubscriberInterface { - GTypeInterface parent_interface; - - void (*component_added) (ECalDataModelSubscriber *subscriber, - ECalClient *client, - ECalComponent *comp); - void (*component_modified) (ECalDataModelSubscriber *subscriber, - ECalClient *client, - ECalComponent *comp); - void (*component_removed) (ECalDataModelSubscriber *subscriber, - ECalClient *client, - const gchar *uid, - const gchar *rid); - void (*freeze) (ECalDataModelSubscriber *subscriber); - void (*thaw) (ECalDataModelSubscriber *subscriber); -}; - -GType e_cal_data_model_subscriber_get_type (void) G_GNUC_CONST; -void e_cal_data_model_subscriber_component_added (ECalDataModelSubscriber *subscriber, - ECalClient *client, - ECalComponent *comp); -void e_cal_data_model_subscriber_component_modified (ECalDataModelSubscriber *subscriber, - ECalClient *client, - ECalComponent *comp); -void e_cal_data_model_subscriber_component_removed (ECalDataModelSubscriber *subscriber, - ECalClient *client, - const gchar *uid, - const gchar *rid); -void e_cal_data_model_subscriber_freeze (ECalDataModelSubscriber *subscriber); -void e_cal_data_model_subscriber_thaw (ECalDataModelSubscriber *subscriber); - -G_END_DECLS - -#endif /* E_CAL_DATA_MODEL_SUBSCRIBER_H */ diff --git a/contrib/evolution/e-cal-data-model.c b/contrib/evolution/e-cal-data-model.c deleted file mode 100644 index 0b6f733d..00000000 --- a/contrib/evolution/e-cal-data-model.c +++ /dev/null @@ -1,3164 +0,0 @@ -/* - * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, see . - * - * Authors: Milan Crha - */ - -#include -/* #include */ - -#include "e-cal-data-model.h" - -void -cal_comp_get_instance_times (ECalClient *client, - ICalComponent *icomp, - const ICalTimezone *default_zone, - ICalTime **out_instance_start, - ICalTime **out_instance_end, - GCancellable *cancellable) -{ - ICalTime *start_time, *end_time; - const ICalTimezone *zone = default_zone; - - g_return_if_fail (E_IS_CAL_CLIENT (client)); - g_return_if_fail (icomp != NULL); - g_return_if_fail (out_instance_start != NULL); - g_return_if_fail (out_instance_end != NULL); - - start_time = i_cal_component_get_dtstart (icomp); - end_time = i_cal_component_get_dtend (icomp); - - /* Some event can have missing DTEND, then use the start_time for them */ - if (!end_time || i_cal_time_is_null_time (end_time)) { - g_clear_object (&end_time); - - end_time = i_cal_time_clone (start_time); - } - - if (i_cal_time_get_timezone (start_time)) { - zone = i_cal_time_get_timezone (start_time); - } else { - ICalParameter *param = NULL; - ICalProperty *prop = i_cal_component_get_first_property (icomp, I_CAL_DTSTART_PROPERTY); - - if (prop) { - param = i_cal_property_get_first_parameter (prop, I_CAL_TZID_PARAMETER); - - if (param) { - const gchar *tzid = NULL; - ICalTimezone *st_zone = NULL; - - tzid = i_cal_parameter_get_tzid (param); - if (tzid && !e_cal_client_get_timezone_sync (client, tzid, &st_zone, cancellable, NULL)) - st_zone = NULL; - - if (st_zone) - zone = st_zone; - - g_object_unref (param); - } - - g_object_unref (prop); - } - } - - *out_instance_start = i_cal_time_clone (start_time); - i_cal_time_set_timezone (*out_instance_start, zone); - - if (i_cal_time_get_timezone (end_time)) { - zone = i_cal_time_get_timezone (end_time); - } else { - ICalParameter *param = NULL; - ICalProperty *prop = i_cal_component_get_first_property (icomp, I_CAL_DTEND_PROPERTY); - - if (!prop) - prop = i_cal_component_get_first_property (icomp, I_CAL_DTSTART_PROPERTY); - - if (prop) { - param = i_cal_property_get_first_parameter (prop, I_CAL_TZID_PARAMETER); - - if (param) { - const gchar *tzid = NULL; - ICalTimezone *end_zone = NULL; - - tzid = i_cal_parameter_get_tzid (param); - if (tzid && !e_cal_client_get_timezone_sync (client, tzid, &end_zone, cancellable, NULL)) - end_zone = NULL; - - if (end_zone) - zone = end_zone; - - g_object_unref (param); - } - - g_object_unref (prop); - } - } - - *out_instance_end = i_cal_time_clone (end_time); - i_cal_time_set_timezone (*out_instance_end, zone); - - g_clear_object (&start_time); - g_clear_object (&end_time); -} - -#define LOCK_PROPS() g_rec_mutex_lock (&data_model->priv->props_lock) -#define UNLOCK_PROPS() g_rec_mutex_unlock (&data_model->priv->props_lock) - -struct _ECalDataModelPrivate { - GThread *main_thread; - ECalDataModelSubmitThreadJobFunc submit_thread_job_func; - GWeakRef *submit_thread_job_responder; - GThreadPool *thread_pool; - - GRecMutex props_lock; /* to guard all the below members */ - - gboolean disposing; - gboolean expand_recurrences; - gboolean skip_cancelled; - gchar *filter; - gchar *full_filter; /* to be used with views */ - ICalTimezone *zone; - time_t range_start; - time_t range_end; - - GHashTable *clients; /* ESource::uid ~> ECalClient */ - GHashTable *views; /* ECalClient ~> ViewData */ - GSList *subscribers; /* ~> SubscriberData */ - - guint32 views_update_freeze; - gboolean views_update_required; -}; - -enum { - PROP_0, - PROP_EXPAND_RECURRENCES, - PROP_TIMEZONE, - PROP_SKIP_CANCELLED -}; - -enum { - VIEW_STATE_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -G_DEFINE_TYPE (ECalDataModel, e_cal_data_model, G_TYPE_OBJECT) - -typedef struct _ComponentData { - ECalComponent *component; - time_t instance_start; - time_t instance_end; - gboolean is_detached; -} ComponentData; - -typedef struct _ViewData { - gint ref_count; - GRecMutex lock; - gboolean is_used; - - ECalClient *client; - ECalClientView *view; - gulong objects_added_id; - gulong objects_modified_id; - gulong objects_removed_id; - gulong progress_id; - gulong complete_id; - - GHashTable *components; /* ECalComponentId ~> ComponentData */ - GHashTable *lost_components; /* ECalComponentId ~> ComponentData; when re-running view, valid till 'complete' is received */ - gboolean received_complete; - GSList *to_expand_recurrences; /* ICalComponent */ - GSList *expanded_recurrences; /* ComponentData */ - gint pending_expand_recurrences; /* how many is waiting to be processed */ - - GCancellable *cancellable; -} ViewData; - -typedef struct _SubscriberData { - ECalDataModelSubscriber *subscriber; - time_t range_start; - time_t range_end; -} SubscriberData; - -static ComponentData * -component_data_new (ECalComponent *comp, - time_t instance_start, - time_t instance_end, - gboolean is_detached) -{ - ComponentData *comp_data; - - g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), NULL); - - comp_data = g_new0 (ComponentData, 1); - comp_data->component = g_object_ref (comp); - comp_data->instance_start = instance_start; - comp_data->instance_end = instance_end; - comp_data->is_detached = is_detached; - - return comp_data; -} - -static void -component_data_free (gpointer ptr) -{ - ComponentData *comp_data = ptr; - - if (comp_data) { - g_object_unref (comp_data->component); - g_free (comp_data); - } -} - -static gboolean -component_data_equal (ComponentData *comp_data1, - ComponentData *comp_data2) -{ - ICalComponent *icomp1, *icomp2; - ICalTime *tt1, *tt2; - gchar *as_str1, *as_str2; - gboolean equal; - - if (comp_data1 == comp_data2) - return TRUE; - - if (!comp_data1 || !comp_data2 || !comp_data1->component || !comp_data2->component) - return FALSE; - - if (comp_data1->instance_start != comp_data2->instance_start || - comp_data1->instance_end != comp_data2->instance_end) - return FALSE; - - icomp1 = e_cal_component_get_icalcomponent (comp_data1->component); - icomp2 = e_cal_component_get_icalcomponent (comp_data2->component); - - if (!icomp1 || !icomp2 || - i_cal_component_get_sequence (icomp1) != i_cal_component_get_sequence (icomp2) || - g_strcmp0 (i_cal_component_get_uid (icomp1), i_cal_component_get_uid (icomp2)) != 0) - return FALSE; - - tt1 = i_cal_component_get_recurrenceid (icomp1); - tt2 = i_cal_component_get_recurrenceid (icomp2); - if (((!tt1 || i_cal_time_is_valid_time (tt1)) ? 1 : 0) != ((!tt2 || i_cal_time_is_valid_time (tt2)) ? 1 : 0) || - ((!tt1 || i_cal_time_is_null_time (tt1)) ? 1 : 0) != ((!tt2 || i_cal_time_is_null_time (tt2)) ? 1 : 0) || - i_cal_time_compare (tt1, tt2) != 0) { - g_clear_object (&tt1); - g_clear_object (&tt2); - return FALSE; - } - - g_clear_object (&tt1); - g_clear_object (&tt2); - - tt1 = i_cal_component_get_dtstamp (icomp1); - tt2 = i_cal_component_get_dtstamp (icomp2); - if (((!tt1 || i_cal_time_is_valid_time (tt1)) ? 1 : 0) != ((!tt2 || i_cal_time_is_valid_time (tt2)) ? 1 : 0) || - ((!tt1 || i_cal_time_is_null_time (tt1)) ? 1 : 0) != ((!tt2 || i_cal_time_is_null_time (tt2)) ? 1 : 0) || - i_cal_time_compare (tt1, tt2) != 0) { - g_clear_object (&tt1); - g_clear_object (&tt2); - return FALSE; - } - - g_clear_object (&tt1); - g_clear_object (&tt2); - - /* Maybe not so effective compare, but might be still more effective - than updating whole UI with false notifications */ - as_str1 = i_cal_component_as_ical_string (icomp1); - as_str2 = i_cal_component_as_ical_string (icomp2); - - equal = g_strcmp0 (as_str1, as_str2) == 0; - - g_free (as_str1); - g_free (as_str2); - - return equal; -} - -static ViewData * -view_data_new (ECalClient *client) -{ - ViewData *view_data; - - g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL); - - view_data = g_new0 (ViewData, 1); - view_data->ref_count = 1; - g_rec_mutex_init (&view_data->lock); - view_data->is_used = TRUE; - view_data->client = g_object_ref (client); - view_data->components = g_hash_table_new_full ( - e_cal_component_id_hash, e_cal_component_id_equal, - e_cal_component_id_free, component_data_free); - - return view_data; -} - -static void -view_data_disconnect_view (ViewData *view_data) -{ - if (view_data && view_data->view) { - #define disconnect(x) G_STMT_START { \ - if (view_data->x) { \ - g_signal_handler_disconnect (view_data->view, view_data->x); \ - view_data->x = 0; \ - } \ - } G_STMT_END - - disconnect (objects_added_id); - disconnect (objects_modified_id); - disconnect (objects_removed_id); - disconnect (progress_id); - disconnect (complete_id); - - #undef disconnect - } -} - -static ViewData * -view_data_ref (ViewData *view_data) -{ - g_return_val_if_fail (view_data != NULL, NULL); - - g_atomic_int_inc (&view_data->ref_count); - - return view_data; -} - -static void -view_data_unref (gpointer ptr) -{ - ViewData *view_data = ptr; - - if (view_data) { - if (g_atomic_int_dec_and_test (&view_data->ref_count)) { - view_data_disconnect_view (view_data); - if (view_data->cancellable) - g_cancellable_cancel (view_data->cancellable); - g_clear_object (&view_data->cancellable); - g_clear_object (&view_data->client); - g_clear_object (&view_data->view); - g_hash_table_destroy (view_data->components); - if (view_data->lost_components) - g_hash_table_destroy (view_data->lost_components); - g_slist_free_full (view_data->to_expand_recurrences, g_object_unref); - g_slist_free_full (view_data->expanded_recurrences, component_data_free); - g_rec_mutex_clear (&view_data->lock); - g_free (view_data); - } - } -} - -static void -view_data_lock (ViewData *view_data) -{ - g_return_if_fail (view_data != NULL); - - g_rec_mutex_lock (&view_data->lock); -} - -static void -view_data_unlock (ViewData *view_data) -{ - g_return_if_fail (view_data != NULL); - - g_rec_mutex_unlock (&view_data->lock); -} - -static SubscriberData * -subscriber_data_new (ECalDataModelSubscriber *subscriber, - time_t range_start, - time_t range_end) -{ - SubscriberData *subs_data; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber), NULL); - - subs_data = g_new0 (SubscriberData, 1); - subs_data->subscriber = g_object_ref (subscriber); - subs_data->range_start = range_start; - subs_data->range_end = range_end; - - return subs_data; -} - -static void -subscriber_data_free (gpointer ptr) -{ - SubscriberData *subs_data = ptr; - - if (subs_data) { - g_clear_object (&subs_data->subscriber); - g_free (subs_data); - } -} - -typedef struct _ViewStateChangedData { - ECalDataModel *data_model; - ECalClientView *view; - ECalDataModelViewState state; - guint percent; - gchar *message; - GError *error; -} ViewStateChangedData; - -static void -view_state_changed_data_free (gpointer ptr) -{ - ViewStateChangedData *vscd = ptr; - - if (vscd) { - g_clear_object (&vscd->data_model); - g_clear_object (&vscd->view); - g_clear_error (&vscd->error); - g_free (vscd->message); - g_free (vscd); - } -} - -static gboolean -cal_data_model_emit_view_state_changed_timeout_cb (gpointer user_data) -{ - ViewStateChangedData *vscd = user_data; - - g_return_val_if_fail (vscd != NULL, FALSE); - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (vscd->data_model), FALSE); - g_return_val_if_fail (E_IS_CAL_CLIENT_VIEW (vscd->view), FALSE); - - g_signal_emit (vscd->data_model, signals[VIEW_STATE_CHANGED], 0, - vscd->view, vscd->state, vscd->percent, vscd->message, vscd->error); - - return FALSE; -} - -static void -cal_data_model_emit_view_state_changed (ECalDataModel *data_model, - ECalClientView *view, - ECalDataModelViewState state, - guint percent, - const gchar *message, - const GError *error) -{ - ViewStateChangedData *vscd; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view)); - - if (e_cal_data_model_get_disposing (data_model)) - return; - - vscd = g_new0 (ViewStateChangedData, 1); - vscd->data_model = g_object_ref (data_model); - vscd->view = g_object_ref (view); - vscd->state = state; - vscd->percent = percent; - vscd->message = g_strdup (message); - vscd->error = error ? g_error_copy (error) : NULL; - - g_timeout_add_full (G_PRIORITY_DEFAULT, 1, - cal_data_model_emit_view_state_changed_timeout_cb, - vscd, view_state_changed_data_free); -} - -typedef void (* InternalThreadJobFunc) (ECalDataModel *data_model, gpointer user_data); - -typedef struct _InternalThreadJobData { - InternalThreadJobFunc func; - gpointer user_data; -} InternalThreadJobData; - -static void -cal_data_model_internal_thread_job_func (gpointer data, - gpointer user_data) -{ - ECalDataModel *data_model = user_data; - InternalThreadJobData *job_data = data; - - g_return_if_fail (job_data != NULL); - g_return_if_fail (job_data->func != NULL); - - job_data->func (data_model, job_data->user_data); - - g_free (job_data); -} - -static void -cal_data_model_submit_internal_thread_job (ECalDataModel *data_model, - InternalThreadJobFunc func, - gpointer user_data) -{ - InternalThreadJobData *job_data; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - g_return_if_fail (func != NULL); - - job_data = g_new0 (InternalThreadJobData, 1); - job_data->func = func; - job_data->user_data = user_data; - - g_thread_pool_push (data_model->priv->thread_pool, job_data, NULL); -} - -typedef struct _SubmitThreadJobData { - ECalDataModel *data_model; - EThreadJobFunc func; - gpointer user_data; - GDestroyNotify free_user_data; - - GCancellable *cancellable; - gboolean finished; - GMutex mutex; - GCond cond; -} SubmitThreadJobData; - -static gboolean -cal_data_model_call_submit_thread_job (gpointer user_data) -{ - SubmitThreadJobData *stj_data = user_data; - - g_return_val_if_fail (stj_data != NULL, FALSE); - - g_mutex_lock (&stj_data->mutex); - - stj_data->cancellable = stj_data->data_model->priv->submit_thread_job_func (stj_data->func, stj_data->user_data, stj_data->free_user_data); - - stj_data->finished = TRUE; - g_cond_signal (&stj_data->cond); - g_mutex_unlock (&stj_data->mutex); - - return FALSE; -} - -/** - * e_cal_data_model_submit_thread_job: - * @data_model: an #ECalDataModel - * @func: function to be run in a dedicated thread - * @user_data: (allow-none): custom data passed into @func; can be #NULL - * @free_user_data: (allow-none): function to be called on @user_data, - * when the job is over; can be #NULL - * - * Runs the @func in a dedicated thread. Any error is propagated to UI. - * The cancellable passed into the @func is a #CamelOperation, thus - * the caller can overwrite progress and description message on it. - * - * Returns: (transfer full): Newly created #GCancellable on success. - * The caller is responsible to g_object_unref() it when done with it. - * - * Note: The @free_user_data, if set, is called in the main thread. - * - * Note: This is a blocking call, it waits until the thread job is submitted. - * - * Since: 3.14 - **/ -GCancellable * -e_cal_data_model_submit_thread_job (ECalDataModel *data_model, - EThreadJobFunc func, - gpointer user_data, - GDestroyNotify free_user_data) -{ - SubmitThreadJobData stj_data; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL); - g_return_val_if_fail (data_model->priv->submit_thread_job_func != NULL, NULL); - - if (g_thread_self () == data_model->priv->main_thread) { - GCancellable *cancellable; - - cancellable = data_model->priv->submit_thread_job_func ( - func, user_data, free_user_data); - - return cancellable; - } - - stj_data.data_model = data_model; - stj_data.func = func; - stj_data.user_data = user_data; - stj_data.free_user_data = free_user_data; - stj_data.cancellable = NULL; - stj_data.finished = FALSE; - g_mutex_init (&stj_data.mutex); - g_cond_init (&stj_data.cond); - - g_timeout_add (1, cal_data_model_call_submit_thread_job, &stj_data); - - g_mutex_lock (&stj_data.mutex); - while (!stj_data.finished) { - g_cond_wait (&stj_data.cond, &stj_data.mutex); - } - g_mutex_unlock (&stj_data.mutex); - - g_cond_clear (&stj_data.cond); - g_mutex_clear (&stj_data.mutex); - - return stj_data.cancellable; -} - -typedef void (* ECalDataModelForeachSubscriberFunc) (ECalDataModel *data_model, - ECalClient *client, - ECalDataModelSubscriber *subscriber, - gpointer user_data); - -static void -cal_data_model_foreach_subscriber_in_range (ECalDataModel *data_model, - ECalClient *client, - time_t in_range_start, - time_t in_range_end, - ECalDataModelForeachSubscriberFunc func, - gpointer user_data) -{ - GSList *link; - - g_return_if_fail (func != NULL); - - LOCK_PROPS (); - - if (in_range_end == (time_t) 0) { - in_range_end = in_range_start; - } - - for (link = data_model->priv->subscribers; link; link = g_slist_next (link)) { - SubscriberData *subs_data = link->data; - - if ((in_range_start == (time_t) 0 && in_range_end == (time_t) 0) || - (subs_data->range_start == (time_t) 0 && subs_data->range_end == (time_t) 0) || - (subs_data->range_start <= in_range_end && subs_data->range_end >= in_range_start)) - func (data_model, client, subs_data->subscriber, user_data); - } - - UNLOCK_PROPS (); -} - -static void -cal_data_model_foreach_subscriber (ECalDataModel *data_model, - ECalClient *client, - ECalDataModelForeachSubscriberFunc func, - gpointer user_data) -{ - g_return_if_fail (func != NULL); - - cal_data_model_foreach_subscriber_in_range (data_model, client, (time_t) 0, (time_t) 0, func, user_data); -} - -static void -cal_data_model_freeze_subscriber_cb (ECalDataModel *data_model, - ECalClient *client, - ECalDataModelSubscriber *subscriber, - gpointer user_data) -{ - e_cal_data_model_subscriber_freeze (subscriber); -} - -static void -cal_data_model_thaw_subscriber_cb (ECalDataModel *data_model, - ECalClient *client, - ECalDataModelSubscriber *subscriber, - gpointer user_data) -{ - e_cal_data_model_subscriber_thaw (subscriber); -} - -static void -cal_data_model_freeze_all_subscribers (ECalDataModel *data_model) -{ - cal_data_model_foreach_subscriber (data_model, NULL, cal_data_model_freeze_subscriber_cb, NULL); -} - -static void -cal_data_model_thaw_all_subscribers (ECalDataModel *data_model) -{ - cal_data_model_foreach_subscriber (data_model, NULL, cal_data_model_thaw_subscriber_cb, NULL); -} - -static void -cal_data_model_gather_subscribers_cb (ECalDataModel *data_model, - ECalClient *client, - ECalDataModelSubscriber *subscriber, - gpointer user_data) -{ - GHashTable *subscribers = user_data; - - g_return_if_fail (subscribers != NULL); - - g_hash_table_insert (subscribers, g_object_ref (subscriber), NULL); -} - -static void -cal_data_model_add_component_cb (ECalDataModel *data_model, - ECalClient *client, - ECalDataModelSubscriber *subscriber, - gpointer user_data) -{ - ECalComponent *comp = user_data; - - g_return_if_fail (comp != NULL); - - e_cal_data_model_subscriber_component_added (subscriber, client, comp); -} - -static void -cal_data_model_modify_component_cb (ECalDataModel *data_model, - ECalClient *client, - ECalDataModelSubscriber *subscriber, - gpointer user_data) -{ - ECalComponent *comp = user_data; - - g_return_if_fail (comp != NULL); - - e_cal_data_model_subscriber_component_modified (subscriber, client, comp); -} - -static void -cal_data_model_remove_one_view_component_cb (ECalDataModel *data_model, - ECalClient *client, - ECalDataModelSubscriber *subscriber, - gpointer user_data) -{ - const ECalComponentId *id = user_data; - - g_return_if_fail (id != NULL); - - e_cal_data_model_subscriber_component_removed (subscriber, client, - e_cal_component_id_get_uid (id), - e_cal_component_id_get_rid (id)); -} - -static void -cal_data_model_remove_components (ECalDataModel *data_model, - ECalClient *client, - GHashTable *components, - GHashTable *also_remove_from) -{ - GList *ids, *ilink; - - g_return_if_fail (data_model != NULL); - g_return_if_fail (components != NULL); - - cal_data_model_freeze_all_subscribers (data_model); - - ids = g_hash_table_get_keys (components); - - for (ilink = ids; ilink; ilink = g_list_next (ilink)) { - ECalComponentId *id = ilink->data; - ComponentData *comp_data; - time_t instance_start = (time_t) 0, instance_end = (time_t) 0; - - if (!id) - continue; - - /* Try to limit which subscribers will be notified about removal */ - comp_data = g_hash_table_lookup (components, id); - if (comp_data) { - instance_start = comp_data->instance_start; - instance_end = comp_data->instance_end; - } - - cal_data_model_foreach_subscriber_in_range (data_model, client, - instance_start, instance_end, - cal_data_model_remove_one_view_component_cb, id); - - if (also_remove_from) - g_hash_table_remove (also_remove_from, id); - } - - g_list_free (ids); - - cal_data_model_thaw_all_subscribers (data_model); -} - -static void -cal_data_model_calc_range (ECalDataModel *data_model, - time_t *range_start, - time_t *range_end) -{ - GSList *link; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - g_return_if_fail (range_start != NULL); - g_return_if_fail (range_end != NULL); - - *range_start = (time_t) 0; - *range_end = (time_t) 0; - - LOCK_PROPS (); - - for (link = data_model->priv->subscribers; link; link = g_slist_next (link)) { - SubscriberData *subs_data = link->data; - - if (!subs_data) - continue; - - if (subs_data->range_start == (time_t) 0 && subs_data->range_end == (time_t) 0) { - *range_start = (time_t) 0; - *range_end = (time_t) 0; - break; - } - - if (link == data_model->priv->subscribers) { - *range_start = subs_data->range_start; - *range_end = subs_data->range_end; - } else { - if (*range_start > subs_data->range_start) - *range_start = subs_data->range_start; - if (*range_end < subs_data->range_end) - *range_end = subs_data->range_end; - } - } - - UNLOCK_PROPS (); -} - -static gboolean -cal_data_model_update_full_filter (ECalDataModel *data_model) -{ - gchar *filter; - time_t range_start, range_end; - gboolean changed; - - LOCK_PROPS (); - - cal_data_model_calc_range (data_model, &range_start, &range_end); - - if (range_start != (time_t) 0 || range_end != (time_t) 0) { - gchar *iso_start, *iso_end; - const gchar *default_tzloc = NULL; - - iso_start = isodate_from_time_t (range_start); - iso_end = isodate_from_time_t (range_end); - - if (data_model->priv->zone && data_model->priv->zone != i_cal_timezone_get_utc_timezone ()) - default_tzloc = i_cal_timezone_get_location (data_model->priv->zone); - if (!default_tzloc) - default_tzloc = ""; - - if (data_model->priv->filter) { - filter = g_strdup_printf ( - "(and (occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\") %s)", - iso_start, iso_end, default_tzloc, data_model->priv->filter); - } else { - filter = g_strdup_printf ( - "(occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\")", - iso_start, iso_end, default_tzloc); - } - - g_free (iso_start); - g_free (iso_end); - } else if (data_model->priv->filter) { - filter = g_strdup (data_model->priv->filter); - } else { - filter = g_strdup ("#t"); - } - - changed = g_strcmp0 (data_model->priv->full_filter, filter) != 0; - - if (changed) { - g_free (data_model->priv->full_filter); - data_model->priv->full_filter = filter; - } else { - g_free (filter); - } - - UNLOCK_PROPS (); - - return changed; -} - -/* This consumes the comp_data - not so nice, but simpler - than adding reference counter for the structure */ -static void -cal_data_model_process_added_component (ECalDataModel *data_model, - ViewData *view_data, - ComponentData *comp_data, - GHashTable *known_instances) -{ - ECalComponentId *id, *old_id = NULL; - ComponentData *old_comp_data = NULL; - time_t old_instance_start = (time_t) 0, old_instance_end = (time_t) 0; - gboolean comp_data_equal; - - g_return_if_fail (data_model != NULL); - g_return_if_fail (view_data != NULL); - g_return_if_fail (comp_data != NULL); - - id = e_cal_component_get_id (comp_data->component); - g_return_if_fail (id != NULL); - - view_data_lock (view_data); - - if (!old_comp_data && view_data->lost_components) - old_comp_data = g_hash_table_lookup (view_data->lost_components, id); - - if (!old_comp_data && known_instances) - old_comp_data = g_hash_table_lookup (known_instances, id); - - if (!old_comp_data) - old_comp_data = g_hash_table_lookup (view_data->components, id); - - if (old_comp_data) { - /* It can be a previously added detached instance received - during recurrences expand */ - if (!comp_data->is_detached) - comp_data->is_detached = old_comp_data->is_detached; - } - - comp_data_equal = component_data_equal (comp_data, old_comp_data); - - if (old_comp_data) { - old_id = e_cal_component_get_id (old_comp_data->component); - old_instance_start = old_comp_data->instance_start; - old_instance_end = old_comp_data->instance_end; - } - - if (view_data->lost_components) - g_hash_table_remove (view_data->lost_components, id); - - if (known_instances) - g_hash_table_remove (known_instances, id); - - /* Note: old_comp_data is freed or NULL now */ - - /* 'id' is stolen by view_data->components */ - g_hash_table_insert (view_data->components, id, comp_data); - - if (!comp_data_equal) { - if (!old_comp_data) { - cal_data_model_foreach_subscriber_in_range (data_model, view_data->client, - comp_data->instance_start, comp_data->instance_end, - cal_data_model_add_component_cb, comp_data->component); - } else if (comp_data->instance_start != old_instance_start || - comp_data->instance_end != old_instance_end) { - /* Component moved to a different time; some subscribers may lose it, - some may just modify it, some may have it added. */ - GHashTable *old_subscribers, *new_subscribers; - GHashTableIter iter; - gpointer key; - - old_subscribers = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); - new_subscribers = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); - - cal_data_model_foreach_subscriber_in_range (data_model, view_data->client, - old_instance_start, old_instance_end, - cal_data_model_gather_subscribers_cb, old_subscribers); - - cal_data_model_foreach_subscriber_in_range (data_model, view_data->client, - comp_data->instance_start, comp_data->instance_end, - cal_data_model_gather_subscribers_cb, new_subscribers); - - g_hash_table_iter_init (&iter, old_subscribers); - while (g_hash_table_iter_next (&iter, &key, NULL)) { - ECalDataModelSubscriber *subscriber = key; - - /* If in both hashes, then the subscriber can be notified with 'modified', - otherwise the component had been 'removed' for it. */ - if (g_hash_table_remove (new_subscribers, subscriber)) - e_cal_data_model_subscriber_component_modified (subscriber, view_data->client, comp_data->component); - else if (old_id) - e_cal_data_model_subscriber_component_removed (subscriber, view_data->client, - e_cal_component_id_get_uid (old_id), - e_cal_component_id_get_rid (old_id)); - } - - /* Those which left in the new_subscribers have the component added. */ - g_hash_table_iter_init (&iter, new_subscribers); - while (g_hash_table_iter_next (&iter, &key, NULL)) { - ECalDataModelSubscriber *subscriber = key; - - e_cal_data_model_subscriber_component_added (subscriber, view_data->client, comp_data->component); - } - - g_hash_table_destroy (old_subscribers); - g_hash_table_destroy (new_subscribers); - } else { - cal_data_model_foreach_subscriber_in_range (data_model, view_data->client, - comp_data->instance_start, comp_data->instance_end, - cal_data_model_modify_component_cb, comp_data->component); - } - } - - view_data_unlock (view_data); - - e_cal_component_id_free (old_id); -} - -typedef struct _GatherComponentsData { - const gchar *uid; - GList **pcomponent_ids; /* ECalComponentId, can be owned by the hash table */ - GHashTable *component_ids_hash; - gboolean copy_ids; - gboolean all_instances; /* FALSE to get only nondetached component instances */ -} GatherComponentsData; - -static void -cal_data_model_gather_components (gpointer key, - gpointer value, - gpointer user_data) -{ - ECalComponentId *id = key; - ComponentData *comp_data = value; - GatherComponentsData *gather_data = user_data; - - g_return_if_fail (id != NULL); - g_return_if_fail (comp_data != NULL); - g_return_if_fail (gather_data != NULL); - g_return_if_fail (gather_data->pcomponent_ids != NULL || gather_data->component_ids_hash != NULL); - g_return_if_fail (gather_data->pcomponent_ids == NULL || gather_data->component_ids_hash == NULL); - - if ((gather_data->all_instances || !comp_data->is_detached) && g_strcmp0 (e_cal_component_id_get_uid (id), gather_data->uid) == 0) { - if (gather_data->component_ids_hash) { - ComponentData *comp_data_copy; - - comp_data_copy = component_data_new (comp_data->component, - comp_data->instance_start, comp_data->instance_end, - comp_data->is_detached); - - if (gather_data->copy_ids) { - g_hash_table_insert (gather_data->component_ids_hash, - e_cal_component_id_copy (id), comp_data_copy); - } else { - g_hash_table_insert (gather_data->component_ids_hash, id, comp_data_copy); - } - } else if (gather_data->copy_ids) { - *gather_data->pcomponent_ids = g_list_prepend (*gather_data->pcomponent_ids, - e_cal_component_id_copy (id)); - } else { - *gather_data->pcomponent_ids = g_list_prepend (*gather_data->pcomponent_ids, id); - } - } -} - -typedef struct _NotifyRecurrencesData { - ECalDataModel *data_model; - ECalClient *client; -} NotifyRecurrencesData; - -static gboolean -cal_data_model_notify_recurrences_cb (gpointer user_data) -{ - NotifyRecurrencesData *notif_data = user_data; - ECalDataModel *data_model; - ViewData *view_data; - - g_return_val_if_fail (notif_data != NULL, FALSE); - - data_model = notif_data->data_model; - - LOCK_PROPS (); - - view_data = g_hash_table_lookup (data_model->priv->views, notif_data->client); - if (view_data) - view_data_ref (view_data); - - UNLOCK_PROPS (); - - if (view_data) { - GHashTable *gathered_uids; - GHashTable *known_instances; - GSList *expanded_recurrences, *link; - - view_data_lock (view_data); - expanded_recurrences = view_data->expanded_recurrences; - view_data->expanded_recurrences = NULL; - - cal_data_model_freeze_all_subscribers (data_model); - - gathered_uids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - known_instances = g_hash_table_new_full ( - (GHashFunc) e_cal_component_id_hash, (GEqualFunc) e_cal_component_id_equal, - (GDestroyNotify) e_cal_component_id_free, component_data_free); - - for (link = expanded_recurrences; link && view_data->is_used; link = g_slist_next (link)) { - ComponentData *comp_data = link->data; - ICalComponent *icomp; - const gchar *uid; - - if (!comp_data) - continue; - - icomp = e_cal_component_get_icalcomponent (comp_data->component); - if (!icomp || !i_cal_component_get_uid (icomp)) - continue; - - uid = i_cal_component_get_uid (icomp); - - if (!g_hash_table_contains (gathered_uids, uid)) { - GatherComponentsData gather_data; - - gather_data.uid = uid; - gather_data.pcomponent_ids = NULL; - gather_data.component_ids_hash = known_instances; - gather_data.copy_ids = TRUE; - gather_data.all_instances = FALSE; - - g_hash_table_foreach (view_data->components, - cal_data_model_gather_components, &gather_data); - - g_hash_table_insert (gathered_uids, g_strdup (uid), GINT_TO_POINTER (1)); - } - - /* Steal the comp_data */ - link->data = NULL; - - cal_data_model_process_added_component (data_model, view_data, comp_data, known_instances); - } - - if (view_data->is_used && g_hash_table_size (known_instances) > 0) { - cal_data_model_remove_components (data_model, view_data->client, known_instances, view_data->components); - g_hash_table_remove_all (known_instances); - } - - if (g_atomic_int_dec_and_test (&view_data->pending_expand_recurrences) && - view_data->is_used && view_data->lost_components && view_data->received_complete) { - cal_data_model_remove_components (data_model, view_data->client, view_data->lost_components, NULL); - g_hash_table_destroy (view_data->lost_components); - view_data->lost_components = NULL; - } - - g_hash_table_destroy (gathered_uids); - g_hash_table_destroy (known_instances); - - view_data_unlock (view_data); - - cal_data_model_thaw_all_subscribers (data_model); - - view_data_unref (view_data); - - g_slist_free_full (expanded_recurrences, component_data_free); - } - - g_clear_object (¬if_data->client); - g_clear_object (¬if_data->data_model); - g_free (notif_data); - - return FALSE; -} - -typedef struct -{ - ECalClient *client; - ICalTimezone *zone; - GSList **pexpanded_recurrences; - gboolean skip_cancelled; -} GenerateInstancesData; - -static gboolean -cal_data_model_instance_generated (ICalComponent *icomp, - ICalTime *instance_start, - ICalTime *instance_end, - gpointer user_data, - GCancellable *cancellable, - GError **error) -{ - GenerateInstancesData *gid = user_data; - ComponentData *comp_data; - ECalComponent *comp_copy; - ICalTime *tt, *tt2; - time_t start_tt, end_tt; - - g_return_val_if_fail (gid != NULL, FALSE); - - if (gid->skip_cancelled) { - ICalProperty *prop; - - prop = i_cal_component_get_first_property (icomp, I_CAL_STATUS_PROPERTY); - if (prop && i_cal_property_get_status (prop) == I_CAL_STATUS_CANCELLED) { - g_object_unref (prop); - return TRUE; - } - - g_clear_object (&prop); - } - - comp_copy = e_cal_component_new_from_icalcomponent (i_cal_component_clone (icomp)); - g_return_val_if_fail (comp_copy != NULL, FALSE); - - tt = i_cal_component_get_dtstart (e_cal_component_get_icalcomponent (comp_copy)); - tt2 = i_cal_time_convert_to_zone (instance_start, gid->zone); - if (i_cal_time_is_date (tt) || !i_cal_time_get_timezone (tt) || i_cal_time_is_utc (tt)) - i_cal_time_set_timezone (tt2, NULL); - else - i_cal_time_set_timezone (tt2, gid->zone); - i_cal_component_set_dtstart (e_cal_component_get_icalcomponent (comp_copy), tt2); - g_clear_object (&tt); - g_clear_object (&tt2); - - tt = i_cal_component_get_dtend (e_cal_component_get_icalcomponent (comp_copy)); - tt2 = i_cal_time_convert_to_zone (instance_end, gid->zone); - if (i_cal_time_is_date (tt) || !i_cal_time_get_timezone (tt) || i_cal_time_is_utc (tt)) - i_cal_time_set_timezone (tt2, NULL); - else - i_cal_time_set_timezone (tt2, gid->zone); - i_cal_component_set_dtend (e_cal_component_get_icalcomponent (comp_copy), tt2); - g_clear_object (&tt); - g_clear_object (&tt2); - - cal_comp_get_instance_times (gid->client, e_cal_component_get_icalcomponent (comp_copy), - gid->zone, &tt, &tt2, cancellable); - - start_tt = i_cal_time_as_timet (tt); - end_tt = i_cal_time_as_timet (tt2); - - g_clear_object (&tt); - g_clear_object (&tt2); - - if (end_tt > start_tt) - end_tt--; - - comp_data = component_data_new (comp_copy, start_tt, end_tt, FALSE); - *gid->pexpanded_recurrences = g_slist_prepend (*gid->pexpanded_recurrences, comp_data); - - g_object_unref (comp_copy); - - return TRUE; -} - -static void -cal_data_model_expand_recurrences_thread (ECalDataModel *data_model, - gpointer user_data) -{ - ECalClient *client = user_data; - GSList *to_expand_recurrences, *link; - GSList *expanded_recurrences = NULL; - time_t range_start, range_end; - ViewData *view_data; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - - LOCK_PROPS (); - - view_data = g_hash_table_lookup (data_model->priv->views, client); - if (view_data) - view_data_ref (view_data); - - range_start = data_model->priv->range_start; - range_end = data_model->priv->range_end; - if (range_end <= range_start) { - range_start = 0; - range_end = time (NULL); - } - - UNLOCK_PROPS (); - - if (!view_data) { - g_object_unref (client); - return; - } - - view_data_lock (view_data); - - if (!view_data->is_used) { - view_data_unlock (view_data); - view_data_unref (view_data); - g_object_unref (client); - return; - } - - to_expand_recurrences = view_data->to_expand_recurrences; - view_data->to_expand_recurrences = NULL; - - view_data_unlock (view_data); - - for (link = to_expand_recurrences; link && view_data->is_used; link = g_slist_next (link)) { - ICalComponent *icomp = link->data; - GenerateInstancesData gid; - - if (!icomp) - continue; - - gid.client = client; - gid.pexpanded_recurrences = &expanded_recurrences; - gid.zone = g_object_ref (data_model->priv->zone); - gid.skip_cancelled = data_model->priv->skip_cancelled; - - e_cal_client_generate_instances_for_object_sync (client, icomp, range_start, range_end, NULL, - cal_data_model_instance_generated, &gid); - - g_clear_object (&gid.zone); - } - - g_slist_free_full (to_expand_recurrences, g_object_unref); - - view_data_lock (view_data); - if (expanded_recurrences) - view_data->expanded_recurrences = g_slist_concat (view_data->expanded_recurrences, expanded_recurrences); - if (view_data->is_used) { - NotifyRecurrencesData *notif_data; - - notif_data = g_new0 (NotifyRecurrencesData, 1); - notif_data->data_model = g_object_ref (data_model); - notif_data->client = g_object_ref (client); - - g_timeout_add (1, cal_data_model_notify_recurrences_cb, notif_data); - } - - view_data_unlock (view_data); - view_data_unref (view_data); - g_object_unref (client); -} - -static void -cal_data_model_process_modified_or_added_objects (ECalClientView *view, - const GSList *objects, - ECalDataModel *data_model, - gboolean is_add) -{ - ViewData *view_data; - ECalClient *client; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - - LOCK_PROPS (); - - client = e_cal_client_view_ref_client (view); - if (!client) { - UNLOCK_PROPS (); - return; - } - - view_data = g_hash_table_lookup (data_model->priv->views, client); - if (view_data) { - view_data_ref (view_data); - g_warn_if_fail (view_data->view == view); - } - - UNLOCK_PROPS (); - - if (!view_data) { - g_clear_object (&client); - return; - } - - view_data_lock (view_data); - - if (view_data->is_used) { - const GSList *link; - GSList *to_expand_recurrences = NULL; - - if (!is_add) { - /* Received a modify before the view was claimed as being complete, - aka fully populated, thus drop any previously known components, - because there is no hope for a merge. */ - if (view_data->lost_components) { - cal_data_model_remove_components (data_model, client, view_data->lost_components, NULL); - g_hash_table_destroy (view_data->lost_components); - view_data->lost_components = NULL; - } - } - - cal_data_model_freeze_all_subscribers (data_model); - - for (link = objects; link; link = g_slist_next (link)) { - ICalComponent *icomp = link->data; - - if (!icomp || !i_cal_component_get_uid (icomp)) - continue; - - if (data_model->priv->expand_recurrences && - !e_cal_util_component_is_instance (icomp) && - e_cal_util_component_has_recurrences (icomp)) { - /* This component requires an expand of recurrences, which - will be done in a dedicated thread, thus remember it */ - to_expand_recurrences = g_slist_prepend (to_expand_recurrences, - i_cal_component_clone (icomp)); - } else { - /* Single or detached instance, the simple case */ - ECalComponent *comp; - ComponentData *comp_data; - ICalTime *start_tt = NULL, *end_tt = NULL; - time_t instance_start, instance_end; - - if (data_model->priv->skip_cancelled && - i_cal_component_get_status (icomp) == I_CAL_STATUS_CANCELLED) - continue; - - comp = e_cal_component_new_from_icalcomponent (i_cal_component_clone (icomp)); - if (!comp) - continue; - - cal_comp_get_instance_times (client, icomp, data_model->priv->zone, &start_tt, &end_tt, NULL); - - instance_start = i_cal_time_as_timet (start_tt); - instance_end = i_cal_time_as_timet (end_tt); - - g_clear_object (&start_tt); - g_clear_object (&end_tt); - - if (instance_end > instance_start) - instance_end--; - - comp_data = component_data_new (comp, instance_start, instance_end, - e_cal_util_component_is_instance (icomp)); - - cal_data_model_process_added_component (data_model, view_data, comp_data, NULL); - - g_object_unref (comp); - } - } - - cal_data_model_thaw_all_subscribers (data_model); - - if (to_expand_recurrences) { - view_data_lock (view_data); - view_data->to_expand_recurrences = g_slist_concat ( - view_data->to_expand_recurrences, to_expand_recurrences); - g_atomic_int_inc (&view_data->pending_expand_recurrences); - view_data_unlock (view_data); - - cal_data_model_submit_internal_thread_job (data_model, - cal_data_model_expand_recurrences_thread, g_object_ref (client)); - } - } - - view_data_unlock (view_data); - view_data_unref (view_data); - - g_clear_object (&client); -} - -static void -cal_data_model_view_objects_added (ECalClientView *view, - const GSList *objects, - ECalDataModel *data_model) -{ - cal_data_model_process_modified_or_added_objects (view, objects, data_model, TRUE); -} - -static void -cal_data_model_view_objects_modified (ECalClientView *view, - const GSList *objects, - ECalDataModel *data_model) -{ - cal_data_model_process_modified_or_added_objects (view, objects, data_model, FALSE); -} - -static void -cal_data_model_view_objects_removed (ECalClientView *view, - const GSList *uids, - ECalDataModel *data_model) -{ - ViewData *view_data; - ECalClient *client; - const GSList *link; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - - LOCK_PROPS (); - - client = e_cal_client_view_ref_client (view); - if (!client) { - UNLOCK_PROPS (); - return; - } - - view_data = g_hash_table_lookup (data_model->priv->views, client); - - g_clear_object (&client); - - if (view_data) { - view_data_ref (view_data); - g_warn_if_fail (view_data->view == view); - } - - UNLOCK_PROPS (); - - if (!view_data) - return; - - view_data_lock (view_data); - if (view_data->is_used) { - GHashTable *gathered_uids; - GList *removed = NULL, *rlink; - - gathered_uids = g_hash_table_new (g_str_hash, g_str_equal); - - for (link = uids; link; link = g_slist_next (link)) { - const ECalComponentId *id = link->data; - - if (id) { - if (!e_cal_component_id_get_rid (id)) { - if (!g_hash_table_contains (gathered_uids, e_cal_component_id_get_uid (id))) { - GatherComponentsData gather_data; - - gather_data.uid = e_cal_component_id_get_uid (id); - gather_data.pcomponent_ids = &removed; - gather_data.component_ids_hash = NULL; - gather_data.copy_ids = TRUE; - gather_data.all_instances = TRUE; - - g_hash_table_foreach (view_data->components, - cal_data_model_gather_components, &gather_data); - if (view_data->lost_components) - g_hash_table_foreach (view_data->lost_components, - cal_data_model_gather_components, &gather_data); - - g_hash_table_insert (gathered_uids, (gpointer) e_cal_component_id_get_uid (id), GINT_TO_POINTER (1)); - } - } else { - removed = g_list_prepend (removed, e_cal_component_id_copy (id)); - } - } - } - - cal_data_model_freeze_all_subscribers (data_model); - - for (rlink = removed; rlink; rlink = g_list_next (rlink)) { - ECalComponentId *id = rlink->data; - - if (id) { - ComponentData *comp_data; - time_t instance_start = (time_t) 0, instance_end = (time_t) 0; - - /* Try to limit which subscribers will be notified about removal */ - comp_data = g_hash_table_lookup (view_data->components, id); - if (comp_data) { - instance_start = comp_data->instance_start; - instance_end = comp_data->instance_end; - } else if (view_data->lost_components) { - comp_data = g_hash_table_lookup (view_data->lost_components, id); - if (comp_data) { - instance_start = comp_data->instance_start; - instance_end = comp_data->instance_end; - } - } - - g_hash_table_remove (view_data->components, id); - if (view_data->lost_components) - g_hash_table_remove (view_data->lost_components, id); - - cal_data_model_foreach_subscriber_in_range (data_model, view_data->client, - instance_start, instance_end, - cal_data_model_remove_one_view_component_cb, id); - } - } - - cal_data_model_thaw_all_subscribers (data_model); - - g_list_free_full (removed, (GDestroyNotify) e_cal_component_id_free); - g_hash_table_destroy (gathered_uids); - } - view_data_unlock (view_data); - view_data_unref (view_data); -} - -static void -cal_data_model_view_progress (ECalClientView *view, - guint percent, - const gchar *message, - ECalDataModel *data_model) -{ - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - - cal_data_model_emit_view_state_changed (data_model, view, E_CAL_DATA_MODEL_VIEW_STATE_PROGRESS, percent, message, NULL); -} - -static void -cal_data_model_view_complete (ECalClientView *view, - const GError *error, - ECalDataModel *data_model) -{ - ViewData *view_data; - ECalClient *client; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - - LOCK_PROPS (); - - client = e_cal_client_view_ref_client (view); - if (!client) { - UNLOCK_PROPS (); - return; - } - - view_data = g_hash_table_lookup (data_model->priv->views, client); - - g_clear_object (&client); - - if (view_data) { - view_data_ref (view_data); - g_warn_if_fail (view_data->view == view); - } - - UNLOCK_PROPS (); - - if (!view_data) - return; - - view_data_lock (view_data); - - view_data->received_complete = TRUE; - if (view_data->is_used && - view_data->lost_components && - !view_data->pending_expand_recurrences) { - cal_data_model_remove_components (data_model, view_data->client, view_data->lost_components, NULL); - g_hash_table_destroy (view_data->lost_components); - view_data->lost_components = NULL; - } - - cal_data_model_emit_view_state_changed (data_model, view, E_CAL_DATA_MODEL_VIEW_STATE_COMPLETE, 0, NULL, error); - - view_data_unlock (view_data); - view_data_unref (view_data); -} - -typedef struct _CreateViewData { - ECalDataModel *data_model; - ECalClient *client; -} CreateViewData; - -static void -create_view_data_free (gpointer ptr) -{ - CreateViewData *cv_data = ptr; - - if (cv_data) { - g_clear_object (&cv_data->data_model); - g_clear_object (&cv_data->client); - g_free (cv_data); - } -} - -static void -cal_data_model_create_view_thread (gpointer user_data, - GCancellable *cancellable, - GError **error) -{ - CreateViewData *cv_data = user_data; - ViewData *view_data; - ECalDataModel *data_model; - ECalClient *client; - ECalClientView *view; - gchar *filter; - - g_return_if_fail (cv_data != NULL); - - data_model = cv_data->data_model; - client = cv_data->client; - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - g_return_if_fail (E_IS_CAL_CLIENT (client)); - - LOCK_PROPS (); - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) { - UNLOCK_PROPS (); - return; - } - - view_data = g_hash_table_lookup (data_model->priv->views, client); - if (!view_data) { - UNLOCK_PROPS (); - g_warn_if_reached (); - return; - } - - filter = g_strdup (data_model->priv->full_filter); - - view_data_ref (view_data); - UNLOCK_PROPS (); - - view_data_lock (view_data); - g_warn_if_fail (view_data->view == NULL); - - if (!e_cal_client_get_view_sync (client, filter, &view_data->view, cancellable, error)) { - view_data_unlock (view_data); - view_data_unref (view_data); - g_free (filter); - return; - } - - g_warn_if_fail (view_data->view != NULL); - - view_data->objects_added_id = g_signal_connect (view_data->view, "objects-added", - G_CALLBACK (cal_data_model_view_objects_added), data_model); - view_data->objects_modified_id = g_signal_connect (view_data->view, "objects-modified", - G_CALLBACK (cal_data_model_view_objects_modified), data_model); - view_data->objects_removed_id = g_signal_connect (view_data->view, "objects-removed", - G_CALLBACK (cal_data_model_view_objects_removed), data_model); - view_data->progress_id = g_signal_connect (view_data->view, "progress", - G_CALLBACK (cal_data_model_view_progress), data_model); - view_data->complete_id = g_signal_connect (view_data->view, "complete", - G_CALLBACK (cal_data_model_view_complete), data_model); - - view = g_object_ref (view_data->view); - - view_data_unlock (view_data); - view_data_unref (view_data); - - g_free (filter); - - if (!g_cancellable_is_cancelled (cancellable)) { - cal_data_model_emit_view_state_changed (data_model, view, E_CAL_DATA_MODEL_VIEW_STATE_START, 0, NULL, NULL); - e_cal_client_view_start (view, error); - } - - g_clear_object (&view); -} - -typedef struct _NotifyRemoveComponentsData { - ECalDataModel *data_model; - ECalClient *client; -} NotifyRemoveComponentsData; - -static void -cal_data_model_notify_remove_components_cb (gpointer key, - gpointer value, - gpointer user_data) -{ - ECalComponentId *id = key; - ComponentData *comp_data = value; - NotifyRemoveComponentsData *nrc_data = user_data; - - g_return_if_fail (id != NULL); - g_return_if_fail (comp_data != NULL); - g_return_if_fail (nrc_data != NULL); - - cal_data_model_foreach_subscriber_in_range (nrc_data->data_model, nrc_data->client, - comp_data->instance_start, comp_data->instance_end, - cal_data_model_remove_one_view_component_cb, id); -} - -static void -cal_data_model_update_client_view (ECalDataModel *data_model, - ECalClient *client) -{ - ViewData *view_data; - CreateViewData *cv_data; - - LOCK_PROPS (); - - view_data = g_hash_table_lookup (data_model->priv->views, client); - if (!view_data) { - view_data = view_data_new (client); - g_hash_table_insert (data_model->priv->views, client, view_data); - } - - view_data_lock (view_data); - - if (view_data->cancellable) - g_cancellable_cancel (view_data->cancellable); - g_clear_object (&view_data->cancellable); - - if (view_data->view) { - view_data_disconnect_view (view_data); - cal_data_model_emit_view_state_changed (data_model, view_data->view, E_CAL_DATA_MODEL_VIEW_STATE_STOP, 0, NULL, NULL); - g_clear_object (&view_data->view); - } - - if (!view_data->received_complete) { - NotifyRemoveComponentsData nrc_data; - - nrc_data.data_model = data_model; - nrc_data.client = client; - - cal_data_model_freeze_all_subscribers (data_model); - - g_hash_table_foreach (view_data->components, - cal_data_model_notify_remove_components_cb, &nrc_data); - - g_hash_table_remove_all (view_data->components); - if (view_data->lost_components) { - g_hash_table_foreach (view_data->lost_components, - cal_data_model_notify_remove_components_cb, &nrc_data); - - g_hash_table_destroy (view_data->lost_components); - view_data->lost_components = NULL; - } - - cal_data_model_thaw_all_subscribers (data_model); - } else { - if (view_data->lost_components) { - NotifyRemoveComponentsData nrc_data; - - nrc_data.data_model = data_model; - nrc_data.client = client; - - cal_data_model_freeze_all_subscribers (data_model); - g_hash_table_foreach (view_data->lost_components, - cal_data_model_notify_remove_components_cb, &nrc_data); - cal_data_model_thaw_all_subscribers (data_model); - - g_hash_table_destroy (view_data->lost_components); - view_data->lost_components = NULL; - } - - view_data->lost_components = view_data->components; - view_data->components = g_hash_table_new_full ( - (GHashFunc) e_cal_component_id_hash, (GEqualFunc) e_cal_component_id_equal, - (GDestroyNotify) e_cal_component_id_free, component_data_free); - } - - view_data_unlock (view_data); - - if (!data_model->priv->full_filter) { - UNLOCK_PROPS (); - return; - } - - cv_data = g_new0 (CreateViewData, 1); - cv_data->data_model = g_object_ref (data_model); - cv_data->client = g_object_ref (client); - - view_data->received_complete = FALSE; - view_data->cancellable = e_cal_data_model_submit_thread_job (data_model, - cal_data_model_create_view_thread, cv_data, create_view_data_free); - - UNLOCK_PROPS (); -} - -static void -cal_data_model_remove_client_view (ECalDataModel *data_model, - ECalClient *client) -{ - ViewData *view_data; - - LOCK_PROPS (); - - view_data = g_hash_table_lookup (data_model->priv->views, client); - - if (view_data) { - NotifyRemoveComponentsData nrc_data; - - view_data_lock (view_data); - - nrc_data.data_model = data_model; - nrc_data.client = client; - - cal_data_model_freeze_all_subscribers (data_model); - - g_hash_table_foreach (view_data->components, - cal_data_model_notify_remove_components_cb, &nrc_data); - g_hash_table_remove_all (view_data->components); - - if (view_data->lost_components) { - g_hash_table_foreach (view_data->lost_components, - cal_data_model_notify_remove_components_cb, &nrc_data); - g_hash_table_remove_all (view_data->lost_components); - } - - cal_data_model_thaw_all_subscribers (data_model); - - if (view_data->view) - cal_data_model_emit_view_state_changed (data_model, view_data->view, E_CAL_DATA_MODEL_VIEW_STATE_STOP, 0, NULL, NULL); - - view_data->is_used = FALSE; - view_data_unlock (view_data); - - g_hash_table_remove (data_model->priv->views, client); - } - - UNLOCK_PROPS (); -} - -static gboolean -cal_data_model_add_to_subscriber (ECalDataModel *data_model, - ECalClient *client, - const ECalComponentId *id, - ECalComponent *component, - time_t instance_start, - time_t instance_end, - gpointer user_data) -{ - ECalDataModelSubscriber *subscriber = user_data; - - g_return_val_if_fail (subscriber != NULL, FALSE); - g_return_val_if_fail (id != NULL, FALSE); - - e_cal_data_model_subscriber_component_added (subscriber, client, component); - - return TRUE; -} - -static gboolean -cal_data_model_add_to_subscriber_except_its_range (ECalDataModel *data_model, - ECalClient *client, - const ECalComponentId *id, - ECalComponent *component, - time_t instance_start, - time_t instance_end, - gpointer user_data) -{ - SubscriberData *subs_data = user_data; - - g_return_val_if_fail (subs_data != NULL, FALSE); - g_return_val_if_fail (id != NULL, FALSE); - - /* subs_data should have set the old time range, which - means only components which didn't fit into the old - time range will be added */ - if (instance_start >= subs_data->range_end || instance_end <= subs_data->range_start) - e_cal_data_model_subscriber_component_added (subs_data->subscriber, client, component); - - return TRUE; -} - -static gboolean -cal_data_model_remove_from_subscriber_except_its_range (ECalDataModel *data_model, - ECalClient *client, - const ECalComponentId *id, - ECalComponent *component, - time_t instance_start, - time_t instance_end, - gpointer user_data) -{ - SubscriberData *subs_data = user_data; - - g_return_val_if_fail (subs_data != NULL, FALSE); - g_return_val_if_fail (id != NULL, FALSE); - - /* subs_data should have set the new time range, which - means only components which don't fit into this new - time range will be removed */ - if (instance_start >= subs_data->range_end || instance_end <= subs_data->range_start) - e_cal_data_model_subscriber_component_removed (subs_data->subscriber, client, - e_cal_component_id_get_uid (id), - e_cal_component_id_get_rid (id)); - - return TRUE; -} - -static void -cal_data_model_set_client_default_zone_cb (gpointer key, - gpointer value, - gpointer user_data) -{ - ECalClient *client = value; - ICalTimezone *zone = user_data; - - g_return_if_fail (E_IS_CAL_CLIENT (client)); - g_return_if_fail (zone != NULL); - - e_cal_client_set_default_timezone (client, zone); -} - -static void -cal_data_model_rebuild_everything (ECalDataModel *data_model, - gboolean complete_rebuild) -{ - GHashTableIter iter; - gpointer key, value; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - - LOCK_PROPS (); - - if (data_model->priv->views_update_freeze > 0) { - data_model->priv->views_update_required = TRUE; - UNLOCK_PROPS (); - return; - } - - data_model->priv->views_update_required = FALSE; - - g_hash_table_iter_init (&iter, data_model->priv->clients); - while (g_hash_table_iter_next (&iter, &key, &value)) { - ECalClient *client = value; - - if (complete_rebuild) - cal_data_model_remove_client_view (data_model, client); - cal_data_model_update_client_view (data_model, client); - } - - UNLOCK_PROPS (); -} - -static void -cal_data_model_update_time_range (ECalDataModel *data_model) -{ - time_t range_start, range_end; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - - LOCK_PROPS (); - - if (data_model->priv->disposing) { - UNLOCK_PROPS (); - - return; - } - - range_start = data_model->priv->range_start; - range_end = data_model->priv->range_end; - - cal_data_model_calc_range (data_model, &range_start, &range_end); - - if (data_model->priv->range_start != range_start || - data_model->priv->range_end != range_end) { - data_model->priv->range_start = range_start; - data_model->priv->range_end = range_end; - - if (cal_data_model_update_full_filter (data_model)) - cal_data_model_rebuild_everything (data_model, FALSE); - } - - UNLOCK_PROPS (); -} - -static void -cal_data_model_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_EXPAND_RECURRENCES: - e_cal_data_model_set_expand_recurrences ( - E_CAL_DATA_MODEL (object), - g_value_get_boolean (value)); - return; - - case PROP_TIMEZONE: - e_cal_data_model_set_timezone ( - E_CAL_DATA_MODEL (object), - g_value_get_pointer (value)); - return; - - case PROP_SKIP_CANCELLED: - e_cal_data_model_set_skip_cancelled ( - E_CAL_DATA_MODEL (object), - g_value_get_boolean (value)); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -cal_data_model_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - switch (property_id) { - case PROP_EXPAND_RECURRENCES: - g_value_set_boolean ( - value, - e_cal_data_model_get_expand_recurrences ( - E_CAL_DATA_MODEL (object))); - return; - - case PROP_TIMEZONE: - g_value_set_pointer ( - value, - e_cal_data_model_get_timezone ( - E_CAL_DATA_MODEL (object))); - return; - - case PROP_SKIP_CANCELLED: - g_value_set_boolean ( - value, - e_cal_data_model_get_skip_cancelled ( - E_CAL_DATA_MODEL (object))); - return; - } - - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); -} - -static void -cal_data_model_dispose (GObject *object) -{ - ECalDataModel *data_model = E_CAL_DATA_MODEL (object); - - data_model->priv->disposing = TRUE; - - /* Chain up to parent's method. */ - G_OBJECT_CLASS (e_cal_data_model_parent_class)->dispose (object); -} - -static void -cal_data_model_finalize (GObject *object) -{ - ECalDataModel *data_model = E_CAL_DATA_MODEL (object); - - g_thread_pool_free (data_model->priv->thread_pool, TRUE, FALSE); - g_hash_table_destroy (data_model->priv->clients); - g_hash_table_destroy (data_model->priv->views); - g_slist_free_full (data_model->priv->subscribers, subscriber_data_free); - g_free (data_model->priv->filter); - g_free (data_model->priv->full_filter); - g_clear_object (&data_model->priv->zone); - - g_rec_mutex_clear (&data_model->priv->props_lock); - - /* Chain up to parent's method. */ - G_OBJECT_CLASS (e_cal_data_model_parent_class)->finalize (object); -} - -static void -e_cal_data_model_class_init (ECalDataModelClass *class) -{ - GObjectClass *object_class; - - g_type_class_add_private (class, sizeof (ECalDataModelPrivate)); - - object_class = G_OBJECT_CLASS (class); - object_class->set_property = cal_data_model_set_property; - object_class->get_property = cal_data_model_get_property; - object_class->dispose = cal_data_model_dispose; - object_class->finalize = cal_data_model_finalize; - - g_object_class_install_property ( - object_class, - PROP_EXPAND_RECURRENCES, - g_param_spec_boolean ( - "expand-recurrences", - "Expand Recurrences", - NULL, - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_TIMEZONE, - g_param_spec_pointer ( - "timezone", - "Time Zone", - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_SKIP_CANCELLED, - g_param_spec_boolean ( - "skip-cancelled", - "Skip Cancelled", - NULL, - FALSE, - G_PARAM_READWRITE)); - - signals[VIEW_STATE_CHANGED] = g_signal_new ( - "view-state-changed", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ECalDataModelClass, view_state_changed), - NULL, NULL, - NULL, - G_TYPE_NONE, 5, E_TYPE_CAL_CLIENT_VIEW, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_ERROR); -} - -static void -e_cal_data_model_init (ECalDataModel *data_model) -{ - data_model->priv = G_TYPE_INSTANCE_GET_PRIVATE (data_model, E_TYPE_CAL_DATA_MODEL, ECalDataModelPrivate); - - /* Suppose the data_model is always created in the main/UI thread */ - data_model->priv->main_thread = g_thread_self (); - data_model->priv->thread_pool = g_thread_pool_new ( - cal_data_model_internal_thread_job_func, data_model, 5, FALSE, NULL); - - data_model->priv->clients = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - data_model->priv->views = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, view_data_unref); - data_model->priv->subscribers = NULL; - - data_model->priv->disposing = FALSE; - data_model->priv->expand_recurrences = FALSE; - data_model->priv->skip_cancelled = FALSE; - data_model->priv->zone = g_object_ref (i_cal_timezone_get_utc_timezone ()); - - data_model->priv->views_update_freeze = 0; - data_model->priv->views_update_required = FALSE; - - g_rec_mutex_init (&data_model->priv->props_lock); -} - -/** - * e_cal_data_model_new: - * @func: a function to be called when the data model needs to create - * a thread job within UI - * - * Creates a new instance of #ECalDataModel. The @func is mandatory, because - * it is used to create new thread jobs with UI feedback. - * - * Returns: (transfer full): A new #ECalDataModel instance - * - * Since: 3.14 - **/ -ECalDataModel * -e_cal_data_model_new (ECalDataModelSubmitThreadJobFunc func) -{ - ECalDataModel *data_model; - - g_return_val_if_fail (func != NULL, NULL); - - data_model = g_object_new (E_TYPE_CAL_DATA_MODEL, NULL); - data_model->priv->submit_thread_job_func = func; - - return data_model; -} - -/** - * e_cal_data_model_new_clone: - * @src_data_model: an #ECalDataModel to clone - * - * Creates a clone of @src_data_model, which means a copy with the same clients, filter and - * other properties set (not the subscribers). - * - * Returns: (transfer full): A new #ECalDataModel instance deriving settings from @src_data_model - * - * Since: 3.14 - **/ -ECalDataModel * -e_cal_data_model_new_clone (ECalDataModel *src_data_model) -{ - ECalDataModel *clone; - GList *clients, *link; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (src_data_model), NULL); - - clone = e_cal_data_model_new (src_data_model->priv->submit_thread_job_func); - - e_cal_data_model_set_expand_recurrences (clone, e_cal_data_model_get_expand_recurrences (src_data_model)); - e_cal_data_model_set_skip_cancelled (clone, e_cal_data_model_get_skip_cancelled (src_data_model)); - e_cal_data_model_set_timezone (clone, e_cal_data_model_get_timezone (src_data_model)); - e_cal_data_model_set_filter (clone, src_data_model->priv->filter); - - clients = e_cal_data_model_get_clients (src_data_model); - for (link = clients; link; link = g_list_next (link)) { - ECalClient *client = link->data; - - e_cal_data_model_add_client (clone, client); - } - - g_list_free_full (clients, g_object_unref); - - return clone; -} - -/** - * e_cal_data_model_get_disposing: - * @data_model: an #EDataModel instance - * - * Obtains whether the @data_model is disposing and will be freed (soon). - * - * Returns: Whether the @data_model is disposing. - * - * Since: 3.14 - **/ -gboolean -e_cal_data_model_get_disposing (ECalDataModel *data_model) -{ - gboolean disposing; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE); - - LOCK_PROPS (); - - disposing = data_model->priv->disposing; - - UNLOCK_PROPS (); - - return disposing; -} - -/** - * e_cal_data_model_set_disposing: - * @data_model: an #EDataModel instance - * @disposing: whether the object is disposing - * - * Sets whether the @data_model is disposing itself (soon). - * If set to %TRUE, then no updates are done on changes - * which would otherwise trigger view and subscriber updates. - * - * Since: 3.14 - **/ -void -e_cal_data_model_set_disposing (ECalDataModel *data_model, - gboolean disposing) -{ - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - - LOCK_PROPS (); - - if ((data_model->priv->disposing ? 1 : 0) == (disposing ? 1 : 0)) { - UNLOCK_PROPS (); - return; - } - - data_model->priv->disposing = disposing; - - UNLOCK_PROPS (); -} - -/** - * e_cal_data_model_get_expand_recurrences: - * @data_model: an #EDataModel instance - * - * Obtains whether the @data_model expands recurrences of recurring - * components by default. The default value is #FALSE, to not expand - * recurrences. - * - * Returns: Whether the @data_model expands recurrences of recurring - * components. - * - * Since: 3.14 - **/ -gboolean -e_cal_data_model_get_expand_recurrences (ECalDataModel *data_model) -{ - gboolean expand_recurrences; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE); - - LOCK_PROPS (); - - expand_recurrences = data_model->priv->expand_recurrences; - - UNLOCK_PROPS (); - - return expand_recurrences; -} - -/** - * e_cal_data_model_set_expand_recurrences: - * @data_model: an #EDataModel instance - * @expand_recurrences: whether to expand recurrences - * - * Sets whether the @data_model should expand recurrences of recurring - * components by default. - * - * Since: 3.14 - **/ -void -e_cal_data_model_set_expand_recurrences (ECalDataModel *data_model, - gboolean expand_recurrences) -{ - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - - LOCK_PROPS (); - - if ((data_model->priv->expand_recurrences ? 1 : 0) == (expand_recurrences ? 1 : 0)) { - UNLOCK_PROPS (); - return; - } - - data_model->priv->expand_recurrences = expand_recurrences; - - cal_data_model_rebuild_everything (data_model, TRUE); - - UNLOCK_PROPS (); -} - -/** - * e_cal_data_model_get_skip_cancelled: - * @data_model: an #EDataModel instance - * - * Obtains whether the @data_model skips cancelled components. - * The default value is #FALSE, to not skip cancelled components. - * - * Returns: Whether the @data_model skips cancelled components. - * - * Since: 3.32 - **/ -gboolean -e_cal_data_model_get_skip_cancelled (ECalDataModel *data_model) -{ - gboolean skip_cancelled; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE); - - LOCK_PROPS (); - - skip_cancelled = data_model->priv->skip_cancelled; - - UNLOCK_PROPS (); - - return skip_cancelled; -} - -/** - * e_cal_data_model_set_skip_cancelled: - * @data_model: an #EDataModel instance - * @skip_cancelled: whether to skip cancelled components - * - * Sets whether the @data_model should skip cancelled components. - * - * Since: 3.32 - **/ -void -e_cal_data_model_set_skip_cancelled (ECalDataModel *data_model, - gboolean skip_cancelled) -{ - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - - LOCK_PROPS (); - - if ((data_model->priv->skip_cancelled ? 1 : 0) == (skip_cancelled ? 1 : 0)) { - UNLOCK_PROPS (); - return; - } - - data_model->priv->skip_cancelled = skip_cancelled; - - cal_data_model_rebuild_everything (data_model, TRUE); - - UNLOCK_PROPS (); -} - -/** - * e_cal_data_model_get_timezone: - * @data_model: an #EDataModel instance - * - * Obtains a timezone being used for calendar views. The returned - * timezone is owned by the @data_model. - * - * Returns: (transfer none): An #ICalTimezone being used for calendar views. - * - * Since: 3.14 - **/ -ICalTimezone * -e_cal_data_model_get_timezone (ECalDataModel *data_model) -{ - ICalTimezone *zone; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL); - - LOCK_PROPS (); - - zone = data_model->priv->zone; - - UNLOCK_PROPS (); - - return zone; -} - -/** - * e_cal_data_model_set_timezone: - * @data_model: an #EDataModel instance - * @zone: an #ICalTimezone - * - * Sets a trimezone to be used for calendar views. This change - * regenerates all views. - * - * Since: 3.14 - **/ -void -e_cal_data_model_set_timezone (ECalDataModel *data_model, - ICalTimezone *zone) -{ - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - g_return_if_fail (zone != NULL); - - LOCK_PROPS (); - - if (data_model->priv->zone != zone) { - g_clear_object (&data_model->priv->zone); - data_model->priv->zone = g_object_ref (zone); - - g_hash_table_foreach (data_model->priv->clients, cal_data_model_set_client_default_zone_cb, zone); - - if (cal_data_model_update_full_filter (data_model)) - cal_data_model_rebuild_everything (data_model, TRUE); - } - - UNLOCK_PROPS (); -} - -/** - * e_cal_data_model_set_filter: - * @data_model: an #EDataModel instance - * @sexp: an expression defining a filter - * - * Sets an additional filter for the views. The filter should not - * contain time constraints, these are meant to be defined by - * subscribers. - * - * Since: 3.14 - **/ -void -e_cal_data_model_set_filter (ECalDataModel *data_model, - const gchar *sexp) -{ - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - g_return_if_fail (sexp != NULL); - - LOCK_PROPS (); - - if (sexp && !*sexp) - sexp = NULL; - - if (g_strcmp0 (data_model->priv->filter, sexp) != 0) { - g_free (data_model->priv->filter); - data_model->priv->filter = g_strdup (sexp); - - if (cal_data_model_update_full_filter (data_model)) - cal_data_model_rebuild_everything (data_model, TRUE); - } - - UNLOCK_PROPS (); -} - -/** - * e_cal_data_model_dup_filter: - * @data_model: an #EDataModel instance - * - * Obtains currently used filter (an expression) for the views. - * - * Returns: (transfer full): A copy of the currently used - * filter for views. Free it with g_free() when done with it. - * Returns #NULL when there is no extra filter set. - * - * Since: 3.14 - **/ -gchar * -e_cal_data_model_dup_filter (ECalDataModel *data_model) -{ - gchar *filter; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL); - - LOCK_PROPS (); - - filter = g_strdup (data_model->priv->filter); - - UNLOCK_PROPS (); - - return filter; -} - -/** - * e_cal_data_model_add_client: - * @data_model: an #EDataModel instance - * @client: an #ECalClient - * - * Adds a new @client into the set of clients which should be used - * to populate data for subscribers. Adding the same client multiple - * times does nothing. - * - * Since: 3.14 - **/ -void -e_cal_data_model_add_client (ECalDataModel *data_model, - ECalClient *client) -{ - ESource *source; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - g_return_if_fail (E_IS_CAL_CLIENT (client)); - - source = e_client_get_source (E_CLIENT (client)); - g_return_if_fail (E_IS_SOURCE (source)); - g_return_if_fail (e_source_get_uid (source) != NULL); - - LOCK_PROPS (); - - if (g_hash_table_contains (data_model->priv->clients, e_source_get_uid (source))) { - UNLOCK_PROPS (); - return; - } - - g_hash_table_insert (data_model->priv->clients, e_source_dup_uid (source), g_object_ref (client)); - - e_cal_client_set_default_timezone (client, data_model->priv->zone); - - cal_data_model_update_client_view (data_model, client); - - UNLOCK_PROPS (); -} - -/** - * e_cal_data_model_remove_client: - * @uid: a UID of a client to remove - * - * Removes a client identified by @uid from a set of clients - * which populate the data for subscribers. Removing the client - * which is not used in the @data_model does nothing. - * - * Since: 3.14 - **/ -void -e_cal_data_model_remove_client (ECalDataModel *data_model, - const gchar *uid) -{ - ECalClient *client; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - g_return_if_fail (uid != NULL); - - LOCK_PROPS (); - - client = g_hash_table_lookup (data_model->priv->clients, uid); - if (!client) { - UNLOCK_PROPS (); - return; - } - - cal_data_model_remove_client_view (data_model, client); - g_hash_table_remove (data_model->priv->clients, uid); - - UNLOCK_PROPS (); -} - -/** - * e_cal_data_model_ref_client: - * @data_model: an #EDataModel instance - * @uid: a UID of a client to return - * - * Obtains an #ECalClient with given @uid from the set of clients - * being used by the @data_modal. Returns #NULL, if no such client - * is used by the @data_model. - * - * Returns: (tranfer full): An #ECalClient with given @uid being - * used by @data_model, or NULL, when no such is used by - * the @data_model. Unref returned (non-NULL) client with - * g_object_unref() when done with it. - * - * Since: 3.14 - **/ -ECalClient * -e_cal_data_model_ref_client (ECalDataModel *data_model, - const gchar *uid) -{ - ECalClient *client; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL); - - LOCK_PROPS (); - - client = g_hash_table_lookup (data_model->priv->clients, uid); - if (client) - g_object_ref (client); - - UNLOCK_PROPS (); - - return client; -} - -/** - * e_cal_data_model_get_clients: - * @data_model: an #EDataModel instance - * - * Obtains a list of all clients being used by the @data_model. - * Each client in the returned list is referenced and the list - * itself is also newly allocated, thus free it with - * g_list_free_full (list, g_object_unref); when done with it. - * - * Returns: (transfer full): A list of currently used #ECalClient-s. - * - * Since: 3.14 - **/ -GList * -e_cal_data_model_get_clients (ECalDataModel *data_model) -{ - GList *clients; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL); - - LOCK_PROPS (); - - clients = g_hash_table_get_values (data_model->priv->clients); - g_list_foreach (clients, (GFunc) g_object_ref, NULL); - - UNLOCK_PROPS (); - - return clients; -} - -static gboolean -cal_data_model_prepend_component (ECalDataModel *data_model, - ECalClient *client, - const ECalComponentId *id, - ECalComponent *comp, - time_t instance_start, - time_t instance_end, - gpointer user_data) -{ - GSList **components = user_data; - - g_return_val_if_fail (components != NULL, FALSE); - g_return_val_if_fail (comp != NULL, FALSE); - - *components = g_slist_prepend (*components, g_object_ref (comp)); - - return TRUE; -} - -/** - * e_cal_data_model_get_components: - * @data_model: an #EDataModel instance - * @in_range_start: Start of the time range - * @in_range_end: End of the time range - * - * Obtains a list of components from the given time range. The time range is - * clamp by the actual time range defined by subscribers (if there is no - * subscriber, or all subscribers define times out of the given time range, - * then no components are returned). - * - * Returns: (transfer full): A #GSList of #ECalComponent-s known for the given - * time range in the time of the call. The #GSList, togher with the components, - * is owned by the caller, which should free it with - * g_slist_free_full (list, g_object_unref); when done with it. - * - * Note: A special case when both @in_range_start and @in_range_end are zero - * is treated as a request for all known components. - * - * Since: 3.14 - **/ -GSList * -e_cal_data_model_get_components (ECalDataModel *data_model, - time_t in_range_start, - time_t in_range_end) -{ - GSList *components = NULL; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), NULL); - - e_cal_data_model_foreach_component (data_model, in_range_start, in_range_end, - cal_data_model_prepend_component, &components); - - return g_slist_reverse (components); -} - -static gboolean -cal_data_model_foreach_component (ECalDataModel *data_model, - time_t in_range_start, - time_t in_range_end, - ECalDataModelForeachFunc func, - gpointer user_data, - gboolean include_lost_components) -{ - GHashTableIter viter; - gpointer key, value; - gboolean checked_all = TRUE; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE); - g_return_val_if_fail (func != NULL, FALSE); - - LOCK_PROPS (); - - /* Is the given time range in the currently used time range? */ - if (!(in_range_start == in_range_end && in_range_start == (time_t) 0) && - (in_range_start > data_model->priv->range_end || - in_range_end < data_model->priv->range_start)) { - UNLOCK_PROPS (); - return checked_all; - } - - g_hash_table_iter_init (&viter, data_model->priv->views); - while (checked_all && g_hash_table_iter_next (&viter, &key, &value)) { - ViewData *view_data = value; - GHashTableIter citer; - - if (!view_data) - continue; - - view_data_lock (view_data); - - g_hash_table_iter_init (&citer, view_data->components); - while (checked_all && g_hash_table_iter_next (&citer, &key, &value)) { - ECalComponentId *id = key; - ComponentData *comp_data = value; - - if (!comp_data) - continue; - - if ((in_range_start == in_range_end && in_range_start == (time_t) 0) || - (comp_data->instance_start < in_range_end && comp_data->instance_end > in_range_start) || - (comp_data->instance_start == comp_data->instance_end && comp_data->instance_end == in_range_start)) { - if (!func (data_model, view_data->client, id, comp_data->component, - comp_data->instance_start, comp_data->instance_end, user_data)) - checked_all = FALSE; - } - } - - if (include_lost_components && view_data->lost_components) { - g_hash_table_iter_init (&citer, view_data->lost_components); - while (checked_all && g_hash_table_iter_next (&citer, &key, &value)) { - ECalComponentId *id = key; - ComponentData *comp_data = value; - - if (!comp_data) - continue; - - if ((in_range_start == in_range_end && in_range_start == (time_t) 0) || - (comp_data->instance_start < in_range_end && comp_data->instance_end > in_range_start) || - (comp_data->instance_start == comp_data->instance_end && comp_data->instance_end == in_range_start)) { - if (!func (data_model, view_data->client, id, comp_data->component, - comp_data->instance_start, comp_data->instance_end, user_data)) - checked_all = FALSE; - } - } - } - - view_data_unlock (view_data); - } - - UNLOCK_PROPS (); - - return checked_all; -} - -/** - * e_cal_data_model_foreach_component: - * @data_model: an #EDataModel instance - * @in_range_start: Start of the time range - * @in_range_end: End of the time range - * @func: a function to be called for each component in the given time range - * @user_data: user data being passed into the @func - * - * Calls @func for each component in the given time range. The time range is - * clamp by the actual time range defined by subscribers (if there is no - * subscriber, or all subscribers define times out of the given time range, - * then the function is not called at all and a #FALSE is returned). - * - * The @func returns #TRUE to continue the traversal. If it wants to stop - * the traversal earlier, then it returns #FALSE. - * - * Returns: Whether all the components were checked. The returned value is - * usually #TRUE, unless the @func stops traversal earlier. - * - * Note: A special case when both @in_range_start and @in_range_end are zero - * is treated as a request for all known components. - * - * Since: 3.14 - **/ -gboolean -e_cal_data_model_foreach_component (ECalDataModel *data_model, - time_t in_range_start, - time_t in_range_end, - ECalDataModelForeachFunc func, - gpointer user_data) -{ - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE); - g_return_val_if_fail (func != NULL, FALSE); - - return cal_data_model_foreach_component (data_model, in_range_start, in_range_end, func, user_data, FALSE); -} - -/** - * e_cal_data_model_subscribe: - * @data_model: an #EDataModel instance - * @subscriber: an #ECalDataModelSubscriber instance - * @range_start: Start of the time range used by the @subscriber - * @range_end: End of the time range used by the @subscriber - * - * Either adds a new @subscriber to the set of subscribers for this - * @data_model, or changes a time range used by the @subscriber, - * in case it was added to the @data_model earlier. - * - * Reference count of the @subscriber is increased by one, in case - * it is newly added. The reference count is decreased by one - * when e_cal_data_model_unsubscribe() is called. - * - * Note: A special case when both @range_start and @range_end are zero - * is treated as a request with no time constraint. This limits - * the result only to those components which satisfy given filter. - * - * Since: 3.14 - **/ -void -e_cal_data_model_subscribe (ECalDataModel *data_model, - ECalDataModelSubscriber *subscriber, - time_t range_start, - time_t range_end) -{ - SubscriberData *subs_data = NULL; - GSList *link; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber)); - - LOCK_PROPS (); - - for (link = data_model->priv->subscribers; link; link = g_slist_next (link)) { - SubscriberData *subs_data = link->data; - - if (!subs_data) - continue; - - if (subs_data->subscriber == subscriber) - break; - } - - if (link != NULL) { - time_t new_range_start = range_start, new_range_end = range_end; - time_t old_range_start, old_range_end; - - /* The subscriber updates its time range (it is already known) */ - subs_data = link->data; - - /* No range change */ - if (range_start == subs_data->range_start && - range_end == subs_data->range_end) { - UNLOCK_PROPS (); - return; - } - - old_range_start = subs_data->range_start; - old_range_end = subs_data->range_end; - - if (new_range_start == (time_t) 0 && new_range_end == (time_t) 0) { - new_range_start = data_model->priv->range_start; - new_range_end = data_model->priv->range_end; - } - - if (new_range_start == (time_t) 0 && new_range_end == (time_t) 0) { - /* The subscriber is looking for everything and the data_model has everything too */ - e_cal_data_model_subscriber_freeze (subs_data->subscriber); - cal_data_model_foreach_component (data_model, - new_range_start, old_range_start, - cal_data_model_add_to_subscriber_except_its_range, subs_data, TRUE); - e_cal_data_model_subscriber_thaw (subs_data->subscriber); - } else { - e_cal_data_model_subscriber_freeze (subs_data->subscriber); - - if (new_range_start >= old_range_end || - new_range_end <= old_range_start) { - subs_data->range_start = range_start; - subs_data->range_end = range_end; - - /* Completely new range, not overlapping with the former range, - everything previously added can be removed... */ - cal_data_model_foreach_component (data_model, - old_range_start, old_range_end, - cal_data_model_remove_from_subscriber_except_its_range, subs_data, TRUE); - - subs_data->range_start = old_range_start; - subs_data->range_end = old_range_end; - - /* ...and components from the new range can be added */ - cal_data_model_foreach_component (data_model, - new_range_start, new_range_end, - cal_data_model_add_to_subscriber_except_its_range, subs_data, TRUE); - } else { - if (new_range_start < old_range_start) { - /* Add those known in the new extended range from the start */ - cal_data_model_foreach_component (data_model, - new_range_start, old_range_start, - cal_data_model_add_to_subscriber_except_its_range, subs_data, TRUE); - } else if (new_range_start > old_range_start) { - subs_data->range_start = range_start; - subs_data->range_end = range_end; - - /* Remove those out of the new range from the start */ - cal_data_model_foreach_component (data_model, - old_range_start, new_range_start, - cal_data_model_remove_from_subscriber_except_its_range, subs_data, TRUE); - - subs_data->range_start = old_range_start; - subs_data->range_end = old_range_end; - } - - if (new_range_end > old_range_end) { - /* Add those known in the new extended range from the end */ - cal_data_model_foreach_component (data_model, - old_range_end, new_range_end, - cal_data_model_add_to_subscriber_except_its_range, subs_data, TRUE); - } else if (new_range_end < old_range_end) { - subs_data->range_start = range_start; - subs_data->range_end = range_end; - - /* Remove those out of the new range from the end */ - cal_data_model_foreach_component (data_model, - new_range_end, old_range_end, - cal_data_model_remove_from_subscriber_except_its_range, subs_data, TRUE); - - subs_data->range_start = old_range_start; - subs_data->range_end = old_range_end; - } - } - - e_cal_data_model_subscriber_thaw (subs_data->subscriber); - } - - subs_data->range_start = range_start; - subs_data->range_end = range_end; - } else { - subs_data = subscriber_data_new (subscriber, range_start, range_end); - - data_model->priv->subscribers = g_slist_prepend (data_model->priv->subscribers, subs_data); - - e_cal_data_model_subscriber_freeze (subscriber); - cal_data_model_foreach_component (data_model, range_start, range_end, - cal_data_model_add_to_subscriber, subscriber, TRUE); - e_cal_data_model_subscriber_thaw (subscriber); - } - - cal_data_model_update_time_range (data_model); - - UNLOCK_PROPS (); -} - -/** - * e_cal_data_model_unsubscribe: - * @data_model: an #EDataModel instance - * @subscriber: an #ECalDataModelSubscriber instance - * - * Removes the @subscriber from the set of subscribers for the @data_model. - * Remove of the @subscriber, which is not in the set of subscribers for - * the @data_model does nothing. - * - * Note: The @subscriber is not notified about a removal of the components - * which could be added previously, while it was subscribed for the change - * notifications. - * - * Since: 3.14 - **/ -void -e_cal_data_model_unsubscribe (ECalDataModel *data_model, - ECalDataModelSubscriber *subscriber) -{ - GSList *link; - - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - g_return_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber)); - - LOCK_PROPS (); - - for (link = data_model->priv->subscribers; link; link = g_slist_next (link)) { - SubscriberData *subs_data = link->data; - - if (!subs_data) - continue; - - if (subs_data->subscriber == subscriber) { - data_model->priv->subscribers = g_slist_remove (data_model->priv->subscribers, subs_data); - subscriber_data_free (subs_data); - break; - } - } - - cal_data_model_update_time_range (data_model); - - UNLOCK_PROPS (); -} - -/** - * e_cal_data_model_get_subscriber_range: - * @data_model: an #EDataModel instance - * @subscriber: an #ECalDataModelSubscriber instance - * @range_start: (out): time range start for the @subscriber - * @range_end: (out): time range end for the @subscriber - * - * Obtains currently set time range for the @subscriber. In case - * the subscriber is not found returns #FALSE and both @range_start - * and @range_end are left untouched. - * - * Returns: Whether the @subscriber was found and the @range_start with - * the @range_end were set to its current time range it uses. - * - * Since: 3.14 - **/ -gboolean -e_cal_data_model_get_subscriber_range (ECalDataModel *data_model, - ECalDataModelSubscriber *subscriber, - time_t *range_start, - time_t *range_end) -{ - GSList *link; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE); - g_return_val_if_fail (E_IS_CAL_DATA_MODEL_SUBSCRIBER (subscriber), FALSE); - g_return_val_if_fail (range_start, FALSE); - g_return_val_if_fail (range_end, FALSE); - - LOCK_PROPS (); - - for (link = data_model->priv->subscribers; link; link = g_slist_next (link)) { - SubscriberData *subs_data = link->data; - - if (!subs_data) - continue; - - if (subs_data->subscriber == subscriber) { - *range_start = subs_data->range_start; - *range_end = subs_data->range_end; - break; - } - } - - UNLOCK_PROPS (); - - return link != NULL; -} - -/** - * e_cal_data_model_freeze_views_update: - * @data_model: an #EDataModel instance - * - * Freezes any views updates until e_cal_data_model_thaw_views_update() is - * called. This can be called nested, then the same count of the calls of - * e_cal_data_model_thaw_views_update() is expected to unlock the views update. - * - * Since: 3.14 - **/ -void -e_cal_data_model_freeze_views_update (ECalDataModel *data_model) -{ - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - - LOCK_PROPS (); - - data_model->priv->views_update_freeze++; - - UNLOCK_PROPS (); -} - -/** - * e_cal_data_model_thaw_views_update: - * @data_model: an #EDataModel instance - * - * A pair function for e_cal_data_model_freeze_views_update(), to unlock - * views update. - * - * Since: 3.14 - **/ -void -e_cal_data_model_thaw_views_update (ECalDataModel *data_model) -{ - g_return_if_fail (E_IS_CAL_DATA_MODEL (data_model)); - - LOCK_PROPS (); - - if (!data_model->priv->views_update_freeze) { - UNLOCK_PROPS (); - g_warn_if_reached (); - return; - } - - data_model->priv->views_update_freeze--; - if (data_model->priv->views_update_freeze == 0 && - data_model->priv->views_update_required) - cal_data_model_rebuild_everything (data_model, TRUE); - - UNLOCK_PROPS (); -} - -/** - * e_cal_data_model_is_views_update_frozen: - * @data_model: an #EDataModel instance - * - * Check whether any views updates are currently frozen. This is influenced by - * e_cal_data_model_freeze_views_update() and e_cal_data_model_thaw_views_update(). - * - * Returns: Whether any views updates are currently frozen. - * - * Since: 3.14 - **/ -gboolean -e_cal_data_model_is_views_update_frozen (ECalDataModel *data_model) -{ - gboolean is_frozen; - - g_return_val_if_fail (E_IS_CAL_DATA_MODEL (data_model), FALSE); - - LOCK_PROPS (); - - is_frozen = data_model->priv->views_update_freeze > 0; - - UNLOCK_PROPS (); - - return is_frozen; -} diff --git a/contrib/evolution/e-cal-data-model.h b/contrib/evolution/e-cal-data-model.h deleted file mode 100644 index ba79c4de..00000000 --- a/contrib/evolution/e-cal-data-model.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2014 Red Hat, Inc. (www.redhat.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, see . - * - * Authors: Milan Crha - */ - -#ifndef E_CAL_DATA_MODEL_H -#define E_CAL_DATA_MODEL_H - -#include - -#include "e-cal-data-model-subscriber.h" - -/* Standard GObject macros */ -#define E_TYPE_CAL_DATA_MODEL \ - (e_cal_data_model_get_type ()) -#define E_CAL_DATA_MODEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_CAL_DATA_MODEL, ECalDataModel)) -#define E_CAL_DATA_MODEL_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_CAL_DATA_MODEL, ECalDataModelClass)) -#define E_IS_CAL_DATA_MODEL(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_CAL_DATA_MODEL)) -#define E_IS_CAL_DATA_MODEL_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_CAL_DATA_MODEL)) -#define E_CAL_DATA_MODEL_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_CAL_DATA_MODEL, ECalDataModelClass)) - -G_BEGIN_DECLS - -typedef enum { - E_CAL_DATA_MODEL_VIEW_STATE_START, - E_CAL_DATA_MODEL_VIEW_STATE_PROGRESS, - E_CAL_DATA_MODEL_VIEW_STATE_COMPLETE, - E_CAL_DATA_MODEL_VIEW_STATE_STOP -} ECalDataModelViewState; - -typedef struct _ECalDataModel ECalDataModel; -typedef struct _ECalDataModelClass ECalDataModelClass; -typedef struct _ECalDataModelPrivate ECalDataModelPrivate; - -struct _ECalDataModel { - GObject parent; - ECalDataModelPrivate *priv; -}; - -struct _ECalDataModelClass { - GObjectClass parent_class; - - /* Signals */ - void (* view_state_changed) (ECalDataModel *data_model, - ECalClientView *view, - ECalDataModelViewState state, - guint percent, - const gchar *message, - const GError *error); -}; - -typedef void (* EThreadJobFunc) (gpointer user_data, - GCancellable *cancellable, - GError **error); -typedef GCancellable * (* ECalDataModelSubmitThreadJobFunc) - (EThreadJobFunc func, - gpointer user_data, - GDestroyNotify free_user_data); - -GType e_cal_data_model_get_type (void); -ECalDataModel * e_cal_data_model_new (ECalDataModelSubmitThreadJobFunc func); -ECalDataModel * e_cal_data_model_new_clone (ECalDataModel *src_data_model); -GCancellable * e_cal_data_model_submit_thread_job - (ECalDataModel *data_model, - EThreadJobFunc func, - gpointer user_data, - GDestroyNotify free_user_data); -gboolean e_cal_data_model_get_disposing (ECalDataModel *data_model); -void e_cal_data_model_set_disposing (ECalDataModel *data_model, - gboolean disposing); -gboolean e_cal_data_model_get_expand_recurrences - (ECalDataModel *data_model); -void e_cal_data_model_set_expand_recurrences - (ECalDataModel *data_model, - gboolean expand_recurrences); -gboolean e_cal_data_model_get_skip_cancelled - (ECalDataModel *data_model); -void e_cal_data_model_set_skip_cancelled - (ECalDataModel *data_model, - gboolean expand_recurrences); -ICalTimezone * e_cal_data_model_get_timezone (ECalDataModel *data_model); -void e_cal_data_model_set_timezone (ECalDataModel *data_model, - ICalTimezone *zone); -void e_cal_data_model_set_filter (ECalDataModel *data_model, - const gchar *sexp); -gchar * e_cal_data_model_dup_filter (ECalDataModel *data_model); -void e_cal_data_model_add_client (ECalDataModel *data_model, - ECalClient *client); -void e_cal_data_model_remove_client (ECalDataModel *data_model, - const gchar *uid); -ECalClient * e_cal_data_model_ref_client (ECalDataModel *data_model, - const gchar *uid); -GList * e_cal_data_model_get_clients (ECalDataModel *data_model); -GSList * e_cal_data_model_get_components (ECalDataModel *data_model, - time_t in_range_start, - time_t in_range_end); - -typedef gboolean (* ECalDataModelForeachFunc) (ECalDataModel *data_model, - ECalClient *client, - const ECalComponentId *id, - ECalComponent *comp, - time_t instance_start, - time_t instance_end, - gpointer user_data); - -gboolean e_cal_data_model_foreach_component - (ECalDataModel *data_model, - time_t in_range_start, - time_t in_range_end, - ECalDataModelForeachFunc func, - gpointer user_data); - -void e_cal_data_model_subscribe (ECalDataModel *data_model, - ECalDataModelSubscriber *subscriber, - time_t range_start, - time_t range_end); -void e_cal_data_model_unsubscribe (ECalDataModel *data_model, - ECalDataModelSubscriber *subscriber); -gboolean e_cal_data_model_get_subscriber_range - (ECalDataModel *data_model, - ECalDataModelSubscriber *subscriber, - time_t *range_start, - time_t *range_end); -void e_cal_data_model_freeze_views_update - (ECalDataModel *data_model); -void e_cal_data_model_thaw_views_update - (ECalDataModel *data_model); -gboolean e_cal_data_model_is_views_update_frozen - (ECalDataModel *data_model); - -G_END_DECLS - -#endif /* E_CAL_DATA_MODEL_H */ diff --git a/contrib/evolution/meson.build b/contrib/evolution/meson.build deleted file mode 100644 index 8b89b6b4..00000000 --- a/contrib/evolution/meson.build +++ /dev/null @@ -1,23 +0,0 @@ -contrib_incs += [ include_directories('.') ] - -libevolution_files = files( - 'e-cal-data-model.c', - 'e-cal-data-model-subscriber.c' -) - -libevolution_deps = [ - libecal_dep, - libedataserver_dep, -] - -libevolution = static_library( - 'evolution', - dependencies: libevolution_deps, - sources: libevolution_files, - pic: true, -) - -libevolution_dep = declare_dependency( - link_with: libevolution, - include_directories: include_directories('.'), -) diff --git a/contrib/meson.build b/contrib/meson.build deleted file mode 100644 index 7b3624be..00000000 --- a/contrib/meson.build +++ /dev/null @@ -1,3 +0,0 @@ -contrib_incs = [] - -subdir('evolution') diff --git a/meson.build b/meson.build index 79f1c7c2..d269c033 100644 --- a/meson.build +++ b/meson.build @@ -189,7 +189,6 @@ src_dir = join_paths(meson.source_root(), 'src') ########### subdir('build-aux') -subdir('contrib') subdir('data') subdir('src') subdir('po') diff --git a/src/core/gcal-manager.h b/src/core/gcal-manager.h index 1d43da4a..22684e86 100644 --- a/src/core/gcal-manager.h +++ b/src/core/gcal-manager.h @@ -19,7 +19,6 @@ #ifndef __GCAL_MANAGER_H__ #define __GCAL_MANAGER_H__ -#include "e-cal-data-model.h" #include "gcal-calendar.h" #include "gcal-event.h" #include "gcal-types.h" diff --git a/src/meson.build b/src/meson.build index 43187dcf..802b30e0 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,7 +4,6 @@ gcal_deps = [ gsettings_desktop_schemas_dep, libedataserverui_dep, libedataserver_dep, - libevolution_dep, libecal_dep, libdazzle_dep, libsoup_dep, @@ -84,9 +83,6 @@ calendar_incs = [ include_directories('weather'), ] -calendar_incs += contrib_incs - - ################### # Private library # ################### @@ -130,7 +126,6 @@ sources = files( 'search/gcal-search-model.c', 'utils/gcal-date-time-utils.c', 'utils/gcal-source-discoverer.c', - 'utils/gcal-thread-utils.c', 'utils/gcal-utils.c', 'views/gcal-month-cell.c', 'views/gcal-month-popover.c', diff --git a/src/utils/gcal-thread-utils.c b/src/utils/gcal-thread-utils.c deleted file mode 100644 index 2a940ab0..00000000 --- a/src/utils/gcal-thread-utils.c +++ /dev/null @@ -1,101 +0,0 @@ -/* gcal-thread-utils.c - * - * Copyright 2019 Georges Basile Stavracas Neto - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#include "gcal-thread-utils.h" - -/* Code kindly provided by Milan Crha */ - -typedef struct { - EThreadJobFunc func; - gpointer user_data; - GDestroyNotify free_user_data; - - GCancellable *cancellable; - GError *error; -} ThreadJobData; - -static void -thread_job_data_free (gpointer ptr) -{ - ThreadJobData *tjd = ptr; - - if (tjd != NULL) - { - /* This should go to UI with more info/description, - * if it is not G_IOI_ERROR_CANCELLED */ - if (tjd->error != NULL && !g_error_matches (tjd->error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - g_warning ("Job failed: %s\n", tjd->error->message); - - if (tjd->free_user_data != NULL) - tjd->free_user_data (tjd->user_data); - - g_clear_object (&tjd->cancellable); - g_clear_error (&tjd->error); - g_free (tjd); - } -} - -static gpointer -thread_job_thread (gpointer user_data) -{ - ThreadJobData *tjd = user_data; - - g_return_val_if_fail (tjd != NULL, NULL); - - if (tjd->func != NULL) - tjd->func (tjd->user_data, tjd->cancellable, &tjd->error); - - thread_job_data_free (tjd); - - return g_thread_self (); -} - -GCancellable* -gcal_thread_submit_job (EThreadJobFunc func, - gpointer user_data, - GDestroyNotify free_user_data) -{ - ThreadJobData *tjd; - GThread *thread; - GCancellable *cancellable; - - cancellable = g_cancellable_new (); - - tjd = g_new0 (ThreadJobData, 1); - tjd->func = func; - tjd->user_data = user_data; - tjd->free_user_data = free_user_data; - /* user should be able to cancel this cancellable somehow */ - tjd->cancellable = g_object_ref (cancellable); - tjd->error = NULL; - - thread = g_thread_try_new (NULL, thread_job_thread, tjd, &tjd->error); - if (thread != NULL) - { - g_thread_unref (thread); - } - else - { - thread_job_data_free (tjd); - g_clear_object (&cancellable); - } - - return cancellable; -} diff --git a/src/utils/gcal-thread-utils.h b/src/utils/gcal-thread-utils.h deleted file mode 100644 index 646b7885..00000000 --- a/src/utils/gcal-thread-utils.h +++ /dev/null @@ -1,33 +0,0 @@ -/* gcal-thread-utils.h - * - * Copyright 2019 Georges Basile Stavracas Neto - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#pragma once - -#include "e-cal-data-model.h" - -#include - -G_BEGIN_DECLS - -GCancellable* gcal_thread_submit_job (EThreadJobFunc func, - gpointer user_data, - GDestroyNotify free_user_data); - -G_END_DECLS diff --git a/src/utils/gcal-utils.h b/src/utils/gcal-utils.h index 163d8d41..c2edc72d 100644 --- a/src/utils/gcal-utils.h +++ b/src/utils/gcal-utils.h @@ -20,7 +20,6 @@ #define __GCAL_UTILS_H__ #include "gcal-date-time-utils.h" -#include "gcal-thread-utils.h" #include "gcal-manager.h" #include diff --git a/src/views/gcal-month-view.c b/src/views/gcal-month-view.c index e4418106..23c69dd0 100644 --- a/src/views/gcal-month-view.c +++ b/src/views/gcal-month-view.c @@ -20,7 +20,6 @@ #define G_LOG_DOMAIN "GcalMonthView" #include "config.h" -#include "e-cal-data-model-subscriber.h" #include "gcal-application.h" #include "gcal-clock.h" #include "gcal-context.h"