[gnome-calendar/fix-shifting-events] core: Handle exceptions in event list




commit 7d7c27d0750279a1ac2560358187f20951c7a505
Author: Ray Strode <rstrode redhat com>
Date:   Fri Oct 14 17:09:28 2022 -0400

    core: Handle exceptions in event list
    
    If a recurrence of events is set up and one of the events gets
    deleted, that event needs to be marked as an exception on the
    main event so that it doesn't get recreated any time the main
    event is edited.
    
    This commit adds code to manage setting up this exception.

 src/core/gcal-event.c    | 81 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/core/gcal-event.h    |  8 +++--
 src/core/gcal-manager.c  | 18 +++++++++++
 src/core/gcal-timeline.c | 11 +++++--
 4 files changed, 114 insertions(+), 4 deletions(-)
---
diff --git a/src/core/gcal-event.c b/src/core/gcal-event.c
index 88087337..e03ab82b 100644
--- a/src/core/gcal-event.c
+++ b/src/core/gcal-event.c
@@ -95,6 +95,7 @@ struct _GcalEvent
   GBinding           *color_binding;
 
   gboolean            all_day;
+  gboolean            excluded;
 
   /* A map of GcalAlarmType */
   GHashTable         *alarms;
@@ -137,11 +138,41 @@ static GParamSpec* properties[N_PROPS] = { NULL, };
  * Auxiliary methods
  */
 
+static void
+check_if_excluded (GcalEvent  *self)
+{
+  ECalComponentDateTime *date;
+  GSList *exclusion_dates, *node;
+
+  GCAL_TRACE_MSG ("Checking if event should be excluded");
+
+  self->excluded = FALSE;
+
+  date = e_cal_component_get_dtstart (self->component);
+  exclusion_dates = e_cal_component_get_exdates (self->component);
+  for (node = exclusion_dates; node != NULL; node = node->next)
+    {
+      ECalComponentDateTime *exclusion_date = node->data;
+
+      if (i_cal_time_compare (e_cal_component_datetime_get_value (exclusion_date),
+                              e_cal_component_datetime_get_value (date)) == 0)
+        {
+          self->excluded = TRUE;
+          break;
+        }
+    }
+  g_slist_free_full (exclusion_dates, e_cal_component_datetime_free);
+
+  g_clear_pointer (&date, e_cal_component_datetime_free);
+}
+
 static void
 clear_range (GcalEvent *self)
 {
   g_clear_pointer (&self->range, gcal_range_unref);
   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RANGE]);
+
+  check_if_excluded (self);
 }
 
 static GTimeZone*
@@ -392,6 +423,8 @@ setup_component (GcalEvent  *self,
       g_clear_object (&date);
     }
 
+  check_if_excluded (self);
+
   /* Summary */
   text = e_cal_component_get_summary (self->component);
   if (text && e_cal_component_text_get_value (text))
@@ -1001,6 +1034,38 @@ gcal_event_apply_instance (GcalEvent *self,
     }
 }
 
+/**
+ * gcal_event_remove_instance:
+ * @self: a #GcalEvent
+ *
+ * Marks the given instance as an exception in the main event recurrence list,
+ * so it essentially gets removed
+ */
+void
+gcal_event_remove_instance (GcalEvent *self,
+                            GcalEvent *instance)
+{
+  GSList *exceptions;
+  ECalComponentDateTime *instance_date;
+
+  g_return_if_fail (GCAL_IS_EVENT (self));
+
+  if (e_cal_component_is_instance (self->component))
+    return;
+
+  if (!e_cal_component_is_instance (instance->component))
+    return;
+
+  instance_date = e_cal_component_get_dtstart (instance->component);
+  exceptions = e_cal_component_get_exdates (self->component);
+  exceptions = g_slist_prepend (exceptions, instance_date);
+
+  e_cal_component_set_exdates (self->component, exceptions);
+  e_cal_component_commit_sequence (self->component);
+
+  g_slist_free_full (exceptions, e_cal_component_datetime_free);
+}
+
 /**
  * gcal_event_get_all_day:
  * @self: a #GcalEvent
@@ -1209,11 +1274,25 @@ gcal_event_get_range (GcalEvent *self)
       self->range = gcal_range_new (gcal_event_get_date_start (self),
                                     gcal_event_get_date_end (self),
                                     self->all_day ? GCAL_RANGE_DATE_ONLY : GCAL_RANGE_DEFAULT);
+
+      check_if_excluded (self);
     }
 
   return self->range;
 }
 
+/**
+ * gcal_event_get_excluded:
+ * @self: a #GcalEvent
+ *
+ * Retrieves whether or not the event has been excluded by an exdate.
+ */
+gboolean
+gcal_event_get_excluded (GcalEvent *self)
+{
+  return self->excluded;
+}
+
 /**
  * gcal_event_get_description:
  * @self a #GcalEvent
@@ -1847,6 +1926,8 @@ gcal_event_set_recurrence (GcalEvent      *self,
 
   g_clear_object (&rrule);
   g_clear_object (&prop);
+
+  check_if_excluded (self);
 }
 
 /**
diff --git a/src/core/gcal-event.h b/src/core/gcal-event.h
index c124bc55..e24e79d6 100644
--- a/src/core/gcal-event.h
+++ b/src/core/gcal-event.h
@@ -57,8 +57,11 @@ GcalEvent*           gcal_event_new_from_event                   (GcalEvent
 
 GcalEvent*           gcal_event_new_main_event_from_instance_event (GcalEvent        *self);
 
-void                 gcal_event_apply_instance                   (GcalEvent *self,
-                                                                  GcalEvent *instance);
+void                 gcal_event_apply_instance                   (GcalEvent          *self,
+                                                                  GcalEvent          *instance);
+
+void                 gcal_event_remove_instance                  (GcalEvent          *self,
+                                                                  GcalEvent          *instance);
 
 gboolean             gcal_event_get_all_day                      (GcalEvent          *self);
 
@@ -83,6 +86,7 @@ void                 gcal_event_set_date_start                   (GcalEvent
                                                                   GDateTime          *dt);
 
 GcalRange*           gcal_event_get_range                        (GcalEvent          *self);
+gboolean             gcal_event_get_excluded                     (GcalEvent          *self);
 
 const gchar*         gcal_event_get_description                  (GcalEvent          *self);
 
diff --git a/src/core/gcal-manager.c b/src/core/gcal-manager.c
index cf9284d6..3538963e 100644
--- a/src/core/gcal-manager.c
+++ b/src/core/gcal-manager.c
@@ -1115,6 +1115,24 @@ gcal_manager_remove_event (GcalManager           *self,
                               on_event_removed,
                               g_object_ref (event));
 
+  if (mod != GCAL_RECURRENCE_MOD_ALL)
+    {
+      g_autoptr (GcalEvent) main_event = NULL;
+
+      main_event = gcal_event_new_main_event_from_instance_event (event);
+      component = gcal_event_get_component (main_event);
+
+      gcal_event_remove_instance (main_event, event);
+
+      e_cal_client_modify_object (gcal_calendar_get_client (calendar),
+                                  e_cal_component_get_icalcomponent (component),
+                                  (ECalObjModType) GCAL_RECURRENCE_MOD_ALL,
+                                  E_CAL_OPERATION_FLAG_NONE,
+                                  NULL,
+                                  on_event_updated,
+                                  g_object_ref (component));
+    }
+
   g_free (rid);
 
   GCAL_EXIT;
diff --git a/src/core/gcal-timeline.c b/src/core/gcal-timeline.c
index dcec4cb3..fbad9fc6 100644
--- a/src/core/gcal-timeline.c
+++ b/src/core/gcal-timeline.c
@@ -679,7 +679,8 @@ timeline_source_dispatch (GSource     *source,
 
           if (subscriber)
             {
-              add_event_to_subscriber (subscriber, event);
+              if (!gcal_event_get_excluded (event))
+                add_event_to_subscriber (subscriber, event);
               g_hash_table_remove (self->queued_adds, subscriber_event_id);
             }
           break;
@@ -703,7 +704,13 @@ timeline_source_dispatch (GSource     *source,
               }
 
             if (subscriber)
-              update_subscriber_event (subscriber, event);
+              {
+
+                if (!gcal_event_get_excluded (event))
+                  update_subscriber_event (subscriber, event);
+                else
+                  remove_event_from_subscriber (subscriber, event);
+              }
           }
           break;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]