1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2005 Jonathan Matthew <jonathan@kaolin.hn.org>
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.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include <libxml/tree.h>
24 #include <glib/gi18n.h>
26 #include <libgnomevfs/gnome-vfs-uri.h>
28 #include "rb-play-queue-source.h"
29 #include "rb-playlist-xml.h"
30 #include "rb-song-info.h"
34 static GObject
*rb_play_queue_source_constructor (GType type
, guint n_construct_properties
,
35 GObjectConstructParam
*construct_properties
);
36 static void rb_play_queue_source_get_property (GObject
*object
,
40 static void rb_play_queue_source_track_info_cell_data_func (GtkTreeViewColumn
*column
,
41 GtkCellRenderer
*renderer
,
42 GtkTreeModel
*tree_model
,
44 RBPlaylistSource
*source
);
45 static void rb_play_queue_source_row_inserted_cb (GtkTreeModel
*model
,
48 RBPlayQueueSource
*source
);
49 static void rb_play_queue_source_row_deleted_cb (GtkTreeModel
*model
,
51 RBPlayQueueSource
*source
);
52 static void rb_play_queue_source_update_count (RBPlayQueueSource
*source
,
55 static void impl_show_entry_view_popup (RBPlaylistSource
*source
,
58 static void impl_save_contents_to_xml (RBPlaylistSource
*source
,
60 static void rb_play_queue_source_cmd_clear (GtkAction
*action
,
61 RBPlayQueueSource
*source
);
62 static GList
*impl_get_ui_actions (RBSource
*source
);
63 static gboolean
impl_show_popup (RBSource
*asource
);
65 #define PLAY_QUEUE_SOURCE_SONGS_POPUP_PATH "/QueuePlaylistViewPopup"
66 #define PLAY_QUEUE_SOURCE_SIDEBAR_POPUP_PATH "/QueueSidebarViewPopup"
67 #define PLAY_QUEUE_SOURCE_POPUP_PATH "/QueueSourcePopup"
69 typedef struct _RBPlayQueueSourcePrivate RBPlayQueueSourcePrivate
;
71 struct _RBPlayQueueSourcePrivate
74 GtkTreeViewColumn
*sidebar_column
;
75 GtkActionGroup
*action_group
;
84 G_DEFINE_TYPE (RBPlayQueueSource
, rb_play_queue_source
, RB_TYPE_STATIC_PLAYLIST_SOURCE
)
85 #define RB_PLAY_QUEUE_SOURCE_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), RB_TYPE_PLAY_QUEUE_SOURCE, RBPlayQueueSourcePrivate))
87 static GtkActionEntry rb_play_queue_source_actions
[] =
89 { "ClearQueue", GTK_STOCK_CLEAR
, N_("Clear _Queue"), NULL
,
90 N_("Remove all songs from the play queue"),
91 G_CALLBACK (rb_play_queue_source_cmd_clear
) }
95 rb_play_queue_sync_playing_state (GObject
*entry_view
,
97 RBPlayQueueSource
*source
)
100 RBPlayQueueSourcePrivate
*priv
= RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (source
);
101 g_object_get (entry_view
, "playing-state", &state
, NULL
);
102 rb_entry_view_set_state (priv
->sidebar
, state
);
106 rb_play_queue_source_finalize (GObject
*object
)
108 RBPlayQueueSourcePrivate
*priv
= RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (object
);
110 if (priv
->action_group
!= NULL
) {
111 g_object_unref (priv
->action_group
);
114 G_OBJECT_CLASS (rb_play_queue_source_parent_class
)->finalize (object
);
118 rb_play_queue_source_class_init (RBPlayQueueSourceClass
*klass
)
120 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
121 RBSourceClass
*source_class
= RB_SOURCE_CLASS (klass
);
122 RBPlaylistSourceClass
*playlist_class
= RB_PLAYLIST_SOURCE_CLASS (klass
);
124 object_class
->constructor
= rb_play_queue_source_constructor
;
125 object_class
->get_property
= rb_play_queue_source_get_property
;
126 object_class
->finalize
= rb_play_queue_source_finalize
;
128 source_class
->impl_can_add_to_queue
= (RBSourceFeatureFunc
) rb_false_function
;
129 source_class
->impl_can_rename
= (RBSourceFeatureFunc
) rb_false_function
;
130 source_class
->impl_can_search
= (RBSourceFeatureFunc
) rb_false_function
;
131 source_class
->impl_can_browse
= (RBSourceFeatureFunc
) rb_false_function
;
132 source_class
->impl_get_ui_actions
= impl_get_ui_actions
;
133 source_class
->impl_show_popup
= impl_show_popup
;
135 playlist_class
->impl_show_entry_view_popup
= impl_show_entry_view_popup
;
136 playlist_class
->impl_save_contents_to_xml
= impl_save_contents_to_xml
;
138 g_object_class_install_property (object_class
,
140 g_param_spec_object ("sidebar",
142 "queue sidebar entry view",
146 g_type_class_add_private (klass
, sizeof (RBPlayQueueSourcePrivate
));
150 rb_play_queue_source_init (RBPlayQueueSource
*source
)
155 rb_play_queue_source_constructor (GType type
,
156 guint n_construct_properties
,
157 GObjectConstructParam
*construct_properties
)
159 GObjectClass
*parent_class
= G_OBJECT_CLASS (rb_play_queue_source_parent_class
);
160 RBPlayQueueSource
*source
= RB_PLAY_QUEUE_SOURCE (
161 parent_class
->constructor (type
, n_construct_properties
, construct_properties
));
162 RBPlayQueueSourcePrivate
*priv
= RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (source
);
163 GObject
*shell_player
;
165 RhythmDB
*db
= rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source
));
166 GtkCellRenderer
*renderer
;
167 RhythmDBQueryModel
*model
;
169 g_object_get (source
, "shell", &shell
, NULL
);
170 shell_player
= rb_shell_get_player (shell
);
171 g_object_unref (shell
);
173 priv
->action_group
= _rb_source_register_action_group (RB_SOURCE (source
),
175 rb_play_queue_source_actions
,
176 G_N_ELEMENTS (rb_play_queue_source_actions
),
179 priv
->sidebar
= rb_entry_view_new (db
, shell_player
, NULL
, TRUE
, TRUE
);
181 g_object_set (G_OBJECT (priv
->sidebar
), "vscrollbar-policy", GTK_POLICY_AUTOMATIC
, NULL
);
183 priv
->sidebar_column
= gtk_tree_view_column_new ();
184 renderer
= gtk_cell_renderer_text_new ();
185 gtk_tree_view_column_pack_start (priv
->sidebar_column
, renderer
, TRUE
);
186 gtk_tree_view_column_set_sizing (priv
->sidebar_column
, GTK_TREE_VIEW_COLUMN_FIXED
);
187 gtk_tree_view_column_set_expand (priv
->sidebar_column
, TRUE
);
188 gtk_tree_view_column_set_clickable (priv
->sidebar_column
, FALSE
);
189 gtk_tree_view_column_set_cell_data_func (priv
->sidebar_column
, renderer
,
190 (GtkTreeCellDataFunc
)
191 rb_play_queue_source_track_info_cell_data_func
,
193 rb_entry_view_append_column_custom (priv
->sidebar
, priv
->sidebar_column
,
194 _("Play Queue"), "Title", NULL
, 0);
195 rb_entry_view_set_columns_clickable (priv
->sidebar
, FALSE
);
196 rb_playlist_source_setup_entry_view (RB_PLAYLIST_SOURCE (source
), priv
->sidebar
);
198 model
= rb_playlist_source_get_query_model (RB_PLAYLIST_SOURCE (source
));
199 rb_entry_view_set_model (priv
->sidebar
, model
);
201 /* sync the state of the main entry view and the sidebar */
202 g_signal_connect_object (G_OBJECT (rb_source_get_entry_view (RB_SOURCE (source
))),
203 "notify::playing-state",
204 G_CALLBACK (rb_play_queue_sync_playing_state
),
207 /* update the queued song count when the query model changes */
208 g_signal_connect_object (G_OBJECT (model
), "row-inserted",
209 G_CALLBACK (rb_play_queue_source_row_inserted_cb
),
211 g_signal_connect_object (G_OBJECT (model
), "row-deleted",
212 G_CALLBACK (rb_play_queue_source_row_deleted_cb
),
215 rb_play_queue_source_update_count (source
, GTK_TREE_MODEL (model
), 0);
217 return G_OBJECT (source
);
221 rb_play_queue_source_get_property (GObject
*object
,
226 RBPlayQueueSourcePrivate
*priv
= RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (object
);
231 g_value_set_object (value
, priv
->sidebar
);
234 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
240 rb_play_queue_source_new (RBShell
*shell
)
242 return RB_SOURCE (g_object_new (RB_TYPE_PLAY_QUEUE_SOURCE
,
243 "name", _("Play Queue"),
246 "entry-type", RHYTHMDB_ENTRY_TYPE_INVALID
,
251 rb_play_queue_source_sidebar_song_info (RBPlayQueueSource
*source
)
253 RBPlayQueueSourcePrivate
*priv
= RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (source
);
254 GtkWidget
*song_info
= NULL
;
256 g_return_if_fail (priv
->sidebar
!= NULL
);
258 song_info
= rb_song_info_new (RB_SOURCE (source
), priv
->sidebar
);
260 gtk_widget_show_all (song_info
);
262 rb_debug ("failed to create dialog, or no selection!");
266 rb_play_queue_source_sidebar_delete (RBPlayQueueSource
*source
)
268 RBPlayQueueSourcePrivate
*priv
= RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (source
);
269 RBEntryView
*sidebar
= priv
->sidebar
;
272 sel
= rb_entry_view_get_selected_entries (sidebar
);
273 for (tem
= sel
; tem
!= NULL
; tem
= tem
->next
)
274 rb_static_playlist_source_remove_entry (RB_STATIC_PLAYLIST_SOURCE (source
),
275 (RhythmDBEntry
*) tem
->data
);
280 rb_play_queue_source_clear_queue (RBPlayQueueSource
*source
)
283 RhythmDBEntry
*entry
;
284 RhythmDBQueryModel
*model
;
286 model
= rb_playlist_source_get_query_model (RB_PLAYLIST_SOURCE (source
));
287 while (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model
), &iter
)) {
288 entry
= rhythmdb_query_model_iter_to_entry (model
, &iter
);
291 rhythmdb_query_model_remove_entry (model
, entry
);
292 rhythmdb_entry_unref (entry
);
298 impl_show_entry_view_popup (RBPlaylistSource
*source
,
302 RBPlayQueueSourcePrivate
*priv
= RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (source
);
303 const char *popup
= PLAY_QUEUE_SOURCE_SONGS_POPUP_PATH
;
304 if (view
== priv
->sidebar
)
305 popup
= PLAY_QUEUE_SOURCE_SIDEBAR_POPUP_PATH
;
306 else if (!over_entry
)
308 _rb_source_show_popup (RB_SOURCE (source
), popup
);
312 rb_play_queue_source_track_info_cell_data_func (GtkTreeViewColumn
*column
,
313 GtkCellRenderer
*renderer
,
314 GtkTreeModel
*tree_model
,
316 RBPlaylistSource
*source
)
318 RhythmDBEntry
*entry
;
324 gtk_tree_model_get (tree_model
, iter
, 0, &entry
, -1);
326 title
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_TITLE
);
327 artist
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ARTIST
);
328 album
= rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_ALBUM
);
330 /* Translators: format is "<title> from <album> by <artist>" */
331 markup
= g_markup_printf_escaped ("%s\n<span size=\"smaller\">%s <i>%s</i>\n%s <i>%s</i></span>",
332 title
, _("from"), album
, _("by"), artist
);
334 g_object_set (G_OBJECT (renderer
), "markup", markup
, NULL
);
337 rhythmdb_entry_unref (entry
);
341 rb_play_queue_source_row_inserted_cb (GtkTreeModel
*model
,
344 RBPlayQueueSource
*source
)
346 rb_play_queue_source_update_count (source
, model
, 0);
350 rb_play_queue_source_row_deleted_cb (GtkTreeModel
*model
,
352 RBPlayQueueSource
*source
)
354 rb_play_queue_source_update_count (source
, model
, -1);
358 rb_play_queue_source_update_count (RBPlayQueueSource
*source
,
362 gint count
= gtk_tree_model_iter_n_children (model
, NULL
) + offset
;
363 RBPlayQueueSourcePrivate
*priv
= RB_PLAY_QUEUE_SOURCE_GET_PRIVATE (source
);
364 char *name
= _("Play Queue");
367 /* update source name */
369 name
= g_strdup_printf ("%s (%d)", name
, count
);
371 g_object_set (G_OBJECT (source
), "name", name
, NULL
);
372 gtk_tree_view_column_set_title (priv
->sidebar_column
, name
);
377 /* make 'clear queue' action sensitive when there are entries in the queue */
378 action
= gtk_action_group_get_action (priv
->action_group
,
380 g_object_set (G_OBJECT (action
), "sensitive", (count
> 0), NULL
);
384 impl_save_contents_to_xml (RBPlaylistSource
*source
,
387 ((RBPlaylistSourceClass
*)rb_play_queue_source_parent_class
)->impl_save_contents_to_xml (source
, node
);
388 xmlSetProp (node
, RB_PLAYLIST_TYPE
, RB_PLAYLIST_QUEUE
);
392 rb_play_queue_source_cmd_clear (GtkAction
*action
,
393 RBPlayQueueSource
*source
)
395 rb_play_queue_source_clear_queue (source
);
399 impl_show_popup (RBSource
*asource
)
401 _rb_source_show_popup (asource
, PLAY_QUEUE_SOURCE_POPUP_PATH
);
406 impl_get_ui_actions (RBSource
*source
)
408 GList
*actions
= NULL
;
410 actions
= g_list_prepend (actions
, g_strdup ("ClearQueue"));