No issues found
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Copyright (C) 2005 Jonathan Matthew <jonathan@kaolin.hn.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 <libxml/tree.h>
32 #include <glib/gi18n.h>
33 #include <gio/gio.h>
34 #include <gtk/gtk.h>
35
36 #include "rb-play-queue-source.h"
37 #include "rb-playlist-xml.h"
38 #include "rb-song-info.h"
39 #include "rb-stock-icons.h"
40 #include "rb-util.h"
41 #include "rb-debug.h"
42 #include "rb-play-order-queue.h"
43
44 /**
45 * SECTION:rb-play-queue-source
46 * @short_description: source object for the play queue
47 *
48 * The main interesting thing about this source is that is
49 * contains a second #RBEntryView to be displayed in the side
50 * pane (beneath the source list). This entry view displays
51 * the track title, artist, and album in a single column,
52 * split across three lines so the information mostly fits in
53 * the usual horizontal space allowed for the side bar.
54 */
55
56 static const char *RB_PLAY_QUEUE_DBUS_PATH = "/org/gnome/Rhythmbox3/PlayQueue";
57 static const char *RB_PLAY_QUEUE_IFACE_NAME = "org.gnome.Rhythmbox3.PlayQueue";
58
59 static const char *rb_play_queue_dbus_spec =
60 "<node>"
61 " <interface name='org.gnome.Rhythmbox3.PlayQueue'>"
62 " <method name='AddToQueue'>"
63 " <arg type='s' name='uri'/>"
64 " </method>"
65 " <method name='RemoveFromQueue'>"
66 " <arg type='s' name='uri'/>"
67 " </method>"
68 " <method name='ClearQueue'/>"
69 " </interface>"
70 "</node>";
71
72 static void rb_play_queue_source_constructed (GObject *object);
73 static void rb_play_queue_source_get_property (GObject *object,
74 guint prop_id,
75 GValue *value,
76 GParamSpec *pspec);
77 static void rb_play_queue_source_track_info_cell_data_func (GtkTreeViewColumn *column,
78 GtkCellRenderer *renderer,
79 GtkTreeModel *tree_model,
80 GtkTreeIter *iter,
81 RBPlaylistSource *source);
82 static void rb_play_queue_source_row_inserted_cb (GtkTreeModel *model,
83 GtkTreePath *path,
84 GtkTreeIter *iter,
85 RBPlayQueueSource *source);
86 static void rb_play_queue_source_row_deleted_cb (GtkTreeModel *model,
87 GtkTreePath *path,
88 RBPlayQueueSource *source);
89 static void rb_play_queue_source_update_count (RBPlayQueueSource *source,
90 GtkTreeModel *model,
91 gint offset);
92 static void impl_show_entry_view_popup (RBPlaylistSource *source,
93 RBEntryView *view,
94 gboolean over_entry);
95 static void impl_save_contents_to_xml (RBPlaylistSource *source,
96 xmlNodePtr node);
97 static void rb_play_queue_source_cmd_clear (GtkAction *action,
98 RBPlayQueueSource *source);
99 static void rb_play_queue_source_cmd_shuffle (GtkAction *action,
100 RBPlayQueueSource *source);
101 static gboolean impl_show_popup (RBDisplayPage *page);
102
103 static void rb_play_queue_dbus_method_call (GDBusConnection *connection,
104 const char *sender,
105 const char *object_path,
106 const char *interface_name,
107 const char *method_name,
108 GVariant *parameters,
109 GDBusMethodInvocation *invocation,
110 RBPlayQueueSource *source);
111
112 #define PLAY_QUEUE_SOURCE_SONGS_POPUP_PATH "/QueuePlaylistViewPopup"
113 #define PLAY_QUEUE_SOURCE_SIDEBAR_POPUP_PATH "/QueueSidebarViewPopup"
114 #define PLAY_QUEUE_SOURCE_POPUP_PATH "/QueueSourcePopup"
115
116 typedef struct _RBPlayQueueSourcePrivate RBPlayQueueSourcePrivate;
117
118 struct _RBPlayQueueSourcePrivate
119 {
120 RBEntryView *sidebar;
121 GtkTreeViewColumn *sidebar_column;
122 GtkActionGroup *action_group;
123 RBPlayOrder *queue_play_order;
124
125 guint dbus_object_id;
126 GDBusConnection *bus;
127 };
128
129 enum
130 {
131 PROP_0,
132 PROP_SIDEBAR,
133 PROP_PLAY_ORDER
134 };
135
136 G_DEFINE_TYPE (RBPlayQueueSource, rb_play_queue_source, RB_TYPE_STATIC_PLAYLIST_SOURCE)
137 #define RB_PLAY_QUEUE_SOURCE_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), RB_TYPE_PLAY_QUEUE_SOURCE, RBPlayQueueSourcePrivate))
138
139 static GtkActionEntry rb_play_queue_source_actions [] =
140 {
141 { "ClearQueue", GTK_STOCK_CLEAR, N_("Clear _Queue"), NULL,
142 N_("Remove all songs from the play queue"),
143 G_CALLBACK (rb_play_queue_source_cmd_clear) },
144 { "ShuffleQueue", GNOME_MEDIA_SHUFFLE, N_("Shuffle Queue"), NULL,
145 N_("Shuffle the tracks in the play queue"),
146 G_CALLBACK (rb_play_queue_source_cmd_shuffle) }
147 };
148
149 static const GDBusInterfaceVTable play_queue_vtable = {
150 (GDBusInterfaceMethodCallFunc) rb_play_queue_dbus_method_call,
151 NULL,
152 NULL
153 };
154
155 static void
156 rb_play_queue_sync_playing_state (GObject *entry_view,
157 GParamSpec *pspec,
158 RBPlayQueueSource *source)
159 {
160 int state;
161 RBPlayQueueSourcePrivate *priv = RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (source);
162 g_object_get (entry_view, "playing-state", &state, NULL);
163 rb_entry_view_set_state (priv->sidebar, state);
164 }
165
166 static void
167 rb_play_queue_source_dispose (GObject *object)
168 {
169 RBPlayQueueSourcePrivate *priv = RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (object);
170
171 if (priv->action_group != NULL) {
172 g_object_unref (priv->action_group);
173 priv->action_group = NULL;
174 }
175
176 if (priv->queue_play_order != NULL) {
177 g_object_unref (priv->queue_play_order);
178 priv->queue_play_order = NULL;
179 }
180
181 if (priv->bus != NULL) {
182 if (priv->dbus_object_id) {
183 g_dbus_connection_unregister_object (priv->bus, priv->dbus_object_id);
184 priv->dbus_object_id = 0;
185 }
186 g_object_unref (priv->bus);
187 }
188
189 G_OBJECT_CLASS (rb_play_queue_source_parent_class)->dispose (object);
190 }
191
192 static void
193 rb_play_queue_source_finalize (GObject *object)
194 {
195 /* do nothing */
196
197 G_OBJECT_CLASS (rb_play_queue_source_parent_class)->finalize (object);
198 }
199
200 static void
201 rb_play_queue_source_class_init (RBPlayQueueSourceClass *klass)
202 {
203 GObjectClass *object_class = G_OBJECT_CLASS (klass);
204 RBDisplayPageClass *page_class = RB_DISPLAY_PAGE_CLASS (klass);
205 RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
206 RBPlaylistSourceClass *playlist_class = RB_PLAYLIST_SOURCE_CLASS (klass);
207
208 object_class->constructed = rb_play_queue_source_constructed;
209 object_class->get_property = rb_play_queue_source_get_property;
210 object_class->finalize = rb_play_queue_source_finalize;
211 object_class->dispose = rb_play_queue_source_dispose;
212
213 page_class->show_popup = impl_show_popup;
214
215 source_class->impl_can_add_to_queue = (RBSourceFeatureFunc) rb_false_function;
216 source_class->impl_can_rename = (RBSourceFeatureFunc) rb_false_function;
217
218 playlist_class->impl_show_entry_view_popup = impl_show_entry_view_popup;
219 playlist_class->impl_save_contents_to_xml = impl_save_contents_to_xml;
220
221 /**
222 * RBPlayQueueSource:sidebar:
223 *
224 * The #RBEntryView for the play queue side pane.
225 */
226 g_object_class_install_property (object_class,
227 PROP_SIDEBAR,
228 g_param_spec_object ("sidebar",
229 "sidebar",
230 "queue sidebar entry view",
231 RB_TYPE_ENTRY_VIEW,
232 G_PARAM_READABLE));
233
234 /**
235 * RBPlayQueueSource:play-order:
236 *
237 * Overrides the play-order property from #RBSource
238 */
239 g_object_class_override_property (object_class,
240 PROP_PLAY_ORDER,
241 "play-order");
242
243 g_type_class_add_private (klass, sizeof (RBPlayQueueSourcePrivate));
244 }
245
246 static void
247 rb_play_queue_source_init (RBPlayQueueSource *source)
248 {
249 }
250
251 static void
252 rb_play_queue_source_constructed (GObject *object)
253 {
254 RBPlayQueueSource *source;
255 RBPlayQueueSourcePrivate *priv;
256 GObject *shell_player;
257 RBShell *shell;
258 RhythmDB *db;
259 GtkCellRenderer *renderer;
260 RhythmDBQueryModel *model;
261 GtkAction *action;
262
263 RB_CHAIN_GOBJECT_METHOD (rb_play_queue_source_parent_class, constructed, object);
264
265 source = RB_PLAY_QUEUE_SOURCE (object);
266 priv = RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (source);
267 db = rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source));
268
269 g_object_get (source, "shell", &shell, NULL);
270 g_object_get (shell, "shell-player", &shell_player, NULL);
271 g_object_unref (shell);
272
273 priv->queue_play_order = rb_queue_play_order_new (RB_SHELL_PLAYER (shell_player));
274
275 priv->action_group = _rb_display_page_register_action_group (RB_DISPLAY_PAGE (source),
276 "PlayQueueActions",
277 rb_play_queue_source_actions,
278 G_N_ELEMENTS (rb_play_queue_source_actions),
279 source);
280 action = gtk_action_group_get_action (priv->action_group,
281 "ClearQueue");
282 /* Translators: this is the toolbutton label for Clear Queue action */
283 g_object_set (G_OBJECT (action), "short-label", _("Clear"), NULL);
284
285 /* Translators: this is the toolbutton label for the 'shuffle queue' action */
286 gtk_action_set_short_label (gtk_action_group_get_action (priv->action_group, "ShuffleQueue"), C_("Queue", "Shuffle"));
287
288 priv->sidebar = rb_entry_view_new (db, shell_player, TRUE, TRUE);
289 g_object_unref (shell_player);
290
291 g_object_set (G_OBJECT (priv->sidebar), "vscrollbar-policy", GTK_POLICY_AUTOMATIC, NULL);
292
293 priv->sidebar_column = gtk_tree_view_column_new ();
294 renderer = gtk_cell_renderer_text_new ();
295 gtk_tree_view_column_pack_start (priv->sidebar_column, renderer, TRUE);
296 gtk_tree_view_column_set_sizing (priv->sidebar_column, GTK_TREE_VIEW_COLUMN_FIXED);
297 gtk_tree_view_column_set_expand (priv->sidebar_column, TRUE);
298 gtk_tree_view_column_set_clickable (priv->sidebar_column, FALSE);
299 gtk_tree_view_column_set_cell_data_func (priv->sidebar_column, renderer,
300 (GtkTreeCellDataFunc)
301 rb_play_queue_source_track_info_cell_data_func,
302 source, NULL);
303 rb_entry_view_append_column_custom (priv->sidebar, priv->sidebar_column,
304 _("Play Queue"), "Title", NULL, 0, NULL);
305 rb_entry_view_set_columns_clickable (priv->sidebar, FALSE);
306 rb_playlist_source_setup_entry_view (RB_PLAYLIST_SOURCE (source), priv->sidebar);
307
308 model = rb_playlist_source_get_query_model (RB_PLAYLIST_SOURCE (source));
309 rb_entry_view_set_model (priv->sidebar, model);
310
311 /* sync the state of the main entry view and the sidebar */
312 g_signal_connect_object (G_OBJECT (rb_source_get_entry_view (RB_SOURCE (source))),
313 "notify::playing-state",
314 G_CALLBACK (rb_play_queue_sync_playing_state),
315 source, 0);
316
317 /* update the queued song count when the query model changes */
318 g_signal_connect_object (G_OBJECT (model), "row-inserted",
319 G_CALLBACK (rb_play_queue_source_row_inserted_cb),
320 source, 0);
321 g_signal_connect_object (G_OBJECT (model), "row-deleted",
322 G_CALLBACK (rb_play_queue_source_row_deleted_cb),
323 source, 0);
324
325 rb_play_queue_source_update_count (source, GTK_TREE_MODEL (model), 0);
326
327 /* register dbus interface */
328 priv->bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
329 if (priv->bus) {
330 GDBusNodeInfo *node_info;
331 GError *error = NULL;
332
333 node_info = g_dbus_node_info_new_for_xml (rb_play_queue_dbus_spec, &error);
334 if (error != NULL) {
335 g_warning ("Unable to parse playlist manager dbus spec: %s", error->message);
336 g_clear_error (&error);
337 return;
338 }
339
340 priv->dbus_object_id = g_dbus_connection_register_object (priv->bus,
341 RB_PLAY_QUEUE_DBUS_PATH,
342 g_dbus_node_info_lookup_interface (node_info, RB_PLAY_QUEUE_IFACE_NAME),
343 &play_queue_vtable,
344 source,
345 NULL,
346 &error);
347 if (error != NULL) {
348 g_warning ("Unable to register play queue dbus object: %s", error->message);
349 g_clear_error (&error);
350 }
351 }
352 }
353
354 static void
355 rb_play_queue_source_get_property (GObject *object,
356 guint prop_id,
357 GValue *value,
358 GParamSpec *pspec)
359 {
360 RBPlayQueueSourcePrivate *priv = RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (object);
361
362 switch (prop_id)
363 {
364 case PROP_SIDEBAR:
365 g_value_set_object (value, priv->sidebar);
366 break;
367 case PROP_PLAY_ORDER:
368 g_value_set_object (value, priv->queue_play_order);
369 break;
370 default:
371 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
372 break;
373 }
374 }
375
376 /**
377 * rb_play_queue_source_new:
378 * @shell: the #RBShell instance
379 *
380 * Creates the play queue source object.
381 *
382 * Return value: the play queue source
383 */
384 RBSource *
385 rb_play_queue_source_new (RBShell *shell)
386 {
387 return RB_SOURCE (g_object_new (RB_TYPE_PLAY_QUEUE_SOURCE,
388 "name", _("Play Queue"),
389 "shell", shell,
390 "is-local", TRUE,
391 "entry-type", NULL,
392 "toolbar-path", "/QueueSourceToolBar",
393 "show-browser", FALSE,
394 NULL));
395 }
396
397 /**
398 * rb_play_queue_source_sidebar_song_info:
399 * @source: the #RBPlayQueueSource
400 *
401 * Creates and displays a #RBSongInfo for the currently selected
402 * entry in the side pane play queue view
403 */
404 void
405 rb_play_queue_source_sidebar_song_info (RBPlayQueueSource *source)
406 {
407 RBPlayQueueSourcePrivate *priv = RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (source);
408 GtkWidget *song_info = NULL;
409
410 g_return_if_fail (priv->sidebar != NULL);
411
412 song_info = rb_song_info_new (RB_SOURCE (source), priv->sidebar);
413 if (song_info)
414 gtk_widget_show_all (song_info);
415 else
416 rb_debug ("failed to create dialog, or no selection!");
417 }
418
419 /**
420 * rb_play_queue_source_sidebar_delete:
421 * @source: the #RBPlayQueueSource
422 *
423 * Deletes the selected entries from the play queue side pane.
424 * This is called by the #RBShellClipboard.
425 */
426 void
427 rb_play_queue_source_sidebar_delete (RBPlayQueueSource *source)
428 {
429 RBPlayQueueSourcePrivate *priv = RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (source);
430 RBEntryView *sidebar = priv->sidebar;
431 GList *sel, *tem;
432
433 sel = rb_entry_view_get_selected_entries (sidebar);
434 for (tem = sel; tem != NULL; tem = tem->next)
435 rb_static_playlist_source_remove_entry (RB_STATIC_PLAYLIST_SOURCE (source),
436 (RhythmDBEntry *) tem->data);
437 g_list_free (sel);
438 }
439
440 /**
441 * rb_play_queue_source_clear_queue:
442 * @source: the #RBPlayQueueSource
443 *
444 * Clears the play queue.
445 */
446 void
447 rb_play_queue_source_clear_queue (RBPlayQueueSource *source)
448 {
449 GtkTreeIter iter;
450 RhythmDBEntry *entry;
451 RhythmDBQueryModel *model;
452
453 model = rb_playlist_source_get_query_model (RB_PLAYLIST_SOURCE (source));
454 while (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter)) {
455 entry = rhythmdb_query_model_iter_to_entry (model, &iter);
456
457 if (entry != NULL) {
458 rhythmdb_query_model_remove_entry (model, entry);
459 rhythmdb_entry_unref (entry);
460 }
461 }
462 }
463
464 static void
465 impl_show_entry_view_popup (RBPlaylistSource *source,
466 RBEntryView *view,
467 gboolean over_entry)
468 {
469 RBPlayQueueSourcePrivate *priv = RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (source);
470 const char *popup = PLAY_QUEUE_SOURCE_SONGS_POPUP_PATH;
471 if (view == priv->sidebar)
472 popup = PLAY_QUEUE_SOURCE_SIDEBAR_POPUP_PATH;
473 else if (!over_entry)
474 return;
475 _rb_display_page_show_popup (RB_DISPLAY_PAGE (source), popup);
476 }
477
478 static void
479 rb_play_queue_source_track_info_cell_data_func (GtkTreeViewColumn *column,
480 GtkCellRenderer *renderer,
481 GtkTreeModel *tree_model,
482 GtkTreeIter *iter,
483 RBPlaylistSource *source)
484 {
485 RhythmDBEntry *entry;
486 const char *title;
487 const char *artist;
488 const char *album;
489 char *markup;
490
491 gtk_tree_model_get (tree_model, iter, 0, &entry, -1);
492
493 title = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE);
494 artist = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST);
495 album = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM);
496
497 /* Translators: format is "<title> from <album> by <artist>" */
498 markup = g_markup_printf_escaped ("%s\n<span size=\"smaller\">%s <i>%s</i>\n%s <i>%s</i></span>",
499 title, _("from"), album, _("by"), artist);
500
501 g_object_set (G_OBJECT (renderer), "markup", markup, NULL);
502
503 g_free (markup);
504 rhythmdb_entry_unref (entry);
505 }
506
507 static void
508 rb_play_queue_source_row_inserted_cb (GtkTreeModel *model,
509 GtkTreePath *path,
510 GtkTreeIter *iter,
511 RBPlayQueueSource *source)
512 {
513 rb_play_queue_source_update_count (source, model, 0);
514 }
515
516 static void
517 rb_play_queue_source_row_deleted_cb (GtkTreeModel *model,
518 GtkTreePath *path,
519 RBPlayQueueSource *source)
520 {
521 rb_play_queue_source_update_count (source, model, -1);
522 }
523
524 static void
525 rb_play_queue_source_update_count (RBPlayQueueSource *source,
526 GtkTreeModel *model,
527 gint offset)
528 {
529 gint count = gtk_tree_model_iter_n_children (model, NULL) + offset;
530 RBPlayQueueSourcePrivate *priv = RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (source);
531 char *name = _("Play Queue");
532 GtkAction *action;
533
534 /* update source name */
535 if (count > 0)
536 name = g_strdup_printf ("%s (%d)", name, count);
537
538 g_object_set (G_OBJECT (source), "name", name, NULL);
539 gtk_tree_view_column_set_title (priv->sidebar_column, name);
540
541 if (count > 0)
542 g_free (name);
543
544 /* make 'clear queue' and 'shuffle queue' actions sensitive when there are entries in the queue */
545 action = gtk_action_group_get_action (priv->action_group,
546 "ClearQueue");
547 g_object_set (G_OBJECT (action), "sensitive", (count > 0), NULL);
548
549 action = gtk_action_group_get_action (priv->action_group, "ShuffleQueue");
550 g_object_set (G_OBJECT (action), "sensitive", (count > 0), NULL);
551 }
552
553 static void
554 impl_save_contents_to_xml (RBPlaylistSource *source,
555 xmlNodePtr node)
556 {
557 ((RBPlaylistSourceClass*)rb_play_queue_source_parent_class)->impl_save_contents_to_xml (source, node);
558 xmlSetProp (node, RB_PLAYLIST_TYPE, RB_PLAYLIST_QUEUE);
559 }
560
561 static void
562 rb_play_queue_source_cmd_clear (GtkAction *action,
563 RBPlayQueueSource *source)
564 {
565 rb_play_queue_source_clear_queue (source);
566 }
567
568 static void
569 rb_play_queue_source_cmd_shuffle (GtkAction *action,
570 RBPlayQueueSource *source)
571 {
572 RhythmDBQueryModel *model;
573
574 model = rb_playlist_source_get_query_model (RB_PLAYLIST_SOURCE (source));
575 rhythmdb_query_model_shuffle_entries (model);
576 }
577
578 static gboolean
579 impl_show_popup (RBDisplayPage *page)
580 {
581 _rb_display_page_show_popup (page, PLAY_QUEUE_SOURCE_POPUP_PATH);
582 return TRUE;
583 }
584
585 static void
586 rb_play_queue_dbus_method_call (GDBusConnection *connection,
587 const char *sender,
588 const char *object_path,
589 const char *interface_name,
590 const char *method_name,
591 GVariant *parameters,
592 GDBusMethodInvocation *invocation,
593 RBPlayQueueSource *source)
594 {
595 RhythmDBEntry *entry;
596 RhythmDB *db;
597 const char *uri;
598
599 if (g_strcmp0 (interface_name, RB_PLAY_QUEUE_IFACE_NAME) != 0) {
600 rb_debug ("method call on unexpected interface %s", interface_name);
601 g_dbus_method_invocation_return_error (invocation,
602 G_DBUS_ERROR,
603 G_DBUS_ERROR_NOT_SUPPORTED,
604 "Method %s.%s not supported",
605 interface_name,
606 method_name);
607 return;
608 }
609
610 if (g_strcmp0 (method_name, "AddToQueue") == 0) {
611 g_variant_get (parameters, "(&s)", &uri);
612
613 db = rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source));
614 entry = rhythmdb_entry_lookup_by_location (db, uri);
615 if (entry == NULL) {
616 RBSource *urisource;
617 RBShell *shell;
618
619 g_object_get (source, "shell", &shell, NULL);
620 urisource = rb_shell_guess_source_for_uri (shell, uri);
621 g_object_unref (shell);
622
623 if (urisource != NULL) {
624 rb_source_add_uri (urisource, uri, NULL, NULL, NULL, NULL, NULL);
625 } else {
626 g_dbus_method_invocation_return_error (invocation,
627 RB_SHELL_ERROR,
628 RB_SHELL_ERROR_NO_SOURCE_FOR_URI,
629 _("No registered source can handle URI %s"),
630 uri);
631 return;
632 }
633 }
634 rb_static_playlist_source_add_location (RB_STATIC_PLAYLIST_SOURCE (source),
635 uri, -1);
636
637 g_dbus_method_invocation_return_value (invocation, NULL);
638 } else if (g_strcmp0 (method_name, "RemoveFromQueue") == 0) {
639 g_variant_get (parameters, "(&s)", &uri);
640
641 if (rb_playlist_source_location_in_map (RB_PLAYLIST_SOURCE (source), uri)) {
642 rb_static_playlist_source_remove_location (RB_STATIC_PLAYLIST_SOURCE (source), uri);
643 }
644
645 g_dbus_method_invocation_return_value (invocation, NULL);
646 } else if (g_strcmp0 (method_name, "ClearQueue") == 0) {
647 rb_play_queue_source_clear_queue (RB_PLAY_QUEUE_SOURCE (source));
648 g_dbus_method_invocation_return_value (invocation, NULL);
649 } else {
650 g_dbus_method_invocation_return_error (invocation,
651 G_DBUS_ERROR,
652 G_DBUS_ERROR_NOT_SUPPORTED,
653 "Method %s.%s not supported",
654 interface_name,
655 method_name);
656 }
657 }