Index: sources/rb-library-child-source.c
===================================================================
--- sources/rb-library-child-source.c	(Revision 0)
+++ sources/rb-library-child-source.c	(Revision 0)
@@ -0,0 +1,392 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Copyright (C) 2008 Christian Becke <christianbecke@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grants permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <gconf/gconf.h>
+
+#include "rhythmdb.h"
+#include "rb-debug.h"
+#include "rb-preferences.h"
+#include "rb-browser-source.h"
+#include "rb-library-child-source.h"
+#include "eel-gconf-extensions.h"
+
+static void rb_library_child_source_class_init (RBLibraryChildSourceClass *klass);
+static void rb_library_child_source_init (RBLibraryChildSource *source);
+static void rb_library_child_source_finalize (GObject *object);
+static void rb_library_child_source_set_property (GObject *object,
+							guint prop_id,
+							const GValue *value,
+							GParamSpec *pspec);
+static void rb_library_child_source_get_property (GObject *object,
+							guint prop_id,
+							GValue *value,
+							GParamSpec *pspec);
+static void impl_delete_thyself (RBSource *source);
+
+static char *get_state_dir (const char *path);
+static gboolean delete_entry (GtkTreeModel *model,
+				GtkTreePath *path,
+				GtkTreeIter *iter,
+				RhythmDB *db);
+static char *get_display_name_for_uri (const char *uri);
+
+/* RBSource implementations */
+static char *impl_get_browser_key (RBSource *source);
+static char *impl_get_paned_key (RBBrowserSource *source);
+
+#define CONF_STATE_LIBRARY_DIR CONF_PREFIX "/state/library" /* Move this one to rb-preferences.h? */
+#define CONF_STATE_LIBRARY_CHILD_SORTING "/sorting"
+#define CONF_STATE_LIBRARY_CHILD_PANED_POSITION "/paned_position"
+#define CONF_STATE_LIBRARY_CHILD_SHOW_BROWSER "/show_browser"
+
+struct _RBLibraryChildSourcePrivate
+{
+	char *path;
+	
+	char *browser_key;
+	char *paned_key;
+
+	gboolean keep_songs_and_state;
+};
+
+enum
+{
+	PROP_0,
+	PROP_PATH
+};
+
+#define RB_LIBRARY_CHILD_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_LIBRARY_CHILD_SOURCE, RBLibraryChildSourcePrivate))
+G_DEFINE_TYPE (RBLibraryChildSource, rb_library_child_source, RB_TYPE_BROWSER_SOURCE);
+
+static void
+rb_library_child_source_class_init (RBLibraryChildSourceClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
+	RBBrowserSourceClass *browser_source_class = RB_BROWSER_SOURCE_CLASS (klass);
+
+	object_class->finalize = rb_library_child_source_finalize;
+	object_class->get_property = rb_library_child_source_get_property;
+	object_class->set_property = rb_library_child_source_set_property;
+
+	source_class->impl_get_browser_key = impl_get_browser_key;
+	source_class->impl_delete_thyself = impl_delete_thyself;
+
+	browser_source_class->impl_get_paned_key = impl_get_paned_key;
+
+	g_object_class_install_property (object_class,
+					PROP_PATH,
+					g_param_spec_string ("path",
+							"path",
+							"Path to library",
+							NULL,
+							G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	
+	g_type_class_add_private (klass, sizeof (RBLibraryChildSourcePrivate));
+}
+
+static void
+rb_library_child_source_init (RBLibraryChildSource *source)
+{
+	source->priv = RB_LIBRARY_CHILD_SOURCE_GET_PRIVATE (source);
+
+	source->priv->keep_songs_and_state = FALSE;
+}
+
+static void
+rb_library_child_source_finalize (GObject *object)
+{
+	RBLibraryChildSource *source;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (RB_IS_LIBRARY_CHILD_SOURCE (object));
+
+	source = RB_LIBRARY_CHILD_SOURCE (object);
+
+	g_return_if_fail (source->priv != NULL);
+
+	g_free (source->priv->path);
+	g_free (source->priv->browser_key);
+	g_free (source->priv->paned_key);
+
+	G_OBJECT_CLASS (rb_library_child_source_parent_class)->finalize (object);
+}
+
+static void
+rb_library_child_source_set_property (GObject *object,
+					guint prop_id,
+					const GValue *value,
+					GParamSpec *pspec)
+{
+	RBLibraryChildSource *source = RB_LIBRARY_CHILD_SOURCE (object);
+
+	switch (prop_id) {
+	case PROP_PATH:
+		source->priv->path = g_strdup (g_value_get_string (value));	
+		char *state_dir;
+		state_dir = get_state_dir (source->priv->path);
+		source->priv->browser_key = g_strconcat (state_dir,
+				CONF_STATE_LIBRARY_CHILD_SHOW_BROWSER, NULL);
+		source->priv->paned_key = g_strconcat (state_dir,
+				CONF_STATE_LIBRARY_CHILD_PANED_POSITION, NULL);	
+		g_free (state_dir);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+rb_library_child_source_get_property (GObject *object,
+					guint prop_id,
+					GValue *value,
+					GParamSpec *pspec)
+{
+	RBLibraryChildSource *source = RB_LIBRARY_CHILD_SOURCE (object);
+
+	switch (prop_id) {
+	case PROP_PATH:
+		g_value_set_string (value, source->priv->path);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static char *
+get_display_name_for_uri (const char *uri)
+{
+	GFile *file;
+	GFileInfo *file_info;
+	GError *err;
+	char *name = NULL;
+
+	file = g_file_new_for_uri (uri);
+	file_info = g_file_query_info (file,
+			G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+			G_FILE_QUERY_INFO_NONE,
+			NULL,
+			&err);
+	
+	if (file != NULL) {
+		g_object_unref (file);
+	}
+
+	if (file_info == NULL) {
+		if (err != NULL) {
+			rb_debug ("g_file_query_info failed for '%s': %s",
+					uri, err->message);
+			g_error_free (err);
+		} else {
+			rb_debug ("g_file_query_info failed for '%s'", uri);
+		}
+		return NULL;
+	}
+
+	name = g_file_info_get_attribute_as_string (file_info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME);
+	g_object_unref (file_info);
+	if (name == NULL) {
+		rb_debug ("g_file_info_get_attribute_string failed!");
+	}
+	
+	return name;
+}
+
+RBSource *
+rb_library_child_source_new (RBSource *parent_source, const char *path)
+{
+	RBSource *source;
+	RBShell *shell;
+	RhythmDB *db;
+	RhythmDBEntryType *entry_type;
+	GPtrArray *query;
+	GdkPixbuf *icon;
+	char *name;
+	char *state_dir;
+	char *sorting_key;
+
+	name = get_display_name_for_uri (path);
+
+	g_object_get (parent_source,
+			"shell", &shell,
+			"entry-type", &entry_type,
+			"icon", &icon,
+			NULL);
+
+	g_object_get (shell, "db", &db, NULL);
+	query = rhythmdb_query_parse (db,
+			RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, entry_type,
+			RHYTHMDB_QUERY_PROP_PREFIX, RHYTHMDB_PROP_LOCATION, path,
+			RHYTHMDB_QUERY_END);
+	g_object_unref (db);
+	
+	state_dir = get_state_dir (path);
+	sorting_key = g_strconcat (state_dir, CONF_STATE_LIBRARY_CHILD_SORTING, NULL);
+	g_free (state_dir);
+
+	source = RB_SOURCE (g_object_new (RB_TYPE_LIBRARY_CHILD_SOURCE,
+					"name", name,
+					"shell", shell,
+					"path", path,
+					"entry-type", entry_type,
+					"sorting-key", sorting_key,
+					"source-group", RB_SOURCE_GROUP_LIBRARY,
+					"icon", icon,
+					"query", query,
+					NULL));
+	
+	if (name != NULL) {
+		g_free (name);
+	}
+	g_object_unref (shell);
+	rhythmdb_query_free (query);
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);	
+	g_free (sorting_key);
+	if (icon != NULL) {
+		g_object_unref (icon);
+	}
+
+	return source;
+}
+
+static char *
+get_state_dir (const char *path)
+{
+	char *state_dir;
+	char *path_escaped;
+
+	path_escaped = gconf_escape_key (path, strlen (path));
+	state_dir = g_strconcat (CONF_STATE_LIBRARY_DIR, "/", path_escaped, NULL);
+	g_free (path_escaped);
+	
+	return state_dir;
+}
+
+static char *
+impl_get_browser_key (RBSource *source)
+{
+	RBLibraryChildSourcePrivate *priv;
+	priv = RB_LIBRARY_CHILD_SOURCE_GET_PRIVATE (RB_LIBRARY_CHILD_SOURCE (source));
+
+	return g_strdup (priv->browser_key);
+}
+
+static char *
+impl_get_paned_key (RBBrowserSource *source)
+{
+	RBLibraryChildSourcePrivate *priv;
+	priv = RB_LIBRARY_CHILD_SOURCE_GET_PRIVATE (RB_LIBRARY_CHILD_SOURCE (source));
+
+	return g_strdup (priv->paned_key);
+}
+
+static gboolean
+delete_entry (GtkTreeModel *model,
+		GtkTreePath *path,
+		GtkTreeIter *iter,
+		RhythmDB *db)
+{
+	RhythmDBEntry *entry;
+	int position;
+	
+	gtk_tree_model_get (model, iter, 0, &entry, 1, &position, -1);
+
+	rb_debug ("deleting: %2d - '%s' - '%s' - '%s'",
+			position,
+			rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST),
+			rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM),
+		 	rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE));
+
+	rhythmdb_entry_delete (db, entry);
+
+	rhythmdb_entry_unref (entry);
+
+	return FALSE;
+}
+
+void
+rb_library_child_source_set_keep_songs_and_state (RBLibraryChildSource *source,
+							gboolean keep)
+{
+	RBLibraryChildSourcePrivate *priv;
+	priv = RB_LIBRARY_CHILD_SOURCE_GET_PRIVATE (source);
+
+	priv->keep_songs_and_state = keep;
+}
+
+static void
+impl_delete_thyself (RBSource *source)
+{
+	RBLibraryChildSourcePrivate *priv;
+
+	priv = RB_LIBRARY_CHILD_SOURCE_GET_PRIVATE (RB_LIBRARY_CHILD_SOURCE (source));
+	
+	if (priv->keep_songs_and_state == TRUE) {
+		rb_debug ("keeping songs and state.");
+		RB_SOURCE_CLASS (rb_library_child_source_parent_class)->impl_delete_thyself (source);
+		return;
+	}
+
+	rb_debug ("deleting songs and state.");
+
+	RBShell *shell;
+	RhythmDBQueryModel *model;
+	RhythmDB *db;
+	char *path;
+	char *state_dir;
+
+	g_object_get (source,
+			"shell", &shell,
+			"base-query-model", &model,
+			"path", &path,
+			NULL);
+	g_object_get (shell, "db", &db, NULL);
+	g_object_unref (shell);
+
+	/* remove songs from db */
+	gtk_tree_model_foreach (GTK_TREE_MODEL (model),
+			(GtkTreeModelForeachFunc)delete_entry,
+			db);
+	g_object_unref (db);
+
+	state_dir = get_state_dir (path);
+	g_free (path);
+
+	/* remove state gconf keys */
+	eel_gconf_recursive_unset (state_dir);
+	eel_gconf_suggest_sync ();	
+	g_free (state_dir);
+
+	RB_SOURCE_CLASS (rb_library_child_source_parent_class)->impl_delete_thyself (source);
+}
+
Index: sources/rb-library-child-source.h
===================================================================
--- sources/rb-library-child-source.h	(Revision 0)
+++ sources/rb-library-child-source.h	(Revision 0)
@@ -0,0 +1,61 @@
+/*
+ *  Copyright (C) 2008 Christian Becke <christianbecke@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grants permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#ifndef __RB_LIBRARY_CHILD_SOURCE_H
+#define __RB_LIBRARY_CHILD_SOURCE_H
+
+#include "rb-browser-source.h"
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_LIBRARY_CHILD_SOURCE         (rb_library_child_source_get_type ())
+#define RB_LIBRARY_CHILD_SOURCE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_LIBRARY_CHILD_SOURCE, RBLibraryChildSource))
+#define RB_LIBRARY_CHILD_SOURCE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_LIBRARY_CHILD_SOURCE, RBLibraryChildSourceClass))
+#define RB_IS_LIBRARY_CHILD_SOURCE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RB_TYPE_LIBRARY_CHILD_SOURCE))
+#define RB_IS_LIBRARY_CHILD_SOURCE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_LIBRARY_CHILD_SOURCE))
+#define RB_LIBRARY_CHILD_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_LIBRARY_CHILD_SOURCE, RBLibraryChildSourceClass))
+
+typedef struct _RBLibraryChildSourcePrivate RBLibraryChildSourcePrivate;
+
+typedef struct
+{
+	RBBrowserSource parent;
+
+	RBLibraryChildSourcePrivate *priv;
+} RBLibraryChildSource;
+
+typedef struct
+{
+	RBBrowserSourceClass parent;
+} RBLibraryChildSourceClass;
+
+GType		rb_library_child_source_get_type 	(void);
+RBSource *	rb_library_child_source_new		(RBSource *parent_source, const char *path);
+void		rb_library_child_source_set_keep_songs_and_state (RBLibraryChildSource *source, gboolean keep);
+G_END_DECLS
+
+#endif /* __RB_LIBRARY_CHILD_SOURCE_H */
Index: sources/rb-library-source.c
===================================================================
--- sources/rb-library-source.c	(Revision 6244)
+++ sources/rb-library-source.c	(Arbeitskopie)
@@ -67,6 +67,7 @@
 #include "rb-library-source.h"
 #include "rb-removable-media-manager.h"
 #include "rb-auto-playlist-source.h"
+#include "rb-library-child-source.h"
 
 static void rb_library_source_class_init (RBLibrarySourceClass *klass);
 static void rb_library_source_init (RBLibrarySource *source);
@@ -122,6 +123,14 @@
 						 RBLibrarySource *source);
 static void layout_example_label_update (RBLibrarySource *source);
 
+typedef struct {
+	GSList *locations;
+	GList *child_sources;
+} SyncData;
+
+static void check_delete_child_source (RBSource *source, SyncData *data);
+static void remove_child_source (RBSource *child_source);
+
 #define CONF_UI_LIBRARY_DIR CONF_PREFIX "/ui/library"
 #define CONF_STATE_LIBRARY_DIR CONF_PREFIX "/state/library"
 #define CONF_STATE_LIBRARY_SORTING CONF_PREFIX "/state/library/sorting"
@@ -1288,66 +1297,99 @@
 rb_library_source_add_child_source (const char *path, RBLibrarySource *library_source)
 {
 	RBSource *source;
-	GPtrArray *query;
 	RBShell *shell;
-	char *name;
-	GdkPixbuf *icon;
-	RhythmDBEntryType entry_type;
-	char *sort_column;
-	int sort_order;
-	GFile *file;
 
 	g_object_get (library_source,
 		      "shell", &shell,
-		      "entry-type", &entry_type,
 		      NULL);
 
-	file = g_file_new_for_uri (path);		/* ? */
-	name = g_file_get_basename (file);
-	g_object_unref (file);
+	source = rb_library_child_source_new (RB_SOURCE (library_source), path);
 
-	rb_entry_view_get_sorting_order (rb_source_get_entry_view (RB_SOURCE (library_source)),
-					 &sort_column, &sort_order);
+	rb_shell_append_source (shell, source, RB_SOURCE (library_source));
+	library_source->priv->child_sources = g_list_prepend (library_source->priv->child_sources, source);
 
-	source = rb_auto_playlist_source_new (shell, name, FALSE);
-	query = rhythmdb_query_parse (library_source->priv->db,
-				      RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, entry_type,
-				      RHYTHMDB_QUERY_PROP_PREFIX, RHYTHMDB_PROP_LOCATION, path,
-				      RHYTHMDB_QUERY_END);
-	rb_auto_playlist_source_set_query (RB_AUTO_PLAYLIST_SOURCE (source), query,
-					   RHYTHMDB_QUERY_MODEL_LIMIT_NONE, NULL,
-					   sort_column, sort_order);
-	rhythmdb_query_free (query);
-	g_free (sort_column);
+	g_object_unref (shell);
+}
 
-	g_object_get (library_source, "icon", &icon, NULL);
-	g_object_set (source, "icon", icon, NULL);
-	if (icon != NULL) {
-		g_object_unref (icon);
+static void
+check_delete_child_source (RBSource *child_source,
+				SyncData *data)
+{
+	char *path;
+	char *name;
+	GSList *found;
+
+	g_object_get (child_source,
+			"path", &path,
+			"name", &name,
+			NULL);
+	
+	rb_debug ("checking source \"%s\" \"%s\" (%p)", name, path, child_source);
+	found = g_slist_find_custom (data->locations, path, (GCompareFunc)strcmp);
+	if (found == NULL) {
+		/* child source not in location list, deleting source */
+		rb_debug ("deleting source \"%s\" %s (%p).", name, path, child_source);
+		data->child_sources = g_list_remove (data->child_sources, child_source);
+		rb_source_delete_thyself (child_source);
+	} else {
+		/* child source for location exists, removing location from list */
+		rb_debug ("found source (%p) for \"%s\": removing from list of sources to be created.",
+				child_source,
+				(char *)found->data);
+		data->locations = g_slist_delete_link (data->locations, found);
 	}
 
-	rb_shell_append_source (shell, source, RB_SOURCE (library_source));
-	library_source->priv->child_sources = g_list_prepend (library_source->priv->child_sources, source);
-
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
-	g_object_unref (shell);
+	g_free (path);
 	g_free (name);
 }
 
 static void
+remove_child_source (RBSource *child_source)
+{
+	rb_debug ("removing child source (%p).", child_source);
+	/* do not remove songs from db and keep gconf state keys */
+	rb_library_child_source_set_keep_songs_and_state (RB_LIBRARY_CHILD_SOURCE (child_source), TRUE);
+	rb_source_delete_thyself (child_source);
+}
+
+static void
 rb_library_source_sync_child_sources (RBLibrarySource *source)
 {
-	GSList *list;
+	GSList *locations;
+	SyncData data;
 
-	list = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
+	locations = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
 
-	/* FIXME: don't delete and re-create sources that are still there */
-	g_list_foreach (source->priv->child_sources, (GFunc)rb_source_delete_thyself, NULL);
+	data.locations = g_slist_copy (locations);
+	data.child_sources = g_list_copy (source->priv->child_sources);
+
+	g_list_foreach (source->priv->child_sources, (GFunc)check_delete_child_source, &data);
+	/* data now contains:
+	 * data.locations: list of locations for which a new child source has to be created
+	 * data.child_sources: list of still valid child_sources
+	 */
+	
 	g_list_free (source->priv->child_sources);
-	source->priv->child_sources = NULL;
+	source->priv->child_sources = g_list_copy (data.child_sources);
+	
+	if (g_slist_length (locations) > 1) {
+		/* only add child sources if there are more than one */
+		rb_debug ("multiple library locations: adding child source(s).");
+		g_slist_foreach (data.locations,
+				(GFunc)rb_library_source_add_child_source,
+				source);
+	} else {
+		/* only one location, don't show child sources */
+		rb_debug ("only one library location: removing child source(s).");
+		g_list_foreach (source->priv->child_sources,
+				(GFunc)remove_child_source,
+				NULL);
+		g_list_free (source->priv->child_sources);
+		source->priv->child_sources = NULL;
+	}
 
-	if (g_slist_length (list) > 1)
-		g_slist_foreach (list, (GFunc)rb_library_source_add_child_source, source);
-	rb_slist_deep_free (list);
+	g_slist_free (data.locations);
+	g_list_free (data.child_sources);
+	rb_slist_deep_free (locations);
 }
 
Index: sources/rb-browser-source.c
===================================================================
--- sources/rb-browser-source.c	(Revision 6244)
+++ sources/rb-browser-source.c	(Arbeitskopie)
@@ -136,6 +136,7 @@
 	RBEntryView *songs;
 	GtkWidget *paned;
 
+	GPtrArray *base_query;
 	RhythmDBQueryModel *cached_all_query;
 	RhythmDBQuery *search_query;
 	RhythmDBPropType search_prop;
@@ -189,7 +190,8 @@
 	PROP_SORTING_KEY,
 	PROP_BASE_QUERY_MODEL,
 	PROP_POPULATE,
-	PROP_SEARCH_TYPE
+	PROP_SEARCH_TYPE,
+	PROP_QUERY
 };
 
 G_DEFINE_ABSTRACT_TYPE (RBBrowserSource, rb_browser_source, RB_TYPE_SOURCE)
@@ -252,6 +254,13 @@
 					  PROP_SEARCH_TYPE,
 					  "search-type");
 
+	g_object_class_install_property (object_class,
+					 PROP_QUERY,
+					 g_param_spec_pointer ("query",
+							      "Query",
+							      "RhythmDBQuery",
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
 	g_type_class_add_private (klass, sizeof (RBBrowserSourcePrivate));
 }
 
@@ -284,6 +293,11 @@
 		source->priv->search_query = NULL;
 	}
 
+	if (source->priv->base_query != NULL) {
+		rhythmdb_query_free (source->priv->base_query);
+		source->priv->base_query = NULL;
+	}
+
 	if (source->priv->cached_all_query != NULL) {
 		g_object_unref (source->priv->cached_all_query);
 		source->priv->cached_all_query = NULL;
@@ -517,6 +531,12 @@
 	case PROP_SEARCH_TYPE:
 		/* ignored */
 		break;
+	case PROP_QUERY:
+		if (source->priv->base_query != NULL) {
+			rhythmdb_query_free (source->priv->base_query);
+		}
+		source->priv->base_query = rhythmdb_query_copy (g_value_get_pointer (value));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -544,6 +564,9 @@
 	case PROP_SEARCH_TYPE:
 		g_value_set_enum (value, RB_SOURCE_SEARCH_INCREMENTAL);
 		break;
+	case PROP_QUERY:
+		source->priv->base_query = rhythmdb_query_copy (g_value_get_pointer (value));
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -575,11 +598,17 @@
 				 source, 0);
 
 	g_object_get (source, "entry-type", &entry_type, NULL);
-	rhythmdb_do_full_query_async (source->priv->db,
+	if (source->priv->base_query == NULL) {
+		rb_debug ("No query set, creating new one.");
+		source->priv->base_query = rhythmdb_query_parse (source->priv->db,
+				RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, entry_type,
+				RHYTHMDB_QUERY_END);
+	}	
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	
+	rhythmdb_do_full_query_async_parsed (source->priv->db,
 				      RHYTHMDB_QUERY_RESULTS (source->priv->cached_all_query),
-				      RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, entry_type,
-				      RHYTHMDB_QUERY_END);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+				      source->priv->base_query);
 }
 
 
@@ -908,8 +937,8 @@
 rb_browser_source_do_query (RBBrowserSource *source, gboolean subset)
 {
 	RhythmDBQueryModel *query_model;
+	GPtrArray *base_query;
 	GPtrArray *query;
-	RhythmDBEntryType entry_type;
 
 	/* use the cached 'all' query to optimise the no-search case */
 	if (source->priv->search_query == NULL) {
@@ -919,15 +948,13 @@
 		return;
 	}
 
-	g_object_get (source, "entry-type", &entry_type, NULL);
-	query = rhythmdb_query_parse (source->priv->db,
-				      RHYTHMDB_QUERY_PROP_EQUALS,
-				      RHYTHMDB_PROP_TYPE,
-				      entry_type,
-				      RHYTHMDB_QUERY_SUBQUERY,
-				      source->priv->search_query,
-				      RHYTHMDB_QUERY_END);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_get (source->priv->cached_all_query, "query", &base_query, NULL);
+	query = rhythmdb_query_copy (base_query);
+	rhythmdb_query_append (source->priv->db,
+				query,
+				RHYTHMDB_QUERY_SUBQUERY,
+				source->priv->search_query,
+				RHYTHMDB_QUERY_END);
 
 	if (subset) {
 		/* if we're appending text to an existing search string, the results will be a subset
Index: sources/Makefile.am
===================================================================
--- sources/Makefile.am	(Revision 6244)
+++ sources/Makefile.am	(Arbeitskopie)
@@ -41,6 +41,8 @@
 	rb-import-errors-source.h	\
 	rb-source-search-basic.c	\
 	rb-source-search-basic.h	\
+	rb-library-child-source.c	\
+	rb-library-child-source.h	\
 	$(NULL)
 
 INCLUDES =						\
Index: lib/eel-gconf-extensions.h
===================================================================
--- lib/eel-gconf-extensions.h	(Revision 6244)
+++ lib/eel-gconf-extensions.h	(Arbeitskopie)
@@ -72,6 +72,7 @@
 void         eel_gconf_notification_remove (guint notification_id);
 
 void	     eel_gconf_unset 		   (const char *key);
+void	eel_gconf_recursive_unset	(const char *key);
 
 #ifdef __cplusplus
 }
Index: lib/eel-gconf-extensions.c
===================================================================
--- lib/eel-gconf-extensions.c	(Revision 6244)
+++ lib/eel-gconf-extensions.c	(Arbeitskopie)
@@ -348,6 +348,26 @@
         eel_gconf_handle_error (&error);
 }
 
+/* This code wasn't part of the original eel-gconf-extensions.c */
+void
+eel_gconf_recursive_unset (const char *key)
+{
+	GConfClient *client;
+	GError *error = NULL;
+
+	g_return_if_fail (key != NULL);
+
+	client = eel_gconf_client_get_global ();
+	g_return_if_fail (client != NULL);
+
+	gconf_client_recursive_unset (client,
+			key,
+			GCONF_UNSET_INCLUDING_SCHEMA_NAMES,
+			&error);
+	eel_gconf_handle_error (&error);
+}
+/* End of added code */
+
 gboolean
 eel_gconf_monitor_add (const char *directory)
 {
