hythmbox-2.98/rhythmdb/rhythmdb-entry-type.c

No issues found

  1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  2  *
  3  *  Copyright (C) 2010  Jonathan Matthew  <jonathan@d14n.org>
  4  *
  5  *  This program is free software; you can redistribute it and/or modify
  6  *  it under the terms of the GNU General Public License as published by
  7  *  the Free Software Foundation; either version 2 of the License, or
  8  *  (at your option) any later version.
  9  *
 10  *  The Rhythmbox authors hereby grant permission for non-GPL compatible
 11  *  GStreamer plugins to be used and distributed together with GStreamer
 12  *  and Rhythmbox. This permission is above and beyond the permissions granted
 13  *  by the GPL license by which Rhythmbox is covered. If you modify this code
 14  *  you may extend this exception to your version of the code, but you are not
 15  *  obligated to do so. If you do not wish to do so, delete this exception
 16  *  statement from your version.
 17  *
 18  *  This program is distributed in the hope that it will be useful,
 19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 21  *  GNU General Public License for more details.
 22  *
 23  *  You should have received a copy of the GNU General Public License
 24  *  along with this program; if not, write to the Free Software
 25  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 26  *
 27  */
 28 
 29 #include "config.h"
 30 
 31 #include "rhythmdb-entry-type.h"
 32 #include "rhythmdb-private.h"
 33 
 34 enum
 35 {
 36 	PROP_0,
 37 	PROP_DB,
 38 	PROP_NAME,
 39 	PROP_SAVE_TO_DISK,
 40 	PROP_TYPE_DATA_SIZE,
 41 	PROP_CATEGORY,
 42 	PROP_HAS_PLAYLISTS		/* temporary */
 43 };
 44 
 45 static void rhythmdb_entry_type_class_init (RhythmDBEntryTypeClass *klass);
 46 static void rhythmdb_entry_type_init (RhythmDBEntryType *etype);
 47 
 48 struct _RhythmDBEntryTypePrivate
 49 {
 50 	RhythmDB *db;
 51 
 52 	char *name;
 53 	gboolean save_to_disk;
 54 	guint entry_type_data_size;
 55 	RhythmDBEntryCategory category;
 56 	gboolean has_playlists;
 57 };
 58 
 59 G_DEFINE_TYPE (RhythmDBEntryType, rhythmdb_entry_type, G_TYPE_OBJECT)
 60 
 61 /**
 62  * SECTION:rhythmdb-entry-type
 63  * @short_description: Database entry type base class
 64  *
 65  * This is the base class for database entry type classes, which provide
 66  * some aspects of the behaviour of database entry types.  There are different
 67  * entry types for songs, radio streams, podcast feeds and episodes, and so on.
 68  *
 69  * Plugins written in Python or Vala can create new entry types by subclassing
 70  * and overriding any methods required.  Plugins written in C can create a new
 71  * instance of the RhythmDBEntryType base class and use its function pointer
 72  * members rather than subclassing.
 73  */
 74 
 75 /**
 76  * rhythmdb_entry_type_get_name:
 77  * @etype: a #RhythmDBEntryType
 78  *
 79  * Returns the name of the entry type
 80  *
 81  * Return value: entry type name
 82  */
 83 const char *
 84 rhythmdb_entry_type_get_name (RhythmDBEntryType *etype)
 85 {
 86 	return etype->priv->name;
 87 }
 88 
 89 /**
 90  * rhythmdb_entry_get_playback_uri:
 91  * @entry: a #RhythmDBEntry
 92  *
 93  * Returns an allocated string containing the playback URI for @entry,
 94  * or NULL if the entry cannot be played.
 95  *
 96  * Return value: playback URI or NULL
 97  */
 98 char *
 99 rhythmdb_entry_get_playback_uri (RhythmDBEntry *entry)
100 {
101 	RhythmDBEntryType *etype = rhythmdb_entry_get_entry_type (entry);
102 	RhythmDBEntryTypeClass *klass = RHYTHMDB_ENTRY_TYPE_GET_CLASS (etype);
103 
104 	if (klass->get_playback_uri) {
105 		return (klass->get_playback_uri) (etype, entry);
106 	} else {
107 		return rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION);
108 	}
109 }
110 
111 /**
112  * rhythmdb_entry_update_availability:
113  * @entry: a #RhythmDBEntry
114  * @avail: an availability event
115  *
116  * Updates @entry to reflect its new availability.
117  */
118 void
119 rhythmdb_entry_update_availability (RhythmDBEntry *entry, RhythmDBEntryAvailability avail)
120 {
121 	RhythmDBEntryType *etype = rhythmdb_entry_get_entry_type (entry);
122 	RhythmDBEntryTypeClass *klass = RHYTHMDB_ENTRY_TYPE_GET_CLASS (etype);
123 
124 	if (klass->update_availability) {
125 		(klass->update_availability) (etype, entry, avail);
126 	} else {
127 		/* do nothing? */
128 	}
129 }
130 
131 /**
132  * rhythmdb_entry_created:
133  * @entry: a newly created #RhythmDBEntry
134  *
135  * Calls the entry type's post-creation method for @entry.
136  */
137 void
138 rhythmdb_entry_created (RhythmDBEntry *entry)
139 {
140 	RhythmDBEntryType *etype;
141 	RhythmDBEntryTypeClass *klass;
142 
143 	etype = rhythmdb_entry_get_entry_type (entry);
144 	klass = RHYTHMDB_ENTRY_TYPE_GET_CLASS (etype);
145 
146 	if (klass->entry_created) {
147 		klass->entry_created (etype, entry);
148 	}
149 }
150 
151 /**
152  * rhythmdb_entry_pre_destroy:
153  * @entry: a #RhythmDBEntry
154  *
155  * Calls the entry type's pre-deletion method for @entry.
156  */
157 void
158 rhythmdb_entry_pre_destroy (RhythmDBEntry *entry)
159 {
160 	RhythmDBEntryType *etype = rhythmdb_entry_get_entry_type (entry);
161 	RhythmDBEntryTypeClass *klass = RHYTHMDB_ENTRY_TYPE_GET_CLASS (etype);
162 	if (klass->destroy_entry) {
163 		klass->destroy_entry (etype, entry);
164 	}
165 }
166 
167 /**
168  * rhythmdb_entry_can_sync_metadata:
169  * @entry: a #RhythmDBEntry
170  *
171  * Calls the entry type's method to check if it can sync metadata for @entry.
172  * Usually this is only true for entries backed by files, where tag-writing is
173  * enabled, and the appropriate tag-writing facilities are available.
174  *
175  * Return value: %TRUE if the entry can be synced
176  */
177 gboolean
178 rhythmdb_entry_can_sync_metadata (RhythmDBEntry *entry)
179 {
180 	RhythmDBEntryType *etype = rhythmdb_entry_get_entry_type (entry);
181 	RhythmDBEntryTypeClass *klass = RHYTHMDB_ENTRY_TYPE_GET_CLASS (etype);
182 	if (klass->can_sync_metadata) {
183 		return klass->can_sync_metadata (etype, entry);
184 	} else {
185 		return FALSE;
186 	}
187 }
188 
189 /**
190  * rhythmdb_entry_sync_metadata:
191  * @entry: a #RhythmDBEntry
192  * @changes: a list of #RhythmDBEntryChange structures
193  * @error: returns error information
194  *
195  * Calls the entry type's method to sync metadata changes for @entry.
196  */
197 void
198 rhythmdb_entry_sync_metadata (RhythmDBEntry *entry, GSList *changes, GError **error)
199 {
200 	RhythmDBEntryType *etype = rhythmdb_entry_get_entry_type (entry);
201 	RhythmDBEntryTypeClass *klass = RHYTHMDB_ENTRY_TYPE_GET_CLASS (etype);
202 	if (klass->sync_metadata) {
203 		klass->sync_metadata (etype, entry, changes, error);
204 	} else {
205 		/* default implementation? */
206 	}
207 }
208 
209 static void
210 rhythmdb_entry_type_init (RhythmDBEntryType *etype)
211 {
212 	etype->priv = G_TYPE_INSTANCE_GET_PRIVATE (etype,
213 						   RHYTHMDB_TYPE_ENTRY_TYPE,
214 						   RhythmDBEntryTypePrivate);
215 }
216 
217 static void
218 impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
219 {
220 	RhythmDBEntryType *etype = RHYTHMDB_ENTRY_TYPE (object);
221 
222 	switch (prop_id) {
223 	case PROP_DB:
224 		etype->priv->db = g_value_get_object (value);
225 		break;
226 	case PROP_NAME:
227 		etype->priv->name = g_value_dup_string (value);
228 		break;
229 	case PROP_SAVE_TO_DISK:
230 		etype->priv->save_to_disk = g_value_get_boolean (value);
231 		break;
232 	case PROP_TYPE_DATA_SIZE:
233 		etype->priv->entry_type_data_size = g_value_get_uint (value);
234 		break;
235 	case PROP_CATEGORY:
236 		etype->priv->category = g_value_get_enum (value);
237 		break;
238 	case PROP_HAS_PLAYLISTS:
239 		etype->priv->has_playlists = g_value_get_boolean (value);
240 		break;
241 	default:
242 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
243 		break;
244 	}
245 }
246 
247 static void
248 impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
249 {
250 	RhythmDBEntryType *etype = RHYTHMDB_ENTRY_TYPE (object);
251 
252 	switch (prop_id) {
253 	case PROP_DB:
254 		g_value_set_object (value, etype->priv->db);
255 		break;
256 	case PROP_NAME:
257 		g_value_set_string (value, etype->priv->name);
258 		break;
259 	case PROP_SAVE_TO_DISK:
260 		g_value_set_boolean (value, etype->priv->save_to_disk);
261 		break;
262 	case PROP_TYPE_DATA_SIZE:
263 		g_value_set_uint (value, etype->priv->entry_type_data_size);
264 		break;
265 	case PROP_CATEGORY:
266 		g_value_set_enum (value, etype->priv->category);
267 		break;
268 	case PROP_HAS_PLAYLISTS:
269 		g_value_set_boolean (value, etype->priv->has_playlists);
270 		break;
271 	default:
272 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
273 		break;
274 	}
275 }
276 
277 static void
278 impl_finalize (GObject *object)
279 {
280 	RhythmDBEntryType *etype = RHYTHMDB_ENTRY_TYPE (object);
281 
282 	g_free (etype->priv->name);
283 
284 	G_OBJECT_CLASS (rhythmdb_entry_type_parent_class)->finalize (object);
285 }
286 
287 static void
288 rhythmdb_entry_type_class_init (RhythmDBEntryTypeClass *klass)
289 {
290 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
291 
292 	object_class->set_property = impl_set_property;
293 	object_class->get_property = impl_get_property;
294 	object_class->finalize = impl_finalize;
295 
296 	/**
297 	 * RhythmDBEntryType:db:
298 	 *
299 	 * The #RhythmDB instance.
300 	 */
301 	g_object_class_install_property (object_class,
302 					 PROP_DB,
303 					 g_param_spec_object ("db",
304 							      "RhythmDB",
305 							      "RhythmDB instance",
306 							      RHYTHMDB_TYPE,
307 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
308 
309 	/**
310 	 * RhythmDBEntryType:name:
311 	 *
312 	 * Entry type name.  This must be unique.
313 	 */
314 	g_object_class_install_property (object_class,
315 					 PROP_NAME,
316 					 g_param_spec_string ("name",
317 							      "name",
318 							      "entry type name",
319 							      NULL,
320 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
321 
322 	/**
323 	 * RhythmDBEntryType:save-to-disk:
324 	 *
325 	 * If %TRUE, entries of this type should be written to the
326 	 * on-disk database.
327 	 */
328 	g_object_class_install_property (object_class,
329 					 PROP_SAVE_TO_DISK,
330 					 g_param_spec_boolean ("save-to-disk",
331 							       "save to disk",
332 							       "whether to save this type of entry to disk",
333 							       FALSE,
334 							       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
335 	/**
336 	 * RhythmDBEntryType:type-data-size:
337 	 *
338 	 * The size of the type-specific data structure to allocate for each
339 	 * entry of this type.
340 	 */
341 	g_object_class_install_property (object_class,
342 					 PROP_TYPE_DATA_SIZE,
343 					 g_param_spec_uint ("type-data-size",
344 							    "type data size",
345 							    "size of entry type specific data",
346 							    0, G_MAXUINT, 0,
347 							    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
348 	/**
349 	 * RhythmDBEntryType:category:
350 	 *
351 	 * The #RhythmDBEntryCategory that this entry type fits into.
352 	 */
353 	g_object_class_install_property (object_class,
354 					 PROP_CATEGORY,
355 					 g_param_spec_enum ("category",
356 							    "category",
357 							    "RhythmDBEntryCategory for the entry type",
358 							    RHYTHMDB_TYPE_ENTRY_CATEGORY,
359 							    RHYTHMDB_ENTRY_NORMAL,
360 							    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
361 	/**
362 	 * RhythmDBEntryType:has-playlists:
363 	 *
364 	 * If %TRUE, entries of this type can be added to playlists.
365 	 */
366 	g_object_class_install_property (object_class,
367 					 PROP_HAS_PLAYLISTS,
368 					 g_param_spec_boolean ("has-playlists",
369 							       "has playlists",
370 							       "whether this type of entry has playlists",
371 							       FALSE,
372 							       G_PARAM_READWRITE));
373 
374 	g_type_class_add_private (klass, sizeof (RhythmDBEntryTypePrivate));
375 }
376 
377 
378 
379 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
380 
381 /**
382  * RhythmDBEntryCategory:
383  * @RHYTHMDB_ENTRY_NORMAL: Normal files on disk
384  * @RHYTHMDB_ENTRY_STREAM: Endless streams (eg shoutcast)
385  * @RHYTHMDB_ENTRY_CONTAINER: Containers for other entries (eg podcast feeds)
386  * @RHYTHMDB_ENTRY_VIRTUAL: Things Rhythmbox shouldn't normally deal with
387  *
388  * Categories used to group entry types.  These are used in a few places to control
389  * handling of entries.
390  */
391 
392 GType
393 rhythmdb_entry_category_get_type (void)
394 {
395 	static GType etype = 0;
396 
397 	if (etype == 0)
398 	{
399 		static const GEnumValue values[] =
400 		{
401 			ENUM_ENTRY (RHYTHMDB_ENTRY_NORMAL, "normal"),
402 			ENUM_ENTRY (RHYTHMDB_ENTRY_STREAM, "stream"),
403 			ENUM_ENTRY (RHYTHMDB_ENTRY_CONTAINER, "container"),
404 			ENUM_ENTRY (RHYTHMDB_ENTRY_VIRTUAL, "virtual"),
405 			{ 0, 0, 0 }
406 		};
407 
408 		etype = g_enum_register_static ("RhythmDBEntryCategory", values);
409 	}
410 
411 	return etype;
412 }
413 
414 /**
415  * RhythmDBEntryAvailability:
416  * @RHYTHMDB_ENTRY_AVAIL_CHECKED: File was checked and found present
417  * @RHYTHMDB_ENTRY_AVAIL_MOUNTED: Filesystem holding the file was mounted
418  * @RHYTHMDB_ENTRY_AVAIL_UNMOUNTED: Filesystem holding the file was unmounted
419  * @RHYTHMDB_ENTRY_AVAIL_NOT_FOUND: File was checked or played and could not be found
420  *
421  * Various events that can result in changes to the entry's availability.
422  */
423 
424 GType
425 rhythmdb_entry_availability_get_type (void)
426 {
427 	static GType etype = 0;
428 
429 	if (etype == 0)
430 	{
431 		static const GEnumValue values[] =
432 		{
433 			ENUM_ENTRY (RHYTHMDB_ENTRY_AVAIL_CHECKED, "checked"),
434 			ENUM_ENTRY (RHYTHMDB_ENTRY_AVAIL_MOUNTED, "mounted"),
435 			ENUM_ENTRY (RHYTHMDB_ENTRY_AVAIL_UNMOUNTED, "unmounted"),
436 			ENUM_ENTRY (RHYTHMDB_ENTRY_AVAIL_NOT_FOUND, "not-found"),
437 			{ 0, 0, 0 }
438 		};
439 
440 		etype = g_enum_register_static ("RhythmDBEntryAvailability", values);
441 	}
442 
443 	return etype;
444 }