[california/wip/725785-create-recurring] First steps, RRULE definition and infrastructure
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [california/wip/725785-create-recurring] First steps, RRULE definition and infrastructure
- Date: Fri, 6 Jun 2014 23:08:44 +0000 (UTC)
commit 4c8838e8cd5556acf9cebd0c3a966faa89a0aadf
Author: Jim Nelson <jim yorba org>
Date: Fri Jun 6 16:07:31 2014 -0700
First steps, RRULE definition and infrastructure
This only starts to add recurring rule parsing to quick-add.
Add recurring UI to create/update widget will come later.
src/Makefile.am | 1 +
src/component/component-date-time.vala | 40 +++
src/component/component-details-parser.vala | 36 +++
src/component/component-event.vala | 45 ++++
src/component/component-recurrence-rule.vala | 350 ++++++++++++++++++++++++++
src/component/component.vala | 33 +++-
vapi/libical.vapi | 5 +-
7 files changed, 506 insertions(+), 4 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 20b2634..4f67b8d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -85,6 +85,7 @@ california_VALASOURCES = \
component/component-event.vala \
component/component-icalendar.vala \
component/component-instance.vala \
+ component/component-recurrence-rule.vala \
component/component-uid.vala \
component/component-vtype.vala \
\
diff --git a/src/component/component-date-time.vala b/src/component/component-date-time.vala
index f8121a5..93a0d34 100644
--- a/src/component/component-date-time.vala
+++ b/src/component/component-date-time.vala
@@ -115,6 +115,46 @@ public class DateTime : BaseObject, Gee.Hashable<DateTime>, Gee.Comparable<DateT
}
/**
+ * Creates a new { link DateTime} for a component's RRULE UNTIL property.
+ */
+ public DateTime.rrule_until(iCal.icalrecurrencetype rrule, DateTime dtstart) throws ComponentError {
+ if (iCal.icaltime_is_null_time(rrule.until) != 0)
+ throw new ComponentError.INVALID("DATE-TIME for RRULE UNTIL is null time");
+
+ if (iCal.icaltime_is_valid_time(rrule.until) != 0)
+ throw new ComponentError.INVALID("DATE-TIME for RRULE UNTIL is invalid");
+
+ bool until_is_date = (iCal.icaltime_is_date(rrule.until) != 0);
+ bool until_is_utc = (iCal.icaltime_is_utc(rrule.until) != 0);
+
+ // "The value of the UNTIL rule part MUST have the same value type as the 'DTSTART'
+ // property
+ if (dtstart.is_date != until_is_date)
+ throw new ComponentError.INVALID("RRULE UNTIL and DTSTART must be of same type
(DATE/DATE-TIME)");
+
+ // "If the 'DTSTART' property is specified as a date with local time, then the UNTIL rule
+ // part MUST also be specified as a date with local time."
+ if (dtstart.is_utc != until_is_utc)
+ throw new ComponentError.INVALID("RRULE UNTIL and DTSTART must be of same time type
(UTC/local)");
+
+ // "if the 'DTSTART' property is specified as a date with UTC time or a date with local time
+ // and a time zone reference, then the UNTIL rule part MUST be specified as a date with
+ // UTC time."
+ if (dtstart.is_date || (!dtstart.is_utc && dtstart.zone != null)) {
+ if (!until_is_utc)
+ throw new ComponentError.INVALID("RRULE UNTIL must be UTC for DTSTART DATE or w/ time zone");
+ }
+
+ // "If specified as a DATE-TIME value, then it MUST be specified in a UTC time format."
+ if (!until_is_date && !until_is_utc)
+ throw new ComponentError.INVALID("RRULE DATE-TIME UNTIL must be UTC");
+
+ kind = iCal.icalproperty_kind.RRULE_PROPERTY;
+ dt = rrule.until;
+ zone = (!until_is_date || until_is_utc) ? Calendar.OlsonZone.utc : null;
+ }
+
+ /**
* Converts the stored iCal DATE-TIME to an { link Calendar.ExactTime}.
*
* Returns null if { link is_date} is true.
diff --git a/src/component/component-details-parser.vala b/src/component/component-details-parser.vala
index e5ad17b..ccea24d 100644
--- a/src/component/component-details-parser.vala
+++ b/src/component/component-details-parser.vala
@@ -158,6 +158,13 @@ public class DetailsParser : BaseObject {
continue;
stack.restore();
+ // A recurring preposition suggests a regular occurrance is being described by the next
+ // two tokens
+ stack.mark();
+ if (token.casefolded in RECURRING_PREPOSITIONS && parse_recurring(stack.pop(), stack.pop()))
+ continue;
+ stack.restore();
+
// only look for location prepositions if not already adding text to the location field
if (!adding_location && token.casefolded in LOCATION_PREPOSITIONS) {
// add current token (the preposition) to summary but not location (because location
@@ -337,6 +344,35 @@ public class DetailsParser : BaseObject {
return true;
}
+ private bool parse_recurring(Token? amount, Token? unit) {
+ // only one is required
+ if (amount == null && unit == null)
+ return false;
+
+ // recurring can be specified with the amount acting as a day specifier, i.e. "every Friday"
+ // or a single unit, i.e. "every day" or "every weekday"
+ if (unit == null) {
+ Calendar.DayOfWeek? dow = Calendar.DayOfWeek.parse(amount.casefolded);
+ if (dow != null) {
+ return true;
+ }
+
+ if (amount.casefolded == DAY) {
+ return true;
+ }
+
+ if (amount.casefolded == WEEKDAY) {
+ return true;
+ }
+
+ if (amount.casefolded == WEEKEND) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
// Adds the text to the summary and location field, if adding_location is set
private void add_text(Token token) {
// always add to summary
diff --git a/src/component/component-event.vala b/src/component/component-event.vala
index 8b157f1..6ef205f 100644
--- a/src/component/component-event.vala
+++ b/src/component/component-event.vala
@@ -20,6 +20,7 @@ public class Event : Instance, Gee.Comparable<Event> {
public const string PROP_IS_ALL_DAY = "is-all-day";
public const string PROP_LOCATION = "location";
public const string PROP_STATUS = "status";
+ public const string PROP_RRULE = "rrule";
public enum Status {
TENTATIVE,
@@ -82,6 +83,11 @@ public class Event : Instance, Gee.Comparable<Event> {
public Status status { get; set; default = Status.CONFIRMED; }
/**
+ * { link RecurrenceRule} (RRULE) for { link Event}.
+ */
+ public RecurrenceRule? rrule { get; private set; default = null; }
+
+ /**
* Create an { link Event} { link Component} from an EDS CalComponent object.
*
* Throws a BackingError if the E.CalComponent's VTYPE is not VEVENT.
@@ -150,6 +156,12 @@ public class Event : Instance, Gee.Comparable<Event> {
status = Status.CONFIRMED;
break;
}
+
+ try {
+ make_recurring(new RecurrenceRule.from_ical(ical_component));
+ } catch (ComponentError comperr) {
+ // ignored; generally means no RRULE in component
+ }
}
private void on_notify(ParamSpec pspec) {
@@ -214,6 +226,20 @@ public class Event : Instance, Gee.Comparable<Event> {
}
break;
+ case PROP_RRULE:
+ // whether rrule is added or removed (cleared), clear from ical_component
+ unowned iCal.icalproperty? rrule_property = ical_component.get_first_property(
+ iCal.icalproperty_kind.RRULE_PROPERTY);
+ while (rrule_property != null) {
+ ical_component.remove_property(rrule_property);
+ rrule_property = ical_component.get_next_property(iCal.icalproperty_kind.RRULE_PROPERTY);
+ }
+
+ // add back if necessary
+ if (rrule != null)
+ rrule.to_ical(ical_component);
+ break;
+
default:
altered = false;
break;
@@ -320,6 +346,25 @@ public class Event : Instance, Gee.Comparable<Event> {
}
/**
+ * Add a { link RecurrenceRule} to the { link Event}.
+ *
+ * Pass null to make non-recurring.
+ */
+ public void make_recurring(RecurrenceRule? rrule) {
+ if (this.rrule != null)
+ this.rrule.by_rule_updated.disconnect(on_by_rule_updated);
+
+ if (rrule != null)
+ rrule.by_rule_updated.connect(on_by_rule_updated);
+
+ this.rrule = rrule;
+ }
+
+ private void on_by_rule_updated() {
+ // TODO: Update ical_component with new RRULE
+ }
+
+ /**
* @inheritDoc
*/
public override bool is_valid() {
diff --git a/src/component/component-recurrence-rule.vala b/src/component/component-recurrence-rule.vala
new file mode 100644
index 0000000..4a579d3
--- /dev/null
+++ b/src/component/component-recurrence-rule.vala
@@ -0,0 +1,350 @@
+/* Copyright 2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+namespace California.Component {
+
+/**
+ * A mutable convenience representation of an iCalendar recurrence rule (RRULE).
+ *
+ * See [[https://tools.ietf.org/html/rfc5545#section-3.3.10]]
+ * and [[https://tools.ietf.org/html/rfc5545#section-3.8.5.3]]
+ */
+
+public class RecurrenceRule : BaseObject {
+ /**
+ * Enumeration of various BY rules (BYSECOND, BYMINUTE, etc.)
+ */
+ public enum ByRule {
+ SECOND,
+ MINUTE,
+ HOUR,
+ DAY,
+ MONTH_DAY,
+ YEAR_DAY,
+ WEEK_NUM,
+ MONTH,
+ SET_POS
+ }
+
+ /**
+ * Frequency.
+ *
+ * This is the only required field in an RRULE.
+ */
+ public iCal.icalrecurrencetype_frequency freq { get; set; }
+
+ /**
+ * Until (end date), inclusive.
+ *
+ * This is mutually exclusive with { link count}.
+ *
+ * @see set_until_date_time
+ */
+ public DateTime? until { get; private set; default = null; }
+
+ /**
+ * Total number of recurrences.
+ *
+ * Zero indicates "not set", not zero recurrences.
+ *
+ * This is mutually exclusive with { link until}.
+ *
+ * @see set_recurrence_count
+ */
+ public int count { get; private set; default = 0; }
+
+ /**
+ * Interval between recurrences.
+ *
+ * A positive integer representing the interval (duration between) of each recurrence. The
+ * actual amount of time elapsed is determined by the { link frequency} property.
+ */
+ private short _interval;
+ public short interval {
+ get { return _interval; }
+ set { _interval = value.clamp(0, short.MAX); }
+ default = 0;
+ }
+
+ /**
+ * Start of work week (WKST).
+ */
+ public Calendar.DayOfWeek? start_of_week { get; set; default = null; }
+
+ private Gee.SortedSet<int> by_second = new Gee.TreeSet<int>();
+ private Gee.SortedSet<int> by_minute = new Gee.TreeSet<int>();
+ private Gee.SortedSet<int> by_hour = new Gee.TreeSet<int>();
+ private Gee.SortedSet<int> by_day = new Gee.TreeSet<int>();
+ private Gee.SortedSet<int> by_month_day = new Gee.TreeSet<int>();
+ private Gee.SortedSet<int> by_year_day = new Gee.TreeSet<int>();
+ private Gee.SortedSet<int> by_week_num = new Gee.TreeSet<int>();
+ private Gee.SortedSet<int> by_month = new Gee.TreeSet<int>();
+ private Gee.SortedSet<int> by_set_pos = new Gee.TreeSet<int>();
+
+ /**
+ * Fired when a BY rule is updated (BYSECOND, BYMINUTE, etc.)
+ */
+ public signal void by_rule_updated(ByRule by_rule);
+
+ public RecurrenceRule(iCal.icalrecurrencetype_frequency freq) {
+ this.freq = freq;
+ }
+
+ internal RecurrenceRule.from_ical(iCal.icalcomponent ical_component) throws ComponentError {
+ // need DTSTART for timezone purposes
+ DateTime dtstart = new DateTime(ical_component, iCal.icalproperty_kind.DTSTART_PROPERTY);
+
+ // fetch the RRULE from the component
+ unowned iCal.icalproperty? rrule_property = ical_component.get_first_property(
+ iCal.icalproperty_kind.RRULE_PROPERTY);
+ if (rrule_property == null)
+ throw new ComponentError.UNAVAILABLE("No RRULE found in component");
+
+ iCal.icalrecurrencetype rrule = rrule_property.get_rrule();
+
+ freq = rrule.freq;
+ if (rrule.count > 0)
+ set_recurrence_count(rrule.count);
+ else
+ set_until_date_time(new DateTime.rrule_until(rrule, dtstart));
+ interval = rrule.interval;
+
+ switch (rrule.week_start) {
+ case iCal.icalrecurrencetype_weekday.SUNDAY_WEEKDAY:
+ start_of_week = Calendar.DayOfWeek.SUN;
+ break;
+
+ case iCal.icalrecurrencetype_weekday.MONDAY_WEEKDAY:
+ start_of_week = Calendar.DayOfWeek.MON;
+ break;
+
+ case iCal.icalrecurrencetype_weekday.TUESDAY_WEEKDAY:
+ start_of_week = Calendar.DayOfWeek.TUE;
+ break;
+
+ case iCal.icalrecurrencetype_weekday.WEDNESDAY_WEEKDAY:
+ start_of_week = Calendar.DayOfWeek.WED;
+ break;
+
+ case iCal.icalrecurrencetype_weekday.THURSDAY_WEEKDAY:
+ start_of_week = Calendar.DayOfWeek.THU;
+ break;
+
+ case iCal.icalrecurrencetype_weekday.FRIDAY_WEEKDAY:
+ start_of_week = Calendar.DayOfWeek.FRI;
+ break;
+
+ case iCal.icalrecurrencetype_weekday.SATURDAY_WEEKDAY:
+ start_of_week = Calendar.DayOfWeek.SAT;
+ break;
+
+ case iCal.icalrecurrencetype_weekday.NO_WEEKDAY:
+ default:
+ start_of_week = null;
+ break;
+ }
+
+ fill_by(rrule.by_second, iCal.BY_SECOND_SIZE, by_second);
+ fill_by(rrule.by_minute, iCal.BY_MINUTE_SIZE, by_minute);
+ fill_by(rrule.by_hour, iCal.BY_HOUR_SIZE, by_hour);
+ fill_by(rrule.by_day, iCal.BY_DAY_SIZE, by_day);
+ fill_by(rrule.by_month_day, iCal.BY_MONTHDAY_SIZE, by_month_day);
+ fill_by(rrule.by_year_day, iCal.BY_YEARDAY_SIZE, by_year_day);
+ fill_by(rrule.by_week_no, iCal.BY_WEEKNO_SIZE, by_week_num);
+ fill_by(rrule.by_month, iCal.BY_MONTH_SIZE, by_month);
+ fill_by(rrule.by_set_pos, iCal.BY_SETPOS_SIZE, by_set_pos);
+ }
+
+ private void fill_by(short[] ical_by_ar, int ical_by_ar_len, Gee.SortedSet<int> by_set) {
+ for (int ctr = 0; ctr < ical_by_ar_len; ctr++) {
+ short by = ical_by_ar[ctr];
+ if (by == iCal.RECURRENCE_ARRAY_MAX)
+ break;
+
+ by_set.add(by);
+ }
+ }
+
+ /**
+ * Sets the { link until} property.
+ *
+ * Also sets { link count} to zero.
+ *
+ * Passing null will clear both properties.
+ */
+ public void set_until_date_time(DateTime? date_time) {
+ until = date_time;
+ count = 0;
+ }
+
+ /**
+ * Sets the { link count} property.
+ *
+ * Also clears { link until}.
+ *
+ * Passing zero will clear both properties.
+ */
+ public void set_recurrence_count(int count) {
+ this.count = count;
+ until = null;
+ }
+
+ /**
+ * Returns a read-only sorted set of BY rule settings.
+ */
+ public Gee.SortedSet<int> get_by_rule(ByRule by_rule) {
+ switch (by_rule) {
+ case ByRule.SECOND:
+ return by_second.read_only_view;
+
+ case ByRule.MINUTE:
+ return by_minute.read_only_view;
+
+ case ByRule.HOUR:
+ return by_hour.read_only_view;
+
+ case ByRule.DAY:
+ return by_day.read_only_view;
+
+ case ByRule.MONTH_DAY:
+ return by_month_day.read_only_view;
+
+ case ByRule.YEAR_DAY:
+ return by_year_day.read_only_view;
+
+ case ByRule.WEEK_NUM:
+ return by_week_num.read_only_view;
+
+ case ByRule.MONTH:
+ return by_month.read_only_view;
+
+ case ByRule.SET_POS:
+ return by_set_pos.read_only_view;
+
+ default:
+ assert_not_reached();
+ }
+ }
+
+ /**
+ * Replaces the existing set of values for the BY rules with the supplied values.
+ *
+ * @see by_rule_updated
+ */
+ public void set_by_rule(ByRule by_rule, Gee.Collection<int>? values) {
+ Gee.SortedSet<int> by_set;
+ switch (by_rule) {
+ case ByRule.SECOND:
+ by_set = by_second;
+ break;
+
+ case ByRule.MINUTE:
+ by_set = by_minute;
+ break;
+
+ case ByRule.HOUR:
+ by_set = by_hour;
+ break;
+
+ case ByRule.DAY:
+ by_set = by_day;
+ break;
+
+ case ByRule.MONTH_DAY:
+ by_set = by_month_day;
+ break;
+
+ case ByRule.YEAR_DAY:
+ by_set = by_year_day;
+ break;
+
+ case ByRule.WEEK_NUM:
+ by_set = by_week_num;
+ break;
+
+ case ByRule.MONTH:
+ by_set = by_month;
+ break;
+
+ case ByRule.SET_POS:
+ by_set = by_set_pos;
+ break;
+
+ default:
+ assert_not_reached();
+ }
+
+ by_set.clear();
+ if (values != null && values.size > 0)
+ by_set.add_all(values);
+
+ by_rule_updated(by_rule);
+ }
+
+ /**
+ * Converts a { link RecurrenceRule} into an iCalendar RRULE property and adds it to the
+ * iCal component.
+ */
+ internal void to_ical(iCal.icalcomponent ical_component) {
+ iCal.icalrecurrencetype rrule = { 0 };
+ rrule.freq = freq;
+ rrule.until = until.dt;
+ rrule.count = count;
+ rrule.interval = interval;
+
+ if (start_of_week == null)
+ rrule.week_start = iCal.icalrecurrencetype_weekday.NO_WEEKDAY;
+ else if (start_of_week == Calendar.DayOfWeek.SUN)
+ rrule.week_start = iCal.icalrecurrencetype_weekday.SUNDAY_WEEKDAY;
+ else if (start_of_week == Calendar.DayOfWeek.MON)
+ rrule.week_start = iCal.icalrecurrencetype_weekday.MONDAY_WEEKDAY;
+ else if (start_of_week == Calendar.DayOfWeek.TUE)
+ rrule.week_start = iCal.icalrecurrencetype_weekday.TUESDAY_WEEKDAY;
+ else if (start_of_week == Calendar.DayOfWeek.WED)
+ rrule.week_start = iCal.icalrecurrencetype_weekday.WEDNESDAY_WEEKDAY;
+ else if (start_of_week == Calendar.DayOfWeek.THU)
+ rrule.week_start = iCal.icalrecurrencetype_weekday.THURSDAY_WEEKDAY;
+ else if (start_of_week == Calendar.DayOfWeek.FRI)
+ rrule.week_start = iCal.icalrecurrencetype_weekday.FRIDAY_WEEKDAY;
+ else if (start_of_week == Calendar.DayOfWeek.SAT)
+ rrule.week_start = iCal.icalrecurrencetype_weekday.SATURDAY_WEEKDAY;
+ else
+ assert_not_reached();
+
+ fill_ical_by(by_second, rrule.by_second, iCal.BY_SECOND_SIZE);
+ fill_ical_by(by_minute, rrule.by_minute, iCal.BY_MINUTE_SIZE);
+ fill_ical_by(by_hour, rrule.by_hour, iCal.BY_HOUR_SIZE);
+ fill_ical_by(by_day, rrule.by_day, iCal.BY_DAY_SIZE);
+ fill_ical_by(by_month_day, rrule.by_month_day, iCal.BY_MONTHDAY_SIZE);
+ fill_ical_by(by_year_day, rrule.by_year_day, iCal.BY_YEARDAY_SIZE);
+ fill_ical_by(by_week_num, rrule.by_week_no, iCal.BY_WEEKNO_SIZE);
+ fill_ical_by(by_month, rrule.by_month, iCal.BY_MONTH_SIZE);
+ fill_ical_by(by_set_pos, rrule.by_set_pos, iCal.BY_SETPOS_SIZE);
+
+ iCal.icalproperty rrule_property = new iCal.icalproperty(iCal.icalproperty_kind.RRULE_PROPERTY);
+ rrule_property.set_rrule(rrule);
+
+ // TODO: Remove any existing RRULE properties
+
+ ical_component.add_property(rrule_property);
+ }
+
+ private void fill_ical_by(Gee.SortedSet<int> by_set, short[] ical_by_ar, int ical_by_ar_len) {
+ int index = 0;
+ foreach (int by in by_set)
+ ical_by_ar[index++] = (short) by;
+
+ if (index < ical_by_ar_len)
+ ical_by_ar[index] = (short) iCal.RECURRENCE_ARRAY_MAX;
+ }
+
+ public override string to_string() {
+ return "RRULE %s".printf(freq.to_string());
+ }
+}
+
+}
+
diff --git a/src/component/component.vala b/src/component/component.vala
index 9c917c8..82b9975 100644
--- a/src/component/component.vala
+++ b/src/component/component.vala
@@ -20,10 +20,14 @@ private int init_count = 0;
private string TODAY;
private string TOMORROW;
private string YESTERDAY;
+private string DAY;
+private string WEEKDAY;
+private string WEEKEND;
private string[] TIME_PREPOSITIONS;
private string[] LOCATION_PREPOSITIONS;
private string[] DURATION_PREPOSITIONS;
private string[] DELAY_PREPOSITIONS;
+private string[] RECURRING_PREPOSITIONS;
private string[] ORDINAL_SUFFIXES;
public void init() throws Error {
@@ -46,6 +50,20 @@ public void init() throws Error {
// For more information see https://wiki.gnome.org/Apps/California/TranslatingQuickAdd
YESTERDAY = _("yesterday").casefold();
+ // Used by quick-add to indicate the user wants to create an event for every day
+ // For more information see https://wiki.gnome.org/Apps/California/TranslatingQuickAdd
+ DAY = _("day").casefold();
+
+ // Used by quick-add to indicate the user wants to create an event for every weekday
+ // (in most Western countries, this means Monday through Friday, i.e. the work week)
+ // For more information see https://wiki.gnome.org/Apps/California/TranslatingQuickAdd
+ WEEKDAY = _("weekday").casefold();
+
+ // Used by quick-add to indicate the user wants to create an event for every weekend
+ // (in most Western countries, this means Saturday and Sunday, i.e. non-work days)
+ // For more information see https://wiki.gnome.org/Apps/California/TranslatingQuickAdd
+ WEEKEND = _("weekend").casefold();
+
// Used by quick-add to determine if the word is a TIME preposition (indicating a
// specific time of day, not a duration). Each word must be separated by semi-colons.
// It's allowable for some or all of these words to
@@ -73,6 +91,15 @@ public void init() throws Error {
// For more information see https://wiki.gnome.org/Apps/California/TranslatingQuickAdd
DELAY_PREPOSITIONS = _("in;").casefold().split(";");
+ // Used by quick-add to determine if the word is a RECURRING preposition (indicating a
+ // regular occurrance in time). Each word must be separated by semi-colons.
+ // It's allowable for some or all of these words to be duplicated in the location
+ // prepositions list (elsewhere) but not another time list.
+ // The list can be empty, but that will limit the parser.
+ // Example: "every 3 days", "every Friday"
+ // For more information see https://wiki.gnome.org/Apps/California/TranslatingQuickAdd
+ RECURRING_PREPOSITIONS = _("every;").casefold().split(";");
+
// Used by quick-add to determine if the word is a LOCATION preposition (indicating a
// specific place). Each word must be separated by semi-colons.
// It's allowable for some or all of these words to be duplicated in
@@ -95,9 +122,9 @@ public void terminate() {
if (!Unit.do_terminate(ref init_count))
return;
- TIME_PREPOSITIONS = LOCATION_PREPOSITIONS = DURATION_PREPOSITIONS = ORDINAL_SUFFIXES =
- DELAY_PREPOSITIONS =null;
- TODAY = TOMORROW = YESTERDAY = null;
+ TIME_PREPOSITIONS = LOCATION_PREPOSITIONS = DURATION_PREPOSITIONS = ORDINAL_SUFFIXES = null;
+ DELAY_PREPOSITIONS = RECURRING_PREPOSITIONS = null;
+ TODAY = TOMORROW = YESTERDAY = DAY = WEEKDAY = WEEKEND = null;
Calendar.terminate();
Collection.terminate();
diff --git a/vapi/libical.vapi b/vapi/libical.vapi
index c583a74..b1429e7 100644
--- a/vapi/libical.vapi
+++ b/vapi/libical.vapi
@@ -1706,7 +1706,10 @@ namespace iCal {
[CCode (cname = "icalperiodtype_null_period")]
public static iCal.icalperiodtype null_period ();
}
- [CCode (cheader_filename = "libical/ical.h")]
+ public const int RECURRENCE_ARRAY_MAX;
+ public const int RUCURRENCE_ARRAY_MAX_BYTE;
+ [CCode (cheader_filename = "libical/ical.h", cname="struct icalrecurrencetype")]
+ [SimpleType]
public struct icalrecurrencetype {
public iCal.icalrecurrencetype_frequency freq;
public iCal.icaltimetype until;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]