1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * arch-tag: Implementation of Rhythmbox playlist management object
5 * Copyright (C) 2003,2004 Colin Walters <walters@gnome.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include <stdio.h> /* rename() */
27 #include <unistd.h> /* unlink() */
29 #include <libxml/tree.h>
30 #include <glib/gi18n.h>
32 #include <libgnomevfs/gnome-vfs.h>
33 #include <libgnomevfs/gnome-vfs-mime-utils.h>
35 #include "rb-playlist-manager.h"
36 #include "rb-playlist-source.h"
37 #include "rb-static-playlist-source.h"
38 #include "rb-auto-playlist-source.h"
39 #include "rb-play-queue-source.h"
40 #include "rb-recorder.h"
41 #include "rb-sourcelist.h"
42 #include "rb-sourcelist-model.h"
43 #include "rb-query-creator.h"
44 #include "totem-pl-parser.h"
46 #include "rb-file-helpers.h"
48 #include "rb-dialog.h"
50 #include "rb-stock-icons.h"
51 #include "eel-gconf-extensions.h"
52 #include "rb-glade-helpers.h"
55 #define RB_PLAYLIST_MGR_VERSION (xmlChar *) "1.0"
56 #define RB_PLAYLIST_MGR_PL (xmlChar *) "rhythmdb-playlists"
58 static void rb_playlist_manager_class_init (RBPlaylistManagerClass
*klass
);
59 static void rb_playlist_manager_init (RBPlaylistManager
*mgr
);
60 static void rb_playlist_manager_finalize (GObject
*object
);
61 static void rb_playlist_manager_set_property (GObject
*object
,
65 static void rb_playlist_manager_get_property (GObject
*object
,
69 static void rb_playlist_manager_cmd_load_playlist (GtkAction
*action
,
70 RBPlaylistManager
*mgr
);
71 static void rb_playlist_manager_cmd_save_playlist (GtkAction
*action
,
72 RBPlaylistManager
*mgr
);
73 static void rb_playlist_manager_cmd_burn_playlist (GtkAction
*action
,
74 RBPlaylistManager
*mgr
);
75 static void rb_playlist_manager_cmd_new_playlist (GtkAction
*action
,
76 RBPlaylistManager
*mgr
);
77 static void rb_playlist_manager_cmd_new_automatic_playlist (GtkAction
*action
,
78 RBPlaylistManager
*mgr
);
79 static void rb_playlist_manager_cmd_rename_playlist (GtkAction
*action
,
80 RBPlaylistManager
*mgr
);
81 static void rb_playlist_manager_cmd_delete_playlist (GtkAction
*action
,
82 RBPlaylistManager
*mgr
);
83 static void rb_playlist_manager_cmd_edit_automatic_playlist (GtkAction
*action
,
84 RBPlaylistManager
*mgr
);
85 static void rb_playlist_manager_cmd_queue_playlist (GtkAction
*action
,
86 RBPlaylistManager
*mgr
);
87 static void rb_playlist_manager_playlist_entries_changed (GtkTreeModel
*entry_view
,
89 RBPlaylistManager
*mgr
);
91 struct RBPlaylistManagerPrivate
95 RBSource
*selected_source
;
97 RBSourceList
*sourcelist
;
99 GtkActionGroup
*actiongroup
;
100 GtkUIManager
*uimanager
;
104 RBStaticPlaylistSource
*loading_playlist
;
108 GMutex
*saving_mutex
;
124 PLAYLIST_LOAD_FINISH
,
128 static guint rb_playlist_manager_signals
[LAST_SIGNAL
] = { 0 };
130 static GtkActionEntry rb_playlist_manager_actions
[] =
132 /* Submenu of Music */
133 { "Playlist", NULL
, N_("_Playlist") },
135 { "MusicPlaylistNewPlaylist", GNOME_MEDIA_PLAYLIST
, N_("_New Playlist"), "<control>N",
136 N_("Create a new playlist"),
137 G_CALLBACK (rb_playlist_manager_cmd_new_playlist
) },
138 { "MusicPlaylistNewAutomaticPlaylist", GNOME_MEDIA_AUTO_PLAYLIST
, N_("New _Automatic Playlist..."), NULL
,
139 N_("Create a new automatically updating playlist"),
140 G_CALLBACK (rb_playlist_manager_cmd_new_automatic_playlist
) },
141 { "MusicPlaylistLoadPlaylist", NULL
, N_("_Load from File..."), NULL
,
142 N_("Choose a playlist to be loaded"),
143 G_CALLBACK (rb_playlist_manager_cmd_load_playlist
) },
144 { "MusicPlaylistSavePlaylist", GTK_STOCK_SAVE_AS
, N_("_Save to File..."), NULL
,
145 N_("Save a playlist to a file"),
146 G_CALLBACK (rb_playlist_manager_cmd_save_playlist
) },
147 { "MusicPlaylistBurnPlaylist", GTK_STOCK_CDROM
, N_("_Create Audio CD..."), NULL
,
148 N_("Create an audio CD from playlist"),
149 G_CALLBACK (rb_playlist_manager_cmd_burn_playlist
) },
150 { "MusicPlaylistRenamePlaylist", NULL
, N_("_Rename"), NULL
,
151 N_("Rename playlist"),
152 G_CALLBACK (rb_playlist_manager_cmd_rename_playlist
) },
153 { "MusicPlaylistDeletePlaylist", GTK_STOCK_REMOVE
, N_("_Delete"), NULL
,
154 N_("Delete playlist"),
155 G_CALLBACK (rb_playlist_manager_cmd_delete_playlist
) },
156 { "EditAutomaticPlaylist", GTK_STOCK_PROPERTIES
, N_("_Edit..."), NULL
,
157 N_("Change this automatic playlist"),
158 G_CALLBACK (rb_playlist_manager_cmd_edit_automatic_playlist
) },
159 { "QueuePlaylist", NULL
, N_("_Queue All Tracks"), NULL
,
160 N_("Add all tracks in this playlist to the queue"),
161 G_CALLBACK (rb_playlist_manager_cmd_queue_playlist
) },
163 static guint rb_playlist_manager_n_actions
= G_N_ELEMENTS (rb_playlist_manager_actions
);
165 G_DEFINE_TYPE (RBPlaylistManager
, rb_playlist_manager
, G_TYPE_OBJECT
)
168 rb_playlist_manager_class_init (RBPlaylistManagerClass
*klass
)
170 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
172 object_class
->finalize
= rb_playlist_manager_finalize
;
174 object_class
->set_property
= rb_playlist_manager_set_property
;
175 object_class
->get_property
= rb_playlist_manager_get_property
;
177 g_object_class_install_property (object_class
,
179 g_param_spec_object ("source",
185 g_object_class_install_property (object_class
,
187 g_param_spec_object ("shell",
194 g_object_class_install_property (object_class
,
196 g_param_spec_object ("sourcelist",
200 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
201 rb_playlist_manager_signals
[PLAYLIST_ADDED
] =
202 g_signal_new ("playlist_added",
203 RB_TYPE_PLAYLIST_MANAGER
,
205 G_STRUCT_OFFSET (RBPlaylistManagerClass
, playlist_added
),
207 g_cclosure_marshal_VOID__OBJECT
,
211 rb_playlist_manager_signals
[PLAYLIST_CREATED
] =
212 g_signal_new ("playlist_created",
213 RB_TYPE_PLAYLIST_MANAGER
,
215 G_STRUCT_OFFSET (RBPlaylistManagerClass
, playlist_created
),
217 g_cclosure_marshal_VOID__OBJECT
,
221 rb_playlist_manager_signals
[PLAYLIST_LOAD_START
] =
222 g_signal_new ("load_start",
223 RB_TYPE_PLAYLIST_MANAGER
,
225 G_STRUCT_OFFSET (RBPlaylistManagerClass
, load_start
),
227 g_cclosure_marshal_VOID__VOID
,
230 rb_playlist_manager_signals
[PLAYLIST_LOAD_FINISH
] =
231 g_signal_new ("load_finish",
232 RB_TYPE_PLAYLIST_MANAGER
,
234 G_STRUCT_OFFSET (RBPlaylistManagerClass
, load_finish
),
236 g_cclosure_marshal_VOID__VOID
,
240 g_type_class_add_private (klass
, sizeof (RBPlaylistManagerPrivate
));
244 rb_playlist_manager_init (RBPlaylistManager
*mgr
)
246 mgr
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (mgr
,
247 RB_TYPE_PLAYLIST_MANAGER
,
248 RBPlaylistManagerPrivate
);
250 mgr
->priv
->saving_mutex
= g_mutex_new ();
251 mgr
->priv
->dirty
= 0;
252 mgr
->priv
->saving
= 0;
256 rb_playlist_manager_shutdown (RBPlaylistManager
*mgr
)
258 g_return_if_fail (RB_IS_PLAYLIST_MANAGER (mgr
));
260 g_mutex_lock (mgr
->priv
->saving_mutex
);
261 g_mutex_unlock (mgr
->priv
->saving_mutex
);
265 rb_playlist_manager_finalize (GObject
*object
)
267 RBPlaylistManager
*mgr
;
269 g_return_if_fail (object
!= NULL
);
270 g_return_if_fail (RB_IS_PLAYLIST_MANAGER (object
));
272 rb_debug ("Finalizing playlist manager");
274 mgr
= RB_PLAYLIST_MANAGER (object
);
276 g_return_if_fail (mgr
->priv
!= NULL
);
278 g_mutex_free (mgr
->priv
->saving_mutex
);
280 G_OBJECT_CLASS (rb_playlist_manager_parent_class
)->finalize (object
);
284 rb_playlist_manager_set_uimanager (RBPlaylistManager
*mgr
,
285 GtkUIManager
*uimanager
)
287 if (mgr
->priv
->uimanager
!= NULL
) {
288 if (mgr
->priv
->actiongroup
!= NULL
) {
289 gtk_ui_manager_remove_action_group (mgr
->priv
->uimanager
,
290 mgr
->priv
->actiongroup
);
292 g_object_unref (G_OBJECT (mgr
->priv
->uimanager
));
293 mgr
->priv
->uimanager
= NULL
;
296 mgr
->priv
->uimanager
= uimanager
;
298 if (mgr
->priv
->actiongroup
== NULL
) {
299 mgr
->priv
->actiongroup
= gtk_action_group_new ("PlaylistActions");
300 gtk_action_group_set_translation_domain (mgr
->priv
->actiongroup
,
302 gtk_action_group_add_actions (mgr
->priv
->actiongroup
,
303 rb_playlist_manager_actions
,
304 rb_playlist_manager_n_actions
,
308 gtk_ui_manager_insert_action_group (mgr
->priv
->uimanager
,
309 mgr
->priv
->actiongroup
,
314 rb_playlist_manager_playlist_entries_changed (GtkTreeModel
*model
, RhythmDBEntry
*entry
, RBPlaylistManager
*mgr
)
319 num_tracks
= gtk_tree_model_iter_n_children (model
, NULL
);
321 action
= gtk_action_group_get_action (mgr
->priv
->actiongroup
, "MusicPlaylistBurnPlaylist");
322 gtk_action_set_visible (action
, (num_tracks
> 0));
326 rb_playlist_manager_playlist_row_inserted_cb (GtkTreeModel
*model
,
329 RBPlaylistManager
*mgr
)
331 RhythmDBEntry
*entry
= rhythmdb_query_model_iter_to_entry (RHYTHMDB_QUERY_MODEL (model
), iter
);
333 rb_playlist_manager_playlist_entries_changed (model
, entry
, mgr
);
338 rb_playlist_manager_set_source (RBPlaylistManager
*mgr
,
341 gboolean playlist_active
;
342 gboolean playlist_local
= FALSE
;
350 if (mgr
->priv
->selected_source
!= NULL
) {
351 RhythmDBQueryModel
*model
;
353 g_object_get (G_OBJECT (mgr
->priv
->selected_source
), "query-model", &model
, NULL
);
355 g_signal_handlers_disconnect_by_func (G_OBJECT (model
),
356 G_CALLBACK (rb_playlist_manager_playlist_entries_changed
),
358 g_signal_handlers_disconnect_by_func (G_OBJECT (model
),
359 G_CALLBACK (rb_playlist_manager_playlist_row_inserted_cb
),
361 g_object_unref (G_OBJECT (model
));
364 party_mode
= rb_shell_get_party_mode (mgr
->priv
->shell
);
366 mgr
->priv
->selected_source
= source
;
367 playlist_active
= RB_IS_PLAYLIST_SOURCE (mgr
->priv
->selected_source
);
368 if (playlist_active
) {
369 g_object_get (G_OBJECT (mgr
->priv
->selected_source
), "is-local", &playlist_local
, NULL
);
372 can_save
= playlist_local
&& !party_mode
;
373 action
= gtk_action_group_get_action (mgr
->priv
->actiongroup
,
374 "MusicPlaylistSavePlaylist");
375 gtk_action_set_visible (action
, can_save
);
377 can_delete
= (playlist_local
&& !party_mode
&&
378 !RB_IS_PLAY_QUEUE_SOURCE (mgr
->priv
->selected_source
));
379 action
= gtk_action_group_get_action (mgr
->priv
->actiongroup
,
380 "MusicPlaylistDeletePlaylist");
381 gtk_action_set_visible (action
, can_delete
);
383 can_edit
= (playlist_local
&& RB_IS_AUTO_PLAYLIST_SOURCE (mgr
->priv
->selected_source
) &&
385 action
= gtk_action_group_get_action (mgr
->priv
->actiongroup
,
386 "EditAutomaticPlaylist");
387 gtk_action_set_visible (action
, can_edit
);
389 can_rename
= playlist_local
&& rb_source_can_rename (mgr
->priv
->selected_source
);
390 action
= gtk_action_group_get_action (mgr
->priv
->actiongroup
,
391 "MusicPlaylistRenamePlaylist");
392 gtk_action_set_visible (action
, can_rename
);
394 if (playlist_active
&& rb_recorder_enabled ()) {
395 RhythmDBQueryModel
*model
;
397 g_object_get (G_OBJECT (mgr
->priv
->selected_source
), "query-model", &model
, NULL
);
398 /* monitor for changes, to enable/disable the burn menu item */
399 g_signal_connect_object (G_OBJECT (model
),
401 G_CALLBACK (rb_playlist_manager_playlist_row_inserted_cb
),
403 g_signal_connect_object (G_OBJECT (model
),
405 G_CALLBACK (rb_playlist_manager_playlist_entries_changed
),
408 rb_playlist_manager_playlist_entries_changed (GTK_TREE_MODEL (model
), NULL
, mgr
);
409 g_object_unref (model
);
411 action
= gtk_action_group_get_action (mgr
->priv
->actiongroup
,
412 "MusicPlaylistBurnPlaylist");
413 gtk_action_set_visible (action
, FALSE
);
418 rb_playlist_manager_set_property (GObject
*object
,
423 RBPlaylistManager
*mgr
= RB_PLAYLIST_MANAGER (object
);
427 rb_playlist_manager_set_source (mgr
, g_value_get_object (value
));
431 GtkUIManager
*uimanager
;
432 mgr
->priv
->shell
= g_value_get_object (value
);
433 g_object_get (G_OBJECT (mgr
->priv
->shell
),
434 "ui-manager", &uimanager
,
435 "db", &mgr
->priv
->db
,
437 rb_playlist_manager_set_uimanager (mgr
, uimanager
);
440 case PROP_SOURCELIST
:
441 mgr
->priv
->sourcelist
= g_value_get_object (value
);
442 mgr
->priv
->window
= GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (mgr
->priv
->sourcelist
)));
445 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
451 rb_playlist_manager_get_property (GObject
*object
,
456 RBPlaylistManager
*mgr
= RB_PLAYLIST_MANAGER (object
);
460 g_value_set_object (value
, mgr
->priv
->selected_source
);
463 g_value_set_object (value
, mgr
->priv
->shell
);
465 case PROP_SOURCELIST
:
466 g_value_set_object (value
, mgr
->priv
->sourcelist
);
469 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
475 rb_playlist_manager_new (RBShell
*shell
,
476 RBSourceList
*sourcelist
)
478 return g_object_new (RB_TYPE_PLAYLIST_MANAGER
,
480 "sourcelist", sourcelist
,
485 rb_playlist_manager_error_quark (void)
487 static GQuark quark
= 0;
489 quark
= g_quark_from_static_string ("rb_playlist_manager_error");
495 handle_playlist_entry_cb (TotemPlParser
*playlist
, const char *uri_maybe
,
497 const char *genre
, RBPlaylistManager
*mgr
)
499 char *uri
= rb_canonicalise_uri (uri_maybe
);
500 RhythmDBEntryType entry_type
;
502 g_return_if_fail (uri
!= NULL
);
504 entry_type
= rb_shell_guess_type_for_uri (mgr
->priv
->shell
, uri
);
505 if (entry_type
== RHYTHMDB_ENTRY_TYPE_INVALID
) {
510 rb_shell_add_uri (mgr
->priv
->shell
,
517 if (entry_type
== RHYTHMDB_ENTRY_TYPE_SONG
) {
518 if (!mgr
->priv
->loading_playlist
) {
519 mgr
->priv
->loading_playlist
=
520 RB_STATIC_PLAYLIST_SOURCE (rb_playlist_manager_new_playlist (mgr
, NULL
, FALSE
));
522 rb_static_playlist_source_add_location (mgr
->priv
->loading_playlist
, uri
, -1);
529 playlist_load_start_cb (TotemPlParser
*parser
, const char *title
, RBPlaylistManager
*mgr
)
531 rb_debug ("loading new playlist %s", title
);
533 if (!mgr
->priv
->loading_playlist
) {
534 mgr
->priv
->loading_playlist
=
535 RB_STATIC_PLAYLIST_SOURCE (rb_playlist_manager_new_playlist (mgr
, title
, FALSE
));
540 playlist_load_end_cb (TotemPlParser
*parser
, const char *title
, RBPlaylistManager
*mgr
)
542 rb_debug ("finished loading playlist %s", title
);
543 mgr
->priv
->loading_playlist
= NULL
;
547 * rb_playlist_manager_parse_file:
548 * @mgr: the #RBPlaylistManager
549 * @uri: URI of the playlist to load
550 * @error: returns a GError in case of error
552 * Parses a playlist file, adding entries to the database and to a new
553 * static playlist. If the playlist file includes a title, the static
554 * playlist created will have the same title.
556 * Returns TRUE on success
559 rb_playlist_manager_parse_file (RBPlaylistManager
*mgr
, const char *uri
, GError
**error
)
561 rb_debug ("loading playlist from %s", uri
);
563 g_signal_emit (G_OBJECT (mgr
), rb_playlist_manager_signals
[PLAYLIST_LOAD_START
], 0);
566 TotemPlParser
*parser
= totem_pl_parser_new ();
568 g_signal_connect_object (G_OBJECT (parser
), "entry",
569 G_CALLBACK (handle_playlist_entry_cb
),
572 g_signal_connect_object (G_OBJECT (parser
), "playlist-start",
573 G_CALLBACK (playlist_load_start_cb
),
576 g_signal_connect_object (G_OBJECT (parser
), "playlist-end",
577 G_CALLBACK (playlist_load_end_cb
),
580 if (g_object_class_find_property (G_OBJECT_GET_CLASS (parser
), "recurse"))
581 g_object_set (G_OBJECT (parser
), "recurse", FALSE
, NULL
);
583 if (totem_pl_parser_parse (parser
, uri
, TRUE
) != TOTEM_PL_PARSER_RESULT_SUCCESS
) {
585 RB_PLAYLIST_MANAGER_ERROR
,
586 RB_PLAYLIST_MANAGER_ERROR_PARSE
,
588 _("The playlist file may be in an unknown format or corrupted."));
591 mgr
->priv
->loading_playlist
= NULL
;
593 g_object_unref (G_OBJECT (parser
));
596 g_signal_emit (G_OBJECT (mgr
), rb_playlist_manager_signals
[PLAYLIST_LOAD_FINISH
], 0);
601 append_new_playlist_source (RBPlaylistManager
*mgr
, RBPlaylistSource
*source
)
603 g_signal_emit (G_OBJECT (mgr
), rb_playlist_manager_signals
[PLAYLIST_ADDED
], 0,
608 * rb_playlist_manager_load_playlists
609 * @mgr: the #RBPlaylistManager
611 * Loads the user's playlists, or if the playlist file does not exists,
612 * reads the default playlist file. Should be called only once on startup.
615 rb_playlist_manager_load_playlists (RBPlaylistManager
*mgr
)
624 file
= g_build_filename (rb_dot_dir (), "playlists.xml", NULL
);
626 /* block saves until the playlists have loaded */
627 g_mutex_lock (mgr
->priv
->saving_mutex
);
629 exists
= g_file_test (file
, G_FILE_TEST_EXISTS
);
631 rb_debug ("personal playlists not found, loading defaults");
633 /* try global playlists */
635 file
= g_strdup (rb_file ("playlists.xml"));
636 exists
= g_file_test (file
, G_FILE_TEST_EXISTS
);
640 rb_debug ("default playlists file not found");
644 doc
= xmlParseFile (file
);
648 root
= xmlDocGetRootElement (doc
);
650 for (child
= root
->children
; child
; child
= child
->next
) {
653 if (xmlNodeIsText (child
))
656 playlist
= rb_playlist_source_new_from_xml (mgr
->priv
->shell
,
659 append_new_playlist_source (mgr
, RB_PLAYLIST_SOURCE (playlist
));
664 g_mutex_unlock (mgr
->priv
->saving_mutex
);
669 rb_playlist_manager_set_dirty (RBPlaylistManager
*mgr
, gboolean dirty
)
671 g_atomic_int_compare_and_exchange (&mgr
->priv
->dirty
, dirty
== FALSE
, dirty
== TRUE
);
674 /* returns TRUE if a playlist has been created, modified, or deleted since last save */
676 rb_playlist_manager_is_dirty (RBPlaylistManager
*mgr
)
678 gboolean dirty
= FALSE
;
679 GtkTreeModel
*fmodel
;
683 g_object_get (G_OBJECT (mgr
->priv
->sourcelist
), "model", &fmodel
, NULL
);
684 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (fmodel
));
685 g_object_unref (fmodel
);
687 if (gtk_tree_model_get_iter_first (model
, &iter
)) {
692 gtk_tree_model_get_value (model
,
694 RB_SOURCELIST_MODEL_COLUMN_SOURCE
,
696 source
= g_value_get_pointer (&v
);
697 if (RB_IS_PLAYLIST_SOURCE (source
) == FALSE
)
700 g_object_get (G_OBJECT (source
),
704 g_object_get (G_OBJECT (source
),
710 } while (gtk_tree_model_iter_next (model
, &iter
));
714 dirty
= g_atomic_int_get (&mgr
->priv
->dirty
);
719 struct RBPlaylistManagerSaveData
721 RBPlaylistManager
*mgr
;
726 rb_playlist_manager_save_data (struct RBPlaylistManagerSaveData
*data
)
731 g_mutex_lock (data
->mgr
->priv
->saving_mutex
);
733 file
= g_build_filename (rb_dot_dir (), "playlists.xml", NULL
);
734 tmpname
= g_strconcat (file
, ".tmp", NULL
);
736 if (xmlSaveFormatFile (tmpname
, data
->doc
, 1) != -1) {
737 rename (tmpname
, file
);
739 rb_debug ("error in xmlSaveFormatFile(), not saving");
741 rb_playlist_manager_set_dirty (data
->mgr
, TRUE
);
743 xmlFreeDoc (data
->doc
);
747 g_atomic_int_compare_and_exchange (&data
->mgr
->priv
->saving
, 1, 0);
748 g_mutex_unlock (data
->mgr
->priv
->saving_mutex
);
750 g_object_unref (G_OBJECT (data
->mgr
));
757 * rb_playlist_manager_save_playlists
758 * @mgr: the #RBPlaylistManager
759 * @force: if TRUE, save playlists synchronously and unconditionally
761 * Saves the user's playlists. If the force flag is
762 * TRUE, the playlists will always be saved. Otherwise, the playlists
763 * will only be saved if a playlist has been created, modified, or deleted
764 * since the last time the playlists were saved, and no save operation is
765 * currently taking place.
767 * Returns TRUE if a playlist save operation has been started
770 rb_playlist_manager_save_playlists (RBPlaylistManager
*mgr
, gboolean force
)
773 struct RBPlaylistManagerSaveData
*data
;
775 GtkTreeModel
*fmodel
;
778 if (!force
&& !rb_playlist_manager_is_dirty (mgr
)) {
779 /* playlists already in sync, so don't bother */
783 if (!g_atomic_int_compare_and_exchange (&mgr
->priv
->saving
, 0, 1) && !force
) {
784 /* already saving, so don't bother */
788 data
= g_new0 (struct RBPlaylistManagerSaveData
, 1);
790 data
->doc
= xmlNewDoc (RB_PLAYLIST_MGR_VERSION
);
791 g_object_ref (G_OBJECT (mgr
));
793 root
= xmlNewDocNode (data
->doc
, NULL
, RB_PLAYLIST_MGR_PL
, NULL
);
794 xmlDocSetRootElement (data
->doc
, root
);
796 g_object_get (G_OBJECT (mgr
->priv
->sourcelist
), "model", &fmodel
, NULL
);
797 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (fmodel
));
798 g_object_unref (fmodel
);
800 if (gtk_tree_model_get_iter_first (model
, &iter
)) {
806 gtk_tree_model_get_value (model
,
808 RB_SOURCELIST_MODEL_COLUMN_SOURCE
,
810 source
= g_value_get_pointer (&v
);
811 if (RB_IS_PLAYLIST_SOURCE (source
) == FALSE
)
814 g_object_get (G_OBJECT (source
), "is-local", &local
, NULL
);
816 rb_playlist_source_save_to_xml (RB_PLAYLIST_SOURCE (source
), root
);
817 } while (gtk_tree_model_iter_next (model
, &iter
));
820 /* mark clean here. if the save fails, we'll mark it dirty again */
821 rb_playlist_manager_set_dirty (data
->mgr
, FALSE
);
824 rb_playlist_manager_save_data (data
);
826 g_thread_create ((GThreadFunc
) rb_playlist_manager_save_data
, data
, FALSE
, NULL
);
832 * rb_playlist_manager_new_playlist
833 * @mgr: the #RBPlaylistManager
834 * @suggested_name: optional name to use for the new playlist
835 * @automatic: if TRUE, create an auto playlist
837 * Creates a new playlist and adds it to the source list.
839 * Returns the new playlist object.
842 rb_playlist_manager_new_playlist (RBPlaylistManager
*mgr
,
843 const char *suggested_name
,
848 playlist
= rb_auto_playlist_source_new (mgr
->priv
->shell
,
852 playlist
= rb_static_playlist_source_new (mgr
->priv
->shell
,
855 RHYTHMDB_ENTRY_TYPE_SONG
);
857 append_new_playlist_source (mgr
, RB_PLAYLIST_SOURCE (playlist
));
858 rb_sourcelist_edit_source_name (mgr
->priv
->sourcelist
, playlist
);
859 rb_playlist_manager_set_dirty (mgr
, TRUE
);
861 g_signal_emit (G_OBJECT (mgr
), rb_playlist_manager_signals
[PLAYLIST_CREATED
], 0,
868 create_name_from_selection_data (RBPlaylistManager
*mgr
,
869 GtkSelectionData
*data
)
874 if (data
->type
== gdk_atom_intern ("text/uri-list", TRUE
)) {
875 list
= gnome_vfs_uri_list_parse ((char *) data
->data
);
881 gboolean mixed_artists
;
882 gboolean mixed_albums
;
886 mixed_artists
= FALSE
;
887 mixed_albums
= FALSE
;
888 for (l
= list
; l
!= NULL
; l
= g_list_next (l
)) {
889 RhythmDBEntry
*entry
;
891 const char *e_artist
;
894 location
= gnome_vfs_uri_to_string ((const GnomeVFSURI
*) l
->data
, 0);
895 if (location
== NULL
) {
899 entry
= rhythmdb_entry_lookup_by_location (mgr
->priv
->db
, location
);
904 e_artist
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ARTIST
);
905 e_album
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ALBUM
);
907 /* get value of first non-NULL artist */
908 if (e_artist
!= NULL
&& artist
== NULL
) {
909 artist
= g_strdup (e_artist
);
912 /* get value of first non-NULL album */
913 if (e_album
!= NULL
&& album
== NULL
) {
914 album
= g_strdup (e_album
);
917 /* pretend that NULL fields always match */
918 if (artist
!= NULL
&& e_artist
!= NULL
919 && strcmp (artist
, e_artist
) != 0) {
920 mixed_artists
= TRUE
;
923 /* pretend that NULL fields always match */
924 if (album
!= NULL
&& e_album
!= NULL
925 && strcmp (album
, e_album
) != 0) {
929 /* if there is a mix of both then stop */
930 if (mixed_artists
&& mixed_albums
) {
935 if (! mixed_artists
&& ! mixed_albums
) {
936 name
= g_strdup_printf ("%s - %s", artist
, album
);
937 } else if (! mixed_artists
) {
938 name
= g_strdup_printf ("%s", artist
);
939 } else if (! mixed_albums
) {
940 name
= g_strdup_printf ("%s", album
);
945 gnome_vfs_uri_list_free (list
);
951 names
= g_strsplit ((char *)data
->data
, "\r\n", 0);
952 name
= g_strjoinv (", ", names
);
957 name
= g_strdup (_("Untitled Playlist"));
964 * rb_playlist_manager_new_playlist_from_selection_data
965 * @mgr: the #RBPlaylistManager
966 * @data: the #GtkSelectionData from which to create a playlist
968 * Creates a new playlist based on selection data from gtk.
969 * Used to implement playlist creation through drag and drop
970 * to the source list.
972 * Returns the new playlist.
975 rb_playlist_manager_new_playlist_from_selection_data (RBPlaylistManager
*mgr
,
976 GtkSelectionData
*data
)
980 char *suggested_name
;
982 automatic
= (data
->type
!= gdk_atom_intern ("text/uri-list", TRUE
));
983 suggested_name
= create_name_from_selection_data (mgr
, data
);
985 playlist
= rb_playlist_manager_new_playlist (mgr
,
988 g_free (suggested_name
);
994 rb_playlist_manager_cmd_new_playlist (GtkAction
*action
,
995 RBPlaylistManager
*mgr
)
997 rb_playlist_manager_new_playlist (mgr
, NULL
, FALSE
);
1001 rb_playlist_manager_set_automatic_playlist (RBPlaylistManager
*mgr
,
1002 RBAutoPlaylistSource
*playlist
,
1003 RBQueryCreator
*creator
)
1005 RBQueryCreatorLimitType type
;
1006 guint limit
, limit_count
= 0, limit_size
= 0, limit_time
= 0;
1007 const char *sort_key
;
1008 gint sort_direction
;
1010 rb_query_creator_get_limit (creator
, &type
, &limit
);
1011 if (type
== RB_QUERY_CREATOR_LIMIT_COUNT
)
1012 limit_count
= limit
;
1013 else if (type
== RB_QUERY_CREATOR_LIMIT_MB
)
1015 else if (type
== RB_QUERY_CREATOR_LIMIT_SECONDS
)
1018 g_assert_not_reached ();
1020 rb_query_creator_get_sort_order (creator
, &sort_key
, &sort_direction
);
1022 rb_auto_playlist_source_set_query (RB_AUTO_PLAYLIST_SOURCE (playlist
),
1023 rb_query_creator_get_query (creator
),
1024 limit_count
, limit_size
, limit_time
,
1025 sort_key
, sort_direction
);
1029 rb_playlist_manager_cmd_new_automatic_playlist (GtkAction
*action
,
1030 RBPlaylistManager
*mgr
)
1032 RBQueryCreator
*creator
= RB_QUERY_CREATOR (rb_query_creator_new (mgr
->priv
->db
));
1035 switch (gtk_dialog_run (GTK_DIALOG (creator
))) {
1036 case GTK_RESPONSE_NONE
:
1037 case GTK_RESPONSE_CLOSE
:
1038 gtk_widget_destroy (GTK_WIDGET (creator
));
1042 playlist
= rb_playlist_manager_new_playlist (mgr
, NULL
, TRUE
);
1044 rb_playlist_manager_set_automatic_playlist (mgr
, RB_AUTO_PLAYLIST_SOURCE (playlist
), creator
);
1046 rb_playlist_manager_set_dirty (mgr
, TRUE
);
1048 gtk_widget_destroy (GTK_WIDGET (creator
));
1052 RBAutoPlaylistSource
*playlist
;
1053 RBPlaylistManager
*mgr
;
1054 RBQueryCreator
*creator
;
1055 gint playlist_deleted_id
;
1056 gint creator_response_id
;
1057 } EditAutoPlaylistData
;
1060 cleanup_edit_data (EditAutoPlaylistData
*data
)
1062 g_signal_handler_disconnect (data
->playlist
, data
->playlist_deleted_id
);
1063 g_signal_handler_disconnect (data
->creator
, data
->creator_response_id
);
1064 gtk_widget_destroy (GTK_WIDGET (data
->creator
));
1069 edit_auto_playlist_response_cb (RBQueryCreator
*dialog
,
1071 EditAutoPlaylistData
*data
)
1073 rb_playlist_manager_set_automatic_playlist (data
->mgr
, data
->playlist
, dialog
);
1074 g_object_set_data (G_OBJECT (data
->playlist
), "rhythmbox-playlist-editor", NULL
);
1076 cleanup_edit_data (data
);
1080 edit_auto_playlist_deleted_cb (RBAutoPlaylistSource
*playlist
, EditAutoPlaylistData
*data
)
1082 g_object_set_data (G_OBJECT (playlist
), "rhythmbox-playlist-editor", NULL
);
1084 cleanup_edit_data (data
);
1088 rb_playlist_manager_cmd_edit_automatic_playlist (GtkAction
*action
,
1089 RBPlaylistManager
*mgr
)
1091 RBQueryCreator
*creator
;
1092 RBAutoPlaylistSource
*playlist
;
1094 guint limit_count
= 0, limit_size
= 0, limit_time
= 0;
1095 const char *sort_key
;
1096 gint sort_direction
;
1097 EditAutoPlaylistData
*data
;
1099 playlist
= RB_AUTO_PLAYLIST_SOURCE (mgr
->priv
->selected_source
);
1100 creator
= g_object_get_data (G_OBJECT (playlist
), "rhythmbox-playlist-editor");
1101 if (creator
== NULL
) {
1102 rb_auto_playlist_source_get_query (playlist
, &query
, &limit_count
, &limit_size
, &limit_time
, &sort_key
, &sort_direction
);
1104 creator
= RB_QUERY_CREATOR (rb_query_creator_new_from_query (mgr
->priv
->db
,
1106 limit_count
, limit_size
, limit_time
,
1107 sort_key
, sort_direction
));
1108 rhythmdb_query_free (query
);
1110 data
= g_new0 (EditAutoPlaylistData
, 1);
1112 data
->playlist
= playlist
;
1113 data
->creator
= creator
;
1114 data
->creator_response_id
=
1115 g_signal_connect (G_OBJECT (creator
),
1117 G_CALLBACK (edit_auto_playlist_response_cb
),
1120 g_object_set_data (G_OBJECT (playlist
), "rhythmbox-playlist-editor", creator
);
1121 data
->playlist_deleted_id
=
1122 g_signal_connect (G_OBJECT (playlist
),
1124 G_CALLBACK (edit_auto_playlist_deleted_cb
),
1127 gtk_window_present (GTK_WINDOW (creator
));
1131 _queue_track_cb (RhythmDBQueryModel
*model
,
1134 RBStaticPlaylistSource
*queue_source
)
1136 RhythmDBEntry
*entry
;
1138 entry
= rhythmdb_query_model_iter_to_entry (model
, iter
);
1139 rb_static_playlist_source_add_entry (queue_source
, entry
, -1);
1145 rb_playlist_manager_cmd_queue_playlist (GtkAction
*action
,
1146 RBPlaylistManager
*mgr
)
1148 RBSource
*queue_source
;
1149 RhythmDBQueryModel
*model
;
1151 g_object_get (G_OBJECT (mgr
->priv
->shell
), "queue-source", &queue_source
, NULL
);
1152 g_object_get (G_OBJECT (mgr
->priv
->selected_source
), "query-model", &model
, NULL
);
1154 gtk_tree_model_foreach (GTK_TREE_MODEL (model
),
1155 (GtkTreeModelForeachFunc
) _queue_track_cb
,
1158 g_object_unref (G_OBJECT (queue_source
));
1159 g_object_unref (G_OBJECT (model
));
1163 rb_playlist_manager_cmd_rename_playlist (GtkAction
*action
,
1164 RBPlaylistManager
*mgr
)
1166 rb_debug ("Renaming playlist %p", mgr
->priv
->selected_source
);
1168 rb_sourcelist_edit_source_name (mgr
->priv
->sourcelist
, mgr
->priv
->selected_source
);
1169 rb_playlist_manager_set_dirty (mgr
, TRUE
);
1173 rb_playlist_manager_cmd_delete_playlist (GtkAction
*action
,
1174 RBPlaylistManager
*mgr
)
1176 rb_debug ("Deleting playlist %p", mgr
->priv
->selected_source
);
1178 rb_source_delete_thyself (mgr
->priv
->selected_source
);
1179 rb_playlist_manager_set_dirty (mgr
, TRUE
);
1183 load_playlist_response_cb (GtkDialog
*dialog
,
1185 RBPlaylistManager
*mgr
)
1187 char *escaped_file
= NULL
;
1188 GError
*error
= NULL
;
1190 if (response_id
!= GTK_RESPONSE_ACCEPT
) {
1191 gtk_widget_destroy (GTK_WIDGET (dialog
));
1195 escaped_file
= gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog
));
1197 gtk_widget_destroy (GTK_WIDGET (dialog
));
1199 if (escaped_file
== NULL
)
1202 if (!rb_playlist_manager_parse_file (mgr
, escaped_file
, &error
)) {
1203 rb_error_dialog (NULL
, _("Couldn't read playlist"),
1205 g_error_free (error
);
1208 g_free (escaped_file
);
1209 rb_playlist_manager_set_dirty (mgr
, TRUE
);
1213 rb_playlist_manager_cmd_load_playlist (GtkAction
*action
,
1214 RBPlaylistManager
*mgr
)
1218 dialog
= rb_file_chooser_new (_("Load Playlist"),
1219 GTK_WINDOW (mgr
->priv
->window
),
1220 GTK_FILE_CHOOSER_ACTION_OPEN
,
1223 g_signal_connect_object (G_OBJECT (dialog
), "response",
1224 G_CALLBACK (load_playlist_response_cb
), mgr
, 0);
1230 const gchar
*description
;
1231 /* NULL terminated array of extensions for this file format. The first
1232 * one is the prefered extension for files of this type. */
1233 const gchar
**extensions
;
1234 const RBPlaylistExportType type
;
1235 } RBPlaylistExportFilter
;
1237 static const char *m3u_extensions
[] = {"m3u", NULL
};
1238 static const char *pls_extensions
[] = {"pls", NULL
};
1240 static RBPlaylistExportFilter playlist_export_formats
[] = {
1241 {N_("MPEG Version 3.0 URL"), m3u_extensions
, RB_PLAYLIST_EXPORT_TYPE_M3U
},
1242 {N_("Shoutcast playlist"), pls_extensions
, RB_PLAYLIST_EXPORT_TYPE_PLS
},
1246 save_playlist_response_cb (GtkDialog
*dialog
,
1248 RBPlaylistManager
*mgr
)
1253 RBPlaylistExportType export_type
= RB_PLAYLIST_EXPORT_TYPE_UNKNOWN
;
1255 if (response_id
!= GTK_RESPONSE_OK
) {
1256 gtk_widget_destroy (GTK_WIDGET (dialog
));
1260 file
= gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog
));
1261 if (file
== NULL
|| file
[0] == '\0')
1264 menu
= g_object_get_data (G_OBJECT(dialog
), "export-menu");
1265 index
= gtk_combo_box_get_active (GTK_COMBO_BOX (menu
));
1267 /* by extension selected */
1271 for (i
= 0; i
< G_N_ELEMENTS (playlist_export_formats
); i
++) {
1274 /* determine the playlist type from the extension */
1275 for (j
= 0; playlist_export_formats
[i
].extensions
[j
] != NULL
; j
++) {
1276 if (g_str_has_suffix (file
, playlist_export_formats
[i
].extensions
[j
])) {
1277 export_type
= playlist_export_formats
[i
].type
;
1283 export_type
= playlist_export_formats
[index
-1].type
;
1286 if (export_type
== RB_PLAYLIST_EXPORT_TYPE_UNKNOWN
) {
1287 rb_error_dialog (NULL
, _("Couldn't save playlist"), _("Unsupported file extension given."));
1289 rb_playlist_source_save_playlist (RB_PLAYLIST_SOURCE (mgr
->priv
->selected_source
),
1290 file
, (export_type
== RB_PLAYLIST_EXPORT_TYPE_M3U
));
1291 gtk_widget_destroy (GTK_WIDGET (dialog
));
1298 export_set_extension_cb (GtkWidget
* widget
, GtkDialog
*dialog
)
1303 const char *extension
;
1305 GString
*basename_str
;
1307 index
= gtk_combo_box_get_active (GTK_COMBO_BOX (widget
));
1311 extension
= playlist_export_formats
[index
-1].extensions
[0];
1312 if (extension
== NULL
)
1315 text
= gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog
));
1316 if (text
== NULL
|| text
[0] == '\0') {
1321 basename
= g_path_get_basename (text
);
1322 basename_str
= g_string_new (basename
);
1323 last_dot
= g_utf8_strrchr (basename
, -1, '.');
1325 g_string_truncate (basename_str
, (last_dot
-basename
));
1329 g_string_append_printf (basename_str
, ".%s", extension
);
1330 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog
), basename_str
->str
);
1331 g_string_free (basename_str
, TRUE
);
1335 filter_get_export_filter_label (RBPlaylistExportFilter
*efilter
)
1340 str
= g_string_new (_(efilter
->description
));
1341 for (ext
= 0; efilter
->extensions
[ext
] != NULL
; ext
++) {
1343 g_string_append (str
, " (*.");
1345 g_string_append (str
, ", *.");
1346 g_string_append (str
, efilter
->extensions
[ext
]);
1350 g_string_append (str
, ")");
1352 return g_string_free (str
, FALSE
);
1356 setup_format_menu (GtkWidget
* menu
, GtkWidget
*dialog
)
1358 GtkTreeModel
*model
;
1361 model
= gtk_combo_box_get_model (GTK_COMBO_BOX (menu
));
1362 gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (menu
), rb_combo_box_hyphen_separator_func
,
1365 for (i
= 0; i
< G_N_ELEMENTS (playlist_export_formats
); i
++) {
1366 gchar
*filter_label
;
1369 filter_label
= filter_get_export_filter_label (&playlist_export_formats
[i
]);
1370 gtk_list_store_insert_with_values (GTK_LIST_STORE (model
), &iter
, -1,
1371 0, filter_label
, -1);
1373 g_free (filter_label
);
1376 g_signal_connect_object (GTK_OBJECT (menu
),
1377 "changed", G_CALLBACK (export_set_extension_cb
),
1382 rb_playlist_manager_cmd_save_playlist (GtkAction
*action
,
1383 RBPlaylistManager
*mgr
)
1386 GtkWidget
*dialog
, *menu
;
1388 xml
= rb_glade_xml_new ("playlist-save.glade",
1389 "playlist_save_dialog",
1391 dialog
= glade_xml_get_widget (xml
, "playlist_save_dialog");
1393 menu
= glade_xml_get_widget (xml
, "playlist_format_menu");
1394 setup_format_menu (menu
, dialog
);
1395 g_object_set_data (G_OBJECT (dialog
), "export-menu", menu
);
1397 /* FIXME: always has "by extension" as default (it should probably remember the last selection) */
1398 gtk_combo_box_set_active (GTK_COMBO_BOX (menu
), 0);
1399 g_signal_connect_object (G_OBJECT (dialog
), "response",
1400 G_CALLBACK (save_playlist_response_cb
),
1403 g_object_unref (G_OBJECT (xml
));
1407 rb_playlist_manager_cmd_burn_playlist (GtkAction
*action
,
1408 RBPlaylistManager
*mgr
)
1410 rb_playlist_source_burn_playlist (RB_PLAYLIST_SOURCE (mgr
->priv
->selected_source
));
1414 * rb_playlist_manager_get_playlists
1415 * @mgr: the #RBPlaylistManager
1417 * Returns a #GList containing all local playlist source objects.
1420 rb_playlist_manager_get_playlists (RBPlaylistManager
*mgr
)
1422 GList
*playlists
= NULL
;
1424 GtkTreeModel
*fmodel
;
1425 GtkTreeModel
*model
;
1427 g_object_get (G_OBJECT (mgr
->priv
->sourcelist
), "model", &fmodel
, NULL
);
1428 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (fmodel
));
1429 g_object_unref (fmodel
);
1431 if (gtk_tree_model_get_iter_first (model
, &iter
)) {
1437 gtk_tree_model_get_value (model
,
1439 RB_SOURCELIST_MODEL_COLUMN_SOURCE
,
1441 source
= g_value_get_pointer (&v
);
1442 if (RB_IS_PLAYLIST_SOURCE (source
) == FALSE
)
1444 if (RB_IS_PLAY_QUEUE_SOURCE (source
) == TRUE
)
1446 g_object_get (G_OBJECT (source
), "is-local", &local
,
1449 playlists
= g_list_prepend (playlists
, source
);
1452 } while (gtk_tree_model_iter_next (model
, &iter
));
1459 * rb_playlist_manager_get_playlist_names
1460 * @mgr: the #RBPlaylistManager
1461 * @playlists: holds the array of playlist names on reutrn
1462 * @error: holds a #GError on return on failure
1464 * Allocates and returns an array containing the names of all local
1465 * playlists. This is part of the playlist manager dbus interface.
1467 * Returns TRUE if successful.
1470 rb_playlist_manager_get_playlist_names (RBPlaylistManager
*mgr
,
1475 GtkTreeModel
*fmodel
;
1476 GtkTreeModel
*model
;
1479 g_object_get (G_OBJECT (mgr
->priv
->sourcelist
), "model", &fmodel
, NULL
);
1480 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (fmodel
));
1481 g_object_unref (fmodel
);
1483 if (!gtk_tree_model_get_iter_first (model
, &iter
)) {
1488 *playlists
= g_new0 (char *, gtk_tree_model_iter_n_children (model
, NULL
) + 1);
1498 gtk_tree_model_get_value (model
, &iter
,
1499 RB_SOURCELIST_MODEL_COLUMN_SOURCE
,
1501 source
= g_value_get_pointer (&v
);
1502 if (!RB_IS_PLAYLIST_SOURCE (source
))
1504 if (RB_IS_PLAY_QUEUE_SOURCE (source
))
1507 g_object_get (G_OBJECT (source
), "name", &source_name
, NULL
);
1508 (*playlists
)[i
++] = source_name
;
1509 } while (gtk_tree_model_iter_next (model
, &iter
));
1515 _get_playlist_by_name (RBPlaylistManager
*mgr
,
1519 GtkTreeModel
*fmodel
;
1520 GtkTreeModel
*model
;
1521 RBSource
*playlist
= NULL
;
1523 g_object_get (G_OBJECT (mgr
->priv
->sourcelist
), "model", &fmodel
, NULL
);
1524 model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (fmodel
));
1525 g_object_unref (G_OBJECT (fmodel
));
1527 if (!gtk_tree_model_get_iter_first (model
, &iter
))
1535 gtk_tree_model_get_value (model
, &iter
,
1536 RB_SOURCELIST_MODEL_COLUMN_SOURCE
,
1538 source
= g_value_get_pointer (&v
);
1539 if (!RB_IS_PLAYLIST_SOURCE (source
))
1541 g_object_get (G_OBJECT (source
), "name", &source_name
, NULL
);
1542 if (strcmp (name
, source_name
) == 0)
1545 g_free (source_name
);
1547 } while (gtk_tree_model_iter_next (model
, &iter
) && playlist
== NULL
);
1553 * rb_playlist_manager_create_static_playlist
1554 * @mgr: the #RBPlaylistManager
1555 * @name: name of the new playlist
1556 * @error: holds a #GError on return on failure
1558 * Creates a new static playlist source with the given name.
1559 * Will fail if a playlist with that name already exists.
1560 * This is part of the playlist manager dbus interface.
1562 * Returns TRUE if successful.
1565 rb_playlist_manager_create_static_playlist (RBPlaylistManager
*mgr
,
1569 if (_get_playlist_by_name (mgr
, name
)) {
1571 RB_PLAYLIST_MANAGER_ERROR
,
1572 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_EXISTS
,
1573 _("Playlist %s already exists"),
1578 rb_playlist_manager_new_playlist (mgr
, name
, FALSE
);
1583 * rb_playlist_manager_delete_playlist
1584 * @mgr: the #RBPlaylistManager
1585 * @name: name of the playlist to delete
1586 * @error: holds a #GError on return on failure
1588 * Deletes the specified playlist. Will fail if no playlist with
1589 * that name exists. This is part of the playlist manager dbus interface.
1591 * Returns TRUE if successful.
1594 rb_playlist_manager_delete_playlist (RBPlaylistManager
*mgr
,
1598 RBSource
*playlist
= _get_playlist_by_name (mgr
, name
);
1601 RB_PLAYLIST_MANAGER_ERROR
,
1602 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_NOT_FOUND
,
1603 _("Unknown playlist: %s"),
1607 rb_source_delete_thyself (playlist
);
1608 rb_playlist_manager_set_dirty (mgr
, TRUE
);
1613 * rb_playlist_manager_add_to_playlist
1614 * @mgr: the #RBPlaylistManager
1615 * @name: name of the playlist to add to
1616 * @uri: URI of the entry to add to the playlist
1617 * @error: holds a #GError on return on failure
1619 * Adds an entry to the specified playlist.
1620 * Fails if no playlist with that name exists.
1621 * This is part of the playlist manager dbus interface.
1623 * Returns TRUE if successful.
1626 rb_playlist_manager_add_to_playlist (RBPlaylistManager
*mgr
,
1627 const gchar
*playlist
,
1631 RBSource
*source
= _get_playlist_by_name (mgr
, playlist
);;
1634 RB_PLAYLIST_MANAGER_ERROR
,
1635 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_NOT_FOUND
,
1636 _("Unknown playlist: %s"),
1640 if (RB_IS_AUTO_PLAYLIST_SOURCE (source
)) {
1642 RB_PLAYLIST_MANAGER_ERROR
,
1643 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_NOT_FOUND
,
1644 _("Playlist %s is an automatic playlist"),
1648 rb_static_playlist_source_add_location (RB_STATIC_PLAYLIST_SOURCE (source
), uri
, -1);
1653 * rb_playlist_manager_remove_from_playlist
1654 * @mgr: the #RBPlaylistManager
1655 * @name: name of the playlist to remove from
1656 * @uri: URI of the entry to remove from the playlist
1657 * @error: holds a #GError on return on failure
1659 * Removes an entry from the specified playlist.
1660 * Fails if no playlist with that name exists.
1661 * This is part of the playlist manager dbus interface.
1663 * Returns TRUE if successful.
1666 rb_playlist_manager_remove_from_playlist (RBPlaylistManager
*mgr
,
1667 const gchar
*playlist
,
1671 RBSource
*source
= _get_playlist_by_name (mgr
, playlist
);;
1674 RB_PLAYLIST_MANAGER_ERROR
,
1675 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_NOT_FOUND
,
1676 _("Unknown playlist: %s"),
1680 if (RB_IS_AUTO_PLAYLIST_SOURCE (source
)) {
1682 RB_PLAYLIST_MANAGER_ERROR
,
1683 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_NOT_FOUND
,
1684 _("Playlist %s is an automatic playlist"),
1689 if (rb_playlist_source_location_in_map (RB_PLAYLIST_SOURCE (source
), uri
))
1690 rb_static_playlist_source_remove_location (RB_STATIC_PLAYLIST_SOURCE (source
), uri
);
1695 * rb_playlist_manager_export_playlist
1696 * @mgr: the #RBPlaylistManager
1697 * @name: name of the playlist to export
1698 * @uri: playlist save location
1699 * @m3u_format: if TRUE, save in M3U format, otherwise save in PLS format
1700 * @error: holds a #GError on return on failure
1702 * Saves the specified playlist to a file in either M3U or PLS format.
1703 * This is part of the playlist manager dbus interface.
1705 * Returns TRUE if successful.
1708 rb_playlist_manager_export_playlist (RBPlaylistManager
*mgr
,
1709 const gchar
*playlist
,
1711 gboolean m3u_format
,
1714 RBSource
*source
= _get_playlist_by_name (mgr
, playlist
);
1717 RB_PLAYLIST_MANAGER_ERROR
,
1718 RB_PLAYLIST_MANAGER_ERROR_PLAYLIST_NOT_FOUND
,
1719 _("Unknown playlist: %s"),
1724 rb_playlist_source_save_playlist (RB_PLAYLIST_SOURCE (source
),