[gnome-calendar/wip/gbsneto/alarms: 6/12] event: add support for alarms



commit 1ddc690810b26c92206ae10431c17ff6970c483c
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Sun Jun 19 11:56:25 2016 -0300

    event: add support for alarms
    
    This commit prepares GcalEvent to handle alarms. Basically,
    it is now able to load the current alarms of an event, and add
    and remove alarms for them.

 src/gcal-event.c |  209 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/gcal-event.h |    9 +++
 2 files changed, 218 insertions(+), 0 deletions(-)
---
diff --git a/src/gcal-event.c b/src/gcal-event.c
index 9cc61a8..f2f9623 100644
--- a/src/gcal-event.c
+++ b/src/gcal-event.c
@@ -43,6 +43,9 @@ struct _GcalEvent
 
   gboolean            all_day;
 
+  /* A map of GcalAlarmType */
+  GHashTable         *alarms;
+
   ECalComponent      *component;
   ESource            *source;
 };
@@ -187,6 +190,65 @@ gcal_event_update_uid_internal (GcalEvent *self)
   g_object_notify (G_OBJECT (self), "uid");
 }
 
+static gint
+get_trigger_minutes (GcalEvent          *self,
+                     ECalComponentAlarm *alarm)
+{
+  ECalComponentAlarmTrigger trigger;
+  GDateTime *alarm_dt;
+  gint diff;
+
+  e_cal_component_alarm_get_trigger (alarm, &trigger);
+
+  /*
+   * We only support alarms relative to the start date, and solely
+   * ignore whetever different it may be.
+   */
+  if (trigger.type != E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START)
+    return -1;
+
+  alarm_dt = g_date_time_add_full (self->dt_start,
+                                   0,
+                                   0,
+                                   - (trigger.u.rel_duration.days + trigger.u.rel_duration.weeks * 7),
+                                   - trigger.u.rel_duration.hours,
+                                   - trigger.u.rel_duration.minutes,
+                                   - trigger.u.rel_duration.seconds);
+
+  diff = g_date_time_difference (self->dt_start, alarm_dt) / G_TIME_SPAN_MINUTE;
+
+  return diff;
+}
+
+static void
+load_alarms (GcalEvent *self)
+{
+  GList *alarm_uids, *l;
+
+  alarm_uids = e_cal_component_get_alarm_uids (self->component);
+
+  for (l = alarm_uids; l != NULL; l = l->next)
+    {
+      ECalComponentAlarm *alarm;
+      gint trigger_minutes;
+
+      alarm = e_cal_component_get_alarm (self->component, l->data);
+      trigger_minutes = get_trigger_minutes (self, alarm);
+
+      /* We only support a single alarm for a given time */
+      if (!g_hash_table_contains (self->alarms, GINT_TO_POINTER (trigger_minutes)))
+        {
+          g_hash_table_insert (self->alarms,
+                               GINT_TO_POINTER (trigger_minutes),
+                               g_strdup (e_cal_component_alarm_get_uid (alarm)));
+        }
+
+      e_cal_component_alarm_free (alarm);
+    }
+
+  cal_obj_uid_list_free (alarm_uids);
+}
+
 static void
 gcal_event_set_component_internal (GcalEvent     *self,
                                    ECalComponent *component)
@@ -253,6 +315,9 @@ gcal_event_set_component_internal (GcalEvent     *self,
       /* Setup UID */
       gcal_event_update_uid_internal (self);
 
+      /* Load and setup the alarms */
+      load_alarms (self);
+
       g_object_notify (G_OBJECT (self), "component");
       g_object_notify (G_OBJECT (self), "location");
       g_object_notify (G_OBJECT (self), "summary");
@@ -555,6 +620,9 @@ gcal_event_init (GcalEvent *self)
   /* Default color of events */
   gdk_rgba_parse (&rgba, "#ffffff");
   self->color = gdk_rgba_copy (&rgba);
+
+  /* Alarms */
+  self->alarms = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
 }
 
 /**
@@ -847,6 +915,147 @@ gcal_event_has_alarms (GcalEvent *self)
 }
 
 /**
+ * gcal_event_get_alarms:
+ * @self: a #GcalEvent
+ *
+ * Retrieves the alarms available for @self.
+ *
+ * Returns: (transfer full): a #GList of #ECalComponentAlarm.
+ */
+GList*
+gcal_event_get_alarms (GcalEvent *self)
+{
+  GHashTable *tmp;
+  GList *alarm_uids, *alarms, *l;
+
+  g_return_val_if_fail (GCAL_IS_EVENT (self), NULL);
+
+  tmp = g_hash_table_new (g_direct_hash, g_direct_equal);
+  alarms = NULL;
+  alarm_uids = e_cal_component_get_alarm_uids (self->component);
+
+  for (l = alarm_uids; l != NULL; l = l->next)
+    {
+      ECalComponentAlarm *alarm;
+      gint trigger_minutes;
+
+      alarm = e_cal_component_get_alarm (self->component, l->data);
+      trigger_minutes = get_trigger_minutes (self, alarm);
+
+      /* We only support a single alarm for a given time */
+      if (!g_hash_table_contains (tmp, GINT_TO_POINTER (trigger_minutes)))
+        {
+          alarms = g_list_prepend (alarms, alarm);
+
+          g_hash_table_insert (tmp, GINT_TO_POINTER (trigger_minutes), NULL);
+        }
+      else
+        {
+          e_cal_component_alarm_free (alarm);
+        }
+    }
+
+  cal_obj_uid_list_free (alarm_uids);
+  g_hash_table_destroy (tmp);
+
+  return alarms;
+}
+
+/**
+ * gcal_event_add_alarm:
+ * @self: a #GcalEvent
+ * @type: the minutes before the start date to trigger the alarm
+ * @has_sound: whether the alarm plays a sound or not
+ *
+ * Adds an alarm to @self that triggers @type minutes before the event's
+ * start date.
+ *
+ * If there's already an alarm for @type, it'll be replaced.
+ */
+void
+gcal_event_add_alarm (GcalEvent *self,
+                      guint      type,
+                      gboolean   has_sound)
+{
+  ECalComponentAlarmTrigger trigger;
+  ECalComponentAlarmAction action;
+  ECalComponentAlarm *alarm;
+  gchar *alarm_uid;
+
+  g_return_if_fail (GCAL_IS_EVENT (self));
+
+  /* Only 1 alarm per relative time */
+  if (g_hash_table_contains (self->alarms, GINT_TO_POINTER (type)))
+    {
+      const gchar *alarm_uid;
+
+      alarm_uid = g_hash_table_lookup (self->alarms, GINT_TO_POINTER (type));
+
+      e_cal_component_remove_alarm (self->component, alarm_uid);
+    }
+
+  /* Alarm */
+  alarm = e_cal_component_alarm_new ();
+
+  /* Setup the alarm trigger */
+  trigger.type = E_CAL_COMPONENT_ALARM_TRIGGER_RELATIVE_START;
+
+  trigger.u.rel_duration = icaldurationtype_null_duration ();
+  trigger.u.rel_duration.is_neg = TRUE;
+  trigger.u.rel_duration.minutes = type;
+
+  e_cal_component_alarm_set_trigger (alarm, trigger);
+
+  /* Action */
+  if (has_sound)
+    action = E_CAL_COMPONENT_ALARM_AUDIO;
+  else
+    action = E_CAL_COMPONENT_ALARM_DISPLAY;
+
+  e_cal_component_alarm_set_action (alarm, action);
+
+  /* Add the alarm to the component */
+  e_cal_component_add_alarm (self->component, alarm);
+
+  /* Add to the hash table */
+  alarm_uid = g_strdup (e_cal_component_alarm_get_uid (alarm));
+
+  g_hash_table_insert (self->alarms, GINT_TO_POINTER (type), alarm_uid);
+
+  e_cal_component_alarm_free (alarm);
+}
+
+/**
+ * gcal_event_remove_alarm:
+ * @self: a #GcalEvent
+ * @type: the minutes before the start date to trigger the alarm
+ *
+ * Removes an alarm from @self that triggers @type minutes before the event's
+ * start date.
+ *
+ * If there's no alarm set for @type, nothing happens.
+ */
+void
+gcal_event_remove_alarm (GcalEvent *self,
+                         guint      type)
+{
+  g_return_if_fail (GCAL_IS_EVENT (self));
+
+  /* Only 1 alarm per relative time */
+  if (g_hash_table_contains (self->alarms, GINT_TO_POINTER (type)))
+    {
+      const gchar *alarm_uid;
+
+      alarm_uid = g_hash_table_lookup (self->alarms, GINT_TO_POINTER (type));
+
+      e_cal_component_remove_alarm (self->component, alarm_uid);
+
+      g_hash_table_remove (self->alarms, GINT_TO_POINTER (type));
+    }
+}
+
+
+/**
  * gcal_event_get_location:
  * @self: a #GcalEvent
  *
diff --git a/src/gcal-event.h b/src/gcal-event.h
index f3eca91..16dc19a 100644
--- a/src/gcal-event.h
+++ b/src/gcal-event.h
@@ -62,6 +62,15 @@ void                 gcal_event_set_description                  (GcalEvent
 
 gboolean             gcal_event_has_alarms                       (GcalEvent          *self);
 
+GList*               gcal_event_get_alarms                       (GcalEvent          *self);
+
+void                 gcal_event_add_alarm                        (GcalEvent          *self,
+                                                                  guint               type,
+                                                                  gboolean            has_sound);
+
+void                 gcal_event_remove_alarm                     (GcalEvent          *self,
+                                                                  guint               type);
+
 const gchar*         gcal_event_get_location                     (GcalEvent          *self);
 
 void                 gcal_event_set_location                     (GcalEvent          *self,


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