Index: lib/rb-util.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/lib/rb-util.c,v
retrieving revision 1.18
diff -u -u -r1.18 rb-util.c
--- lib/rb-util.c	30 Nov 2005 04:54:31 -0000	1.18
+++ lib/rb-util.c	3 Jan 2006 03:16:15 -0000
@@ -567,3 +567,40 @@
 	return str;
 }
 
+gboolean
+string_list_equal (GList *a, GList *b)
+{
+	GList *sorted_a_keys;
+	GList *sorted_b_keys;
+	GList *a_ptr, *b_ptr;
+	gboolean ret = TRUE;
+
+	if (g_list_length (a) != g_list_length (b))
+		return FALSE;
+
+	for (sorted_a_keys = NULL; a; a = a->next) {
+		sorted_a_keys = g_list_prepend (sorted_a_keys,
+					       g_utf8_collate_key (a->data, -1));
+	}
+	for (sorted_b_keys = NULL; b; b = b->next) {
+		sorted_b_keys = g_list_prepend (sorted_b_keys,
+					       g_utf8_collate_key (b->data, -1));
+	}
+	sorted_a_keys = g_list_sort (sorted_a_keys, (GCompareFunc) strcmp);
+	sorted_b_keys = g_list_sort (sorted_b_keys, (GCompareFunc) strcmp);
+	
+	for (a_ptr = sorted_a_keys, b_ptr = sorted_b_keys;
+	     a_ptr && b_ptr; a_ptr = a_ptr->next, b_ptr = b_ptr->next) {
+		if (strcmp (a_ptr->data, b_ptr->data)) {
+			ret = FALSE;
+			break;
+		}
+	}
+	g_list_foreach (sorted_a_keys, (GFunc) g_free, NULL);
+	g_list_foreach (sorted_b_keys, (GFunc) g_free, NULL);
+	g_list_free (sorted_a_keys);
+	g_list_free (sorted_b_keys);
+	return ret;
+}
+
+
Index: lib/rb-util.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/lib/rb-util.h,v
retrieving revision 1.14
diff -u -u -r1.14 rb-util.h
--- lib/rb-util.h	30 Nov 2005 04:54:31 -0000	1.14
+++ lib/rb-util.h	3 Jan 2006 03:16:15 -0000
@@ -52,6 +52,8 @@
 gchar* rb_search_fold (const char *original);
 gchar** rb_string_split_words (const gchar *string);
 
+gboolean string_list_equal (GList *a, GList *b);
+
 G_END_DECLS
 
 #endif /* __RB_UTIL_H */
Index: rhythmdb/rhythmdb.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.c,v
retrieving revision 1.152
diff -u -u -r1.152 rhythmdb.c
--- rhythmdb/rhythmdb.c	19 Dec 2005 10:17:12 -0000	1.152
+++ rhythmdb/rhythmdb.c	3 Jan 2006 03:16:17 -0000
@@ -3733,6 +3733,38 @@
 	}
 }
 
+void
+rhythmdb_query_append_prop_multiple (RhythmDB *db, GPtrArray *query, guint propid, GList *items)
+{
+	GPtrArray *subquery;
+
+	if (items == NULL)
+		return;
+
+	subquery = g_ptr_array_new ();
+
+	rhythmdb_query_append (db,
+			       subquery,
+			       RHYTHMDB_QUERY_PROP_EQUALS,
+			       propid,
+			       items->data,
+			       RHYTHMDB_QUERY_END);
+	items = items->next;
+	while (items) {
+		rhythmdb_query_append (db,
+				       subquery,
+				       RHYTHMDB_QUERY_DISJUNCTION,
+				       RHYTHMDB_QUERY_PROP_EQUALS,
+				       propid,
+				       items->data,
+				       RHYTHMDB_QUERY_END);
+		items = items->next;
+	}
+	rhythmdb_query_append (db, query, RHYTHMDB_QUERY_SUBQUERY, subquery,
+			       RHYTHMDB_QUERY_END);
+}
+
+
 static gboolean
 rhythmdb_idle_save (RhythmDB *db)
 {
Index: rhythmdb/rhythmdb.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.h,v
retrieving revision 1.63
diff -u -u -r1.63 rhythmdb.h
--- rhythmdb/rhythmdb.h	27 Dec 2005 06:38:28 -0000	1.63
+++ rhythmdb/rhythmdb.h	3 Jan 2006 03:16:17 -0000
@@ -538,6 +538,7 @@
 void		rhythmdb_query_free			(GPtrArray *query);
 GPtrArray *	rhythmdb_query_copy			(GPtrArray *array);
 void		rhythmdb_query_preprocess		(GPtrArray *query);
+void		rhythmdb_query_append_prop_multiple	(RhythmDB *db, GPtrArray *query, guint propid, GList *items);
 
 void		rhythmdb_query_serialize		(RhythmDB *db, GPtrArray *query,
 							 xmlNodePtr node);
Index: shell/rb-source-header.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/shell/rb-source-header.c,v
retrieving revision 1.38
diff -u -u -r1.38 rb-source-header.c
--- shell/rb-source-header.c	12 Dec 2005 04:16:37 -0000	1.38
+++ shell/rb-source-header.c	3 Jan 2006 03:16:17 -0000
@@ -428,6 +428,7 @@
 				   header->priv->disclosed);
 	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (viewbrowser_action),
 				      header->priv->disclosed);
+	rb_source_browser_toggled (header->priv->selected_source, header->priv->disclosed);
 }
 
 static void
Index: sources/rb-auto-playlist-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-auto-playlist-source.c,v
retrieving revision 1.2
diff -u -u -r1.2 rb-auto-playlist-source.c
--- sources/rb-auto-playlist-source.c	11 Dec 2005 11:58:14 -0000	1.2
+++ sources/rb-auto-playlist-source.c	3 Jan 2006 03:16:18 -0000
@@ -27,19 +27,34 @@
 #include <string.h>
 
 #include "rb-auto-playlist-source.h"
+#include "rb-property-view.h"
 #include "rb-util.h"
 #include "rb-debug.h"
+#include "eel-gconf-extensions.h"
 #include "rb-stock-icons.h"
 #include "rb-playlist-xml.h"
 
+
+typedef enum
+{
+	RB_LIBRARY_QUERY_TYPE_ALL,
+	RB_LIBRARY_QUERY_TYPE_GENRE,
+	RB_LIBRARY_QUERY_TYPE_ARTIST,
+	RB_LIBRARY_QUERY_TYPE_ALBUM,
+	RB_LIBRARY_QUERY_TYPE_SEARCH,
+} RBLibraryQueryType;
+
 static GObject *rb_auto_playlist_source_constructor (GType type, guint n_construct_properties,
 						      GObjectConstructParam *construct_properties);
+static void rb_auto_playlist_source_finalize (GObject *object);
+
 /* source methods */
 static GdkPixbuf *impl_get_pixbuf (RBSource *source);
 static gboolean impl_show_popup (RBSource *source);
 static gboolean impl_receive_drag (RBSource *asource, GtkSelectionData *data);
 static void impl_search (RBSource *asource, const char *search_text);
 static void impl_reset_filters (RBSource *asource);
+static void impl_browser_toggled (RBSource *source, gboolean enabled);
 
 /* playlist methods */
 static void impl_save_contents_to_xml (RBPlaylistSource *source,
@@ -47,7 +62,32 @@
 
 static void rb_auto_playlist_source_songs_sort_order_changed_cb (RBEntryView *view, 
 								 RBAutoPlaylistSource *source); 
-static void rb_auto_playlist_source_do_query (RBAutoPlaylistSource *source);
+static void rb_auto_playlist_source_do_query (RBAutoPlaylistSource *source, RBLibraryQueryType qtype);
+
+/* browser stuff */
+static GList *impl_get_extra_views (RBSource *source);
+void rb_auto_playlist_source_browser_views_activated_cb (GtkWidget *widget,
+							 RBAutoPlaylistSource *source);
+static void update_browser_views_visibility (RBAutoPlaylistSource *source);
+static void rb_auto_playlist_source_browser_views_changed (GConfClient *client,
+							   guint cnxn_id,
+							   GConfEntry *entry,
+							   RBAutoPlaylistSource *source);
+#define CONF_UI_LIBRARY_BROWSER_VIEWS CONF_PREFIX "/ui/library/browser_views"
+
+static void rb_auto_playlist_source_handle_genre_selection (RBAutoPlaylistSource *libsource, GList *genres);
+static void rb_auto_playlist_source_handle_artist_selection (RBAutoPlaylistSource *libsource, GList *artists);
+static void rb_auto_playlist_source_handle_album_selection (RBAutoPlaylistSource *libsource, GList *albums);
+static void genres_selected_cb (RBPropertyView *propview, GList *genres,
+			       RBAutoPlaylistSource *libsource);
+static void genres_selection_reset_cb (RBPropertyView *propview, RBAutoPlaylistSource *libsource);
+static void artists_selected_cb (RBPropertyView *propview, GList *artists,
+			       RBAutoPlaylistSource *libsource);
+static void artists_selection_reset_cb (RBPropertyView *propview, RBAutoPlaylistSource *libsource);
+static void albums_selected_cb (RBPropertyView *propview, GList *albums,
+			       RBAutoPlaylistSource *libsource);
+static void albums_selection_reset_cb (RBPropertyView *propview, RBAutoPlaylistSource *libsource);
+
 
 #define AUTO_PLAYLIST_SOURCE_POPUP_PATH "/AutoPlaylistSourcePopup"
 
@@ -57,10 +97,31 @@
 {
 	GPtrArray *query;
 	gboolean query_resetting;
-	char *search_text;
 	guint limit_count;
 	guint limit_mb;
 	guint limit_time;
+
+	/* browsers */
+	guint browser_view_notify_id;
+
+	GtkWidget *browser;
+	GtkWidget *vbox;
+	GtkWidget *paned;
+
+	RBPropertyView *genres;
+	RBPropertyView *artists;
+	RBPropertyView *albums;
+	GSList *browser_views_group;
+
+	RhythmDBQueryModel *cached_all_query;
+	RhythmDBPropertyModel *cached_genres_model;
+	RhythmDBPropertyModel *cached_artists_model;
+	RhythmDBPropertyModel *cached_albums_model;
+
+	char *search_text;
+	GList *selected_genres;
+	GList *selected_artists;
+	GList *selected_albums;
 };
 
 G_DEFINE_TYPE (RBAutoPlaylistSource, rb_auto_playlist_source, RB_TYPE_PLAYLIST_SOURCE)
@@ -76,15 +137,19 @@
 	RBPlaylistSourceClass *playlist_class = RB_PLAYLIST_SOURCE_CLASS (klass);
 
 	object_class->constructor = rb_auto_playlist_source_constructor;
+	object_class->finalize = rb_auto_playlist_source_finalize;
 
 	source_class->impl_get_pixbuf = impl_get_pixbuf;
 	source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
 	source_class->impl_can_delete = (RBSourceFeatureFunc) rb_false_function;
 	source_class->impl_receive_drag = impl_receive_drag;
 	source_class->impl_show_popup = impl_show_popup;
+	source_class->impl_can_browse = (RBSourceFeatureFunc) rb_true_function;
+	source_class->impl_browser_toggled = impl_browser_toggled;
 	source_class->impl_can_search = (RBSourceFeatureFunc) rb_true_function;
 	source_class->impl_search = impl_search;
 	source_class->impl_reset_filters = impl_reset_filters;
+	source_class->impl_get_extra_views = impl_get_extra_views;
 
 	playlist_class->impl_save_contents_to_xml = impl_save_contents_to_xml;
 	
@@ -100,6 +165,7 @@
 static void
 rb_auto_playlist_source_init (RBAutoPlaylistSource *source)
 {
+
 }
 
 static GObject *
@@ -109,17 +175,94 @@
 	RBEntryView *songs;
 	RBAutoPlaylistSource *source;
 	GObjectClass *parent_class = G_OBJECT_CLASS (rb_auto_playlist_source_parent_class);
+	RBAutoPlaylistSourcePrivate *priv;
 
 	source = RB_AUTO_PLAYLIST_SOURCE (
 			parent_class->constructor (type, n_construct_properties, construct_properties));
+	priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
+
+	priv->vbox = gtk_vbox_new (FALSE, 5);
+	gtk_container_add (GTK_CONTAINER (source), priv->vbox);
+
+	priv->paned = gtk_vpaned_new ();
+	priv->browser = gtk_hbox_new (TRUE, 5);
+	gtk_paned_pack1 (GTK_PANED (priv->paned), GTK_WIDGET (priv->browser), TRUE, FALSE);
+
+	/* set up genres treeview */
+	priv->genres = rb_property_view_new (rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source)),
+					     RHYTHMDB_PROP_GENRE, _("Genre"));
+	rb_property_view_set_selection_mode (priv->genres, GTK_SELECTION_MULTIPLE);
+	g_signal_connect_object (G_OBJECT (priv->genres),
+				 "properties-selected",
+				 G_CALLBACK (genres_selected_cb),
+				 source, 0);
+	g_signal_connect_object (G_OBJECT (priv->genres),
+				 "property-selection-reset", G_CALLBACK (genres_selection_reset_cb),
+				 source, 0);
+
+	gtk_box_pack_start_defaults (GTK_BOX (priv->browser), GTK_WIDGET (priv->genres));
+
+	/* set up artist treeview */
+	priv->artists = rb_property_view_new (rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source)),
+					      RHYTHMDB_PROP_ARTIST, _("Artist"));
+	rb_property_view_set_selection_mode (priv->artists, GTK_SELECTION_MULTIPLE);
+	g_signal_connect_object (G_OBJECT (priv->artists),
+				 "properties-selected",
+				 G_CALLBACK (artists_selected_cb),
+				 source, 0);
+	g_signal_connect_object (G_OBJECT (priv->artists),
+				 "property-selection-reset", G_CALLBACK (artists_selection_reset_cb),
+				 source, 0);
+
+	gtk_box_pack_start_defaults (GTK_BOX (priv->browser), GTK_WIDGET (priv->artists));
+
+	/* set up albums treeview */
+	priv->albums = rb_property_view_new (rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source)),
+					     RHYTHMDB_PROP_ALBUM, _("Album"));
+	rb_property_view_set_selection_mode (priv->albums, GTK_SELECTION_MULTIPLE);
+	g_signal_connect_object (G_OBJECT (priv->albums),
+				 "properties-selected",
+				 G_CALLBACK (albums_selected_cb),
+				 source, 0);
+	g_signal_connect_object (G_OBJECT (priv->albums),
+				 "property-selection-reset", G_CALLBACK (albums_selection_reset_cb),
+				 source, 0);
+
+	gtk_box_pack_start_defaults (GTK_BOX (priv->browser), GTK_WIDGET (priv->albums));
+
 
 	songs = rb_source_get_entry_view (RB_SOURCE (source));
 	g_signal_connect_object (G_OBJECT (songs), "sort-order-changed",
 				 G_CALLBACK (rb_auto_playlist_source_songs_sort_order_changed_cb), source, 0);
+
+	/* reparent the entry view */
+	g_object_ref (G_OBJECT (songs));
+	gtk_container_remove (GTK_CONTAINER (source), GTK_WIDGET (songs));
+	gtk_paned_pack2 (GTK_PANED (priv->paned), GTK_WIDGET (songs), TRUE, FALSE);
+	gtk_box_pack_start_defaults (GTK_BOX (priv->vbox), priv->paned);
 	
+	gtk_widget_show_all (GTK_WIDGET (source));
+	update_browser_views_visibility (source);
+	priv->browser_view_notify_id =
+		eel_gconf_notification_add (CONF_UI_LIBRARY_BROWSER_VIEWS,
+				    (GConfClientNotifyFunc) rb_auto_playlist_source_browser_views_changed, source);
+
 	return G_OBJECT (source);
 }
 
+static void
+rb_auto_playlist_source_finalize (GObject *object)
+{
+	RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (object);
+
+	eel_gconf_notification_remove (priv->browser_view_notify_id);
+
+	if (priv->cached_all_query)
+		g_object_unref (G_OBJECT (priv->cached_all_query));
+
+	G_OBJECT_CLASS (rb_auto_playlist_source_parent_class)->finalize (object);
+}
+
 RBSource *
 rb_auto_playlist_source_new (RBShell *shell, const char *name, gboolean local)
 {
@@ -195,6 +338,157 @@
 	return RB_SOURCE (source);
 }
 
+static void
+update_browser_views_visibility (RBAutoPlaylistSource *source)
+{
+	RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
+	GtkWidget *genres = GTK_WIDGET (priv->genres);
+	GtkWidget *artists = GTK_WIDGET (priv->artists);
+	GtkWidget *albums = GTK_WIDGET (priv->albums);
+	int views = eel_gconf_get_integer (CONF_UI_LIBRARY_BROWSER_VIEWS);
+
+	switch (views)
+	{
+	case 0:
+		gtk_widget_hide (genres);
+		gtk_widget_show (artists);
+		gtk_widget_show (albums);
+		rb_auto_playlist_source_handle_genre_selection (source, NULL);
+		/* Since this is hidden now, reset the query */
+		break;
+	case 1:
+		gtk_widget_show (genres);
+		gtk_widget_show (artists);
+		gtk_widget_hide (albums);
+		rb_auto_playlist_source_handle_album_selection (source, NULL);
+		break;
+	case 2:
+		/* All are shown */
+		gtk_widget_show (genres);
+		gtk_widget_show (artists);
+		gtk_widget_show (albums);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+rb_auto_playlist_source_browser_views_changed (GConfClient *client,
+					       guint cnxn_id,
+					       GConfEntry *entry,
+					       RBAutoPlaylistSource *source)
+{
+	update_browser_views_visibility (source);
+}
+
+static void
+rb_auto_playlist_source_handle_genre_selection (RBAutoPlaylistSource *source, GList *genres)
+{
+	RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
+
+	if (string_list_equal (priv->selected_genres, genres))
+		return;
+	g_list_foreach (priv->selected_genres, (GFunc) g_free, NULL);
+	g_list_free (priv->selected_genres);
+	priv->selected_genres = genres;
+	rb_auto_playlist_source_do_query (source, RB_LIBRARY_QUERY_TYPE_GENRE);
+
+	rb_source_notify_filter_changed (RB_SOURCE (source));
+}
+
+static void
+genres_selected_cb (RBPropertyView *propview, GList *genres,
+		   RBAutoPlaylistSource *source)
+{
+	rb_debug ("genre selected"); 
+	rb_auto_playlist_source_handle_genre_selection (source, genres);
+}
+
+static void
+genres_selection_reset_cb (RBPropertyView *propview, RBAutoPlaylistSource *source)
+{
+	RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
+
+	rb_debug ("genre selection reset"); 
+	g_list_foreach (priv->selected_genres, (GFunc) g_free, NULL);
+	g_list_free (priv->selected_genres);
+	priv->selected_genres = NULL;
+	rb_auto_playlist_source_do_query (source, RB_LIBRARY_QUERY_TYPE_GENRE);
+}
+
+static void
+rb_auto_playlist_source_handle_artist_selection (RBAutoPlaylistSource *source, GList *artists)
+{
+	RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
+
+	if (string_list_equal (priv->selected_artists, artists))
+		return;
+	g_list_foreach (priv->selected_artists, (GFunc) g_free, NULL);
+	g_list_free (priv->selected_artists);
+	priv->selected_artists = artists;
+	rb_auto_playlist_source_do_query (source, RB_LIBRARY_QUERY_TYPE_ARTIST);
+
+	rb_source_notify_filter_changed (RB_SOURCE (source));
+}
+
+static void
+artists_selected_cb (RBPropertyView *propview, GList *artists,
+		   RBAutoPlaylistSource *source)
+{
+	rb_debug ("artist selected"); 
+	rb_auto_playlist_source_handle_artist_selection (source, artists);
+}
+
+static void
+artists_selection_reset_cb (RBPropertyView *propview, RBAutoPlaylistSource *source)
+{
+	RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
+
+	rb_debug ("artist selection reset"); 
+	g_list_foreach (priv->selected_artists, (GFunc) g_free, NULL);
+	g_list_free (priv->selected_artists);
+	priv->selected_artists = NULL;
+	rb_auto_playlist_source_do_query (source, RB_LIBRARY_QUERY_TYPE_ARTIST);
+}
+
+static void
+rb_auto_playlist_source_handle_album_selection (RBAutoPlaylistSource *source, GList *albums)
+{
+	RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
+
+	if (string_list_equal (priv->selected_albums, albums))
+		return;
+	g_list_foreach (priv->selected_albums, (GFunc) g_free, NULL);
+	g_list_free (priv->selected_albums);
+	priv->selected_albums = albums;
+	rb_auto_playlist_source_do_query (source, RB_LIBRARY_QUERY_TYPE_ALBUM);
+
+	rb_source_notify_filter_changed (RB_SOURCE (source));
+}
+
+static void
+albums_selected_cb (RBPropertyView *propview, GList *albums,
+		   RBAutoPlaylistSource *source)
+{
+	rb_debug ("album selected"); 
+	rb_auto_playlist_source_handle_album_selection (source, albums);
+}
+
+static void
+albums_selection_reset_cb (RBPropertyView *propview, RBAutoPlaylistSource *source)
+{
+	RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
+
+	rb_debug ("album selection reset"); 
+	g_list_foreach (priv->selected_albums, (GFunc) g_free, NULL);
+	g_list_free (priv->selected_albums);
+	priv->selected_albums = NULL;
+	rb_auto_playlist_source_do_query (source, RB_LIBRARY_QUERY_TYPE_ALBUM);
+}
+
+
+
 static GdkPixbuf *
 impl_get_pixbuf (RBSource *asource)
 {
@@ -214,6 +508,24 @@
 {
 	RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
 	gboolean changed = FALSE;
+	
+	if (priv->selected_genres != NULL)
+		changed = TRUE;
+	g_list_foreach (priv->selected_genres, (GFunc) g_free, NULL);
+	g_list_free (priv->selected_genres);
+	priv->selected_genres = NULL;
+
+	if (priv->selected_artists != NULL)
+		changed = TRUE;
+	g_list_foreach (priv->selected_artists, (GFunc) g_free, NULL);
+	g_list_free (priv->selected_artists);
+	priv->selected_artists = NULL;
+
+	if (priv->selected_albums != NULL)
+		changed = TRUE;
+	g_list_foreach (priv->selected_albums, (GFunc) g_free, NULL);
+	g_list_free (priv->selected_albums);
+	priv->selected_albums = NULL;
 
 	if (priv->search_text != NULL) {
 		changed = TRUE;
@@ -222,7 +534,7 @@
 	}
 
 	if (changed) {
-		rb_auto_playlist_source_do_query (RB_AUTO_PLAYLIST_SOURCE (source));
+		rb_auto_playlist_source_do_query (RB_AUTO_PLAYLIST_SOURCE (source), RB_LIBRARY_QUERY_TYPE_ALL);
 		rb_source_notify_filter_changed (source);
 	}
 }
@@ -245,11 +557,23 @@
 
 	g_free (priv->search_text);
 	priv->search_text = g_strdup (search_text);
-	rb_auto_playlist_source_do_query (RB_AUTO_PLAYLIST_SOURCE (source));
+	rb_auto_playlist_source_do_query (RB_AUTO_PLAYLIST_SOURCE (source), RB_LIBRARY_QUERY_TYPE_SEARCH);
 
 	rb_source_notify_filter_changed (source);
 }
 
+static GList *
+impl_get_extra_views (RBSource *source)
+{
+	RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
+	GList *ret;
+
+	ret = g_list_prepend (NULL, priv->albums);
+	ret = g_list_prepend (ret, priv->artists);
+	ret = g_list_prepend (ret, priv->genres);
+	return ret;
+}
+
 static RhythmDBPropType
 rb_auto_playlist_source_drag_atom_to_prop (GdkAtom smasher)
 {
@@ -265,6 +589,17 @@
 	}
 }
 
+static void
+impl_browser_toggled (RBSource *source, gboolean enabled)
+{
+	RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
+
+	if (enabled)
+		gtk_widget_show (priv->browser);
+	else
+		gtk_widget_hide (priv->browser);
+}
+
 static gboolean
 impl_receive_drag (RBSource *asource, GtkSelectionData *data)
 {
@@ -362,35 +697,202 @@
 	rhythmdb_query_serialize (rb_playlist_source_get_db (psource), query, node);
 }
 
-static void
-rb_auto_playlist_source_do_query (RBAutoPlaylistSource *source)
+static GPtrArray *
+construct_query_from_selection (RBAutoPlaylistSource *source)
 {
 	RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
 	RhythmDB *db = rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source));
-	RhythmDBQueryModel *model;
-
-	model = g_object_new (RHYTHMDB_TYPE_QUERY_MODEL,
-			      "db", db,
-			      "max-count", priv->limit_count,
-			      "max-size", priv->limit_mb, 
-			      "max-time", priv->limit_time, 
-			      NULL);
+	GPtrArray *query = rhythmdb_query_copy (priv->query);
 
 	if (priv->search_text) {
-		GPtrArray *query = rhythmdb_query_copy (priv->query);
-
+		GPtrArray *subquery = rhythmdb_query_parse (db,
+							    RHYTHMDB_QUERY_PROP_LIKE,
+							    RHYTHMDB_PROP_SEARCH_MATCH,
+							    priv->search_text,
+							    RHYTHMDB_QUERY_END);
 		rhythmdb_query_append (db,
 				       query,
-				       RHYTHMDB_QUERY_PROP_LIKE,
-				       RHYTHMDB_PROP_SEARCH_MATCH,
-				       priv->search_text,
+				       RHYTHMDB_QUERY_SUBQUERY,
+				       subquery,
 				       RHYTHMDB_QUERY_END);
-		rhythmdb_do_full_query_async_parsed (db, GTK_TREE_MODEL (model), query);
-		rhythmdb_query_free (query);
+		/* select where type="song" and
+		 *  (genre like "foo" or artist like "foo" or album like "foo")
+		 */
+	}
+
+	if (priv->selected_genres) {
+		if (priv->selected_genres->next == NULL)
+			rhythmdb_query_append (db,
+					       query,
+					       RHYTHMDB_QUERY_PROP_EQUALS,
+					       RHYTHMDB_PROP_GENRE,
+					       priv->selected_genres->data,
+					       RHYTHMDB_QUERY_END);
+		else 
+			rhythmdb_query_append_prop_multiple (db,
+							     query,
+							     RHYTHMDB_PROP_GENRE,
+							     priv->selected_genres);
+	}
+
+	if (priv->selected_artists) {
+		if (priv->selected_artists->next == NULL)
+			rhythmdb_query_append (db,
+					       query,
+					       RHYTHMDB_QUERY_PROP_EQUALS,
+					       RHYTHMDB_PROP_ARTIST,
+					       priv->selected_artists->data,
+					       RHYTHMDB_QUERY_END);
+		else 
+			rhythmdb_query_append_prop_multiple (db,
+							     query,
+							     RHYTHMDB_PROP_ARTIST,
+							     priv->selected_artists);
+	}
+
+	if (priv->selected_albums) {
+		if (priv->selected_albums->next == NULL)
+			rhythmdb_query_append (db,
+					       query,
+					       RHYTHMDB_QUERY_PROP_EQUALS,
+					       RHYTHMDB_PROP_ALBUM,
+					       priv->selected_albums->data,
+					       RHYTHMDB_QUERY_END);
+		else 
+			rhythmdb_query_append_prop_multiple (db,
+							     query,
+							     RHYTHMDB_PROP_ALBUM,
+							     priv->selected_albums);
+	}
+	return query;
+}
+
+static void
+rb_auto_playlist_source_do_query (RBAutoPlaylistSource *source, RBLibraryQueryType qtype)
+{
+	RBAutoPlaylistSourcePrivate *priv = RB_AUTO_PLAYLIST_SOURCE_GET_PRIVATE (source);
+	RhythmDB *db = rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source));
+	RhythmDBQueryModel *query_model;
+	RhythmDBPropertyModel *genre_model = NULL;
+	RhythmDBPropertyModel *artist_model = NULL;
+	RhythmDBPropertyModel *album_model = NULL;
+	GPtrArray *query;
+	gboolean is_all_query;
+	gboolean do_new_query = TRUE;
+
+	is_all_query = (priv->selected_genres == NULL &&
+			priv->selected_artists == NULL &&	    
+			priv->selected_albums == NULL &&	    
+			priv->search_text == NULL);
+
+	if ((priv->cached_all_query == NULL) || is_all_query ) {
+		if (priv->cached_all_query == NULL) {
+			rb_debug ("caching new query");
+			query_model = priv->cached_all_query =
+				g_object_new (RHYTHMDB_TYPE_QUERY_MODEL,
+					      "db", db,
+					      "max-count", priv->limit_count,
+					      "max-size", priv->limit_mb,
+					      "max-time", priv->limit_time,
+					      NULL);
+			priv->cached_genres_model = rhythmdb_property_model_new (db, RHYTHMDB_PROP_GENRE);
+			priv->cached_artists_model = rhythmdb_property_model_new (db, RHYTHMDB_PROP_ARTIST);
+			priv->cached_albums_model = rhythmdb_property_model_new (db, RHYTHMDB_PROP_ALBUM);
+		} else {
+			rb_debug ("using cached query");
+			query_model = priv->cached_all_query;
+			do_new_query = FALSE;
+		}
+		
+		g_object_set (G_OBJECT (priv->cached_genres_model),
+			      "query-model", priv->cached_all_query, NULL);
+		g_object_set (G_OBJECT (priv->cached_artists_model),
+			      "query-model", priv->cached_all_query, NULL);
+		g_object_set (G_OBJECT (priv->cached_albums_model),
+			      "query-model", priv->cached_all_query, NULL);
+		rb_property_view_set_model (priv->genres,
+					    priv->cached_genres_model);
+		rb_property_view_set_model (priv->artists,
+					    priv->cached_artists_model);
+		rb_property_view_set_model (priv->albums,
+					    priv->cached_albums_model);
 	} else {
-		rhythmdb_do_full_query_async_parsed (db, GTK_TREE_MODEL (model), priv->query);
+		rb_debug ("query is not special");
+		query_model = g_object_new (RHYTHMDB_TYPE_QUERY_MODEL,
+					    "db", db,
+					    "max-count", priv->limit_count,
+					    "max-size", priv->limit_mb,
+					    "max-time", priv->limit_time, 
+					    NULL);
+
+		if (priv->selected_genres == NULL) {
+			rb_property_view_set_model (priv->genres,
+						    priv->cached_genres_model);
+			if (priv->selected_artists == NULL) {
+				rb_property_view_set_model (priv->artists,
+							    priv->cached_artists_model);
+				if (priv->selected_albums == NULL)
+					rb_property_view_set_model (priv->albums,
+								    priv->cached_albums_model);
+			}
+		}
+		switch (qtype) {
+		case RB_LIBRARY_QUERY_TYPE_ALL:
+			rb_debug ("resetting genres view");
+			g_list_foreach (priv->selected_genres,
+					(GFunc) g_free, NULL);
+			g_list_free (priv->selected_genres);
+			priv->selected_genres = NULL;
+
+			rb_property_view_reset (priv->genres);
+			genre_model = rb_property_view_get_model (priv->genres);
+			g_object_set (G_OBJECT (genre_model), "query-model",
+				      query_model, NULL);
+			g_object_unref (G_OBJECT (genre_model));
+		case RB_LIBRARY_QUERY_TYPE_GENRE:
+			rb_debug ("resetting artist view");
+			g_list_foreach (priv->selected_artists,
+					(GFunc) g_free, NULL);
+			g_list_free (priv->selected_artists);
+			priv->selected_artists = NULL;
+
+			rb_property_view_reset (priv->artists);
+			artist_model = rb_property_view_get_model (priv->artists);
+			g_object_set (G_OBJECT (artist_model), "query-model",
+				      query_model, NULL);
+			g_object_unref (G_OBJECT (artist_model));
+		case RB_LIBRARY_QUERY_TYPE_ARTIST:
+			rb_debug ("resetting album view");
+			g_list_foreach (priv->selected_albums,
+					(GFunc) g_free, NULL);
+			g_list_free (priv->selected_albums);
+			priv->selected_albums = NULL;
+
+			rb_property_view_reset (priv->albums);
+			album_model = rb_property_view_get_model (priv->albums);
+			g_object_set (G_OBJECT (album_model), "query-model",
+				      query_model, NULL);
+			g_object_unref (G_OBJECT (album_model));
+		case RB_LIBRARY_QUERY_TYPE_ALBUM:
+		case RB_LIBRARY_QUERY_TYPE_SEARCH:
+			break;
+		}
 	}
-	rb_playlist_source_set_query_model (RB_PLAYLIST_SOURCE (source), model);
+
+	rb_debug ("setting query model");
+	rb_playlist_source_set_query_model (RB_PLAYLIST_SOURCE (source), query_model);
+
+	if (do_new_query) {
+		query = construct_query_from_selection (source);
+		
+		rb_debug ("doing query");
+		rhythmdb_do_full_query_async_parsed (db, GTK_TREE_MODEL (query_model), query);
+		rhythmdb_query_free (query);
+	}
+	
+	if (!is_all_query)
+		g_object_unref (G_OBJECT (query_model));
+	
 }
 
 void
@@ -417,7 +919,7 @@
 	priv->limit_count = limit_count;
 	priv->limit_mb = limit_mb;
 	priv->limit_time = limit_time;
-	rb_auto_playlist_source_do_query (source);
+	rb_auto_playlist_source_do_query (source, RB_LIBRARY_QUERY_TYPE_ALL);
 
 	priv->query_resetting = FALSE;
 }
Index: sources/rb-library-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-library-source.c,v
retrieving revision 1.140
diff -u -u -r1.140 rb-library-source.c
--- sources/rb-library-source.c	18 Dec 2005 21:13:02 -0000	1.140
+++ sources/rb-library-source.c	3 Jan 2006 03:16:19 -0000
@@ -753,82 +753,12 @@
 	return source;
 }
 
-static gboolean
-string_list_equal (GList *a, GList *b)
-{
-	GList *sorted_a_keys;
-	GList *sorted_b_keys;
-	GList *a_ptr, *b_ptr;
-	gboolean ret = TRUE;
-
-	if (g_list_length (a) != g_list_length (b))
-		return FALSE;
-
-	for (sorted_a_keys = NULL; a; a = a->next) {
-		sorted_a_keys = g_list_prepend (sorted_a_keys,
-					       g_utf8_collate_key (a->data, -1));
-	}
-	for (sorted_b_keys = NULL; b; b = b->next) {
-		sorted_b_keys = g_list_prepend (sorted_b_keys,
-					       g_utf8_collate_key (b->data, -1));
-	}
-	sorted_a_keys = g_list_sort (sorted_a_keys, (GCompareFunc) strcmp);
-	sorted_b_keys = g_list_sort (sorted_b_keys, (GCompareFunc) strcmp);
-	
-	for (a_ptr = sorted_a_keys, b_ptr = sorted_b_keys;
-	     a_ptr && b_ptr; a_ptr = a_ptr->next, b_ptr = b_ptr->next) {
-		if (strcmp (a_ptr->data, b_ptr->data)) {
-			ret = FALSE;
-			break;
-		}
-	}
-	g_list_foreach (sorted_a_keys, (GFunc) g_free, NULL);
-	g_list_foreach (sorted_b_keys, (GFunc) g_free, NULL);
-	g_list_free (sorted_a_keys);
-	g_list_free (sorted_b_keys);
-	return ret;
-}
-
-
-
-static void
-rb_library_source_gather_hash_keys (char *key, gpointer unused,
-				    GList **data)
-{
-	*data = g_list_prepend (*data, key);
-}
-
 static void
 rb_library_source_free_list_data (gpointer *data, gpointer unused)
 {
 	g_free (data);
 }
 
-static GList *
-rb_library_source_gather_properties (RBLibrarySource *source,
-				     RhythmDBPropType prop)
-{
-	GList *selected, *tem;
-	GHashTable *selected_set;
-
-	selected_set = g_hash_table_new (g_str_hash, g_str_equal);
-	selected = rb_entry_view_get_selected_entries (source->priv->songs);
-	for (tem = selected; tem; tem = tem->next) {
-		RhythmDBEntry *entry = tem->data;
-		char *val = g_strdup (rhythmdb_entry_get_string (entry, prop));
-		g_hash_table_insert (selected_set, val, NULL);
-	}
-
-
-	g_list_free (selected);
-	
-	tem = NULL;
-	g_hash_table_foreach (selected_set, (GHFunc) rb_library_source_gather_hash_keys,
-			      &tem);
-	g_hash_table_destroy (selected_set);
-	return tem;
-}
-
 static void
 rb_library_source_cmd_choose_genre (GtkAction *action,
 				    RBShell *shell)
@@ -839,7 +769,7 @@
 	rb_debug ("choosing genre");
 
 	g_object_get (G_OBJECT (shell), "selected-source", &source, NULL);
-	props = rb_library_source_gather_properties (source, RHYTHMDB_PROP_GENRE);
+	props = rb_source_gather_selected_properties (RB_SOURCE (source), RHYTHMDB_PROP_GENRE);
 	rb_property_view_set_selection (source->priv->genres, props);
 	g_list_foreach (props, (GFunc) rb_library_source_free_list_data, NULL);
 	g_list_free (props);
@@ -856,7 +786,7 @@
 	rb_debug ("choosing artist");
 
 	g_object_get (G_OBJECT (shell), "selected-source", &source, NULL);
-	props = rb_library_source_gather_properties (source, RHYTHMDB_PROP_ARTIST);
+	props = rb_source_gather_selected_properties (RB_SOURCE (source), RHYTHMDB_PROP_ARTIST);
 	rb_property_view_set_selection (source->priv->artists, props);
 	g_list_foreach (props, (GFunc) rb_library_source_free_list_data, NULL);
 	g_list_free (props);
@@ -873,7 +803,7 @@
 	rb_debug ("choosing album");
 
 	g_object_get (G_OBJECT (shell), "selected-source", &source, NULL);
-	props = rb_library_source_gather_properties (source, RHYTHMDB_PROP_ALBUM);
+	props = rb_source_gather_selected_properties (RB_SOURCE (source), RHYTHMDB_PROP_ALBUM);
 	rb_property_view_set_selection (source->priv->albums, props);
 	g_list_foreach (props, (GFunc) rb_library_source_free_list_data, NULL);
 	g_list_free (props);
@@ -940,7 +870,7 @@
 	g_list_foreach (libsource->priv->selected_artists, (GFunc) g_free, NULL);
 	g_list_free (libsource->priv->selected_artists);
 	libsource->priv->selected_artists = NULL;
-	rb_library_source_do_query (libsource, RB_LIBRARY_QUERY_TYPE_ALBUM);
+	rb_library_source_do_query (libsource, RB_LIBRARY_QUERY_TYPE_ARTIST);
 }
 
 static void
@@ -1405,38 +1335,6 @@
 	return klass->impl_has_drop_support (source);
 }
 
-
-static void
-push_multi_equals_query (RhythmDB *db, GPtrArray *query, guint propid, GList *items)
-{
-	GPtrArray *subquery = g_ptr_array_new ();
-
-	if (!items) {
-		g_ptr_array_free (subquery, TRUE);
-		return;
-	}
-
-	rhythmdb_query_append (db,
-			       subquery,
-			       RHYTHMDB_QUERY_PROP_EQUALS,
-			       propid,
-			       items->data,
-			       RHYTHMDB_QUERY_END);
-	items = items->next;
-	while (items) {
-		rhythmdb_query_append (db,
-				       subquery,
-				       RHYTHMDB_QUERY_DISJUNCTION,
-				       RHYTHMDB_QUERY_PROP_EQUALS,
-				       propid,
-				       items->data,
-				       RHYTHMDB_QUERY_END);
-		items = items->next;
-	}
-	rhythmdb_query_append (db, query, RHYTHMDB_QUERY_SUBQUERY, subquery,
-			       RHYTHMDB_QUERY_END);
-}
-
 static GPtrArray *
 construct_query_from_selection (RBLibrarySource *source)
 {
@@ -1478,10 +1376,10 @@
 					       source->priv->selected_genres->data,
 					       RHYTHMDB_QUERY_END);
 		else 
-			push_multi_equals_query (source->priv->db,
-						 query,
-						 RHYTHMDB_PROP_GENRE,
-						 source->priv->selected_genres);
+			rhythmdb_query_append_prop_multiple (source->priv->db,
+							     query,
+							     RHYTHMDB_PROP_GENRE,
+							     source->priv->selected_genres);
 	}
 
 	if (source->priv->selected_artists) {
@@ -1493,10 +1391,10 @@
 					       source->priv->selected_artists->data,
 					       RHYTHMDB_QUERY_END);
 		else 
-			push_multi_equals_query (source->priv->db,
-						 query,
-						 RHYTHMDB_PROP_ARTIST,
-						 source->priv->selected_artists);
+			rhythmdb_query_append_prop_multiple (source->priv->db,
+							     query,
+							     RHYTHMDB_PROP_ARTIST,
+							     source->priv->selected_artists);
 	}
 
 	if (source->priv->selected_albums) {
@@ -1508,10 +1406,10 @@
 					       source->priv->selected_albums->data,
 					       RHYTHMDB_QUERY_END);
 		else 
-			push_multi_equals_query (source->priv->db,
-						 query,
-						 RHYTHMDB_PROP_ALBUM,
-						 source->priv->selected_albums);
+			rhythmdb_query_append_prop_multiple (source->priv->db,
+							     query,
+							     RHYTHMDB_PROP_ALBUM,
+							     source->priv->selected_albums);
 	}
 	return query;
 }
Index: sources/rb-playlist-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-playlist-source.c,v
retrieving revision 1.95
diff -u -u -r1.95 rb-playlist-source.c
--- sources/rb-playlist-source.c	10 Dec 2005 12:08:25 -0000	1.95
+++ sources/rb-playlist-source.c	3 Jan 2006 03:16:19 -0000
@@ -105,8 +105,6 @@
 	RhythmDBEntryType entry_type;
 	RhythmDBQueryModel *model;
 
-	GtkWidget *vbox;
-
 	RBEntryView *songs;
 
 	gboolean dirty;
@@ -218,10 +216,6 @@
 	shell_player = rb_shell_get_player (shell);
 	g_object_unref (G_OBJECT (shell));
 
-	source->priv->vbox = gtk_vbox_new (FALSE, 5);
-
-	gtk_container_add (GTK_CONTAINER (source), source->priv->vbox);
-
 	source->priv->entries = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
 	g_signal_connect_object (G_OBJECT (source->priv->db), "entry_added",
@@ -274,7 +268,7 @@
 
 	rb_playlist_source_setup_entry_view (source, source->priv->songs);
 
-	gtk_box_pack_start_defaults (GTK_BOX (source->priv->vbox), GTK_WIDGET (source->priv->songs));
+	gtk_container_add (GTK_CONTAINER (source), GTK_WIDGET (source->priv->songs));
 		
 	gtk_widget_show_all (GTK_WIDGET (source));
 
Index: sources/rb-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-source.c,v
retrieving revision 1.51
diff -u -u -r1.51 rb-source.c
--- sources/rb-source.c	12 Dec 2005 04:16:37 -0000	1.51
+++ sources/rb-source.c	3 Jan 2006 03:16:20 -0000
@@ -116,6 +116,7 @@
 
 	klass->impl_can_browse = (RBSourceFeatureFunc) rb_false_function;
 	klass->impl_get_browser_key = default_get_browser_key;
+	klass->impl_browser_toggled = NULL;
 	klass->impl_get_extra_views = default_get_extra_views;
 	klass->impl_can_rename = default_can_rename;
 	klass->impl_can_search = default_can_search;
@@ -406,6 +407,15 @@
 }
 
 void
+rb_source_browser_toggled (RBSource *source, gboolean enabled)
+{
+	RBSourceClass *klass = RB_SOURCE_GET_CLASS (source);
+
+	if (klass->impl_browser_toggled != NULL)
+		klass->impl_browser_toggled (source, enabled);
+}
+
+void
 rb_source_notify_status_changed (RBSource *source)
 {
 	g_signal_emit (G_OBJECT (source), rb_source_signals[STATUS_CHANGED], 0);
@@ -836,6 +846,36 @@
 		priv->idle_status_changed_id = 
 			g_idle_add ((GSourceFunc) idle_emit_status_changed, source);
 	}
+}
+
+static void
+rb_source_gather_hash_keys (char *key, gpointer unused, GList **data)
+{
+	*data = g_list_prepend (*data, key);
+}
+
+GList *
+rb_source_gather_selected_properties (RBSource *source,
+				      RhythmDBPropType prop)
+{
+	GList *selected, *tem;
+	GHashTable *selected_set;
+
+	selected_set = g_hash_table_new (g_str_hash, g_str_equal);
+	selected = rb_entry_view_get_selected_entries (rb_source_get_entry_view (RB_SOURCE (source)));
+	for (tem = selected; tem; tem = tem->next) {
+		RhythmDBEntry *entry = tem->data;
+		char *val = g_strdup (rhythmdb_entry_get_string (entry, prop));
+		g_hash_table_insert (selected_set, val, NULL);
+	}
+
+	g_list_free (selected);
+	
+	tem = NULL;
+	g_hash_table_foreach (selected_set, (GHFunc) rb_source_gather_hash_keys,
+			      &tem);
+	g_hash_table_destroy (selected_set);
+	return tem;
 }
 
 
Index: sources/rb-source.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-source.h,v
retrieving revision 1.32
diff -u -u -r1.32 rb-source.h
--- sources/rb-source.h	12 Dec 2005 04:16:37 -0000	1.32
+++ sources/rb-source.h	3 Jan 2006 03:16:20 -0000
@@ -74,6 +74,7 @@
 
 	gboolean	(*impl_can_browse)	(RBSource *source);
 	const char *	(*impl_get_browser_key)	(RBSource *source);
+	void		(*impl_browser_toggled)	(RBSource *source, gboolean enabled);
 
 	RBEntryView *	(*impl_get_entry_view)	(RBSource *source);
 	GList *		(*impl_get_extra_views)	(RBSource *source);
@@ -131,6 +132,7 @@
 
 gboolean	rb_source_can_browse		(RBSource *source);
 const char *	rb_source_get_browser_key	(RBSource *source);
+void		rb_source_browser_toggled	(RBSource *source, gboolean enabled);
 
 RBEntryView *	rb_source_get_entry_view	(RBSource *source);
 
@@ -140,7 +142,6 @@
 gboolean	rb_source_can_rename		(RBSource *source);
 
 gboolean	rb_source_can_search		(RBSource *source);
-
 void		rb_source_search		(RBSource *source,
 						 const char *text);
 
@@ -179,6 +180,8 @@
 void		rb_source_activate		(RBSource *source);
 void		rb_source_deactivate		(RBSource *source);
 gboolean	rb_source_disconnect		(RBSource *source);
+
+GList *		rb_source_gather_selected_properties (RBSource *source, RhythmDBPropType prop);
 
 /* Protected method, should only be used by objects inheriting from RBSource */
 void            _rb_source_show_popup           (RBSource *source, 
