From 27bb337f5400e45f377d824d4b6924e99a03389b Mon Sep 17 00:00:00 2001 From: Yash Singh Date: Mon, 3 Jul 2017 00:06:11 +0530 Subject: [PATCH] recurrence: Add recurrence struct to parse recurrence-rules Currently, gnome-calendar has no component to deal with recurrence-rules of events. This missing component is however required to create and modify recurring events. This patch adds the required GcalRecurrence component which parses the recurrence-rules with details like: * Frequency of the recurring event * Duration of the recurrences: ** If they repeat until a particular date ** If they repeat a fixed number of times ** If they repeat forever and then stores these details in a suitable format in the GcalRecurrence structure. The gcal-recurrence functions simplify the task of handling and editing recurrences. This structure is the first step towards creating a new 'recurrence' property of an event. https://bugzilla.gnome.org/show_bug.cgi?id=782755 --- src/Makefile.am | 2 + src/gcal-recurrence.c | 264 ++++++++++++++++++++++++++++++++++++++++++ src/gcal-recurrence.h | 76 ++++++++++++ 3 files changed, 342 insertions(+) create mode 100644 src/gcal-recurrence.c create mode 100644 src/gcal-recurrence.h diff --git a/src/Makefile.am b/src/Makefile.am index d63f5456..967e03ed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -67,6 +67,8 @@ gnome_calendar_SOURCES = \ gcal-multi-choice.h \ gcal-quick-add-popover.c \ gcal-quick-add-popover.h \ + gcal-recurrence.c \ + gcal-recurrence.h \ gcal-search-view.h \ gcal-search-view.c \ gcal-shell-search-provider.h \ diff --git a/src/gcal-recurrence.c b/src/gcal-recurrence.c new file mode 100644 index 00000000..04603e76 --- /dev/null +++ b/src/gcal-recurrence.c @@ -0,0 +1,264 @@ +/* -*- mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * gcal-recurrence.c + * Copyright (C) 2017 Yash Singh + * + * gnome-calendar 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. + * + * gnome-calendar 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 . + */ + +#include "gcal-recurrence.h" +#include "gcal-utils.h" +#include "gcal-event.h" + +#include + +G_DEFINE_BOXED_TYPE (GcalRecurrence, gcal_recurrence, gcal_recurrence_copy, gcal_recurrence_free) + +/** + * gcal_recurrence_new: + * + * Creates a new #GcalRecurrence + * + * Returns: (transfer full): a #GcalRecurrence + */ +GcalRecurrence* +gcal_recurrence_new (void) +{ + GcalRecurrence *new_recur; + + new_recur = g_slice_new (GcalRecurrence); + + new_recur->frequency = GCAL_RECURRENCE_NO_REPEAT; + new_recur->limit_type = GCAL_RECURRENCE_FOREVER; + + new_recur->limit.until = NULL; + new_recur->limit.count = 0; + + return new_recur; +} + +/** + * gcal_recurrence_copy: + * @recur: a #GcalRecurrence + * + * Creates a copy of @recur + * + * Returns: (transfer full): a #GcalRecurrence + */ +GcalRecurrence* +gcal_recurrence_copy (GcalRecurrence *recur) +{ + GcalRecurrence *new_recur; + + g_return_val_if_fail (recur != NULL, NULL); + + new_recur = gcal_recurrence_new (); + + new_recur->frequency = recur->frequency; + new_recur->limit_type = recur->limit_type; + + if (recur->limit_type == GCAL_RECURRENCE_UNTIL && recur->limit.until) + new_recur->limit.until = g_date_time_ref (recur->limit.until); + + new_recur->limit.count = recur->limit.count; + + return new_recur; +} + +/** + * gcal_recurrence_free: + * @recur: a #GcalRecurrence. + * + * Frees @recur + */ +void +gcal_recurrence_free (GcalRecurrence *recur) +{ + gcal_clear_datetime (&recur->limit.until); + g_slice_free (GcalRecurrence, recur); +} + +/** + * gcal_recurrence_parse_recurrence_rules: + * @comp: an #ECalComponent + * + * Parses the rrule of the @comp and + * sets the GcalRecurrence struct accordingly. + * + * Returns: (transfer full): a #GcalRecurrence + */ +GcalRecurrence* +gcal_recurrence_parse_recurrence_rules (ECalComponent *comp) +{ + GcalRecurrence *recur; + icalproperty *prop; + icalcomponent *icalcomp; + struct icalrecurrencetype rrule; + + if (!e_cal_component_has_recurrences (comp)) + return NULL; + + recur = gcal_recurrence_new (); + icalcomp = e_cal_component_get_icalcomponent (comp); + + prop = icalcomponent_get_first_property (icalcomp, ICAL_RRULE_PROPERTY); + g_return_val_if_fail (prop != NULL, NULL); + + rrule = icalproperty_get_rrule (prop); + + switch (rrule.freq) + { + case ICAL_DAILY_RECURRENCE: + recur->frequency = GCAL_RECURRENCE_DAILY; + break; + + case ICAL_WEEKLY_RECURRENCE: + { + if (rrule.by_day[0] == ICAL_MONDAY_WEEKDAY && + rrule.by_day[1] == ICAL_TUESDAY_WEEKDAY && + rrule.by_day[2] == ICAL_WEDNESDAY_WEEKDAY && + rrule.by_day[3] == ICAL_THURSDAY_WEEKDAY && + rrule.by_day[4] == ICAL_FRIDAY_WEEKDAY && + rrule.by_day[5] != ICAL_SATURDAY_WEEKDAY && + rrule.by_day[6] != ICAL_SUNDAY_WEEKDAY) + { + recur->frequency = GCAL_RECURRENCE_MON_FRI; + } + else + { + recur->frequency = GCAL_RECURRENCE_WEEKLY; + } + break; + } + + case ICAL_MONTHLY_RECURRENCE: + recur->frequency = GCAL_RECURRENCE_MONTHLY; + break; + + case ICAL_YEARLY_RECURRENCE: + recur->frequency = GCAL_RECURRENCE_YEARLY; + break; + + default: + recur->frequency = GCAL_RECURRENCE_OTHER; + } + + if (rrule.count > 0) + { + recur->limit_type = GCAL_RECURRENCE_COUNT; + recur->limit.count = rrule.count; + } + else if (rrule.until.year != 0) + { + recur->limit_type = GCAL_RECURRENCE_UNTIL; + recur->limit.until = icaltime_to_datetime (&rrule.until); + } + else + { + recur->limit_type = GCAL_RECURRENCE_FOREVER; + } + + return recur; +} + +/** + * gcal_recurrence_to_rrule: + * @recur: a #GcalRecurrence + * + * Converts @recur into corresponding rrule. + * + * Returns: (transfer full): a #struct icalrecurrencetype + */ +struct icalrecurrencetype* +gcal_recurrence_to_rrule (GcalRecurrence *recur) +{ + struct icalrecurrencetype *rrule; + + if (!recur) + return NULL; + + /* Initialize and clear the rrule to get rid of unwanted fields */ + rrule = g_new0 (struct icalrecurrencetype, 1); + icalrecurrencetype_clear (rrule); + + rrule->until.second = 0; + rrule->until.minute = 0; + rrule->until.hour = 0; + rrule->until.is_date = TRUE; + rrule->until.is_utc = FALSE; + + switch (recur->frequency) + { + case GCAL_RECURRENCE_DAILY: + rrule->freq = ICAL_DAILY_RECURRENCE; + break; + + case GCAL_RECURRENCE_WEEKLY: + rrule->freq = ICAL_WEEKLY_RECURRENCE; + break; + + case GCAL_RECURRENCE_MONTHLY: + rrule->freq = ICAL_MONTHLY_RECURRENCE; + break; + + case GCAL_RECURRENCE_YEARLY: + rrule->freq = ICAL_YEARLY_RECURRENCE; + break; + + case GCAL_RECURRENCE_NO_REPEAT: + rrule->freq = ICAL_NO_RECURRENCE; + break; + + case GCAL_RECURRENCE_MON_FRI: + { + rrule->freq = ICAL_WEEKLY_RECURRENCE; + rrule->by_day[0] = ICAL_MONDAY_WEEKDAY; + rrule->by_day[1] = ICAL_TUESDAY_WEEKDAY; + rrule->by_day[2] = ICAL_WEDNESDAY_WEEKDAY; + rrule->by_day[3] = ICAL_THURSDAY_WEEKDAY; + rrule->by_day[4] = ICAL_FRIDAY_WEEKDAY; + break; + } + + default: + rrule->freq = ICAL_NO_RECURRENCE; + break; + } + + switch (recur->limit_type) + { + case GCAL_RECURRENCE_COUNT: + rrule->count = recur->limit.count; + break; + + case GCAL_RECURRENCE_UNTIL: + { + rrule->until.second = g_date_time_get_second (recur->limit.until); + rrule->until.minute = g_date_time_get_minute (recur->limit.until); + rrule->until.hour = g_date_time_get_hour (recur->limit.until); + rrule->until.day = g_date_time_get_day_of_month (recur->limit.until); + rrule->until.month = g_date_time_get_year (recur->limit.until); + rrule->until.year = g_date_time_get_month (recur->limit.until); + break; + } + + case GCAL_RECURRENCE_FOREVER: + break; + + default: + break; + } + + return rrule; +} diff --git a/src/gcal-recurrence.h b/src/gcal-recurrence.h new file mode 100644 index 00000000..737b27b1 --- /dev/null +++ b/src/gcal-recurrence.h @@ -0,0 +1,76 @@ +/* -*- mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * gcal-recurrence.h + * Copyright (C) 2017 Yash Singh + * + * gnome-calendar 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. + * + * gnome-calendar 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 . + */ + +#ifndef GCAL_RECURRENCE_H +#define GCAL_RECURRENCE_H + +#include +#include + +G_BEGIN_DECLS + +#define GCAL_TYPE_RECURRENCE (gcal_recurrence_get_type()) + +typedef struct _GcalRecurrence GcalRecurrence; + +typedef enum +{ + GCAL_RECURRENCE_NO_REPEAT, + GCAL_RECURRENCE_DAILY, + GCAL_RECURRENCE_MON_FRI, + GCAL_RECURRENCE_WEEKLY, + GCAL_RECURRENCE_MONTHLY, + GCAL_RECURRENCE_YEARLY, + GCAL_RECURRENCE_OTHER +} GcalRecurrenceFrequency; + +typedef enum +{ + GCAL_RECURRENCE_FOREVER, + GCAL_RECURRENCE_COUNT, + GCAL_RECURRENCE_UNTIL +} GcalRecurrenceLimitType; + +struct _GcalRecurrence +{ + GcalRecurrenceFrequency frequency; + GcalRecurrenceLimitType limit_type; + + struct { + GDateTime *until; + guint count; + } limit; + +}; + +GType gcal_recurrence_get_type (void) G_GNUC_CONST; + +GcalRecurrence* gcal_recurrence_new (void); + +GcalRecurrence* gcal_recurrence_copy (GcalRecurrence *recur); + +void gcal_recurrence_free (GcalRecurrence *recur); + +GcalRecurrence* gcal_recurrence_parse_recurrence_rules (ECalComponent *comp); + +struct icalrecurrencetype* gcal_recurrence_to_rrule (GcalRecurrence *recur); + +G_END_DECLS + +#endif /* GCAL_RECURRENCE_H */