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 }