16
16
* You should have received a copy of the GNU General Public License
17
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26
#include <libxml/tree.h>
27
#include <glib/gi18n.h>
23
28
#include <gtk/gtk.h>
24
#include <libgnome/gnome-i18n.h>
25
29
#include <libgnomevfs/gnome-vfs-uri.h>
26
#include <libxml/tree.h>
29
31
#include "rb-static-playlist-source.h"
32
#include "rb-library-browser.h"
30
33
#include "rb-util.h"
31
34
#include "rb-debug.h"
32
35
#include "rb-stock-icons.h"
36
39
static GObject *rb_static_playlist_source_constructor (GType type, guint n_construct_properties,
37
40
GObjectConstructParam *construct_properties);
41
static void rb_static_playlist_source_dispose (GObject *object);
38
42
static void rb_static_playlist_source_finalize (GObject *object);
40
44
/* source methods */
41
static GdkPixbuf *impl_get_pixbuf (RBSource *source);
42
45
static GList * impl_cut (RBSource *source);
43
46
static void impl_paste (RBSource *asource, GList *entries);
44
47
static void impl_delete (RBSource *source);
45
48
static void impl_search (RBSource *asource, const char *search_text);
49
static void impl_browser_toggled (RBSource *source, gboolean enabled);
46
50
static void impl_reset_filters (RBSource *asource);
47
51
static gboolean impl_receive_drag (RBSource *source, GtkSelectionData *data);
52
static GList *impl_get_search_actions (RBSource *source);
53
static GPtrArray *construct_query_from_selection (RBStaticPlaylistSource *source);
49
55
/* playlist methods */
50
56
static void impl_save_contents_to_xml (RBPlaylistSource *source,
61
static GList *impl_get_property_views (RBSource *source);
62
void rb_static_playlist_source_browser_views_activated_cb (GtkWidget *widget,
63
RBStaticPlaylistSource *source);
64
static void rb_static_playlist_source_browser_changed_cb (RBLibraryBrowser *entry,
66
RBStaticPlaylistSource *source);
53
68
static void rb_static_playlist_source_do_query (RBStaticPlaylistSource *source);
55
70
static void rb_static_playlist_source_add_list_uri (RBStaticPlaylistSource *source,
64
79
RBStaticPlaylistSource *source);
81
static void search_action_changed (GtkRadioAction *action,
82
GtkRadioAction *current,
85
static GtkRadioActionEntry rb_static_playlist_source_radio_actions [] =
87
{ "StaticPlaylistSearchAll", NULL, N_("All"), NULL, N_("Search all fields"), 0 },
88
{ "StaticPlaylistSearchArtists", NULL, N_("Artists"), NULL, N_("Search artists"), 1 },
89
{ "StaticPlaylistSearchAlbums", NULL, N_("Albums"), NULL, N_("Search albums"), 2 },
90
{ "StaticPlaylistSearchTitles", NULL, N_("Titles"), NULL, N_("Search titles"), 3 }
66
93
G_DEFINE_TYPE (RBStaticPlaylistSource, rb_static_playlist_source, RB_TYPE_PLAYLIST_SOURCE)
67
94
#define RB_STATIC_PLAYLIST_SOURCE_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), \
68
95
RB_TYPE_STATIC_PLAYLIST_SOURCE, \
88
122
RBPlaylistSourceClass *playlist_class = RB_PLAYLIST_SOURCE_CLASS (klass);
90
124
object_class->constructor = rb_static_playlist_source_constructor;
125
object_class->dispose = rb_static_playlist_source_dispose;
91
126
object_class->finalize = rb_static_playlist_source_finalize;
93
128
source_class->impl_can_cut = (RBSourceFeatureFunc) rb_true_function;
94
source_class->impl_can_copy = (RBSourceFeatureFunc) rb_true_function;
129
source_class->impl_can_paste = (RBSourceFeatureFunc) rb_true_function;
95
130
source_class->impl_can_delete = (RBSourceFeatureFunc) rb_true_function;
96
131
source_class->impl_cut = impl_cut;
97
132
source_class->impl_paste = impl_paste;
98
133
source_class->impl_delete = impl_delete;
99
source_class->impl_get_pixbuf = impl_get_pixbuf;
100
134
source_class->impl_receive_drag = impl_receive_drag;
101
135
source_class->impl_can_search = (RBSourceFeatureFunc) rb_true_function;
102
136
source_class->impl_search = impl_search;
103
137
source_class->impl_reset_filters = impl_reset_filters;
138
source_class->impl_can_browse = (RBSourceFeatureFunc) rb_true_function;
139
source_class->impl_browser_toggled = impl_browser_toggled;
140
source_class->impl_get_property_views = impl_get_property_views;
141
source_class->impl_get_search_actions = impl_get_search_actions;
105
143
playlist_class->impl_save_contents_to_xml = impl_save_contents_to_xml;
117
155
rb_static_playlist_source_init (RBStaticPlaylistSource *source)
157
RBStaticPlaylistSourceClass *klass = RB_STATIC_PLAYLIST_SOURCE_GET_CLASS (source);
159
rb_source_set_pixbuf (RB_SOURCE (source), klass->pixbuf);
163
rb_static_playlist_source_dispose (GObject *object)
165
RBStaticPlaylistSourcePrivate *priv = RB_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (object);
169
if (priv->base_model) {
170
g_object_unref (G_OBJECT (priv->base_model));
171
priv->base_model = NULL;
174
G_OBJECT_CLASS (rb_static_playlist_source_parent_class)->dispose (object);
138
193
parent_class->constructor (type, n_construct_properties, construct_properties));
139
194
RBStaticPlaylistSourcePrivate *priv = RB_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (source);
140
195
RBPlaylistSource *psource = RB_PLAYLIST_SOURCE (source);
198
RhythmDBEntryType entry_type;
142
200
priv->base_model = rb_playlist_source_get_query_model (RB_PLAYLIST_SOURCE (psource));
143
201
g_object_set (G_OBJECT (priv->base_model), "show-hidden", TRUE, NULL);
202
g_object_ref (G_OBJECT (priv->base_model));
204
priv->paned = gtk_vpaned_new ();
206
g_object_get (G_OBJECT (source), "shell", &shell, NULL);
207
priv->action_group = _rb_source_register_action_group (RB_SOURCE (source),
208
"StaticPlaylistActions",
211
gtk_action_group_add_radio_actions (priv->action_group,
212
rb_static_playlist_source_radio_actions,
213
G_N_ELEMENTS (rb_static_playlist_source_radio_actions),
215
(GCallback)search_action_changed,
217
priv->search_prop = RHYTHMDB_PROP_SEARCH_MATCH;
218
g_object_unref (G_OBJECT (shell));
220
g_object_get (G_OBJECT (source), "entry-type", &entry_type, NULL);
221
priv->browser = rb_library_browser_new (rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source)),
223
gtk_paned_pack1 (GTK_PANED (priv->paned), GTK_WIDGET (priv->browser), TRUE, FALSE);
224
g_signal_connect_object (G_OBJECT (priv->browser), "notify::output-model",
225
G_CALLBACK (rb_static_playlist_source_browser_changed_cb),
228
rb_library_browser_set_model (priv->browser, priv->base_model, FALSE);
145
229
rb_static_playlist_source_do_query (source);
231
/* reparent the entry view */
232
songs = rb_source_get_entry_view (RB_SOURCE (source));
233
g_object_ref (G_OBJECT (songs));
234
gtk_container_remove (GTK_CONTAINER (source), GTK_WIDGET (songs));
235
gtk_paned_pack2 (GTK_PANED (priv->paned), GTK_WIDGET (songs), TRUE, FALSE);
236
gtk_container_add (GTK_CONTAINER (source), priv->paned);
147
238
/* watch these to find out when things are dropped into the entry view */
148
239
g_signal_connect_object (G_OBJECT (priv->base_model), "row-inserted",
271
360
impl_search (RBSource *source, const char *search_text)
273
362
RBStaticPlaylistSourcePrivate *priv = RB_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (source);
363
char *old_search_text = NULL;
365
if (search_text != NULL && search_text[0] == '\0')
275
368
if (search_text == NULL && priv->search_text == NULL)
277
if (search_text != NULL && priv->search_text != NULL &&
278
!strcmp (search_text, priv->search_text))
370
if (search_text != NULL && priv->search_text != NULL
371
&& !strcmp (search_text, priv->search_text))
281
if (search_text[0] == '\0')
284
rb_debug ("doing search for \"%s\"", search_text ? search_text : "(NULL)");
286
g_free (priv->search_text);
287
priv->search_text = g_strdup (search_text);
374
old_search_text = priv->search_text;
375
if (search_text == NULL) {
376
priv->search_text = NULL;
378
priv->search_text = g_strdup (search_text);
380
g_free (old_search_text);
382
rb_debug ("doing search for \"%s\"", priv->search_text ? priv->search_text : "(NULL)");
288
384
rb_static_playlist_source_do_query (RB_STATIC_PLAYLIST_SOURCE (source));
290
rb_source_notify_filter_changed (source);
388
impl_get_property_views (RBSource *source)
390
RBStaticPlaylistSourcePrivate *priv = RB_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (source);
393
ret = rb_library_browser_get_property_views (priv->browser);
399
impl_browser_toggled (RBSource *source, gboolean enabled)
401
RBStaticPlaylistSourcePrivate *priv = RB_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (source);
403
priv->browser_shown = enabled;
406
gtk_widget_show (GTK_WIDGET (priv->browser));
408
gtk_widget_hide (GTK_WIDGET (priv->browser));
412
construct_query_from_selection (RBStaticPlaylistSource *source)
414
RBStaticPlaylistSourcePrivate *priv = RB_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (source);
415
RBPlaylistSource *psource = RB_PLAYLIST_SOURCE (source);
416
RhythmDB *db = rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (psource));
417
GPtrArray *query = NULL;
419
query = g_ptr_array_new();
421
if (priv->search_text) {
422
rhythmdb_query_append (db,
424
RHYTHMDB_QUERY_PROP_LIKE, priv->search_prop, priv->search_text,
296
434
RBStaticPlaylistSourcePrivate *priv = RB_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (source);
297
435
RBPlaylistSource *psource = RB_PLAYLIST_SOURCE (source);
298
436
RhythmDB *db = rb_playlist_source_get_db (psource);
299
GPtrArray *query = NULL;
301
439
if (priv->filter_model)
302
440
g_object_unref (priv->filter_model);
303
441
priv->filter_model = rhythmdb_query_model_new_empty (db);
304
442
g_object_set (G_OBJECT (priv->filter_model), "base-model", priv->base_model, NULL);
306
query = g_ptr_array_new();
308
if (priv->search_text) {
309
rhythmdb_query_append (db,
311
RHYTHMDB_QUERY_PROP_LIKE, RHYTHMDB_PROP_SEARCH_MATCH, priv->search_text,
444
query = construct_query_from_selection (source);
315
445
g_object_set (G_OBJECT (priv->filter_model), "query", query, NULL);
316
446
rhythmdb_query_free (query);
317
448
rhythmdb_query_model_reapply_query (priv->filter_model, TRUE);
318
rb_playlist_source_set_query_model (psource, priv->filter_model);
449
rb_library_browser_set_model (priv->browser, priv->filter_model, FALSE);
453
rb_static_playlist_source_browser_changed_cb (RBLibraryBrowser *browser,
455
RBStaticPlaylistSource *source)
457
RBEntryView *songs = rb_source_get_entry_view (RB_SOURCE (source));
458
RhythmDBQueryModel *query_model;
460
g_object_get (G_OBJECT (browser), "output-model", &query_model, NULL);
461
rb_entry_view_set_model (songs, query_model);
462
rb_playlist_source_set_query_model (RB_PLAYLIST_SOURCE (source), query_model);
463
g_object_unref (G_OBJECT (query_model));
465
rb_source_notify_filter_changed (RB_SOURCE (source));
323
469
impl_receive_drag (RBSource *asource, GtkSelectionData *data)
326
472
RBStaticPlaylistSource *source = RB_STATIC_PLAYLIST_SOURCE (asource);
328
474
if (data->type == gdk_atom_intern ("text/uri-list", TRUE)) {
329
list = gnome_vfs_uri_list_parse ((char *) data->data);
332
rb_static_playlist_source_add_list_uri (source, list);
475
list = rb_uri_list_parse ((char *)data->data);
477
rb_static_playlist_source_add_list_uri (source, list);
353
498
xmlNodePtr child_node = xmlNewChild (node, NULL, RB_PLAYLIST_LOCATION, NULL);
354
499
RhythmDBEntry *entry;
355
500
xmlChar *encoded;
501
const char *location;
357
503
gtk_tree_model_get (GTK_TREE_MODEL (priv->base_model), &iter, 0, &entry, -1);
359
encoded = xmlEncodeEntitiesReentrant (NULL, BAD_CAST entry->location);
505
location = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
506
encoded = xmlEncodeEntitiesReentrant (NULL, BAD_CAST location);
361
508
xmlNodeSetContent (child_node, encoded);
362
509
g_free (encoded);
370
517
GList *i, *uri_list = NULL;
371
518
RBPlaylistSource *psource = RB_PLAYLIST_SOURCE (source);
519
RhythmDBEntry *entry;
373
521
g_return_if_fail (list != NULL);
375
for (i = list; i != NULL; i = g_list_next (i))
376
uri_list = g_list_prepend (uri_list, gnome_vfs_uri_to_string ((const GnomeVFSURI *) i->data, 0));
523
for (i = list; i != NULL; i = g_list_next (i)) {
524
char *uri = (char *) i->data;
525
uri_list = g_list_prepend (uri_list, rb_canonicalise_uri (uri));
377
527
uri_list = g_list_reverse (uri_list);
379
gnome_vfs_uri_list_free (list);
529
rb_list_deep_free (list);
381
531
if (uri_list == NULL)
384
534
for (i = uri_list; i != NULL; i = i->next) {
385
535
char *uri = i->data;
386
536
if (uri != NULL) {
387
rhythmdb_add_uri (rb_playlist_source_get_db (psource), uri);
537
entry = rhythmdb_entry_lookup_by_location (rb_playlist_source_get_db (psource), uri);
539
rhythmdb_add_uri (rb_playlist_source_get_db (psource), uri);
388
541
rb_static_playlist_source_add_location (source, uri, -1);
411
564
RhythmDBEntryType entry_type;
413
566
g_object_get (G_OBJECT (source), "entry-type", &entry_type, NULL);
414
if (entry_type != -1 &&
415
rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TYPE) != entry_type) {
567
if (entry_type != RHYTHMDB_ENTRY_TYPE_INVALID &&
568
rhythmdb_entry_get_entry_type (entry) != entry_type) {
416
569
rb_debug ("attempting to add an entry of the wrong type to playlist");
496
649
RhythmDBEntry *entry,
499
rb_static_playlist_source_add_location_internal (source, entry->location, index);
652
const char *location;
654
location = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
655
rb_static_playlist_source_add_location_internal (source, location, index);
503
659
rb_static_playlist_source_remove_entry (RBStaticPlaylistSource *source,
504
660
RhythmDBEntry *entry)
506
rb_static_playlist_source_remove_location (source, entry->location);
662
const char *location;
664
location = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
665
rb_static_playlist_source_remove_location (source, location);
544
703
rb_static_playlist_source_add_entry (source, entry, -1);
707
impl_get_search_actions (RBSource *source)
709
GList *actions = NULL;
711
actions = g_list_prepend (actions, g_strdup ("StaticPlaylistSearchTitles"));
712
actions = g_list_prepend (actions, g_strdup ("StaticPlaylistSearchAlbums"));
713
actions = g_list_prepend (actions, g_strdup ("StaticPlaylistSearchArtists"));
714
actions = g_list_prepend (actions, g_strdup ("StaticPlaylistSearchAll"));
719
static RhythmDBPropType
720
search_action_to_prop (GtkAction *action)
723
RhythmDBPropType prop;
725
name = gtk_action_get_name (action);
728
prop = RHYTHMDB_PROP_SEARCH_MATCH;
729
} else if (strcmp (name, "StaticPlaylistSearchAll") == 0) {
730
prop = RHYTHMDB_PROP_SEARCH_MATCH;
731
} else if (strcmp (name, "StaticPlaylistSearchArtists") == 0) {
732
prop = RHYTHMDB_PROP_ARTIST_FOLDED;
733
} else if (strcmp (name, "StaticPlaylistSearchAlbums") == 0) {
734
prop = RHYTHMDB_PROP_ALBUM_FOLDED;
735
} else if (strcmp (name, "StaticPlaylistSearchTitles") == 0) {
736
prop = RHYTHMDB_PROP_TITLE_FOLDED;
738
prop = RHYTHMDB_PROP_SEARCH_MATCH;
745
search_action_changed (GtkRadioAction *action,
746
GtkRadioAction *current,
749
RBStaticPlaylistSource *source;
750
RBStaticPlaylistSourcePrivate *priv;
753
g_object_get (G_OBJECT (shell), "selected-source", &source, NULL);
754
priv = RB_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (source);
756
active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (current));
760
priv->search_prop = search_action_to_prop (GTK_ACTION (current));
761
rb_static_playlist_source_do_query (source);
762
rb_source_notify_filter_changed (RB_SOURCE (source));