1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * GData Client
4 * Copyright (C) Philip Withnall 2009–2010 <philip@tecnocode.co.uk>
5 *
6 * GData Client is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * GData Client is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with GData Client. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /**
21 * SECTION:gdata-gd-reminder
22 * @short_description: GData reminder element
23 * @stability: Stable
24 * @include: gdata/gd/gdata-gd-reminder.h
25 *
26 * #GDataGDReminder represents a "reminder" element from the
27 * <ulink type="http" url="http://code.google.com/apis/gdata/docs/2.0/elements.html#gdReminder">GData specification</ulink>.
28 *
29 * Since: 0.4.0
30 */
31
32 #include <glib.h>
33 #include <libxml/parser.h>
34
35 #include "gdata-gd-reminder.h"
36 #include "gdata-parsable.h"
37 #include "gdata-parser.h"
38 #include "gdata-types.h"
39 #include "gdata-comparable.h"
40
41 static void gdata_gd_reminder_comparable_init (GDataComparableIface *iface);
42 static void gdata_gd_reminder_finalize (GObject *object);
43 static void gdata_gd_reminder_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
44 static void gdata_gd_reminder_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
45 static gboolean pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error);
46 static void pre_get_xml (GDataParsable *parsable, GString *xml_string);
47 static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces);
48
49 struct _GDataGDReminderPrivate {
50 gchar *method;
51 gint64 absolute_time;
52 gint relative_time;
53 };
54
55 enum {
56 PROP_METHOD = 1,
57 PROP_ABSOLUTE_TIME,
58 PROP_IS_ABSOLUTE_TIME,
59 PROP_RELATIVE_TIME
60 };
61
G_DEFINE_TYPE_WITH_CODE(GDataGDReminder,gdata_gd_reminder,GDATA_TYPE_PARSABLE,G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE,gdata_gd_reminder_comparable_init))62 G_DEFINE_TYPE_WITH_CODE (GDataGDReminder, gdata_gd_reminder, GDATA_TYPE_PARSABLE,
63 G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMPARABLE, gdata_gd_reminder_comparable_init))
64
65 static void
66 gdata_gd_reminder_class_init (GDataGDReminderClass *klass)
67 {
68 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
69 GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
70
71 g_type_class_add_private (klass, sizeof (GDataGDReminderPrivate));
72
73 gobject_class->get_property = gdata_gd_reminder_get_property;
74 gobject_class->set_property = gdata_gd_reminder_set_property;
75 gobject_class->finalize = gdata_gd_reminder_finalize;
76
77 parsable_class->pre_parse_xml = pre_parse_xml;
78 parsable_class->pre_get_xml = pre_get_xml;
79 parsable_class->get_namespaces = get_namespaces;
80 parsable_class->element_name = "reminder";
81 parsable_class->element_namespace = "gd";
82
83 /**
84 * GDataGDReminder:method:
85 *
86 * The notification method the reminder should use. For example: %GDATA_GD_REMINDER_ALERT or %GDATA_GD_REMINDER_EMAIL.
87 *
88 * For more information, see the
89 * <ulink type="http" url="http://code.google.com/apis/gdata/docs/2.0/elements.html#gdReminder">GData specification</ulink>.
90 *
91 * Since: 0.4.0
92 */
93 g_object_class_install_property (gobject_class, PROP_METHOD,
94 g_param_spec_string ("method",
95 "Method", "The notification method the reminder should use.",
96 NULL,
97 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
98
99 /**
100 * GDataGDReminder:absolute-time:
101 *
102 * Absolute time at which the reminder should be issued.
103 *
104 * For more information, see the
105 * <ulink type="http" url="http://code.google.com/apis/gdata/docs/2.0/elements.html#gdReminder">GData specification</ulink>.
106 *
107 * Since: 0.4.0
108 */
109 g_object_class_install_property (gobject_class, PROP_ABSOLUTE_TIME,
110 g_param_spec_int64 ("absolute-time",
111 "Absolute time", "Absolute time at which the reminder should be issued.",
112 -1, G_MAXINT64, -1,
113 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
114
115 /**
116 * GDataGDReminder:is-absolute-time:
117 *
118 * Whether the reminder is specified as an absolute or relative time.
119 *
120 * For more information, see the
121 * <ulink type="http" url="http://code.google.com/apis/gdata/docs/2.0/elements.html#gdReminder">GData specification</ulink>.
122 *
123 * Since: 0.4.0
124 */
125 g_object_class_install_property (gobject_class, PROP_IS_ABSOLUTE_TIME,
126 g_param_spec_boolean ("is-absolute-time",
127 "Absolute time?", "Whether the reminder is specified as an absolute or relative time.",
128 FALSE,
129 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
130
131 /**
132 * GDataGDReminder:relative-time:
133 *
134 * Time at which the reminder should be issued, in minutes relative to the start time of the corresponding event.
135 *
136 * For more information, see the
137 * <ulink type="http" url="http://code.google.com/apis/gdata/docs/2.0/elements.html#gdReminder">GData specification</ulink>.
138 *
139 * Since: 0.4.0
140 */
141 g_object_class_install_property (gobject_class, PROP_RELATIVE_TIME,
142 g_param_spec_int ("relative-time",
143 "Relative time", "Time at which the reminder should be issued, in minutes.",
144 -1, G_MAXINT, -1,
145 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
146 }
147
148 static gint
compare_with(GDataComparable * self,GDataComparable * other)149 compare_with (GDataComparable *self, GDataComparable *other)
150 {
151 gint method_cmp, time_cmp;
152 GDataGDReminder *a = (GDataGDReminder*) self, *b = (GDataGDReminder*) other;
153
154 if (gdata_gd_reminder_is_absolute_time (a) != gdata_gd_reminder_is_absolute_time (b))
155 return 1;
156
157 method_cmp = g_strcmp0 (a->priv->method, b->priv->method);
158 if (gdata_gd_reminder_is_absolute_time (a) == TRUE) {
159 time_cmp = a->priv->absolute_time - b->priv->absolute_time;
160 } else {
161 time_cmp = a->priv->relative_time - b->priv->relative_time;
162 }
163
164 if (method_cmp == 0)
165 return time_cmp;
166 else
167 return method_cmp;
168 }
169
170 static void
gdata_gd_reminder_comparable_init(GDataComparableIface * iface)171 gdata_gd_reminder_comparable_init (GDataComparableIface *iface)
172 {
173 iface->compare_with = compare_with;
174 }
175
176 static void
gdata_gd_reminder_init(GDataGDReminder * self)177 gdata_gd_reminder_init (GDataGDReminder *self)
178 {
179 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_GD_REMINDER, GDataGDReminderPrivate);
180 self->priv->absolute_time = -1;
181 }
182
183 static void
gdata_gd_reminder_finalize(GObject * object)184 gdata_gd_reminder_finalize (GObject *object)
185 {
186 GDataGDReminderPrivate *priv = GDATA_GD_REMINDER (object)->priv;
187
188 g_free (priv->method);
189
190 /* Chain up to the parent class */
191 G_OBJECT_CLASS (gdata_gd_reminder_parent_class)->finalize (object);
192 }
193
194 static void
gdata_gd_reminder_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)195 gdata_gd_reminder_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
196 {
197 GDataGDReminderPrivate *priv = GDATA_GD_REMINDER (object)->priv;
198
199 switch (property_id) {
200 case PROP_METHOD:
201 g_value_set_string (value, priv->method);
202 break;
203 case PROP_ABSOLUTE_TIME:
204 g_value_set_int64 (value, priv->absolute_time);
205 break;
206 case PROP_IS_ABSOLUTE_TIME:
207 g_value_set_boolean (value, gdata_gd_reminder_is_absolute_time (GDATA_GD_REMINDER (object)));
208 break;
209 case PROP_RELATIVE_TIME:
210 g_value_set_int (value, priv->relative_time);
211 break;
212 default:
213 /* We don't have any other property... */
214 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
215 break;
216 }
217 }
218
219 static void
gdata_gd_reminder_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)220 gdata_gd_reminder_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
221 {
222 GDataGDReminder *self = GDATA_GD_REMINDER (object);
223
224 switch (property_id) {
225 case PROP_METHOD:
226 gdata_gd_reminder_set_method (self, g_value_get_string (value));
227 break;
228 case PROP_ABSOLUTE_TIME:
229 gdata_gd_reminder_set_absolute_time (self, g_value_get_int64 (value));
230 break;
231 case PROP_RELATIVE_TIME:
232 gdata_gd_reminder_set_relative_time (self, g_value_get_int (value));
233 break;
234 default:
235 /* We don't have any other property... */
236 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
237 break;
238 }
239 }
240
241 static gboolean
pre_parse_xml(GDataParsable * parsable,xmlDoc * doc,xmlNode * root_node,gpointer user_data,GError ** error)242 pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error)
243 {
244 GDataGDReminderPrivate *priv = GDATA_GD_REMINDER (parsable)->priv;
245 xmlChar *absolute_time, *relative_time;
246 gint64 absolute_time_int64;
247 gint relative_time_int = -1;
248 gboolean is_absolute_time = FALSE;
249
250 /* Absolute time */
251 absolute_time = xmlGetProp (root_node, (xmlChar*) "absoluteTime");
252 if (absolute_time != NULL) {
253 is_absolute_time = TRUE;
254 if (gdata_parser_int64_from_iso8601 ((gchar*) absolute_time, &absolute_time_int64) == FALSE) {
255 /* Error */
256 gdata_parser_error_not_iso8601_format (root_node, (gchar*) absolute_time, error);
257 xmlFree (absolute_time);
258 return FALSE;
259 }
260 xmlFree (absolute_time);
261 }
262
263 /* Relative time */
264 relative_time = xmlGetProp (root_node, (xmlChar*) "days");
265 if (relative_time != NULL) {
266 relative_time_int = g_ascii_strtoll ((gchar*) relative_time, NULL, 10) * 60 * 24;
267 } else {
268 relative_time = xmlGetProp (root_node, (xmlChar*) "hours");
269 if (relative_time != NULL) {
270 relative_time_int = g_ascii_strtoll ((gchar*) relative_time, NULL, 10) * 60;
271 } else {
272 relative_time = xmlGetProp (root_node, (xmlChar*) "minutes");
273 if (relative_time != NULL)
274 relative_time_int = g_ascii_strtoll ((gchar*) relative_time, NULL, 10);
275 }
276 }
277 xmlFree (relative_time);
278
279 if (is_absolute_time == TRUE) {
280 priv->absolute_time = absolute_time_int64;
281 priv->relative_time = -1;
282 } else {
283 priv->absolute_time = -1;
284 priv->relative_time = relative_time_int;
285 }
286
287 priv->method = (gchar*) xmlGetProp (root_node, (xmlChar*) "method");
288
289 return TRUE;
290 }
291
292 static void
pre_get_xml(GDataParsable * parsable,GString * xml_string)293 pre_get_xml (GDataParsable *parsable, GString *xml_string)
294 {
295 GDataGDReminderPrivate *priv = GDATA_GD_REMINDER (parsable)->priv;
296
297 if (priv->relative_time == -1) {
298 gchar *absolute_time = gdata_parser_int64_to_iso8601 (priv->absolute_time);
299 g_string_append_printf (xml_string, " absoluteTime='%s'", absolute_time);
300 g_free (absolute_time);
301 } else {
302 g_string_append_printf (xml_string, " minutes='%i'", priv->relative_time);
303 }
304
305 if (priv->method != NULL)
306 gdata_parser_string_append_escaped (xml_string, " method='", priv->method, "'");
307 }
308
309 static void
get_namespaces(GDataParsable * parsable,GHashTable * namespaces)310 get_namespaces (GDataParsable *parsable, GHashTable *namespaces)
311 {
312 g_hash_table_insert (namespaces, (gchar*) "gd", (gchar*) "http://schemas.google.com/g/2005");
313 }
314
315 /**
316 * gdata_gd_reminder_new:
317 * @method: (allow-none): the notification method the reminder should use, or %NULL
318 * @absolute_time: the absolute time for the reminder, or <code class="literal">-1</code>
319 * @relative_time: the relative time for the reminder, in minutes, or <code class="literal">-1</code>
320 *
321 * Creates a new #GDataGDReminder. More information is available in the <ulink type="http"
322 * url="http://code.google.com/apis/gdata/docs/2.0/elements.html#gdReminder">GData specification</ulink>.
323 *
324 * Return value: a new #GDataGDReminder, or %NULL; unref with g_object_unref()
325 *
326 * Since: 0.2.0
327 */
328 GDataGDReminder *
gdata_gd_reminder_new(const gchar * method,gint64 absolute_time,gint relative_time)329 gdata_gd_reminder_new (const gchar *method, gint64 absolute_time, gint relative_time)
330 {
331 g_return_val_if_fail (absolute_time == -1 || relative_time == -1, NULL);
332 g_return_val_if_fail (absolute_time >= -1, NULL);
333 g_return_val_if_fail (relative_time >= -1, NULL);
334 return g_object_new (GDATA_TYPE_GD_REMINDER, "absolute-time", absolute_time, "relative-time", relative_time, "method", method, NULL);
335 }
336
337 /**
338 * gdata_gd_reminder_get_method:
339 * @self: a #GDataGDReminder
340 *
341 * Gets the #GDataGDReminder:method property.
342 *
343 * Return value: the method, or %NULL
344 *
345 * Since: 0.4.0
346 */
347 const gchar *
gdata_gd_reminder_get_method(GDataGDReminder * self)348 gdata_gd_reminder_get_method (GDataGDReminder *self)
349 {
350 g_return_val_if_fail (GDATA_IS_GD_REMINDER (self), NULL);
351 return self->priv->method;
352 }
353
354 /**
355 * gdata_gd_reminder_set_method:
356 * @self: a #GDataGDReminder
357 * @method: (allow-none): the new method, or %NULL
358 *
359 * Sets the #GDataGDReminder:method property to @method.
360 *
361 * Set @method to %NULL to unset the property.
362 *
363 * Since: 0.4.0
364 */
365 void
gdata_gd_reminder_set_method(GDataGDReminder * self,const gchar * method)366 gdata_gd_reminder_set_method (GDataGDReminder *self, const gchar *method)
367 {
368 g_return_if_fail (GDATA_IS_GD_REMINDER (self));
369
370 g_free (self->priv->method);
371 self->priv->method = g_strdup (method);
372 g_object_notify (G_OBJECT (self), "method");
373 }
374
375 /**
376 * gdata_gd_reminder_get_absolute_time:
377 * @self: a #GDataGDReminder
378 *
379 * Gets the #GDataGDReminder:absolute-time property. If the property is unset, <code class="literal">-1</code> will be returned.
380 *
381 * Return value: the UNIX timestamp of the absolute time for the reminder, or <code class="literal">-1</code>
382 *
383 * Since: 0.4.0
384 */
385 gint64
gdata_gd_reminder_get_absolute_time(GDataGDReminder * self)386 gdata_gd_reminder_get_absolute_time (GDataGDReminder *self)
387 {
388 g_return_val_if_fail (GDATA_IS_GD_REMINDER (self), -1);
389 return self->priv->absolute_time;
390 }
391
392 /**
393 * gdata_gd_reminder_set_absolute_time:
394 * @self: a #GDataGDReminder
395 * @absolute_time: the new absolute time, or <code class="literal">-1</code>
396 *
397 * Sets the #GDataGDReminder:absolute-time property to @absolute_time.
398 *
399 * Set @absolute_time to <code class="literal">-1</code> to unset the property.
400 *
401 * Since: 0.4.0
402 */
403 void
gdata_gd_reminder_set_absolute_time(GDataGDReminder * self,gint64 absolute_time)404 gdata_gd_reminder_set_absolute_time (GDataGDReminder *self, gint64 absolute_time)
405 {
406 g_return_if_fail (GDATA_IS_GD_REMINDER (self));
407 g_return_if_fail (absolute_time >= -1);
408
409 self->priv->absolute_time = absolute_time;
410 g_object_notify (G_OBJECT (self), "absolute-time");
411 }
412
413 /**
414 * gdata_gd_reminder_is_absolute_time:
415 * @self: a #GDataGDReminder
416 *
417 * Returns whether the reminder is specified as an absolute time, or as a number of minutes after
418 * the corresponding event's start time.
419 *
420 * Return value: %TRUE if the reminder is absolute, %FALSE otherwise
421 *
422 * Since: 0.4.0
423 */
424 gboolean
gdata_gd_reminder_is_absolute_time(GDataGDReminder * self)425 gdata_gd_reminder_is_absolute_time (GDataGDReminder *self)
426 {
427 g_return_val_if_fail (GDATA_IS_GD_REMINDER (self), FALSE);
428 return (self->priv->relative_time == -1) ? TRUE : FALSE;
429 }
430
431 /**
432 * gdata_gd_reminder_get_relative_time:
433 * @self: a #GDataGDReminder
434 *
435 * Gets the #GDataGDReminder:relative-time property.
436 *
437 * Return value: the relative time, or <code class="literal">-1</code>
438 *
439 * Since: 0.4.0
440 */
441 gint
gdata_gd_reminder_get_relative_time(GDataGDReminder * self)442 gdata_gd_reminder_get_relative_time (GDataGDReminder *self)
443 {
444 g_return_val_if_fail (GDATA_IS_GD_REMINDER (self), -1);
445 return self->priv->relative_time;
446 }
447
448 /**
449 * gdata_gd_reminder_set_relative_time:
450 * @self: a #GDataGDReminder
451 * @relative_time: the new relative time, or <code class="literal">-1</code>
452 *
453 * Sets the #GDataGDReminder:relative-time property to @relative_time.
454 *
455 * Set @relative_time to <code class="literal">-1</code> to unset the property.
456 *
457 * Since: 0.4.0
458 */
459 void
gdata_gd_reminder_set_relative_time(GDataGDReminder * self,gint relative_time)460 gdata_gd_reminder_set_relative_time (GDataGDReminder *self, gint relative_time)
461 {
462 g_return_if_fail (GDATA_IS_GD_REMINDER (self));
463 g_return_if_fail (relative_time >= -1);
464
465 self->priv->relative_time = relative_time;
466 g_object_notify (G_OBJECT (self), "method");
467 }
468