[libgdata] [calendar] Added recurrence support to GDataCalendarEvent



commit 895a3f25756f0a368e6844c6caaf0b80c5612bef
Author: Philip Withnall <philip tecnocode co uk>
Date:   Mon Apr 27 18:44:26 2009 +0100

    [calendar] Added recurrence support to GDataCalendarEvent
    
    Added gdata_calendar_event_[get|set]_recurrence,
    gdata_calendar_event_get_original_event_details and
    gdata_calendar_event_is_exception. Added a test case too.
---
 docs/reference/gdata-sections.txt              |    4 +
 gdata/gdata-entry.c                            |    2 +-
 gdata/gdata-feed.c                             |    2 +-
 gdata/gdata.symbols                            |    4 +
 gdata/services/calendar/gdata-calendar-event.c |  170 +++++++++++++++++++++++-
 gdata/services/calendar/gdata-calendar-event.h |    4 +
 gdata/tests/calendar.c                         |   64 +++++++++
 7 files changed, 245 insertions(+), 5 deletions(-)

diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index 535051d..9b01681 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -521,6 +521,10 @@ gdata_calendar_event_add_place
 gdata_calendar_event_get_times
 gdata_calendar_event_get_primary_time
 gdata_calendar_event_add_time
+gdata_calendar_event_get_recurrence
+gdata_calendar_event_set_recurrence
+gdata_calendar_event_get_original_event_details
+gdata_calendar_event_is_exception
 gdata_calendar_event_get_anyone_can_add_self
 gdata_calendar_event_set_anyone_can_add_self
 gdata_calendar_event_get_guests_can_invite_others
diff --git a/gdata/gdata-entry.c b/gdata/gdata-entry.c
index 20f670c..672462b 100644
--- a/gdata/gdata-entry.c
+++ b/gdata/gdata-entry.c
@@ -567,7 +567,7 @@ real_parse_xml (GDataEntry *self, xmlDoc *doc, xmlNode *node, GError **error)
 		buffer = xmlBufferCreate ();
 		xmlNodeDump (buffer, doc, node, 0, 0);
 		g_string_append (self->priv->extra_xml, (gchar*) xmlBufferContent (buffer));
-		g_message ("Unhandled XML: %s", (gchar*) xmlBufferContent (buffer));
+		g_message ("Unhandled XML in <entry>: %s", (gchar*) xmlBufferContent (buffer));
 		xmlBufferFree (buffer);
 
 		/* Get the namespaces */
diff --git a/gdata/gdata-feed.c b/gdata/gdata-feed.c
index 2b042df..d4632d2 100644
--- a/gdata/gdata-feed.c
+++ b/gdata/gdata-feed.c
@@ -659,7 +659,7 @@ _gdata_feed_new_from_xml (const gchar *xml, gint length, GType entry_type,
 			xmlBuffer *buffer = xmlBufferCreate ();
 			xmlNodeDump (buffer, doc, node, 0, 0);
 			g_string_append (extra_xml, (gchar*) xmlBufferContent (buffer));
-			g_message ("Unhandled XML: %s", (gchar*) xmlBufferContent (buffer));
+			g_message ("Unhandled XML in <feed>: %s", (gchar*) xmlBufferContent (buffer));
 			xmlBufferFree (buffer);
 		}
 
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index 769c485..ad0800a 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -198,6 +198,10 @@ gdata_calendar_event_get_places
 gdata_calendar_event_add_time
 gdata_calendar_event_get_times
 gdata_calendar_event_get_primary_time
+gdata_calendar_event_get_recurrence
+gdata_calendar_event_set_recurrence
+gdata_calendar_event_get_original_event_details
+gdata_calendar_event_is_exception
 gdata_calendar_query_get_type
 gdata_calendar_query_new
 gdata_calendar_query_new_with_limits
diff --git a/gdata/services/calendar/gdata-calendar-event.c b/gdata/services/calendar/gdata-calendar-event.c
index 35024b6..1ef5e30 100644
--- a/gdata/services/calendar/gdata-calendar-event.c
+++ b/gdata/services/calendar/gdata-calendar-event.c
@@ -64,6 +64,9 @@ struct _GDataCalendarEventPrivate {
 	guint anyone_can_add_self : 1;
 	GList *people; /* GDataGDWho */
 	GList *places; /* GDataGDWhere */
+	gchar *recurrence;
+	gchar *original_event_id;
+	gchar *original_event_uri;
 };
 
 enum {
@@ -76,7 +79,10 @@ enum {
 	PROP_GUESTS_CAN_MODIFY,
 	PROP_GUESTS_CAN_INVITE_OTHERS,
 	PROP_GUESTS_CAN_SEE_GUESTS,
-	PROP_ANYONE_CAN_ADD_SELF
+	PROP_ANYONE_CAN_ADD_SELF,
+	PROP_RECURRENCE,
+	PROP_ORIGINAL_EVENT_ID,
+	PROP_ORIGINAL_EVENT_URI
 };
 
 G_DEFINE_TYPE (GDataCalendarEvent, gdata_calendar_event, GDATA_TYPE_ENTRY)
@@ -200,8 +206,8 @@ gdata_calendar_event_class_init (GDataCalendarEventClass *klass)
 	 *
 	 * Indicates whether event attendees may invite other people to the event.
 	 *
-	 * For more information, see the <ulink type="http" url="http://code.google.com/apis/calendar/docs/2.0/reference.html#gCalguestsCanInviteOthers";>
-	 * GData specification</ulink>.
+	 * For more information, see the <ulink type="http"
+	 * url="http://code.google.com/apis/calendar/docs/2.0/reference.html#gCalguestsCanInviteOthers";>GData specification</ulink>.
 	 **/
 	g_object_class_install_property (gobject_class, PROP_GUESTS_CAN_INVITE_OTHERS,
 				g_param_spec_boolean ("guests-can-invite-others",
@@ -233,6 +239,49 @@ gdata_calendar_event_class_init (GDataCalendarEventClass *klass)
 					"Anyone can add self", "Indicates whether anyone can add themselves to the attendee list of the event.",
 					FALSE,
 					G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * GDataCalendarEvent:recurrence:
+	 *
+	 * Represents the dates and times when a recurring event takes place. The returned string is in iCal format, as a list of properties.
+	 *
+	 * For more information, see the <ulink type="http" url="http://code.google.com/apis/gdata/elements.html#gdRecurrence";>
+	 * GData specification</ulink>.
+	 *
+	 * Since: 0.3.0
+	 **/
+	g_object_class_install_property (gobject_class, PROP_RECURRENCE,
+				g_param_spec_string ("recurrence",
+					"Recurrence", "Represents the dates and times when a recurring event takes place.",
+					NULL,
+					G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * GDataCalendarEvent:original-event-id:
+	 *
+	 * The event ID for the original event, if this event is an exception to a recurring event.
+	 *
+	 * Since: 0.3.0
+	 **/
+	g_object_class_install_property (gobject_class, PROP_ORIGINAL_EVENT_ID,
+				g_param_spec_string ("original-event-id",
+					"Original event ID", "The event ID for the original event, if this event is an exception to a recurring event.",
+					NULL,
+					G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * GDataCalendarEvent:original-event-uri:
+	 *
+	 * The event URI for the original event, if this event is an exception to a recurring event.
+	 *
+	 * Since: 0.3.0
+	 **/
+	g_object_class_install_property (gobject_class, PROP_ORIGINAL_EVENT_URI,
+				g_param_spec_string ("original-event-uri",
+					"Original event URI", "The event URI for the original event, if this event is an exception"
+					" to a recurring event.",
+					NULL,
+					G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -256,6 +305,9 @@ gdata_calendar_event_finalize (GObject *object)
 	g_list_free (priv->people);
 	g_list_foreach (priv->places, (GFunc) gdata_gd_where_free, NULL);
 	g_list_free (priv->places);
+	g_free (priv->recurrence);
+	xmlFree ((xmlChar*) priv->original_event_id);
+	xmlFree ((xmlChar*) priv->original_event_uri);
 
 	/* Chain up to the parent class */
 	G_OBJECT_CLASS (gdata_calendar_event_parent_class)->finalize (object);
@@ -297,6 +349,15 @@ gdata_calendar_event_get_property (GObject *object, guint property_id, GValue *v
 		case PROP_ANYONE_CAN_ADD_SELF:
 			g_value_set_boolean (value, priv->anyone_can_add_self);
 			break;
+		case PROP_RECURRENCE:
+			g_value_set_string (value, priv->recurrence);
+			break;
+		case PROP_ORIGINAL_EVENT_ID:
+			g_value_set_string (value, priv->original_event_id);
+			break;
+		case PROP_ORIGINAL_EVENT_URI:
+			g_value_set_string (value, priv->original_event_uri);
+			break;
 		default:
 			/* We don't have any other property... */
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -337,6 +398,9 @@ gdata_calendar_event_set_property (GObject *object, guint property_id, const GVa
 		case PROP_ANYONE_CAN_ADD_SELF:
 			gdata_calendar_event_set_anyone_can_add_self (self, g_value_get_boolean (value));
 			break;
+		case PROP_RECURRENCE:
+			gdata_calendar_event_set_recurrence (self, g_value_get_string (value));
+			break;
 		default:
 			/* We don't have any other property... */
 			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -568,6 +632,19 @@ parse_xml (GDataEntry *entry, xmlDoc *doc, xmlNode *node, GError **error)
 		xmlFree (label);
 
 		gdata_calendar_event_add_place (self, where);
+	} else if (xmlStrcmp (node->name, (xmlChar*) "recurrence") == 0) {
+		/* gd:recurrence */
+		xmlChar *recurrence = xmlNodeListGetString (doc, node->xmlChildrenNode, TRUE);
+		gdata_calendar_event_set_recurrence (self, (gchar*) recurrence);
+		xmlFree (recurrence);
+	} else if (xmlStrcmp (node->name, (xmlChar*) "originalEvent") == 0) {
+		/* gd:originalEvent */
+		g_object_freeze_notify (G_OBJECT (self));
+		self->priv->original_event_id = (gchar*) xmlGetProp (node, (xmlChar*) "id");
+		g_object_notify (G_OBJECT (self), "original-event-id");
+		self->priv->original_event_uri = (gchar*) xmlGetProp (node, (xmlChar*) "href");
+		g_object_notify (G_OBJECT (self), "original-event-uri");
+		g_object_thaw_notify (G_OBJECT (self));
 	} else if (GDATA_ENTRY_CLASS (gdata_calendar_event_parent_class)->parse_xml (entry, doc, node, error) == FALSE) {
 		/* Error! */
 		return FALSE;
@@ -624,6 +701,9 @@ get_xml (GDataEntry *entry, GString *xml_string)
 	else
 		g_string_append (xml_string, "<gCal:anyoneCanAddSelf value='false'/>");
 
+	if (priv->recurrence != NULL)
+		g_string_append_printf (xml_string, "<gd:recurrence>%s</gd:recurrence>", priv->recurrence);
+
 	for (i = priv->times; i != NULL; i = i->next) {
 		gchar *start_time;
 		GDataGDWhen *when = (GDataGDWhen*) i->data;
@@ -1154,3 +1234,87 @@ gdata_calendar_event_get_primary_time (GDataCalendarEvent *self, GTimeVal *start
 
 	return TRUE;
 }
+
+/**
+ * gdata_calendar_event_get_recurrence:
+ * @self: a #GDataCalendarEvent
+ *
+ * Gets the #GDataCalendarEvent:recurrence property.
+ *
+ * Return value: the event recurrence patterns, or %NULL
+ *
+ * Since: 0.3.0
+ **/
+const gchar *
+gdata_calendar_event_get_recurrence (GDataCalendarEvent *self)
+{
+	g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), NULL);
+	return self->priv->recurrence;
+}
+
+/**
+ * gdata_calendar_event_set_recurrence:
+ * @self: a #GDataCalendarEvent
+ * @recurrence: a new event recurrence, or %NULL
+ *
+ * Sets the #GDataCalendarEvent:recurrence property to the new recurrence, @recurrence.
+ *
+ * Set @recurrence to %NULL to unset the property in the event.
+ *
+ * Since: 0.3.0
+ **/
+void
+gdata_calendar_event_set_recurrence (GDataCalendarEvent *self, const gchar *recurrence)
+{
+	g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
+
+	g_free (self->priv->recurrence);
+	self->priv->recurrence = g_strdup (recurrence);
+	g_object_notify (G_OBJECT (self), "recurrence");
+}
+
+/**
+ * gdata_calendar_event_get_original_event_details:
+ * @self: a #GDataCalendarEvent
+ * @event_id: return location for the original event's ID, or %NULL
+ * @event_uri: return location for the original event's URI, or %NULL
+ *
+ * Gets details of the original event, if this event is an exception to a recurring event. The original
+ * event's ID and the URI of the event's XML are returned in @event_id and @event_uri, respectively.
+ *
+ * If this event is not an exception to a recurring event, @event_id and @event_uri will be set to %NULL.
+ * See gdata_calendar_event_is_exception() to determine more simply whether an event is an exception to a
+ * recurring event.
+ *
+ * If both @event_id and @event_uri are %NULL, this function is a no-op.
+ *
+ * Since: 0.3.0
+ **/
+void
+gdata_calendar_event_get_original_event_details (GDataCalendarEvent *self, gchar **event_id, gchar **event_uri)
+{
+	g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
+
+	if (event_id != NULL)
+		*event_id = g_strdup (self->priv->original_event_id);
+	if (event_uri != NULL)
+		*event_uri = g_strdup (self->priv->original_event_uri);
+}
+
+/**
+ * gdata_calendar_event_is_exception:
+ * @self: a #GDataCalendarEvent
+ *
+ * Determines whether the event is an exception to a recurring event. If it is, details of the original event
+ * can be retrieved using gdata_calendar_event_get_original_event_details().
+ *
+ * Return value: %TRUE if the event is an exception, %FALSE otherwise
+ *
+ * Since: 0.3.0.
+ **/
+gboolean
+gdata_calendar_event_is_exception (GDataCalendarEvent *self)
+{
+	g_return_val_if_fail (GDATA_IS_CALENDAR_EVENT (self), FALSE);
+	return (self->priv->original_event_id != NULL && self->priv->original_event_uri != NULL) ? TRUE : FALSE;
+}
diff --git a/gdata/services/calendar/gdata-calendar-event.h b/gdata/services/calendar/gdata-calendar-event.h
index f991697..aee82df 100644
--- a/gdata/services/calendar/gdata-calendar-event.h
+++ b/gdata/services/calendar/gdata-calendar-event.h
@@ -89,6 +89,10 @@ GList *gdata_calendar_event_get_places (GDataCalendarEvent *self);
 void gdata_calendar_event_add_time (GDataCalendarEvent *self, GDataGDWhen *when);
 GList *gdata_calendar_event_get_times (GDataCalendarEvent *self);
 gboolean gdata_calendar_event_get_primary_time (GDataCalendarEvent *self, GTimeVal *start_time, GTimeVal *end_time, GDataGDWhen **when);
+const gchar *gdata_calendar_event_get_recurrence (GDataCalendarEvent *self);
+void gdata_calendar_event_set_recurrence (GDataCalendarEvent *self, const gchar *recurrence);
+void gdata_calendar_event_get_original_event_details (GDataCalendarEvent *self, gchar **event_id, gchar **event_uri);
+gboolean gdata_calendar_event_is_exception (GDataCalendarEvent *self);
 
 G_END_DECLS
 
diff --git a/gdata/tests/calendar.c b/gdata/tests/calendar.c
index 451065b..dc006be 100644
--- a/gdata/tests/calendar.c
+++ b/gdata/tests/calendar.c
@@ -373,6 +373,69 @@ test_xml_dates (void)
 }
 
 static void
+test_xml_recurrence (void)
+{
+	GDataCalendarEvent *event;
+	gchar *xml;
+	GError *error = NULL;
+	gchar *id, *uri;
+
+	event = gdata_calendar_event_new_from_xml (
+		"<entry xmlns='http://www.w3.org/2005/Atom' "
+		 	"xmlns:gd='http://schemas.google.com/g/2005' "
+		 	"xmlns:gCal='http://schemas.google.com/gCal/2005' "
+		 	"xmlns:app='http://www.w3.org/2007/app'>"
+			"<id>http://www.google.com/calendar/feeds/libgdata test googlemail com/events/g5928e82rrch95b25f8ud0dlsg_20090429T153000Z</id>"
+			"<published>2009-04-25T15:22:47.000Z</published>"
+			"<updated>2009-04-27T17:54:10.000Z</updated>"
+			"<app:edited xmlns:app='http://www.w3.org/2007/app'>2009-04-27T17:54:10.000Z</app:edited>"
+			"<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'/>"
+			"<title>Test daily instance event</title>"
+			"<content></content>"
+			"<link rel='alternate' type='text/html' href='http://www.google.com/calendar/event?eid=ZzU5MjhlODJycmNoOTViMjVmOHVkMGRsc2dfMjAwOTA0MjlUMTUzMDAwWiBsaWJnZGF0YS50ZXN0QGdvb2dsZW1haWwuY29t' title='alternate'/>"
+			"<link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/libgdata test googlemail com/private/full/g5928e82rrch95b25f8ud0dlsg_20090429T153000Z'/>"
+			"<link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/libgdata test googlemail com/private/full/g5928e82rrch95b25f8ud0dlsg_20090429T153000Z'/>"
+			"<author>"
+				"<name>GData Test</name>"
+				"<email>libgdata test googlemail com</email>"
+			"</author>"
+			"<gd:originalEvent id='g5928e82rrch95b25f8ud0dlsg' href='http://www.google.com/calendar/feeds/libgdata test googlemail com/private/full/g5928e82rrch95b25f8ud0dlsg'>"
+				"<gd:when startTime='2009-04-29T16:30:00.000+01:00'/>"
+			"</gd:originalEvent>"
+			"<gCal:guestsCanModify value='false'/>"
+			"<gCal:guestsCanInviteOthers value='false'/>"
+			"<gCal:guestsCanSeeGuests value='false'/>"
+			"<gCal:anyoneCanAddSelf value='false'/>"
+			"<gd:comments>"
+				"<gd:feedLink href='http://www.google.com/calendar/feeds/libgdata test googlemail com/private/full/g5928e82rrch95b25f8ud0dlsg_20090429T153000Z/comments'/>"
+			"</gd:comments>"
+			"<gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'/>"
+			"<gd:visibility value='http://schemas.google.com/g/2005#event.private'/>"
+			"<gd:transparency value='http://schemas.google.com/g/2005#event.opaque'/>"
+			"<gCal:uid value='g5928e82rrch95b25f8ud0dlsg google com'/>"
+			"<gCal:sequence value='0'/>"
+			"<gd:when startTime='2009-04-29T17:30:00.000+01:00' endTime='2009-04-29T17:30:00.000+01:00'>"
+				"<gd:reminder minutes='10' method='email'/>"
+				"<gd:reminder minutes='10' method='alert'/>"
+			"</gd:when>"
+			"<gd:who rel='http://schemas.google.com/g/2005#event.organizer' valueString='GData Test' email='libgdata test googlemail com'/>"
+			"<gd:where valueString=''/>"
+		"</entry>", -1, &error);
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_ENTRY (event));
+	g_clear_error (&error);
+
+	/* Check the original event */
+	g_assert (gdata_calendar_event_is_exception (event) == TRUE);
+
+	gdata_calendar_event_get_original_event_details (event, &id, &uri);
+	g_assert_cmpstr (id, ==, "g5928e82rrch95b25f8ud0dlsg");
+	g_assert_cmpstr (uri, ==, "http://www.google.com/calendar/feeds/libgdata test googlemail com/private/full/g5928e82rrch95b25f8ud0dlsg");
+
+	g_object_unref (event);
+}
+
+static void
 test_query_uri (void)
 {
 	GTimeVal time_val, time_val2;
@@ -466,6 +529,7 @@ main (int argc, char *argv[])
 	if (g_test_slow () == TRUE)
 		g_test_add_func ("/calendar/insert/simple", test_insert_simple);
 	g_test_add_func ("/calendar/xml/dates", test_xml_dates);
+	g_test_add_func ("/calendar/xml/recurrence", test_xml_recurrence);
 	g_test_add_func ("/calendar/query/uri", test_query_uri);
 
 	retval = g_test_run ();



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