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-media-category
22 * @short_description: Media RSS category element
23 * @stability: Stable
24 * @include: gdata/media/gdata-media-category.h
25 *
26 * #GDataMediaCategory represents a "category" element from the
27 * <ulink type="http" url="http://video.search.yahoo.com/mrss">Media RSS specification</ulink>.
28 *
29 * Since: 0.4.0
30 */
31
32 #include <glib.h>
33 #include <libxml/parser.h>
34
35 #include "gdata-media-category.h"
36 #include "gdata-parsable.h"
37 #include "gdata-parser.h"
38 #include "gdata-types.h"
39
40 static void gdata_media_category_finalize (GObject *object);
41 static void gdata_media_category_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
42 static void gdata_media_category_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
43 static gboolean pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error);
44 static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error);
45 static void pre_get_xml (GDataParsable *parsable, GString *xml_string);
46 static void get_xml (GDataParsable *parsable, GString *xml_string);
47 static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces);
48
49 struct _GDataMediaCategoryPrivate {
50 gchar *category;
51 gchar *scheme;
52 gchar *label;
53 };
54
55 enum {
56 PROP_CATEGORY = 1,
57 PROP_SCHEME,
58 PROP_LABEL
59 };
60
G_DEFINE_TYPE(GDataMediaCategory,gdata_media_category,GDATA_TYPE_PARSABLE)61 G_DEFINE_TYPE (GDataMediaCategory, gdata_media_category, GDATA_TYPE_PARSABLE)
62
63 static void
64 gdata_media_category_class_init (GDataMediaCategoryClass *klass)
65 {
66 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
67 GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
68
69 g_type_class_add_private (klass, sizeof (GDataMediaCategoryPrivate));
70
71 gobject_class->get_property = gdata_media_category_get_property;
72 gobject_class->set_property = gdata_media_category_set_property;
73 gobject_class->finalize = gdata_media_category_finalize;
74
75 parsable_class->pre_parse_xml = pre_parse_xml;
76 parsable_class->parse_xml = parse_xml;
77 parsable_class->pre_get_xml = pre_get_xml;
78 parsable_class->get_xml = get_xml;
79 parsable_class->get_namespaces = get_namespaces;
80 parsable_class->element_name = "category";
81 parsable_class->element_namespace = "media";
82
83 /**
84 * GDataMediaCategory:category:
85 *
86 * The category name.
87 *
88 * For more information, see the <ulink type="http" url="http://video.search.yahoo.com/mrss">Media RSS specification</ulink>.
89 *
90 * Since: 0.4.0
91 */
92 g_object_class_install_property (gobject_class, PROP_CATEGORY,
93 g_param_spec_string ("category",
94 "Category", "The category name.",
95 NULL,
96 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
97
98 /**
99 * GDataMediaCategory:scheme:
100 *
101 * A URI that identifies the categorization scheme.
102 *
103 * For more information, see the <ulink type="http" url="http://video.search.yahoo.com/mrss">Media RSS specification</ulink>.
104 *
105 * Since: 0.4.0
106 */
107 g_object_class_install_property (gobject_class, PROP_SCHEME,
108 g_param_spec_string ("scheme",
109 "Scheme", "A URI that identifies the categorization scheme.",
110 NULL,
111 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
112
113 /**
114 * GDataMediaCategory:label:
115 *
116 * A human-readable label that can be displayed in end-user applications.
117 *
118 * For more information, see the <ulink type="http" url="http://video.search.yahoo.com/mrss">Media RSS specification</ulink>.
119 *
120 * Since: 0.4.0
121 */
122 g_object_class_install_property (gobject_class, PROP_LABEL,
123 g_param_spec_string ("label",
124 "Label", "A human-readable label that can be displayed in end-user applications.",
125 NULL,
126 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
127 }
128
129 static void
gdata_media_category_init(GDataMediaCategory * self)130 gdata_media_category_init (GDataMediaCategory *self)
131 {
132 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_MEDIA_CATEGORY, GDataMediaCategoryPrivate);
133 }
134
135 static void
gdata_media_category_finalize(GObject * object)136 gdata_media_category_finalize (GObject *object)
137 {
138 GDataMediaCategoryPrivate *priv = GDATA_MEDIA_CATEGORY (object)->priv;
139
140 g_free (priv->category);
141 g_free (priv->scheme);
142 g_free (priv->label);
143
144 /* Chain up to the parent class */
145 G_OBJECT_CLASS (gdata_media_category_parent_class)->finalize (object);
146 }
147
148 static void
gdata_media_category_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)149 gdata_media_category_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
150 {
151 GDataMediaCategoryPrivate *priv = GDATA_MEDIA_CATEGORY (object)->priv;
152
153 switch (property_id) {
154 case PROP_CATEGORY:
155 g_value_set_string (value, priv->category);
156 break;
157 case PROP_SCHEME:
158 g_value_set_string (value, priv->scheme);
159 break;
160 case PROP_LABEL:
161 g_value_set_string (value, priv->label);
162 break;
163 default:
164 /* We don't have any other property... */
165 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
166 break;
167 }
168 }
169
170 static void
gdata_media_category_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)171 gdata_media_category_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
172 {
173 GDataMediaCategory *self = GDATA_MEDIA_CATEGORY (object);
174
175 switch (property_id) {
176 case PROP_CATEGORY:
177 gdata_media_category_set_category (self, g_value_get_string (value));
178 break;
179 case PROP_SCHEME:
180 gdata_media_category_set_scheme (self, g_value_get_string (value));
181 break;
182 case PROP_LABEL:
183 gdata_media_category_set_label (self, g_value_get_string (value));
184 break;
185 default:
186 /* We don't have any other property... */
187 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
188 break;
189 }
190 }
191
192 static gboolean
pre_parse_xml(GDataParsable * parsable,xmlDoc * doc,xmlNode * root_node,gpointer user_data,GError ** error)193 pre_parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *root_node, gpointer user_data, GError **error)
194 {
195 GDataMediaCategoryPrivate *priv = GDATA_MEDIA_CATEGORY (parsable)->priv;
196 xmlChar *category, *scheme;
197
198 category = xmlNodeListGetString (doc, root_node->children, TRUE);
199 if (category == NULL || *category == '\0') {
200 xmlFree (category);
201 return gdata_parser_error_required_content_missing (root_node, error);
202 }
203
204 scheme = xmlGetProp (root_node, (xmlChar*) "scheme");
205 if (scheme != NULL && *scheme == '\0') {
206 xmlFree (scheme);
207 xmlFree (category);
208 return gdata_parser_error_required_property_missing (root_node, "scheme", error);
209 } else if (scheme == NULL) {
210 /* Default */
211 scheme = xmlStrdup ((xmlChar*) "http://video.search.yahoo.com/mrss/category_schema");
212 }
213
214 priv->category = (gchar*) category;
215 priv->scheme = (gchar*) scheme;
216 priv->label = (gchar*) xmlGetProp (root_node, (xmlChar*) "label");
217
218 return TRUE;
219 }
220
221 static gboolean
parse_xml(GDataParsable * parsable,xmlDoc * doc,xmlNode * node,gpointer user_data,GError ** error)222 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
223 {
224 /* Textual content's handled in pre_parse_xml */
225 if (node->type != XML_ELEMENT_NODE)
226 return TRUE;
227
228 return GDATA_PARSABLE_CLASS (gdata_media_category_parent_class)->parse_xml (parsable, doc, node, user_data, error);
229 }
230
231 static void
pre_get_xml(GDataParsable * parsable,GString * xml_string)232 pre_get_xml (GDataParsable *parsable, GString *xml_string)
233 {
234 GDataMediaCategoryPrivate *priv = GDATA_MEDIA_CATEGORY (parsable)->priv;
235
236 if (priv->scheme != NULL)
237 gdata_parser_string_append_escaped (xml_string, " scheme='", priv->scheme, "'");
238 if (priv->label != NULL)
239 gdata_parser_string_append_escaped (xml_string, " label='", priv->label, "'");
240 }
241
242 static void
get_xml(GDataParsable * parsable,GString * xml_string)243 get_xml (GDataParsable *parsable, GString *xml_string)
244 {
245 gdata_parser_string_append_escaped (xml_string, NULL, GDATA_MEDIA_CATEGORY (parsable)->priv->category, NULL);
246 }
247
248 static void
get_namespaces(GDataParsable * parsable,GHashTable * namespaces)249 get_namespaces (GDataParsable *parsable, GHashTable *namespaces)
250 {
251 g_hash_table_insert (namespaces, (gchar*) "media", (gchar*) "http://search.yahoo.com/mrss/");
252 }
253
254 /**
255 * gdata_media_category_new:
256 * @category: a category describing the content
257 * @scheme: (allow-none): a URI identifying the categorisation scheme, or %NULL
258 * @label: (allow-none): a human-readable name for the category, or %NULL
259 *
260 * Creates a new #GDataMediaCategory. More information is available in the <ulink type="http"
261 * url="http://search.yahoo.com/mrss/">Media RSS specification</ulink>.
262 *
263 * Return value: a new #GDataMediaCategory, or %NULL; unref with g_object_unref()
264 */
265 GDataMediaCategory *
gdata_media_category_new(const gchar * category,const gchar * scheme,const gchar * label)266 gdata_media_category_new (const gchar *category, const gchar *scheme, const gchar *label)
267 {
268 g_return_val_if_fail (category != NULL && *category != '\0', NULL);
269 g_return_val_if_fail (scheme == NULL || *scheme != '\0', NULL);
270 return g_object_new (GDATA_TYPE_MEDIA_CATEGORY, "category", category, "scheme", scheme, "label", label, NULL);
271 }
272
273 /**
274 * gdata_media_category_get_category:
275 * @self: a #GDataMediaCategory
276 *
277 * Gets the #GDataMediaCategory:category property.
278 *
279 * Return value: the actual category
280 *
281 * Since: 0.4.0
282 */
283 const gchar *
gdata_media_category_get_category(GDataMediaCategory * self)284 gdata_media_category_get_category (GDataMediaCategory *self)
285 {
286 g_return_val_if_fail (GDATA_IS_MEDIA_CATEGORY (self), NULL);
287 return self->priv->category;
288 }
289
290 /**
291 * gdata_media_category_set_category:
292 * @self: a #GDataMediaCategory
293 * @category: the new category
294 *
295 * Sets the #GDataMediaCategory:category property to @category.
296 *
297 * Since: 0.4.0
298 */
299 void
gdata_media_category_set_category(GDataMediaCategory * self,const gchar * category)300 gdata_media_category_set_category (GDataMediaCategory *self, const gchar *category)
301 {
302 g_return_if_fail (GDATA_IS_MEDIA_CATEGORY (self));
303 g_return_if_fail (category != NULL && *category != '\0');
304
305 g_free (self->priv->category);
306 self->priv->category = g_strdup (category);
307 g_object_notify (G_OBJECT (self), "category");
308 }
309
310 /**
311 * gdata_media_category_get_scheme:
312 * @self: a #GDataMediaCategory
313 *
314 * Gets the #GDataMediaCategory:scheme property.
315 *
316 * Return value: the category's scheme, or %NULL
317 *
318 * Since: 0.4.0
319 */
320 const gchar *
gdata_media_category_get_scheme(GDataMediaCategory * self)321 gdata_media_category_get_scheme (GDataMediaCategory *self)
322 {
323 g_return_val_if_fail (GDATA_IS_MEDIA_CATEGORY (self), NULL);
324 return self->priv->scheme;
325 }
326
327 /**
328 * gdata_media_category_set_scheme:
329 * @self: a #GDataMediaCategory
330 * @scheme: (allow-none): the category's new scheme, or %NULL
331 *
332 * Sets the #GDataMediaCategory:scheme property to @scheme.
333 *
334 * Set @scheme to %NULL to unset the property.
335 *
336 * Since: 0.4.0
337 */
338 void
gdata_media_category_set_scheme(GDataMediaCategory * self,const gchar * scheme)339 gdata_media_category_set_scheme (GDataMediaCategory *self, const gchar *scheme)
340 {
341 g_return_if_fail (GDATA_IS_MEDIA_CATEGORY (self));
342 g_return_if_fail (scheme == NULL || *scheme != '\0');
343
344 if (scheme == NULL)
345 scheme = "http://video.search.yahoo.com/mrss/category_schema";
346
347 g_free (self->priv->scheme);
348 self->priv->scheme = g_strdup (scheme);
349 g_object_notify (G_OBJECT (self), "scheme");
350 }
351
352 /**
353 * gdata_media_category_get_label:
354 * @self: a #GDataMediaCategory
355 *
356 * Gets the #GDataMediaCategory:label property.
357 *
358 * Return value: the category's label, or %NULL
359 *
360 * Since: 0.4.0
361 */
362 const gchar *
gdata_media_category_get_label(GDataMediaCategory * self)363 gdata_media_category_get_label (GDataMediaCategory *self)
364 {
365 g_return_val_if_fail (GDATA_IS_MEDIA_CATEGORY (self), NULL);
366 return self->priv->label;
367 }
368
369 /**
370 * gdata_media_category_set_label:
371 * @self: a #GDataMediaCategory
372 * @label: (allow-none): the category's new label, or %NULL
373 *
374 * Sets the #GDataMediaCategory:label property to @label.
375 *
376 * Set @label to %NULL to unset the property.
377 *
378 * Since: 0.4.0
379 */
380 void
gdata_media_category_set_label(GDataMediaCategory * self,const gchar * label)381 gdata_media_category_set_label (GDataMediaCategory *self, const gchar *label)
382 {
383 g_return_if_fail (GDATA_IS_MEDIA_CATEGORY (self));
384
385 g_free (self->priv->label);
386 self->priv->label = g_strdup (label);
387 g_object_notify (G_OBJECT (self), "label");
388 }
389