void
rb_podcast_main_source_add_subsources (RBPodcastMainSource *source)
{
	RhythmDBQuery *query;
	RBSource *podcast_subsource;
	RBPodcastManager *podcast_mgr;
	RhythmDB *db;
	RBShell *shell;

	g_object_get (source,
		      "shell", &shell,
		      "podcast-manager", &podcast_mgr,
		      NULL);
	g_object_get (shell, "db", &db, NULL);

	query = rhythmdb_query_parse (db,
				      RHYTHMDB_QUERY_PROP_EQUALS,
				      RHYTHMDB_PROP_TYPE,
				      RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
				      RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN,
				      RHYTHMDB_PROP_FIRST_SEEN,
				      3600 * 24 * 7,
				      RHYTHMDB_QUERY_END);

	podcast_subsource = rb_podcast_source_new (shell,
						   podcast_mgr,
						   query,
						   _("New Episodes"),
						   RB_STOCK_AUTO_PLAYLIST);
	rhythmdb_query_free (query);
	rb_source_set_hidden_when_empty (podcast_subsource, TRUE);
	rb_shell_append_source (shell, podcast_subsource, RB_SOURCE (source));

	query = rhythmdb_query_parse (db,
				      RHYTHMDB_QUERY_PROP_EQUALS,
				      RHYTHMDB_PROP_TYPE,
				      RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
				      RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN,
				      RHYTHMDB_PROP_LAST_SEEN,
				      3600 * 24 * 7,
				      RHYTHMDB_QUERY_END);

	podcast_subsource = rb_podcast_source_new (shell,
						   podcast_mgr,
						   query,
						   _("New Downloads"),		/* better name? */
						   RB_STOCK_AUTO_PLAYLIST);
	rhythmdb_query_free (query);
	rb_source_set_hidden_when_empty (podcast_subsource, TRUE);
	rb_shell_append_source (shell, podcast_subsource, RB_SOURCE (source));

	g_object_unref (db);
	g_object_unref (shell);
}
RBSource *
rb_podcast_main_source_new (RBShell *shell, RBPodcastManager *podcast_manager)
{
	RBSource *source;
	RhythmDBQuery *base_query;
	RhythmDB *db;

	g_object_get (shell, "db", &db, NULL);
	base_query = rhythmdb_query_parse (db,
					   RHYTHMDB_QUERY_PROP_EQUALS,
					   RHYTHMDB_PROP_TYPE,
					   RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
					   RHYTHMDB_QUERY_END);
	g_object_unref (db);

	source = RB_SOURCE (g_object_new (RB_TYPE_PODCAST_MAIN_SOURCE,
					  "name", _("Podcasts"),
					  "shell", shell,
					  "entry-type", RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
					  "source-group", RB_SOURCE_GROUP_LIBRARY,
					  "search-type", RB_SOURCE_SEARCH_INCREMENTAL,
					  "podcast-manager", podcast_manager,
					  "base-query", base_query,
					  NULL));

	rhythmdb_query_free (base_query);

	rb_shell_register_entry_type_for_source (shell, source,
						 RHYTHMDB_ENTRY_TYPE_PODCAST_FEED);
	rb_shell_register_entry_type_for_source (shell, source,
						 RHYTHMDB_ENTRY_TYPE_PODCAST_POST);

	return source;
}
static void
rb_static_playlist_source_finalize (GObject *object)
{
	RBStaticPlaylistSourcePrivate *priv = RB_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (object);

	rb_debug ("Finalizing static playlist source %p", object);

	if (priv->search_query != NULL) {
		rhythmdb_query_free (priv->search_query);
		priv->search_query = NULL;
	}

	G_OBJECT_CLASS (rb_static_playlist_source_parent_class)->finalize (object);
}
END_TEST

START_TEST (test_query_creator_load_sort_artist_dec)
{
	RhythmDBQuery *query;

	query = rhythmdb_query_parse (db,
				      RHYTHMDB_QUERY_END);
	query_creator_test_load_query (db,
				       query,
				       RHYTHMDB_QUERY_MODEL_LIMIT_NONE, NULL,
				       "Artist", GTK_SORT_DESCENDING);
	rhythmdb_query_free (query);
}
END_TEST

START_TEST (test_query_creator_load_query_simple)
{
	RhythmDBQuery *query;

	query = rhythmdb_query_parse (db,
				      RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TITLE, "foo",
				      RHYTHMDB_QUERY_END);
	query_creator_test_load_query (db,
				       query,
				       RHYTHMDB_QUERY_MODEL_LIMIT_NONE, NULL,
				       "Title", GTK_SORT_ASCENDING);
	rhythmdb_query_free (query);
}
END_TEST

START_TEST (test_query_creator_load_query_multiple)
{
	RhythmDBQuery *query;

	query = rhythmdb_query_parse (db,
				      RHYTHMDB_QUERY_PROP_LIKE, RHYTHMDB_PROP_ARTIST_FOLDED, "bar",
				      RHYTHMDB_QUERY_PROP_PREFIX, RHYTHMDB_PROP_ARTIST_FOLDED, "bar",
				      RHYTHMDB_QUERY_PROP_LESS, RHYTHMDB_PROP_DURATION, 47,
				      RHYTHMDB_QUERY_END);
	query_creator_test_load_query (db,
				       query,
				       RHYTHMDB_QUERY_MODEL_LIMIT_NONE, NULL,
				       "Title", GTK_SORT_ASCENDING);
	rhythmdb_query_free (query);
}
END_TEST

START_TEST (test_query_creator_load_query_disjunction)
{
	RhythmDBQuery *query;

	query = rhythmdb_query_parse (db,
				      RHYTHMDB_QUERY_PROP_YEAR_EQUALS, RHYTHMDB_PROP_DATE, 729025/*1997*/,
				      RHYTHMDB_QUERY_DISJUNCTION,
				      RHYTHMDB_QUERY_PROP_CURRENT_TIME_WITHIN, RHYTHMDB_PROP_LAST_PLAYED, 500,
				      RHYTHMDB_QUERY_END);
	query_creator_test_load_query (db,
				       query,
				       RHYTHMDB_QUERY_MODEL_LIMIT_NONE, NULL,
				       "Title", GTK_SORT_ASCENDING);
	rhythmdb_query_free (query);
}
Beispiel #8
0
static void
visit_playlist_dirs (RBPspSource *source,
                     GFile *file)
{
    RBShell *shell;
    RhythmDB *db;
    RhythmDBEntryType *entry_type;
    char *playlist_path;
    char *playlist_name;
    RBSource *playlist;
    GPtrArray *query;

    playlist_path = g_file_get_uri (file);		/* or _get_path? */

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

    /* FIXME this isn't good enough, we only need the files directly under the playlist directory,
     * not sub-dirs */
    query = rhythmdb_query_parse (db,
                                  RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, entry_type,
                                  RHYTHMDB_QUERY_PROP_PREFIX, RHYTHMDB_PROP_LOCATION, playlist_path,
                                  RHYTHMDB_QUERY_END);
    g_free (playlist_path);
    g_object_unref (entry_type);

    playlist_name = g_file_get_basename (file);
    playlist = rb_auto_playlist_source_new (shell, playlist_name, FALSE);
    g_free (playlist_name);

    rb_auto_playlist_source_set_query (RB_AUTO_PLAYLIST_SOURCE (playlist), query,
                                       RHYTHMDB_QUERY_MODEL_LIMIT_NONE, NULL,
                                       NULL, 0);
    rb_generic_player_source_add_playlist (RB_GENERIC_PLAYER_SOURCE (source), shell, RB_SOURCE (playlist));
    rhythmdb_query_free (query);

    g_object_unref (shell);
    g_object_unref (db);
}
END_TEST

START_TEST (test_query_creator_load_limit_gb)
{
	RhythmDBQuery *query;
	GArray *array;

	query = rhythmdb_query_parse (db,
				      RHYTHMDB_QUERY_END);
	array = g_array_sized_new (FALSE, TRUE, sizeof (GValue), 0);
	g_array_set_clear_func (array, (GDestroyNotify) g_value_unset);
	rb_value_array_append_data (array, G_TYPE_UINT64, (guint64)(14 * 1000));
	query_creator_test_load_query (db,
				       query,
				       RHYTHMDB_QUERY_MODEL_LIMIT_SIZE, array,
				       "Title", GTK_SORT_ASCENDING);
	rhythmdb_query_free (query);
	g_array_unref (array);
}
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
impl_search (RBSource *source, RBSourceSearch *search, const char *cur_text, const char *new_text)
{
	RBStaticPlaylistSourcePrivate *priv = RB_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (source);
	RhythmDB *db;

	if (search == NULL) {
		search = priv->default_search;
	}

	/* replace our search query */
	if (priv->search_query != NULL) {
		rhythmdb_query_free (priv->search_query);
		priv->search_query = NULL;
	}
	db = rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source));
	priv->search_query = rb_source_search_create_query (search, db, new_text);

	rb_static_playlist_source_do_query (RB_STATIC_PLAYLIST_SOURCE (source));
}
static void
impl_reset_filters (RBSource *source)
{
	RBStaticPlaylistSourcePrivate *priv = RB_STATIC_PLAYLIST_SOURCE_GET_PRIVATE (source);
	gboolean changed = FALSE;

	if (rb_library_browser_reset (priv->browser))
		changed = TRUE;

	if (priv->search_query != NULL) {
		changed = TRUE;
		rhythmdb_query_free (priv->search_query);
		priv->search_query = NULL;
	}

	if (changed) {
		rb_static_playlist_source_do_query (RB_STATIC_PLAYLIST_SOURCE (source));
		rb_source_notify_filter_changed (source);
	}
}
static void
rb_iradio_source_dispose (GObject *object)
{
	RBIRadioSource *source;

	source = RB_IRADIO_SOURCE (object);

	if (source->priv->dispose_has_run) {
		/* If dispose did already run, return. */
		return;
	}
	/* Make sure dispose does not run twice. */
	source->priv->dispose_has_run = TRUE;

	if (source->priv->player) {
		g_object_unref (source->priv->player);
		source->priv->player = NULL;
	}

	if (source->priv->db) {
		g_object_unref (source->priv->db);
		source->priv->db = NULL;
	}

	if (source->priv->action_group != NULL) {
		g_object_unref (source->priv->action_group);
		source->priv->action_group = NULL;
	}

	if (source->priv->default_search != NULL) {
		g_object_unref (source->priv->default_search);
		source->priv->default_search = NULL;
	}

	if (source->priv->search_query != NULL) {
		rhythmdb_query_free (source->priv->search_query);
		source->priv->search_query = NULL;
	}

	G_OBJECT_CLASS (rb_iradio_source_parent_class)->dispose (object);
}
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);
}
static void
impl_search (RBSource *asource,
	     RBSourceSearch *search,
	     const char *cur_text,
	     const char *new_text)
{
	RBIRadioSource *source = RB_IRADIO_SOURCE (asource);

	if (source->priv->search_query != NULL) {
		rhythmdb_query_free (source->priv->search_query);
	}

	if (search == NULL) {
		search = source->priv->default_search;
	}
	source->priv->search_query = rb_source_search_create_query (search, source->priv->db, new_text);

	rb_iradio_source_do_query (source);

	rb_source_notify_filter_changed (RB_SOURCE (source));
}
RBSource *
rb_podcast_main_source_new (RBShell *shell, RBPodcastManager *podcast_manager)
{
	RBSource *source;
	RhythmDBQuery *base_query;
	RhythmDB *db;
	GSettings *settings;

	g_object_get (shell, "db", &db, NULL);
	base_query = rhythmdb_query_parse (db,
					   RHYTHMDB_QUERY_PROP_EQUALS,
					   RHYTHMDB_PROP_TYPE,
					   RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
					   RHYTHMDB_QUERY_END);
	g_object_unref (db);

	settings = g_settings_new (PODCAST_SETTINGS_SCHEMA);

	source = RB_SOURCE (g_object_new (RB_TYPE_PODCAST_MAIN_SOURCE,
					  "name", _("Podcasts"),
					  "shell", shell,
					  "entry-type", RHYTHMDB_ENTRY_TYPE_PODCAST_POST,
					  "podcast-manager", podcast_manager,
					  "base-query", base_query,
					  "settings", g_settings_get_child (settings, "source"),
					  "toolbar-path", "/PodcastSourceToolBar",
					  "show-all-feeds", TRUE,
					  NULL));
	g_object_unref (settings);

	rhythmdb_query_free (base_query);

	rb_shell_register_entry_type_for_source (shell, source,
						 RHYTHMDB_ENTRY_TYPE_PODCAST_FEED);
	rb_shell_register_entry_type_for_source (shell, source,
						 RHYTHMDB_ENTRY_TYPE_PODCAST_POST);

	return source;
}
Beispiel #17
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);
}
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;
}
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);
}
Beispiel #20
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);
}
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 ();
}
static void
query_creator_test_load_query (RhythmDB *db,
			       RhythmDBQuery *query,
			       RhythmDBQueryModelLimitType limit_type,
			       GArray *limit_value,
			       const char *sort_column,
			       gint sort_direction)
{
	GtkWidget *creator;
	RhythmDBQuery *squery;
	RhythmDBQuery *query2 = NULL;
	GArray *limit_value2 = NULL;
	const char *sort_column2 = NULL;
	RhythmDBQueryModelLimitType limit_type2;
	gint sort_direction2;
	char *str1, *str2;

	squery = rhythmdb_query_parse (db,
				       RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, RHYTHMDB_ENTRY_TYPE_SONG,
				       RHYTHMDB_QUERY_SUBQUERY, query,
				       RHYTHMDB_QUERY_END);

	creator = rb_query_creator_new_from_query (db,
						   squery,
						   limit_type, limit_value,
						   sort_column, sort_direction);
	
	str1 = rhythmdb_query_to_string (db, squery);
	fail_unless (creator != NULL,
		     "could not create query editor for %s", str1);

	/* check queries */
	query2 = rb_query_creator_get_query (RB_QUERY_CREATOR (creator));
	str2 = rhythmdb_query_to_string (db, query2);
	fail_unless (rhythmdb_query_equal (squery, query2),
		     "queries differ: %s; %s", str1, str2);
	rhythmdb_query_free (query2);
	g_free (str2);
	g_free (str1);

	/* check limits */
	rb_query_creator_get_limit (RB_QUERY_CREATOR (creator),
				    &limit_type2, &limit_value2);
	str1 = rb_gvalue_array_to_string (limit_value);
	str2 = rb_gvalue_array_to_string (limit_value2);
	fail_unless (limit_type == limit_type2,
		     "limit types differ: %d; %d", limit_type, limit_type2);
	fail_unless (rb_value_array_equal (limit_value, limit_value2),
		     "limit values differ: %s; %s", str1, str2);
	g_free (str2);
	g_free (str1);
	if (limit_value2)
		g_array_unref (limit_value2);

	/* check sorting */
	rb_query_creator_get_sort_order (RB_QUERY_CREATOR (creator),
					 &sort_column2, &sort_direction2);
	fail_unless (strcmp (sort_column2, sort_column) == 0,
		     "sort columns differ: %s; %s", sort_column, sort_column2);
	fail_unless (sort_direction2 == sort_direction,
		     "sort directions differ: %d; %d", sort_direction, sort_direction2);

	rhythmdb_query_free (squery);
	gtk_widget_destroy (creator);
}
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);
}
static void
rb_missing_files_source_constructed (GObject *object)
{
	GObject *shell_player;
	RBMissingFilesSource *source;
	RBShell *shell;
	GPtrArray *query;
	RhythmDBQueryModel *model;
	RhythmDBEntryType *entry_type;

	RB_CHAIN_GOBJECT_METHOD (rb_missing_files_source_parent_class, constructed, object);
	source = RB_MISSING_FILES_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_PROP_EQUALS,
				      	RHYTHMDB_PROP_HIDDEN,
					TRUE,
				      RHYTHMDB_QUERY_END);
	g_object_unref (entry_type);

	model = rhythmdb_query_model_new (source->priv->db, query,
					  NULL, NULL, NULL, FALSE);

	rhythmdb_query_free (query);

	g_object_set (model, "show-hidden", TRUE, NULL);

	/* 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_TRACK_NUMBER, FALSE);
	rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_TITLE, TRUE);
/*	rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_GENRE, FALSE); */
	rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_ARTIST, FALSE);
	rb_entry_view_append_column (source->priv->view, RB_ENTRY_VIEW_COL_ALBUM, FALSE);
	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_LAST_SEEN, TRUE);

	rb_entry_view_set_columns_clickable (source->priv->view, TRUE);

	gtk_container_add (GTK_CONTAINER (source), GTK_WIDGET (source->priv->view));
	g_signal_connect_object (source->priv->view, "show_popup",
				 G_CALLBACK (rb_missing_files_source_songs_show_popup_cb), source, 0);
	g_signal_connect_object (source->priv->view, "sort-order-changed",
				 G_CALLBACK (rb_missing_files_source_songs_sort_order_changed_cb), source, 0);

	gtk_widget_show_all (GTK_WIDGET (source));

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