Example #1
0
END_TEST

START_TEST (test_rhythmdb_deserialisation3)
{
	RhythmDBQueryModel *model;

	/* two entries of different types db */
	g_object_set (G_OBJECT (db), "name", "deserialization-test3.xml", NULL);
	set_waiting_signal (G_OBJECT (db), "load-complete");
	rhythmdb_load (db);
	wait_for_signal ();

	model = rhythmdb_query_model_new_empty (db);
	g_object_set (G_OBJECT (model), "show-hidden", TRUE, NULL);
	set_waiting_signal (G_OBJECT (model), "complete");
	rhythmdb_do_full_query (db, RHYTHMDB_QUERY_RESULTS (model),
				NULL,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TYPE, RHYTHMDB_ENTRY_TYPE_IGNORE,
				RHYTHMDB_QUERY_END);
	wait_for_signal ();
	/* FIXME: this fails for some reason
	fail_unless (gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL) == 1, "deserialisation incorrect");*/
	g_object_unref (model);

	/* TODO: check values */
}
static void
start_media_browse (RBGriloSource *source, GrlMedia *container, GtkTreeIter *container_iter, guint limit)
{
	rb_debug ("starting media browse for %s",
		  grl_source_get_name (source->priv->grilo_source));

	/* cancel existing operation? */
	if (source->priv->media_browse_op != 0) {
		grl_operation_cancel (source->priv->media_browse_op);
	}

	if (source->priv->media_browse_container != NULL) {
		g_object_unref (source->priv->media_browse_container);
	}
	source->priv->media_browse_container = container;
	if (container_iter != NULL) {
		/* hrm, probably have to use row references here.. */
		source->priv->media_browse_container_iter = *container_iter;
	}
	source->priv->media_browse_position = 0;
	source->priv->media_browse_limit = limit;
	source->priv->media_browse_got_containers = FALSE;

	if (source->priv->query_model != NULL) {
		g_object_unref (source->priv->query_model);
	}
	source->priv->query_model = rhythmdb_query_model_new_empty (source->priv->db);
	rb_entry_view_set_model (RB_ENTRY_VIEW (source->priv->entry_view), source->priv->query_model);
	g_object_set (source, "query-model", source->priv->query_model, NULL);

	media_browse_next (source);
}
Example #3
0
int
main (int argc, char **argv)
{
	GtkWidget *main_window;
	GtkTreeModel *main_model;
	GtkTreeIter iter;
	RBEntryView *view;
	RhythmDB *db;
	RhythmDBEntry *entry;

	gtk_init (&argc, &argv);
	gdk_threads_init ();
	rb_thread_helpers_init ();
	rb_file_helpers_init (TRUE);
	rb_stock_icons_init ();
	rb_debug_init (TRUE);

	GDK_THREADS_ENTER ();

	db = rhythmdb_tree_new ("test");

	rhythmdb_write_lock (db);

	entry = create_entry (db, "file:///sin.mp3",
			      "Sin", "Pretty Hate Machine", "Nine Inch Nails", "Rock");
	
	rhythmdb_write_unlock (db);

	rhythmdb_read_lock (db);

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TYPE, RHYTHMDB_ENTRY_TYPE_IGNORE,
				RHYTHMDB_QUERY_END);

	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));
	g_assert (gtk_tree_model_get_iter_first (main_model, &iter));

	main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

	view = rb_entry_view_new (db, rb_file ("rb-entry-view-library.xml"));

	rb_entry_view_set_query_model (view, RHYTHMDB_QUERY_MODEL (main_model));

	gtk_container_add (GTK_CONTAINER (main_window), GTK_WIDGET (view));

	g_signal_connect (G_OBJECT (main_window), "destroy",
			  G_CALLBACK (gtk_main_quit), NULL);

	gtk_widget_show_all (GTK_WIDGET (main_window));

	gtk_main ();
	
	rhythmdb_shutdown (db);
	g_object_unref (G_OBJECT (db));
	GDK_THREADS_LEAVE ();
	
	exit (0);
}
Example #4
0
/**
 * rb_transfer_target_check_duplicate:
 * @target: an #RBTransferTarget
 * @entry: a #RhythmDBEntry to check
 *
 * This checks for an existing entry in the target that matches
 * the title, album, artist, and track number of the entry being
 * considered.  This can be used to implement @should_transfer.
 *
 * Return value: %TRUE if the entry already exists on the target.
 */
gboolean
rb_transfer_target_check_duplicate (RBTransferTarget *target, RhythmDBEntry *entry)
{
	RhythmDBEntryType *entry_type;
	RhythmDB *db;
	RBShell *shell;
	const char *title;
	const char *album;
	const char *artist;
	gulong track_number;
	GtkTreeModel *query_model;
	GtkTreeIter iter;
	gboolean is_dup;

	g_object_get (target, "shell", &shell, "entry-type", &entry_type, NULL);
	g_object_get (shell, "db", &db, NULL);
	g_object_unref (shell);

	query_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	title = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE);
	album = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM);
	artist = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST);
	track_number = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER);
	rhythmdb_do_full_query (db, RHYTHMDB_QUERY_RESULTS (query_model),
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TYPE, entry_type,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_ARTIST, artist,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_ALBUM, album,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TITLE, title,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TRACK_NUMBER, track_number,
				RHYTHMDB_QUERY_END);

	is_dup = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (query_model), &iter);
	g_object_unref (entry_type);
	g_object_unref (query_model);
	g_object_unref (db);
	if (is_dup) {
		rb_debug ("not transferring %lu - %s - %s - %s as already present",
			  track_number, title, album, artist);
	}
	return is_dup;
}
static void
test_query_eval (RhythmDB *db, RhythmDBQuery *query, RhythmDBEntry *entry, gboolean expected, const char *what)
{
	RhythmDBQueryModel *model;
	RhythmDBQuery *processed;
	GtkTreeIter iter = {0,};

	/* direct evaluation - need to preprocess it first */
	processed = rhythmdb_query_copy (query);
	rhythmdb_query_preprocess (db, processed);
	fail_unless (rhythmdb_evaluate_query (db, processed, entry) == expected, what);
	rhythmdb_query_free (processed);

	/* query evaluation - query is preprocessed by rhythmdb */
	model = rhythmdb_query_model_new_empty (db);
	rhythmdb_do_full_query_parsed (db, RHYTHMDB_QUERY_RESULTS (model), query);
	fail_unless (rhythmdb_query_model_entry_to_iter (model, entry, &iter) == expected, what);
	g_object_unref (model);
}
static void
rb_static_playlist_source_do_query (RBStaticPlaylistSource *source)
{
	RBStaticPlaylistSourcePrivate *priv = RB_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (source);
	RBPlaylistSource *psource = RB_PLAYLIST_SOURCE (source);
	RhythmDB *db = rb_playlist_source_get_db (psource);
	GPtrArray *query;

	if (priv->filter_model != NULL) {
		g_object_unref (priv->filter_model);
	}
	priv->filter_model = rhythmdb_query_model_new_empty (db);
	g_object_set (priv->filter_model, "base-model", priv->base_model, NULL);

	query = construct_query_from_selection (source);
	g_object_set (priv->filter_model, "query", query, NULL);
	rhythmdb_query_free (query);

	rhythmdb_query_model_reapply_query (priv->filter_model, TRUE);
	rb_library_browser_set_model (priv->browser, priv->filter_model, FALSE);
}
Example #7
0
END_TEST

START_TEST (test_rhythmdb_deserialisation1)
{
	RhythmDBQueryModel *model;

	/* empty db */
	g_object_set (G_OBJECT (db), "name", "deserialization-test1.xml", NULL);
	set_waiting_signal (G_OBJECT (db), "load-complete");
	rhythmdb_load (db);
	wait_for_signal ();

	model = rhythmdb_query_model_new_empty (db);
	g_object_set (G_OBJECT (model), "show-hidden", TRUE, NULL);
	set_waiting_signal (G_OBJECT (model), "complete");
	rhythmdb_do_full_query (db, RHYTHMDB_QUERY_RESULTS (model),
				NULL,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TYPE, RHYTHMDB_ENTRY_TYPE_IGNORE,
				RHYTHMDB_QUERY_END);
	wait_for_signal ();
	fail_unless (gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL) == 0, "deserialisation incorrect");
	g_object_unref (model);
}
static void
rebuild_child_model (RBLibraryBrowser *widget,
		     gint property_index,
		     gboolean query_pending)
{
	RBLibraryBrowserPrivate *priv = RB_LIBRARY_BROWSER_GET_PRIVATE (widget);
	RhythmDBPropertyModel *prop_model;
	RhythmDBQueryModel *base_model, *child_model;
	RBPropertyView *view;
	RhythmDBQuery *query;
	GList *selections;

	g_assert (property_index >= 0);
	g_assert (property_index < num_browser_properties);

	/* get the query model for the previous property view */
	view = g_hash_table_lookup (priv->property_views, (gpointer)browser_properties[property_index].type);
	prop_model = rb_property_view_get_model (view);
	g_object_get (prop_model, "query-model", &base_model, NULL);

	selections = g_hash_table_lookup (priv->selections, (gpointer)browser_properties[property_index].type);
	if (selections != NULL) {

		/* create a new query model based on it, filtered by
		 * the selections of the previous property view.
		 * we need the entry type query criteria to allow the
		 * backend to optimise the query.
		 */
		query = rhythmdb_query_parse (priv->db,
				              RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, priv->entry_type,
					      RHYTHMDB_QUERY_END);
		rhythmdb_query_append_prop_multiple (priv->db,
						     query,
						     browser_properties[property_index].type,
						     selections);

		child_model = rhythmdb_query_model_new_empty (priv->db);
		if (query_pending) {
			rb_debug ("rebuilding child model for browser %d; query is pending", property_index);
			g_object_set (child_model,
				      "query", query,
				      "base-model", base_model,
				      NULL);
		} else {
			rb_debug ("rebuilding child model for browser %d; running new query", property_index);
			rhythmdb_query_model_chain (child_model, base_model, FALSE);
			rhythmdb_do_full_query_parsed (priv->db,
						       RHYTHMDB_QUERY_RESULTS (child_model),
						       query);
		}
		rhythmdb_query_free (query);
	} else {
		rb_debug ("no selection for browser %d - reusing parent model", property_index);
		child_model = g_object_ref (base_model);
	}

	/* If this is the last property, use the child model as the output model
	 * for the browser.  Otherwise, use it as the input for the next property
	 * view.
	 */
	if (property_index == num_browser_properties-1) {
		if (priv->output_model != NULL) {
			g_object_unref (priv->output_model);
		}

		priv->output_model = child_model;

		g_object_notify (G_OBJECT (widget), "output-model");

	} else {
		view = g_hash_table_lookup (priv->property_views, (gpointer)browser_properties[property_index+1].type);
		ignore_selection_changes (widget, view, TRUE);

		prop_model = rb_property_view_get_model (view);
		g_object_set (prop_model, "query-model", child_model, NULL);

		g_object_unref (child_model);

		rebuild_child_model (widget, property_index + 1, query_pending);
		restore_selection (widget, property_index + 1, query_pending);
	}

	g_object_unref (base_model);
}
Example #9
0
static void
rb_import_errors_source_constructed (GObject *object)
{
	GObject *shell_player;
	RBImportErrorsSource *source;
	RBShell *shell;
	GPtrArray *query;
	RhythmDBQueryModel *model;
	RhythmDBEntryType *entry_type;
	GtkWidget *box;
	GtkWidget *label;

	RB_CHAIN_GOBJECT_METHOD (rb_import_errors_source_parent_class, constructed, object);

	source = RB_IMPORT_ERRORS_SOURCE (object);

	g_object_get (source,
		      "shell", &shell,
		      "entry-type", &entry_type,
		      NULL);
	g_object_get (shell, "db", &source->priv->db, NULL);
	shell_player = rb_shell_get_player (shell);
	g_object_unref (shell);

	/* construct real query */
	query = rhythmdb_query_parse (source->priv->db,
				      RHYTHMDB_QUERY_PROP_EQUALS,
				      	RHYTHMDB_PROP_TYPE,
					entry_type,
				      RHYTHMDB_QUERY_END);

	model = rhythmdb_query_model_new (source->priv->db, query,
					  (GCompareDataFunc) rhythmdb_query_model_string_sort_func,
					  GUINT_TO_POINTER (RHYTHMDB_PROP_LOCATION), NULL, FALSE);
	rhythmdb_query_free (query);

	/* set up entry view */
	source->priv->view = rb_entry_view_new (source->priv->db, shell_player,
						NULL, FALSE, FALSE);

	rb_entry_view_set_model (source->priv->view, model);

	rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_LOCATION, TRUE);
	rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_ERROR, TRUE);

	g_signal_connect_object (source->priv->view, "show_popup",
				 G_CALLBACK (rb_import_errors_source_songs_show_popup_cb), source, 0);

	g_object_set (source, "query-model", model, NULL);
	g_object_unref (model);

	/* set up query model for tracking missing plugin information */
	query = rhythmdb_query_parse (source->priv->db,
				      RHYTHMDB_QUERY_PROP_EQUALS,
				        RHYTHMDB_PROP_TYPE,
					entry_type,
				      RHYTHMDB_QUERY_PROP_NOT_EQUAL,
				        RHYTHMDB_PROP_COMMENT,
					"",
				      RHYTHMDB_QUERY_END);

	source->priv->missing_plugin_model = rhythmdb_query_model_new_empty (source->priv->db);
	rhythmdb_do_full_query_async_parsed (source->priv->db,
					     RHYTHMDB_QUERY_RESULTS (source->priv->missing_plugin_model),
					     query);
	rhythmdb_query_free (query);

	/* set up info bar for triggering codec installation */
	source->priv->infobar = gtk_info_bar_new_with_buttons (_("Install Plugins"), GTK_RESPONSE_OK, NULL);
	g_signal_connect_object (source->priv->infobar,
				 "response",
				 G_CALLBACK (infobar_response_cb),
				 source, 0);

	label = gtk_label_new (_("Additional GStreamer plugins are required to play some of these files."));
	gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (source->priv->infobar))),
			   label);

	g_object_unref (entry_type);

	box = gtk_vbox_new (FALSE, 6);
	gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (source->priv->view), TRUE, TRUE, 0);
	gtk_box_pack_start (GTK_BOX (box), source->priv->infobar, FALSE, FALSE, 0);

	gtk_container_add (GTK_CONTAINER (source), box);
	gtk_widget_show_all (GTK_WIDGET (source));
	gtk_widget_hide (source->priv->infobar);

	/* show the info bar when there are missing plugin entries */
	g_signal_connect_object (source->priv->missing_plugin_model,
				 "row-inserted",
				 G_CALLBACK (missing_plugin_row_inserted_cb),
				 source, 0);
	g_signal_connect_object (source->priv->missing_plugin_model,
				 "row-deleted",
				 G_CALLBACK (missing_plugin_row_deleted_cb),
				 source, 0);
}
END_TEST

/* this tests that chained query models, where the base shows hidden entries
 * forwards visibility changes correctly. This is basically what static playlists do */
START_TEST (test_hidden_chain_filter)
{
	RhythmDBQueryModel *base_model;
	RhythmDBQueryModel *filter_model;
	RhythmDBQuery *query;
	RhythmDBEntry *entry;
	GtkTreeIter iter;
	GValue val = {0,};

	start_test_case ();

	/* setup */
	base_model = rhythmdb_query_model_new_empty (db);
	g_object_set (base_model, "show-hidden", TRUE, NULL);

	filter_model = rhythmdb_query_model_new_empty (db);
	g_object_set (filter_model, "base-model", base_model, NULL);
	query = g_ptr_array_new ();
	g_object_set (filter_model, "query", query, NULL);
	rhythmdb_query_free (query);

	entry = rhythmdb_entry_new (db, RHYTHMDB_ENTRY_TYPE_IGNORE, "file:///whee.ogg");
	rhythmdb_commit (db);

	g_value_init (&val, G_TYPE_BOOLEAN);


	/* add entry to base, should be in both */
	rhythmdb_query_model_add_entry (base_model, entry, -1);
	fail_unless (rhythmdb_query_model_entry_to_iter (base_model, entry, &iter));
	fail_unless (rhythmdb_query_model_entry_to_iter (filter_model, entry, &iter));

	end_step ();

	/* hide entry, should be in base and not filtered */
	g_value_set_boolean (&val, TRUE);
	set_waiting_signal (G_OBJECT (db), "entry-changed");
	rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_HIDDEN, &val);
	rhythmdb_commit (db);
	wait_for_signal ();

	fail_unless (rhythmdb_query_model_entry_to_iter (base_model, entry, &iter));
	fail_if (rhythmdb_query_model_entry_to_iter (filter_model, entry, &iter));

	end_step ();

	/* show entry again, should be in both */
	g_value_set_boolean (&val, FALSE);
	set_waiting_signal (G_OBJECT (db), "entry-changed");
	rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_HIDDEN, &val);
	rhythmdb_commit (db);
	wait_for_signal ();

	fail_unless (rhythmdb_query_model_entry_to_iter (base_model, entry, &iter));
	fail_unless (rhythmdb_query_model_entry_to_iter (filter_model, entry, &iter));

	end_step ();

	/* tidy up */
	rhythmdb_entry_delete (db, entry);
	g_object_unref (base_model);
	g_object_unref (filter_model);
	g_value_unset (&val);

	end_test_case ();
}
Example #11
0
static void
impl_constructed (GObject *object)
{
	RBPodcastAddDialog *dialog;
	GtkBuilder *builder;
	GtkWidget *widget;
	GtkWidget *paned;
	GtkTreeViewColumn *column;
	GtkCellRenderer *renderer;
	RBEntryView *episodes;
	RBShellPlayer *shell_player;
	RhythmDBQuery *query;
	RhythmDBQueryModel *query_model;
	const char *episode_strings[3];

	RB_CHAIN_GOBJECT_METHOD (rb_podcast_add_dialog_parent_class, constructed, object);
	dialog = RB_PODCAST_ADD_DIALOG (object);

	g_object_get (dialog->priv->podcast_mgr, "db", &dialog->priv->db, NULL);

	builder = rb_builder_load ("podcast-add-dialog.ui", NULL);

	dialog->priv->info_bar_message = gtk_label_new ("");
	dialog->priv->info_bar = gtk_info_bar_new ();
	g_object_set (dialog->priv->info_bar, "spacing", 0, NULL);
	gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (dialog->priv->info_bar))),
			   dialog->priv->info_bar_message);
	gtk_widget_set_no_show_all (dialog->priv->info_bar, TRUE);
	gtk_box_pack_start (GTK_BOX (dialog), dialog->priv->info_bar, FALSE, FALSE, 0);
	gtk_widget_show (dialog->priv->info_bar_message);

	dialog->priv->subscribe_button = GTK_WIDGET (gtk_builder_get_object (builder, "subscribe-button"));
	g_signal_connect_object (dialog->priv->subscribe_button, "clicked", G_CALLBACK (subscribe_clicked_cb), dialog, 0);
	gtk_widget_set_sensitive (dialog->priv->subscribe_button, FALSE);

	dialog->priv->feed_view = GTK_WIDGET (gtk_builder_get_object (builder, "feed-view"));
	g_signal_connect (dialog->priv->feed_view, "row-activated", G_CALLBACK (feed_activated_cb), dialog);
	g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->feed_view)),
			  "changed",
			  G_CALLBACK (feed_selection_changed_cb),
			  dialog);


	dialog->priv->search_entry = rb_search_entry_new (FALSE);
	gtk_widget_set_size_request (GTK_WIDGET (dialog->priv->search_entry), 400, -1);
	g_object_set (dialog->priv->search_entry,"explicit-mode", TRUE, NULL);
	g_signal_connect (dialog->priv->search_entry, "search", G_CALLBACK (search_cb), dialog);
	g_signal_connect (dialog->priv->search_entry, "activate", G_CALLBACK (search_cb), dialog);
	gtk_container_add (GTK_CONTAINER (gtk_builder_get_object (builder, "search-entry-box")),
			   GTK_WIDGET (dialog->priv->search_entry));

	g_signal_connect (gtk_builder_get_object (builder, "close-button"),
			  "clicked",
			  G_CALLBACK (close_clicked_cb),
			  dialog);

	dialog->priv->feed_model = gtk_list_store_new (7,
						       G_TYPE_STRING,	/* name */
						       G_TYPE_STRING,	/* author */
						       GDK_TYPE_PIXBUF, /* image */
						       G_TYPE_FILE,	/* image file */
						       G_TYPE_INT,	/* episode count */
						       G_TYPE_POINTER,	/* RBPodcastChannel */
						       G_TYPE_ULONG);	/* date */
	gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->priv->feed_view), GTK_TREE_MODEL (dialog->priv->feed_model));

	column = gtk_tree_view_column_new_with_attributes (_("Title"), gtk_cell_renderer_pixbuf_new (), "pixbuf", FEED_COLUMN_IMAGE, NULL);
	renderer = gtk_cell_renderer_text_new ();
	g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
	gtk_tree_view_column_pack_start (column, renderer, TRUE);
	gtk_tree_view_column_set_attributes (column, renderer, "text", FEED_COLUMN_TITLE, NULL);

	gtk_tree_view_column_set_expand (column, TRUE);
	gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->feed_view), column);

	renderer = gtk_cell_renderer_text_new ();
	g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
	column = gtk_tree_view_column_new_with_attributes (_("Author"), renderer, "text", FEED_COLUMN_AUTHOR, NULL);
	gtk_tree_view_column_set_expand (column, TRUE);
	gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->feed_view), column);

	renderer = gtk_cell_renderer_text_new ();
	column = gtk_tree_view_column_new_with_attributes (_("Episodes"), renderer, NULL);
	gtk_tree_view_column_set_cell_data_func (column, renderer, episode_count_column_cell_data_func, NULL, NULL);
	episode_strings[0] = "0000";
	episode_strings[1] = _("Episodes");
	episode_strings[2] = NULL;
	rb_set_tree_view_column_fixed_width (dialog->priv->feed_view, column, renderer, episode_strings, 6);
	gtk_tree_view_append_column (GTK_TREE_VIEW (dialog->priv->feed_view), column);

	widget = GTK_WIDGET (gtk_builder_get_object (builder, "podcast-add-dialog"));
	gtk_box_pack_start (GTK_BOX (dialog), widget, TRUE, TRUE, 0);

	/* set up episode view */
	g_object_get (dialog->priv->shell, "shell-player", &shell_player, NULL);
	episodes = rb_entry_view_new (dialog->priv->db, G_OBJECT (shell_player), TRUE, FALSE);
	g_object_unref (shell_player);

	g_signal_connect (episodes, "entry-activated", G_CALLBACK (episode_entry_activated_cb), dialog);

	/* date column */
	column = gtk_tree_view_column_new ();
	renderer = gtk_cell_renderer_text_new();

	gtk_tree_view_column_pack_start (column, renderer, TRUE);

	gtk_tree_view_column_set_clickable (column, TRUE);
	gtk_tree_view_column_set_resizable (column, TRUE);
	gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
	{
		const char *sample_strings[3];
		sample_strings[0] = _("Date");
		sample_strings[1] = rb_entry_view_get_time_date_column_sample ();
		sample_strings[2] = NULL;
		rb_entry_view_set_fixed_column_width (episodes, column, renderer, sample_strings);
	}

	gtk_tree_view_column_set_cell_data_func (column, renderer,
						 (GtkTreeCellDataFunc) podcast_post_date_cell_data_func,
						 dialog, NULL);

	rb_entry_view_append_column_custom (episodes, column,
					    _("Date"), "Date",
					    (GCompareDataFunc) podcast_post_date_sort_func,
					    0, NULL);
	rb_entry_view_append_column (episodes, RB_ENTRY_VIEW_COL_TITLE, TRUE);
	rb_entry_view_append_column (episodes, RB_ENTRY_VIEW_COL_DURATION, TRUE);
	rb_entry_view_set_sorting_order (RB_ENTRY_VIEW (episodes), "Date", GTK_SORT_DESCENDING);
	g_signal_connect (episodes,
			  "notify::sort-order",
			  G_CALLBACK (episodes_sort_changed_cb),
			  dialog);

	query = rhythmdb_query_parse (dialog->priv->db,
				      RHYTHMDB_QUERY_PROP_EQUALS,
				      RHYTHMDB_PROP_TYPE,
				      RHYTHMDB_ENTRY_TYPE_PODCAST_SEARCH,
				      RHYTHMDB_QUERY_END);
	query_model = rhythmdb_query_model_new_empty (dialog->priv->db);
	rb_entry_view_set_model (episodes, query_model);

	rhythmdb_do_full_query_async_parsed (dialog->priv->db, RHYTHMDB_QUERY_RESULTS (query_model), query);
	rhythmdb_query_free (query);

	g_object_unref (query_model);

	paned = GTK_WIDGET (gtk_builder_get_object (builder, "paned"));
	g_signal_connect (paned, "size-allocate", G_CALLBACK (paned_size_allocate_cb), dialog);
	gtk_paned_pack2 (GTK_PANED (paned),
			 GTK_WIDGET (episodes),
			 TRUE,
			 FALSE);

	gtk_widget_show_all (GTK_WIDGET (dialog));
	g_object_unref (builder);
}
Example #12
0
static void
impl_constructed (GObject *object)
{
	RBImportDialog *dialog;
	RhythmDBQuery *query;
	GtkBuilder *builder;
	GSettings *settings;
	char **locations;

	RB_CHAIN_GOBJECT_METHOD (rb_import_dialog_parent_class, constructed, object);
	dialog = RB_IMPORT_DIALOG (object);

	g_object_get (dialog->priv->shell,
		      "db", &dialog->priv->db,
		      "shell-player", &dialog->priv->shell_player,
		      NULL);

	/* create entry types */
	dialog->priv->entry_type = g_object_new (rb_import_dialog_entry_type_get_type (),
						 "db", dialog->priv->db,
						 "name", "import-dialog",
						 NULL);
	dialog->priv->ignore_type = g_object_new (rb_import_dialog_ignore_type_get_type (),
						  "db", dialog->priv->db,
						  "name", "import-dialog-ignore",
						  NULL);
	rhythmdb_register_entry_type (dialog->priv->db, dialog->priv->entry_type);
	rhythmdb_register_entry_type (dialog->priv->db, dialog->priv->ignore_type);


	builder = rb_builder_load ("import-dialog.ui", NULL);

	dialog->priv->import_button = GTK_WIDGET (gtk_builder_get_object (builder, "import-button"));
	g_signal_connect_object (dialog->priv->import_button, "clicked", G_CALLBACK (import_clicked_cb), dialog, 0);
	gtk_widget_set_sensitive (dialog->priv->import_button, FALSE);

	dialog->priv->copy_check = GTK_WIDGET (gtk_builder_get_object (builder, "copy-check"));

	g_signal_connect (gtk_builder_get_object (builder, "close-button"),
			  "clicked",
			  G_CALLBACK (close_clicked_cb),
			  dialog);

	dialog->priv->file_chooser = GTK_WIDGET (gtk_builder_get_object (builder, "file-chooser-button"));
	
	/* select the first library location, since the default may be
	 * the user's home dir or / or something that will take forever to scan.
	 */
	settings = g_settings_new ("org.gnome.rhythmbox.rhythmdb");
	locations = g_settings_get_strv (settings, "locations");
	if (locations[0] != NULL) {
		dialog->priv->current_uri = g_strdup (locations[0]);
	} else {
		dialog->priv->current_uri = g_filename_to_uri (rb_music_dir (), NULL, NULL);
	}
	gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dialog->priv->file_chooser),
						 dialog->priv->current_uri);
	g_strfreev (locations);
	g_object_unref (settings);

	g_signal_connect_object (dialog->priv->file_chooser, "selection-changed", G_CALLBACK (current_folder_changed_cb), dialog, 0);

	/* not sure why we have to set this, it should be the default */
	gtk_widget_set_vexpand (gtk_widget_get_parent (dialog->priv->file_chooser), FALSE);

	dialog->priv->info_bar_container = GTK_WIDGET (gtk_builder_get_object (builder, "info-bar-container"));

	/* set up entry view */
	dialog->priv->entry_view = rb_entry_view_new (dialog->priv->db, G_OBJECT (dialog->priv->shell_player), TRUE, FALSE);

	g_signal_connect (dialog->priv->entry_view, "entry-activated", G_CALLBACK (entry_activated_cb), dialog);
	g_signal_connect (dialog->priv->entry_view, "selection-changed", G_CALLBACK (selection_changed_cb), dialog);

	rb_entry_view_append_column (dialog->priv->entry_view, RB_ENTRY_VIEW_COL_TRACK_NUMBER, FALSE);
	rb_entry_view_append_column (dialog->priv->entry_view, RB_ENTRY_VIEW_COL_TITLE, TRUE);
	rb_entry_view_append_column (dialog->priv->entry_view, RB_ENTRY_VIEW_COL_GENRE, FALSE);
	rb_entry_view_append_column (dialog->priv->entry_view, RB_ENTRY_VIEW_COL_ARTIST, FALSE);
	rb_entry_view_append_column (dialog->priv->entry_view, RB_ENTRY_VIEW_COL_ALBUM, FALSE);
	rb_entry_view_append_column (dialog->priv->entry_view, RB_ENTRY_VIEW_COL_YEAR, FALSE);
	rb_entry_view_append_column (dialog->priv->entry_view, RB_ENTRY_VIEW_COL_DURATION, FALSE);
 	rb_entry_view_append_column (dialog->priv->entry_view, RB_ENTRY_VIEW_COL_QUALITY, FALSE);
	rb_entry_view_append_column (dialog->priv->entry_view, RB_ENTRY_VIEW_COL_PLAY_COUNT, FALSE);
	rb_entry_view_append_column (dialog->priv->entry_view, RB_ENTRY_VIEW_COL_BPM, FALSE);
	rb_entry_view_append_column (dialog->priv->entry_view, RB_ENTRY_VIEW_COL_COMMENT, FALSE);
	rb_entry_view_append_column (dialog->priv->entry_view, RB_ENTRY_VIEW_COL_LOCATION, FALSE);

	settings = g_settings_new ("org.gnome.rhythmbox.sources");
	g_settings_bind (settings, "visible-columns", dialog->priv->entry_view, "visible-columns", G_SETTINGS_BIND_DEFAULT);
	g_object_unref (settings);

	g_signal_connect (dialog->priv->entry_view,
			  "notify::sort-order",
			  G_CALLBACK (sort_changed_cb),
			  dialog);
	rb_entry_view_set_sorting_order (dialog->priv->entry_view, "Album", GTK_SORT_ASCENDING);

	gtk_container_add (GTK_CONTAINER (gtk_builder_get_object (builder, "entry-view-container")),
			   GTK_WIDGET (dialog->priv->entry_view));

	dialog->priv->query_model = rhythmdb_query_model_new_empty (dialog->priv->db);
	rb_entry_view_set_model (dialog->priv->entry_view, dialog->priv->query_model);
	query = rhythmdb_query_parse (dialog->priv->db,
				      RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, dialog->priv->entry_type,
				      RHYTHMDB_QUERY_END);
	rhythmdb_do_full_query_async_parsed (dialog->priv->db, RHYTHMDB_QUERY_RESULTS (dialog->priv->query_model), query);
	rhythmdb_query_free (query);

	g_signal_connect (dialog->priv->query_model, "post-entry-delete", G_CALLBACK (entry_deleted_cb), dialog);
	g_signal_connect (dialog->priv->query_model, "row-inserted", G_CALLBACK (entry_inserted_cb), dialog);

	gtk_container_add (GTK_CONTAINER (dialog), GTK_WIDGET (gtk_builder_get_object (builder, "import-dialog")));

	gtk_widget_show_all (GTK_WIDGET (dialog));
	g_object_unref (builder);
}
Example #13
0
static void
rb_playlist_source_constructed (GObject *object)
{
	GObject *shell_player;
	RBPlaylistSource *source;
	RBShell *shell;
	RhythmDB *db;
	RhythmDBQueryModel *query_model;
	GtkBuilder *builder;
	GSettings *settings;

	RB_CHAIN_GOBJECT_METHOD (rb_playlist_source_parent_class, constructed, object);
	source = RB_PLAYLIST_SOURCE (object);

	g_object_get (source, "shell", &shell, NULL);
	g_object_get (shell,
		      "db", &db,
		      "shell-player", &shell_player,
		      NULL);
	rb_playlist_source_set_db (source, db);
	g_object_unref (db);

	g_object_unref (shell);

	/* store playlist settings using the memory backend
	 * this means the settings path doesn't have to be consistent,
	 * it just has to be unique, so the address of the source object works.
	 * for local playlists, we write the settings into the playlist file on disk
	 * to make them persistent.
	 */
	g_object_get (source, "settings", &settings, NULL);
	if (settings == NULL) {
		char *path;
		path = g_strdup_printf ("/org/gnome/rhythmbox/playlist/%p/", source);
		settings = g_settings_new_with_backend_and_path ("org.gnome.rhythmbox.source",
								 playlist_settings_backend,
								 path);
		g_free (path);

		g_object_set (source, "settings", settings, NULL);
	}

	g_signal_connect (settings, "changed", G_CALLBACK (playlist_settings_changed_cb), source);
	g_object_unref (settings);

	builder = rb_builder_load ("playlist-popup.ui", NULL);
	source->priv->popup = G_MENU (gtk_builder_get_object (builder, "playlist-popup"));
	rb_application_link_shared_menus (RB_APPLICATION (g_application_get_default ()), source->priv->popup);
	g_object_ref (source->priv->popup);
	g_object_unref (builder);

	source->priv->entries = g_hash_table_new_full (rb_refstring_hash, rb_refstring_equal,
						       (GDestroyNotify)rb_refstring_unref, NULL);

	source->priv->songs = rb_entry_view_new (source->priv->db,
						 shell_player,
						 TRUE, TRUE);
	g_object_unref (shell_player);

	g_signal_connect_object (source->priv->songs,
				 "notify::sort-order",
				 G_CALLBACK (rb_playlist_source_songs_sort_order_changed_cb),
				 source, 0);

	query_model = rhythmdb_query_model_new_empty (source->priv->db);
	rb_playlist_source_set_query_model (source, query_model);
	g_object_unref (query_model);

	{
		const char *title = "";
		const char *strings[3] = {0};

		GtkTreeViewColumn *column = gtk_tree_view_column_new ();
		GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();

		g_object_set(renderer,
			     "style", PANGO_STYLE_OBLIQUE,
			     "weight", PANGO_WEIGHT_LIGHT,
			     "xalign", 1.0,
			     NULL);

		gtk_tree_view_column_pack_start (column, renderer, TRUE);

		gtk_tree_view_column_set_resizable (column, TRUE);
		gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);

		strings[0] = title;
		strings[1] = "9999";
		rb_entry_view_set_fixed_column_width (source->priv->songs, column, renderer,
						      strings);
		gtk_tree_view_column_set_cell_data_func (column, renderer,
							 (GtkTreeCellDataFunc)
							 rb_playlist_source_track_cell_data_func,
							 source, NULL);
		rb_entry_view_insert_column_custom (source->priv->songs, column, title,
						    "PlaylistTrack", NULL, 0, NULL, 0);
	}

	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_TRACK_NUMBER, FALSE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_TITLE, TRUE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_GENRE, FALSE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_ARTIST, FALSE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_COMPOSER, FALSE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_ALBUM, FALSE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_YEAR, FALSE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_DURATION, FALSE);
 	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_QUALITY, FALSE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_RATING, FALSE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_PLAY_COUNT, FALSE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_COMMENT, FALSE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_LOCATION, FALSE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_FIRST_SEEN, FALSE);
	rb_entry_view_append_column (source->priv->songs, RB_ENTRY_VIEW_COL_BPM, FALSE);
	rb_entry_view_set_columns_clickable (source->priv->songs, FALSE);

	rb_playlist_source_setup_entry_view (source, source->priv->songs);

	gtk_container_add (GTK_CONTAINER (source), GTK_WIDGET (source->priv->songs));

	gtk_widget_show_all (GTK_WIDGET (source));
}
int
main (int argc, char **argv)
{
	RhythmDB *db;
	RhythmDBEntry *entry, *entry2, *entry3, *entry4;
	GtkTreeModel *main_model;
	GtkTreeIter iter;
	guint testnum = 1;
	query_func qfunc;

	gtk_init (&argc, &argv);
	gdk_threads_init ();
	rb_thread_helpers_init ();
	rb_debug_init (TRUE);

	GDK_THREADS_ENTER ();

	qfunc = rhythmdb_do_full_query;

begin:	

	db = rhythmdb_tree_new ("test");

	/*
	 *  TEST 1: Entry creation with album
	 */
	g_print ("Test %d\n", testnum);
	rhythmdb_write_lock (db);

	entry = create_entry (db, "file:///sin.mp3",
			      "Sin", "Pretty Hate Machine", "Nine Inch Nails", "Rock");
	
	rhythmdb_write_unlock (db);
	g_print ("Test %d\n", testnum);
	
	testnum++;
	/*
	 *  TEST 2: Do a query for all songs, verify our single song is in it
	 */
	g_print ("Test %d\n", testnum);
	rhythmdb_read_lock (db);

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	qfunc (db, main_model,
	       RHYTHMDB_QUERY_PROP_EQUALS,
	       RHYTHMDB_PROP_TYPE, RHYTHMDB_ENTRY_TYPE_IGNORE,
	       RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (gtk_tree_model_get_iter_first (main_model, &iter));
	/* We should only have one entry. */
	g_assert (!gtk_tree_model_iter_next (main_model, &iter));

	VERIFY_META_MODELS ("Pretty Hate Machine", "Nine Inch Nails", "Rock");
	VERIFY_MAIN_MODEL (entry);
	DESTROY_MODELS ();

	rhythmdb_read_unlock (db);
	g_print ("Test %d\n", testnum);

	testnum++;
	/*
	 *  TEST 3: Do a query for songs named "Sin"
	 */
	g_print ("Test %d\n", testnum);
	rhythmdb_read_lock (db);

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TITLE, "Sin",
				RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (gtk_tree_model_get_iter_first (main_model, &iter));
	/* We should only have one entry. */
	g_assert (!gtk_tree_model_iter_next (main_model, &iter));

	VERIFY_META_MODELS ("Pretty Hate Machine", "Nine Inch Nails", "Rock");
	VERIFY_MAIN_MODEL (entry);
	DESTROY_MODELS ();

	rhythmdb_read_unlock (db);
	g_print ("Test %d\n", testnum);

	testnum++;
	/*
	 *  TEST 4: Do a query for songs named "Cow", should be empty
	 */
	g_print ("Test %d\n", testnum);
	rhythmdb_read_lock (db);

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TITLE, "Cow",
				RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (!gtk_tree_model_get_iter_first (main_model, &iter));

	DESTROY_MODELS ();

	rhythmdb_read_unlock (db);
	g_print ("Test %d\n", testnum);

	testnum++;
	/*
	 *  TEST 5
	 *  Do a query for songs named "Cow" and "Sin", should be empty.
	 */
	g_print ("Test %d\n", testnum);
	rhythmdb_read_lock (db);

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TITLE, "Cow",
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TITLE, "Sin",
				RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (!gtk_tree_model_get_iter_first (main_model, &iter));

	DESTROY_MODELS ();
	rhythmdb_read_unlock (db);
	g_print ("Test %d\n", testnum);

	testnum++;
	/*
	 *  TEST 6
	 *  Do a query for songs named "Cow" or "Sin", should have our song.
	 */
	g_print ("Test %d\n", testnum);
	rhythmdb_read_lock (db);

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TITLE, "Cow",
				RHYTHMDB_QUERY_DISJUNCTION,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TITLE, "Sin",
				RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (gtk_tree_model_get_iter_first (main_model, &iter));
	/* We should only have one entry. */
	g_assert (!gtk_tree_model_iter_next (main_model, &iter));

	VERIFY_META_MODELS ("Pretty Hate Machine", "Nine Inch Nails", "Rock");
	VERIFY_MAIN_MODEL (entry);
	DESTROY_MODELS ();

	rhythmdb_read_unlock (db);
	g_print ("Test %d\n", testnum);

	testnum++;
	/*
	 *  TEST 7
	 *  Do a query for songs with Genre "Rock", should have our song.
	 */
	g_print ("Test %d\n", testnum);
	rhythmdb_read_lock (db);

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_GENRE, "Rock",
				RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (gtk_tree_model_get_iter_first (main_model, &iter));
	/* We should only have one entry. */
	g_assert (!gtk_tree_model_iter_next (main_model, &iter));

	VERIFY_META_MODELS ("Pretty Hate Machine", "Nine Inch Nails", "Rock");
	VERIFY_MAIN_MODEL (entry);
	DESTROY_MODELS ();

	rhythmdb_read_unlock (db);
	g_print ("Test %d\n", testnum);

	testnum++;
	/*
	 *  TEST 8
	 *  Do a query for songs with Genre "Nine Inch Nails",
	 *  should be empty.
	 */
	g_print ("Test %d\n", testnum);
	rhythmdb_read_lock (db);

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_GENRE, "Nine Inch Nails",
				RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (!gtk_tree_model_get_iter_first (main_model, &iter));

	DESTROY_MODELS ();

	rhythmdb_read_unlock (db);
	g_print ("Test %d\n", testnum);
	
	testnum++;
	/*
	 *  TEST 9
	 *  Do a query for songs with album "Pretty Hate Machine",
	 *  should have our song.
	 */
	g_print ("Test %d\n", testnum);
	rhythmdb_read_lock (db);

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_ALBUM, "Pretty Hate Machine",
				RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (gtk_tree_model_get_iter_first (main_model, &iter));
	/* We should only have one entry. */
	g_assert (!gtk_tree_model_iter_next (main_model, &iter));

	VERIFY_META_MODELS ("Pretty Hate Machine", "Nine Inch Nails", "Rock");
	VERIFY_MAIN_MODEL (entry);
	DESTROY_MODELS ();

	rhythmdb_read_unlock (db);
	g_print ("Test %d\n", testnum);

	testnum++;
	/*
	 *  TEST 10
	 *  Do a query for songs with artist "Nine Inch Nails",
	 *  should have our song.
	 */
	g_print ("Test %d\n", testnum);
	rhythmdb_read_lock (db);

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_ARTIST, "Nine Inch Nails",
				RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (gtk_tree_model_get_iter_first (main_model, &iter));
	/* We should only have one entry. */
	g_assert (!gtk_tree_model_iter_next (main_model, &iter));

	VERIFY_META_MODELS ("Pretty Hate Machine", "Nine Inch Nails", "Rock");
	VERIFY_MAIN_MODEL (entry);
	DESTROY_MODELS ();

	rhythmdb_read_unlock (db);
	g_print ("Test %d\n", testnum);

	testnum++;
	g_print ("Test %d\n", testnum);
	rhythmdb_write_lock (db);

	entry2 = create_entry (db, "file:///head like a hole.mp3",
			       "Head Like A Hole", "Pretty Hate Machine",
			       "Nine Inch Nails", "Rock");

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_ARTIST, "Nine Inch Nails",
				RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (gtk_tree_model_get_iter_first (main_model, &iter));
	g_assert (gtk_tree_model_iter_next (main_model, &iter));
	g_assert (!gtk_tree_model_iter_next (main_model, &iter));

	VERIFY_META_MODELS ("Pretty Hate Machine", "Nine Inch Nails", "Rock");
	VERIFY_MAIN_MODEL (entry);
	VERIFY_MAIN_MODEL (entry2);
	DESTROY_MODELS ();
	
	rhythmdb_write_unlock (db);
	g_print ("Test %d\n", testnum);

	testnum++;
	g_print ("Test %d\n", testnum);
	rhythmdb_write_lock (db);

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_ALBUM, "Pretty Hate Machine",
				RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (gtk_tree_model_get_iter_first (main_model, &iter));
	g_assert (gtk_tree_model_iter_next (main_model, &iter));
	g_assert (!gtk_tree_model_iter_next (main_model, &iter));

	VERIFY_META_MODELS ("Pretty Hate Machine", "Nine Inch Nails", "Rock");
	VERIFY_MAIN_MODEL (entry);
	VERIFY_MAIN_MODEL (entry2);
	DESTROY_MODELS ();
	
	rhythmdb_write_unlock (db);
	g_print ("Test %d\n", testnum);

	testnum++;
	g_print ("Test %d\n", testnum);
	rhythmdb_write_lock (db);

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_GENRE, "Rock",
				RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (gtk_tree_model_get_iter_first (main_model, &iter));
	g_assert (gtk_tree_model_iter_next (main_model, &iter));
	g_assert (!gtk_tree_model_iter_next (main_model, &iter));

	VERIFY_META_MODELS ("Pretty Hate Machine", "Nine Inch Nails", "Rock");
	VERIFY_MAIN_MODEL (entry);
	VERIFY_MAIN_MODEL (entry2);
	DESTROY_MODELS ();
	
	rhythmdb_write_unlock (db);
	g_print ("Test %d\n", testnum);

	g_print ("Test %d\n", testnum);
	rhythmdb_write_lock (db);

	entry3 = create_entry (db, "file:///angel.ogg",
			       "Angel", "Mezzanine", "Massive Attack", "Electronica");

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_GENRE, "Electronica",
				RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (gtk_tree_model_get_iter_first (main_model, &iter));
	g_assert (!gtk_tree_model_iter_next (main_model, &iter));

	VERIFY_META_MODELS ("Mezzanine", "Massive Attack", "Electronica");
	VERIFY_MAIN_MODEL (entry3);
	DESTROY_MODELS ();
	
	rhythmdb_write_unlock (db);
	g_print ("Test %d\n", testnum);

	testnum++;
	g_print ("Test %d\n", testnum);
	rhythmdb_write_lock (db);

	entry4 = create_entry (db, "file:///killa bees.ogg",
			       "Killa Bees", "Armageddon", "Usual Suspects", "Drum N' Bass");

	main_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
	rhythmdb_do_full_query (db, main_model,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TITLE, "Angel",
				RHYTHMDB_QUERY_DISJUNCTION,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TITLE, "Sin",
				RHYTHMDB_QUERY_DISJUNCTION,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TITLE, "Head Like A Hole",
				RHYTHMDB_QUERY_DISJUNCTION,
				RHYTHMDB_QUERY_PROP_EQUALS,
				RHYTHMDB_PROP_TITLE, "Killa Bees",
				RHYTHMDB_QUERY_END);
	wait_for_model_completion (RHYTHMDB_QUERY_MODEL (main_model));

	g_assert (gtk_tree_model_get_iter_first (main_model, &iter));
	g_assert (gtk_tree_model_iter_next (main_model, &iter));
	g_assert (gtk_tree_model_iter_next (main_model, &iter));
	g_assert (gtk_tree_model_iter_next (main_model, &iter));
	g_assert (!gtk_tree_model_iter_next (main_model, &iter));

	VERIFY_META_MODELS ("Mezzanine", "Massive Attack", "Electronica");
	VERIFY_META_MODELS ("Armageddon", "Usual Suspects", "Drum N' Bass");
	VERIFY_META_MODELS ("Pretty Hate Machine", "Nine Inch Nails", "Rock");
	VERIFY_MAIN_MODEL (entry);
	VERIFY_MAIN_MODEL (entry2);
	VERIFY_MAIN_MODEL (entry3);
	VERIFY_MAIN_MODEL (entry4);
	DESTROY_MODELS ();
	
	rhythmdb_write_unlock (db);
	g_print ("Test %d\n", testnum);

	testnum++;

	if (qfunc == rhythmdb_do_full_query) {
		rhythmdb_shutdown (db);
		g_object_unref (G_OBJECT (db));
		qfunc = rhythmdb_do_full_query_async;
		goto begin;
	}

	/*
	 * THE END
	 */
	rhythmdb_shutdown (db);
	g_object_unref (G_OBJECT (db));
	GDK_THREADS_LEAVE ();
	
	exit (0);
}
static void
rb_iradio_source_do_query (RBIRadioSource *source)
{
	RhythmDBQueryModel *genre_query_model = NULL;
	RhythmDBQueryModel *station_query_model = NULL;
	RhythmDBPropertyModel *genre_model;
	GPtrArray *query;
	RhythmDBEntryType *entry_type;

	/* don't update the selection while we're rebuilding the query */
	source->priv->setting_new_query = TRUE;

	/* construct and run the query for the search box.
	 * this is used as the model for the genre view.
	 */

	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_END);
	g_object_unref (entry_type);

	if (source->priv->search_query != NULL) {
		rhythmdb_query_append (source->priv->db,
				       query,
				       RHYTHMDB_QUERY_SUBQUERY,
				       source->priv->search_query,
				       RHYTHMDB_QUERY_END);
	}

	genre_model = rb_property_view_get_model (source->priv->genres);

	genre_query_model = rhythmdb_query_model_new_empty (source->priv->db);
	g_object_set (genre_model, "query-model", genre_query_model, NULL);

	rhythmdb_do_full_query_parsed (source->priv->db,
				       RHYTHMDB_QUERY_RESULTS (genre_query_model),
				       query);

	rhythmdb_query_free (query);
	query = NULL;

	/* check the selected genre is still available, and if not, select 'all' */
	if (source->priv->selected_genre != NULL) {
		GList *sel = NULL;

		if (!rhythmdb_property_model_iter_from_string (genre_model,
							       source->priv->selected_genre,
							       NULL)) {
			g_free (source->priv->selected_genre);
			source->priv->selected_genre = NULL;
		}

		sel = g_list_prepend (sel, source->priv->selected_genre);
		rb_property_view_set_selection (source->priv->genres, sel);
		g_list_free (sel);
	}

	/* if a genre is selected, construct a new query for it, and create
	 * a new model based on the search box query model.  otherwise, just
	 * reuse the search box query model.
	 */

	if (source->priv->selected_genre != NULL) {
		rb_debug ("matching on genre \"%s\"", source->priv->selected_genre);

		station_query_model = rhythmdb_query_model_new_empty (source->priv->db);
		query = rhythmdb_query_parse (source->priv->db,
					      RHYTHMDB_QUERY_PROP_EQUALS,
					      RHYTHMDB_PROP_GENRE,
					      source->priv->selected_genre,
					      RHYTHMDB_QUERY_END);

		g_object_set (station_query_model,
			      "query", query,
			      "base-model", genre_query_model,
			      NULL);

		rhythmdb_query_free (query);
		query = NULL;
	} else {
		station_query_model = g_object_ref (genre_query_model);
	}

	rb_entry_view_set_model (source->priv->stations, station_query_model);
	g_object_set (source, "query-model", station_query_model, NULL);

	g_object_unref (genre_query_model);
	g_object_unref (station_query_model);

	source->priv->setting_new_query = FALSE;
}