hythmbox-2.98/plugins/audiocd/rb-audiocd-source.c

Location Tool Test ID Function Issue
rb-audiocd-source.c:794:2 clang-analyzer Value stored to 'l' is never read
   1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
   2  *
   3  *  Copyright (C) 2005-2006 James Livingston  <doclivingston@gmail.com>
   4  *
   5  *  This program is free software; you can redistribute it and/or modify
   6  *  it under the terms of the GNU General Public License as published by
   7  *  the Free Software Foundation; either version 2 of the License, or
   8  *  (at your option) any later version.
   9  *
  10  *  The Rhythmbox authors hereby grant permission for non-GPL compatible
  11  *  GStreamer plugins to be used and distributed together with GStreamer
  12  *  and Rhythmbox. This permission is above and beyond the permissions granted
  13  *  by the GPL license by which Rhythmbox is covered. If you modify this code
  14  *  you may extend this exception to your version of the code, but you are not
  15  *  obligated to do so. If you do not wish to do so, delete this exception
  16  *  statement from your version.
  17  *
  18  *  This program is distributed in the hope that it will be useful,
  19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21  *  GNU General Public License for more details.
  22  *
  23  *  You should have received a copy of the GNU General Public License
  24  *  along with this program; if not, write to the Free Software
  25  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
  26  *
  27  */
  28 
  29 #include "config.h"
  30 
  31 #include <string.h>
  32 
  33 #include <gtk/gtk.h>
  34 #include <glib/gi18n.h>
  35 #include <gst/gst.h>
  36 
  37 #include "rhythmdb.h"
  38 #include "rb-shell.h"
  39 #include "rb-audiocd-source.h"
  40 #include "rb-device-source.h"
  41 #include "rb-util.h"
  42 #include "rb-debug.h"
  43 #include "rb-dialog.h"
  44 #include "rb-builder-helpers.h"
  45 #include "rb-file-helpers.h"
  46 #include "rb-source-toolbar.h"
  47 #include "rb-shell-player.h"
  48 #include "rb-audiocd-info.h"
  49 #include "rb-musicbrainz-lookup.h"
  50 
  51 enum
  52 {
  53 	PROP_0,
  54 	PROP_VOLUME,
  55 };
  56 
  57 static void rb_audiocd_source_dispose (GObject *object);
  58 static void rb_audiocd_source_finalize (GObject *object);
  59 static void rb_audiocd_source_constructed (GObject *object);
  60 static void rb_audiocd_device_source_init (RBDeviceSourceInterface *interface);
  61 static void impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
  62 static void impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
  63 
  64 static gboolean impl_show_popup (RBDisplayPage *page);
  65 static void impl_delete_thyself (RBDisplayPage *page);
  66 
  67 static guint impl_want_uri (RBSource *source, const char *uri);
  68 static gboolean impl_uri_is_source (RBSource *source, const char *uri);
  69 static RBEntryView *impl_get_entry_view (RBSource *source);
  70 
  71 static gboolean update_artist_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
  72 static gboolean update_artist_sort_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
  73 static gboolean update_album_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
  74 static gboolean update_genre_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
  75 static gboolean update_year_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
  76 static gboolean update_disc_number_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
  77 
  78 static void rb_audiocd_source_load_disc_info (RBAudioCdSource *source);
  79 static gboolean rb_audiocd_source_load_metadata (RBAudioCdSource *source);
  80 static void reload_metadata_cmd (GtkAction *action, RBAudioCdSource *source);
  81 static void copy_tracks_cmd (GtkAction *action, RBAudioCdSource *source);
  82 
  83 static void extract_cell_data_func (GtkTreeViewColumn *column,
  84 				    GtkCellRenderer *renderer,
  85 				    GtkTreeModel *model,
  86 				    GtkTreeIter *iter,
  87 				    RBAudioCdSource *source);
  88 static void extract_toggled_cb (GtkCellRendererToggle *renderer,
  89 				char *path,
  90 				RBAudioCdSource *source);
  91 static void extract_column_clicked_cb (GtkTreeViewColumn *column,
  92 				       RBAudioCdSource *source);
  93 
  94 typedef struct
  95 {
  96 	gboolean extract;
  97 } RBAudioCDEntryData;
  98 
  99 struct _RBAudioCdSourcePrivate
 100 {
 101 	GVolume *volume;
 102 
 103 	gchar *device_path;
 104 	RBAudioCDInfo *disc_info;
 105 	RBMusicBrainzData *mb_data;
 106 	GList *releases;
 107 	GList *tracks;
 108 
 109 	GCancellable *cancel_disc_info;
 110 	GtkWidget *infogrid;
 111 	GtkWidget *info_bar;
 112 
 113 	RBEntryView *entry_view;
 114 	GtkWidget *artist_entry;
 115 	GtkWidget *artist_sort_entry;
 116 	GtkWidget *album_entry;
 117 	GtkWidget *year_entry;
 118 	GtkWidget *genre_entry;
 119 	GtkWidget *disc_number_entry;
 120 
 121 	GtkActionGroup *action_group;
 122 };
 123 
 124 G_DEFINE_DYNAMIC_TYPE_EXTENDED (
 125 	RBAudioCdSource,
 126 	rb_audiocd_source,
 127 	RB_TYPE_SOURCE,
 128 	0,
 129 	G_IMPLEMENT_INTERFACE_DYNAMIC (RB_TYPE_DEVICE_SOURCE,
 130 				       rb_audiocd_device_source_init))
 131 
 132 
 133 /* entry type */
 134 typedef struct _RhythmDBEntryType RBAudioCdEntryType;
 135 typedef struct _RhythmDBEntryTypeClass RBAudioCdEntryTypeClass;
 136 
 137 GType rb_audiocd_entry_type_get_type (void);
 138 
 139 G_DEFINE_DYNAMIC_TYPE (RBAudioCdEntryType, rb_audiocd_entry_type, RHYTHMDB_TYPE_ENTRY_TYPE);
 140 
 141 static GtkActionEntry rb_audiocd_source_actions[] = {
 142 	{ "AudioCdCopyTracks", GTK_STOCK_CDROM, N_("_Extract to Library"), NULL,
 143 	  N_("Copy tracks to the library"),
 144 	  G_CALLBACK (copy_tracks_cmd) },
 145 	{ "AudioCdSourceReloadMetadata", GTK_STOCK_REFRESH, N_("Reload"), NULL,
 146 	N_("Reload Album Information"),
 147 	G_CALLBACK (reload_metadata_cmd) },
 148 };
 149 
 150 static void
 151 rb_audiocd_entry_type_class_init (RBAudioCdEntryTypeClass *klass)
 152 {
 153 	RhythmDBEntryTypeClass *etype_class = RHYTHMDB_ENTRY_TYPE_CLASS (klass);
 154 	etype_class->can_sync_metadata = (RhythmDBEntryTypeBooleanFunc) rb_true_function;
 155 	etype_class->sync_metadata = (RhythmDBEntryTypeSyncFunc) rb_null_function;
 156 }
 157 
 158 static void
 159 rb_audiocd_entry_type_class_finalize (RBAudioCdEntryTypeClass *klass)
 160 {
 161 }
 162 
 163 static void
 164 rb_audiocd_entry_type_init (RBAudioCdEntryType *etype)
 165 {
 166 }
 167 
 168 static RhythmDB *
 169 get_db_for_source (RBAudioCdSource *source)
 170 {
 171 	RBShell *shell;
 172 	RhythmDB *db;
 173 
 174 	g_object_get (source, "shell", &shell, NULL);
 175 	g_object_get (shell, "db", &db, NULL);
 176 	g_object_unref (shell);
 177 
 178 	return db;
 179 }
 180 
 181 static void
 182 rb_audiocd_device_source_init (RBDeviceSourceInterface *interface)
 183 {
 184 	/* nothing, the default implementations are fine */
 185 }
 186 
 187 static void
 188 rb_audiocd_source_class_init (RBAudioCdSourceClass *klass)
 189 {
 190 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 191 	RBDisplayPageClass *page_class = RB_DISPLAY_PAGE_CLASS (klass);
 192 	RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
 193 
 194 	object_class->constructed = rb_audiocd_source_constructed;
 195 	object_class->dispose = rb_audiocd_source_dispose;
 196 	object_class->finalize = rb_audiocd_source_finalize;
 197 	object_class->set_property = impl_set_property;
 198 	object_class->get_property = impl_get_property;
 199 
 200 	page_class->show_popup = impl_show_popup;
 201 	page_class->delete_thyself = impl_delete_thyself;
 202 
 203 	source_class->impl_can_paste = (RBSourceFeatureFunc) rb_false_function;
 204 	source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
 205 	source_class->impl_can_copy = (RBSourceFeatureFunc) rb_true_function;
 206 
 207 	source_class->impl_get_entry_view = impl_get_entry_view;
 208 	source_class->impl_uri_is_source = impl_uri_is_source;
 209 	source_class->impl_try_playlist = (RBSourceFeatureFunc) rb_true_function;	/* shouldn't need this. */
 210 	source_class->impl_want_uri = impl_want_uri;
 211 
 212 	g_object_class_install_property (object_class,
 213 					 PROP_VOLUME,
 214 					 g_param_spec_object ("volume",
 215 							      "volume",
 216 							      "volume",
 217 							      G_TYPE_VOLUME,
 218 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 219 	g_type_class_add_private (klass, sizeof (RBAudioCdSourcePrivate));
 220 }
 221 
 222 static void
 223 rb_audiocd_source_class_finalize (RBAudioCdSourceClass *klass)
 224 {
 225 }
 226 
 227 static void
 228 rb_audiocd_source_init (RBAudioCdSource *source)
 229 {
 230 	source->priv = G_TYPE_INSTANCE_GET_PRIVATE (source,
 231 						    RB_TYPE_AUDIOCD_SOURCE,
 232 						    RBAudioCdSourcePrivate);
 233 }
 234 
 235 static void
 236 rb_audiocd_source_finalize (GObject *object)
 237 {
 238 	RBAudioCdSource *source = RB_AUDIOCD_SOURCE (object);
 239 
 240 	g_free (source->priv->device_path);
 241 
 242 	if (source->priv->tracks) {
 243 		g_list_free (source->priv->tracks);
 244 	}
 245 
 246 	if (source->priv->disc_info) {
 247 		rb_audiocd_info_free (source->priv->disc_info);
 248 	}
 249 	if (source->priv->mb_data) {
 250 		rb_musicbrainz_data_free (source->priv->mb_data);
 251 	}
 252 
 253 	G_OBJECT_CLASS (rb_audiocd_source_parent_class)->finalize (object);
 254 }
 255 
 256 static void
 257 rb_audiocd_source_dispose (GObject *object)
 258 {
 259 	RBAudioCdSource *source = RB_AUDIOCD_SOURCE (object);
 260 
 261 	if (source->priv->action_group != NULL) {
 262 		g_object_unref (source->priv->action_group);
 263 		source->priv->action_group = NULL;
 264 	}
 265 
 266 	G_OBJECT_CLASS (rb_audiocd_source_parent_class)->dispose (object);
 267 }
 268 
 269 static inline void
 270 force_no_spacing (GtkWidget *widget)
 271 {
 272 	static GtkCssProvider *provider = NULL;
 273 
 274 	if (provider == NULL) {
 275 		const char *style =
 276 			"GtkCheckButton {\n"
 277 			"	-GtkCheckButton-indicator-spacing: 0\n"
 278 			"}\n";
 279 
 280 		provider = gtk_css_provider_new ();
 281 		gtk_css_provider_load_from_data (provider, style, -1, NULL);
 282 	}
 283 
 284 	gtk_style_context_add_provider (gtk_widget_get_style_context (widget),
 285 					GTK_STYLE_PROVIDER (provider),
 286 					GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
 287 }
 288 
 289 static void
 290 sort_order_changed_cb (GObject *object, GParamSpec *pspec, RBAudioCdSource *source)
 291 {
 292 	rb_debug ("sort order changed");
 293 	rb_entry_view_resort_model (RB_ENTRY_VIEW (object));
 294 }
 295 
 296 static void
 297 rb_audiocd_source_constructed (GObject *object)
 298 {
 299 	RBAudioCdSource *source;
 300 	GtkCellRenderer *renderer;
 301 	GtkTreeViewColumn *extract;
 302 	GtkUIManager *ui_manager;
 303 	GtkBuilder *builder;
 304 	GtkWidget *grid;
 305 	GtkWidget *widget;
 306 	GtkAction *action;
 307 	GObject *plugin;
 308 	RBShell *shell;
 309 	RBShellPlayer *shell_player;
 310 	RhythmDB *db;
 311 	RhythmDBQueryModel *query_model;
 312 	RhythmDBQuery *query;
 313 	RhythmDBEntryType *entry_type;
 314 	RBSourceToolbar *toolbar;
 315 	char *ui_file;
 316 	int toggle_width;
 317 
 318 	RB_CHAIN_GOBJECT_METHOD (rb_audiocd_source_parent_class, constructed, object);
 319 	source = RB_AUDIOCD_SOURCE (object);
 320 
 321 	rb_device_source_set_display_details (RB_DEVICE_SOURCE (source));
 322 	source->priv->device_path = g_volume_get_identifier (source->priv->volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
 323 
 324 	g_object_get (source, "shell", &shell, NULL);
 325 	g_object_get (shell,
 326 		      "db", &db,
 327 		      "shell-player", &shell_player,
 328 		      "ui-manager", &ui_manager,
 329 		      NULL);
 330 
 331 	source->priv->action_group =
 332 		_rb_display_page_register_action_group (RB_DISPLAY_PAGE (source),
 333 							"AudioCdActions",
 334 							NULL, 0, NULL);
 335 	_rb_action_group_add_display_page_actions (source->priv->action_group,
 336 						   G_OBJECT (shell),
 337 						   rb_audiocd_source_actions,
 338 						   G_N_ELEMENTS (rb_audiocd_source_actions));
 339 	g_object_unref (shell);
 340 
 341 	action = gtk_action_group_get_action (source->priv->action_group,
 342 					      "AudioCdCopyTracks");
 343 	/* Translators: this is the toolbar button label
 344 	   for Copy to Library action. */
 345 	g_object_set (action, "short-label", _("Extract"), NULL);
 346 
 347 	/* source toolbar */
 348 	toolbar = rb_source_toolbar_new (RB_DISPLAY_PAGE (source), ui_manager);
 349 	g_object_unref (ui_manager);
 350 
 351 	g_object_get (source, "entry-type", &entry_type, NULL);
 352 	query = rhythmdb_query_parse (db,
 353 				      RHYTHMDB_QUERY_PROP_EQUALS,
 354 				      RHYTHMDB_PROP_TYPE,
 355 				      entry_type,
 356 				      RHYTHMDB_QUERY_END);
 357 	g_object_unref (entry_type);
 358 
 359 	query_model = rhythmdb_query_model_new (db,
 360 						query,
 361 						(GCompareDataFunc) rhythmdb_query_model_track_sort_func,
 362 						NULL, NULL, FALSE);
 363 	rhythmdb_do_full_query_parsed (db, RHYTHMDB_QUERY_RESULTS (query_model), query);
 364 	g_object_set (source, "query-model", query_model, NULL);
 365 	rhythmdb_query_free (query);
 366 
 367 	/* we want audio cds to sort by track# by default */
 368 	source->priv->entry_view = rb_entry_view_new (db, G_OBJECT (shell_player), TRUE, FALSE);
 369 	g_signal_connect_object (source->priv->entry_view,
 370 				 "notify::sort-order",
 371 				 G_CALLBACK (sort_order_changed_cb),
 372 				 source, 0);
 373 	rb_entry_view_set_sorting_order (source->priv->entry_view, "Track", GTK_SORT_ASCENDING);
 374 	rb_entry_view_set_model (source->priv->entry_view, query_model);
 375 
 376 	rb_entry_view_append_column (source->priv->entry_view, RB_ENTRY_VIEW_COL_TRACK_NUMBER, TRUE);
 377 	rb_entry_view_append_column (source->priv->entry_view, RB_ENTRY_VIEW_COL_TITLE, TRUE);
 378 	rb_entry_view_append_column (source->priv->entry_view, RB_ENTRY_VIEW_COL_ARTIST, TRUE);
 379 	rb_entry_view_append_column (source->priv->entry_view, RB_ENTRY_VIEW_COL_GENRE, FALSE);
 380 	rb_entry_view_append_column (source->priv->entry_view, RB_ENTRY_VIEW_COL_DURATION, FALSE);
 381 
 382 	/* enable in-place editing for titles, artists, and genres */
 383 	rb_entry_view_set_column_editable (source->priv->entry_view, RB_ENTRY_VIEW_COL_TITLE, TRUE);
 384 	rb_entry_view_set_column_editable (source->priv->entry_view, RB_ENTRY_VIEW_COL_ARTIST, TRUE);
 385 	rb_entry_view_set_column_editable (source->priv->entry_view, RB_ENTRY_VIEW_COL_GENRE, TRUE);
 386 
 387 	/* create the 'extract' column */
 388 	renderer = gtk_cell_renderer_toggle_new ();
 389 	extract = gtk_tree_view_column_new ();
 390 	gtk_tree_view_column_pack_start (extract, renderer, FALSE);
 391 	gtk_tree_view_column_set_cell_data_func (extract,
 392 						 renderer,
 393 						 (GtkTreeCellDataFunc) extract_cell_data_func,
 394 						 source,
 395 						 NULL);
 396 	gtk_tree_view_column_set_clickable (extract, TRUE);
 397 	widget = gtk_check_button_new ();
 398 	g_object_set (widget, "active", TRUE, NULL);
 399 	force_no_spacing (widget);
 400 	gtk_widget_show_all (widget);
 401 	g_signal_connect_object (extract, "clicked", G_CALLBACK (extract_column_clicked_cb), source, 0);
 402 	gtk_tree_view_column_set_widget (extract, widget);
 403 
 404 	g_signal_connect_object (renderer, "toggled", G_CALLBACK (extract_toggled_cb), source, 0);
 405 
 406 	/* set column width */
 407 	gtk_cell_renderer_get_preferred_width (renderer, GTK_WIDGET (source->priv->entry_view), NULL, &toggle_width);
 408 	gtk_tree_view_column_set_sizing (extract, GTK_TREE_VIEW_COLUMN_FIXED);
 409 	gtk_tree_view_column_set_fixed_width (extract, toggle_width + 10);
 410 
 411 	rb_entry_view_insert_column_custom (source->priv->entry_view, extract, "", "Extract", NULL, NULL, NULL, 1);
 412 	gtk_widget_set_tooltip_text (gtk_tree_view_column_get_widget (extract),
 413 	                             _("Select tracks to be extracted"));
 414 
 415 	/* set up the album info widgets */
 416 	g_object_get (source, "plugin", &plugin, NULL);
 417 	ui_file = rb_find_plugin_data_file (G_OBJECT (plugin), "album-info.ui");
 418 	g_assert (ui_file != NULL);
 419 	g_object_unref (plugin);
 420 
 421 	builder = rb_builder_load (ui_file, NULL);
 422 	g_free (ui_file);
 423 
 424 	source->priv->infogrid = GTK_WIDGET (gtk_builder_get_object (builder, "album_info"));
 425 	g_assert (source->priv->infogrid != NULL);
 426 
 427 	source->priv->artist_entry = GTK_WIDGET (gtk_builder_get_object (builder, "artist_entry"));
 428 	source->priv->artist_sort_entry = GTK_WIDGET (gtk_builder_get_object (builder, "artist_sort_entry"));
 429 	source->priv->album_entry = GTK_WIDGET (gtk_builder_get_object (builder, "album_entry"));
 430 	source->priv->year_entry = GTK_WIDGET (gtk_builder_get_object (builder, "year_entry"));
 431 	source->priv->genre_entry = GTK_WIDGET (gtk_builder_get_object (builder, "genre_entry"));
 432 	source->priv->disc_number_entry = GTK_WIDGET (gtk_builder_get_object (builder, "disc_number_entry"));
 433 
 434 	g_signal_connect_object (source->priv->artist_entry, "focus-out-event", G_CALLBACK (update_artist_cb), source, 0);
 435 	g_signal_connect_object (source->priv->artist_sort_entry, "focus-out-event", G_CALLBACK (update_artist_sort_cb), source, 0);
 436 	g_signal_connect_object (source->priv->album_entry, "focus-out-event", G_CALLBACK (update_album_cb), source, 0);
 437 	g_signal_connect_object (source->priv->genre_entry, "focus-out-event", G_CALLBACK (update_genre_cb), source, 0);
 438 	g_signal_connect_object (source->priv->year_entry, "focus-out-event", G_CALLBACK (update_year_cb), source, 0);
 439 	g_signal_connect_object (source->priv->disc_number_entry, "focus-out-event", G_CALLBACK (update_disc_number_cb), source, 0);
 440 
 441 	grid = gtk_grid_new ();
 442 	gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
 443 	gtk_grid_attach (GTK_GRID (grid), GTK_WIDGET (toolbar), 0, 0, 1, 1);
 444 	gtk_grid_attach (GTK_GRID (grid), source->priv->infogrid, 0, 1, 1, 1);
 445 	gtk_grid_attach (GTK_GRID (grid), GTK_WIDGET (source->priv->entry_view), 0, 2, 1, 1);
 446 	gtk_widget_set_margin_top (GTK_WIDGET (grid), 6);
 447 	g_object_unref (builder);
 448 
 449 	rb_source_bind_settings (RB_SOURCE (source), GTK_WIDGET (source->priv->entry_view), NULL, NULL);
 450 
 451 	gtk_widget_show_all (grid);
 452 	gtk_container_add (GTK_CONTAINER (source), grid);
 453 
 454 	source->priv->cancel_disc_info = g_cancellable_new ();
 455 	rb_audiocd_source_load_disc_info (source);
 456 
 457 	g_object_unref (db);
 458 	g_object_unref (shell_player);
 459 }
 460 
 461 RBSource *
 462 rb_audiocd_source_new (GObject *plugin,
 463 		       RBShell *shell,
 464 		       GVolume *volume)
 465 {
 466 	GObject *source;
 467 	GSettings *settings;
 468 	RhythmDBEntryType *entry_type;
 469 	RhythmDB *db;
 470 	char *name;
 471 	char *path;
 472 
 473 	path = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
 474 	name = g_strdup_printf ("audiocd: %s", path);
 475 	g_free (path);
 476 
 477 	g_object_get (shell, "db", &db, NULL);
 478 	entry_type = g_object_new (rb_audiocd_entry_type_get_type (),
 479 				   "db", db,
 480 				   "name", name,
 481 				   "save-to-disk", FALSE,
 482 				   "category", RHYTHMDB_ENTRY_NORMAL,
 483 				   "type-data-size", sizeof(RBAudioCDEntryData),
 484 				   NULL);
 485 	rhythmdb_register_entry_type (db, entry_type);
 486 	g_object_unref (db);
 487 	g_free (name);
 488 
 489 	settings = g_settings_new ("org.gnome.rhythmbox.plugins.audiocd");
 490 	source = g_object_new (RB_TYPE_AUDIOCD_SOURCE,
 491 			       "entry-type", entry_type,
 492 			       "volume", volume,
 493 			       "shell", shell,
 494 			       "plugin", plugin,
 495 			       "load-status", RB_SOURCE_LOAD_STATUS_LOADING,
 496 			       "show-browser", FALSE,
 497 			       "settings", g_settings_get_child (settings, "source"),
 498 			       "toolbar-path", "/AudioCdSourceToolBar",
 499 			       NULL);
 500 	g_object_unref (settings);
 501 
 502 	rb_shell_register_entry_type_for_source (shell, RB_SOURCE (source), entry_type);
 503 
 504 	return RB_SOURCE (source);
 505 }
 506 
 507 static void
 508 impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
 509 {
 510 	RBAudioCdSource *source = RB_AUDIOCD_SOURCE (object);
 511 
 512 	switch (prop_id) {
 513 	case PROP_VOLUME:
 514 		source->priv->volume = g_value_dup_object (value);
 515 		break;
 516 	default:
 517 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 518 		break;
 519 	}
 520 }
 521 
 522 static void
 523 impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 524 {
 525 	RBAudioCdSource *source = RB_AUDIOCD_SOURCE (object);
 526 
 527 	switch (prop_id) {
 528 	case PROP_VOLUME:
 529 		g_value_set_object (value, source->priv->volume);
 530 		break;
 531 	default:
 532 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 533 		break;
 534 	}
 535 }
 536 
 537 static void
 538 entry_set_string_prop (RhythmDB *db,
 539 		       RhythmDBEntry *entry,
 540 		       RhythmDBPropType propid,
 541 		       gboolean default_to_empty,
 542 		       const char *str)
 543 {
 544 	GValue value = {0,};
 545 
 546 	if (!str) {
 547 		if (default_to_empty) {
 548 			str = "";
 549 		} else {
 550 			str = _("Unknown");
 551 		}
 552 	}
 553 
 554 	if (!g_utf8_validate (str, -1, NULL)) {
 555 		rb_debug ("Got invalid UTF-8 tag data");
 556 		str = _("<Invalid unicode>");
 557 	}
 558 
 559 	g_value_init (&value, G_TYPE_STRING);
 560 	g_value_set_string (&value, str);
 561 	rhythmdb_entry_set (RHYTHMDB (db), entry, propid, &value);
 562 	g_value_unset (&value);
 563 }
 564 
 565 static void
 566 clear_info_bar (RBAudioCdSource *source)
 567 {
 568 	if (source->priv->info_bar != NULL) {
 569 		gtk_widget_hide (source->priv->info_bar);
 570 		gtk_container_remove (GTK_CONTAINER (source->priv->infogrid), source->priv->info_bar);
 571 		source->priv->info_bar = NULL;
 572 	}
 573 }
 574 
 575 static void
 576 show_info_bar (RBAudioCdSource *source, GtkWidget *info_bar)
 577 {
 578 	clear_info_bar (source);
 579 
 580 	gtk_widget_show_all (info_bar);
 581 	gtk_grid_attach (GTK_GRID (source->priv->infogrid), info_bar, 0, 0, 2, 1);
 582 	source->priv->info_bar = info_bar;
 583 }
 584 
 585 
 586 static void
 587 submit_info_bar_response_cb (GtkInfoBar *info_bar, gint response_id, RBAudioCdSource *source)
 588 {
 589 	GError *error = NULL;
 590 
 591 	if (response_id == GTK_RESPONSE_OK) {
 592 		char *submit_url;
 593 
 594 		submit_url = rb_musicbrainz_create_submit_url (
 595 			source->priv->disc_info->musicbrainz_disc_id,
 596 			source->priv->disc_info->musicbrainz_full_disc_id);
 597 
 598 		if (!gtk_show_uri (NULL, submit_url, GDK_CURRENT_TIME, &error)) {
 599 			rb_debug ("Could not launch submit URL %s: %s", submit_url, error->message);
 600 			g_error_free (error);
 601 		}
 602 		g_free (submit_url);
 603 	}
 604 
 605 	clear_info_bar (source);
 606 }
 607 
 608 static void
 609 show_submit_info_bar (RBAudioCdSource *source)
 610 {
 611 	GtkWidget *info_bar;
 612 	GtkWidget *label;
 613 	GtkWidget *box;
 614 	char *message;
 615 
 616 	rb_debug ("showing musicbrainz submit info bar");
 617 
 618 	info_bar = gtk_info_bar_new_with_buttons (_("S_ubmit Album"), GTK_RESPONSE_OK,
 619 						  _("H_ide"), GTK_RESPONSE_CANCEL,
 620 						  NULL);
 621 
 622 	message = g_strdup_printf ("<b>%s</b>\n%s", _("Could not find this album on MusicBrainz."),
 623 				   _("You can improve the MusicBrainz database by adding this album."));
 624 	label = gtk_label_new (NULL);
 625 	gtk_label_set_markup (GTK_LABEL (label), message);
 626 	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
 627 	g_free (message);
 628 
 629 	box = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar));
 630 	gtk_container_add (GTK_CONTAINER (box), label);
 631 
 632 	g_signal_connect (G_OBJECT (info_bar), "response",
 633 			  G_CALLBACK (submit_info_bar_response_cb), source);
 634 	show_info_bar (source, info_bar);
 635 }
 636 
 637 static void
 638 mb_error_info_bar_response_cb (GtkInfoBar *info_bar, gint response_id, RBAudioCdSource *source)
 639 {
 640 	if (response_id == GTK_RESPONSE_OK) {
 641 		rb_audiocd_source_load_metadata (source);
 642 	}
 643 	clear_info_bar (source);
 644 }
 645 
 646 static void
 647 show_lookup_error_info_bar (RBAudioCdSource *source, GError *error)
 648 {
 649 	GtkWidget *info_bar;
 650 	GtkWidget *label;
 651 	GtkWidget *box;
 652 	char *message;
 653 
 654 	rb_debug ("showing musicbrainz error info bar");
 655 
 656 	info_bar = gtk_info_bar_new_with_buttons (_("_Retry"), GTK_RESPONSE_OK,
 657 						  _("H_ide"), GTK_RESPONSE_CANCEL,
 658 						  NULL);
 659 
 660 	message = g_strdup_printf ("<b>%s</b>\n%s", _("Could not search MusicBrainz for album details."),
 661 				   error->message);
 662 	label = gtk_label_new (NULL);
 663 	gtk_label_set_markup (GTK_LABEL (label), message);
 664 	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
 665 	g_free (message);
 666 
 667 	box = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar));
 668 	gtk_container_add (GTK_CONTAINER (box), label);
 669 
 670 	g_signal_connect (G_OBJECT (info_bar), "response",
 671 			  G_CALLBACK (mb_error_info_bar_response_cb), source);
 672 	show_info_bar (source, info_bar);
 673 }
 674 
 675 static void
 676 cd_error_info_bar_response_cb (GtkInfoBar *info_bar, gint response_id, RBAudioCdSource *source)
 677 {
 678 	if (response_id == GTK_RESPONSE_OK) {
 679 		rb_audiocd_source_load_disc_info (source);
 680 	}
 681 	clear_info_bar (source);
 682 }
 683 
 684 static void
 685 show_cd_error_info_bar (RBAudioCdSource *source, GError *error)
 686 {
 687 	GtkWidget *info_bar;
 688 	GtkWidget *label;
 689 	GtkWidget *box;
 690 	char *message;
 691 
 692 	rb_debug ("showing cd read error info bar");
 693 
 694 	info_bar = gtk_info_bar_new_with_buttons (_("_Retry"), GTK_RESPONSE_OK,
 695 						  _("H_ide"), GTK_RESPONSE_CANCEL,
 696 						  NULL);
 697 
 698 	message = g_strdup_printf ("<b>%s</b>\n%s", _("Could not read the CD device."),
 699 				   error->message);
 700 	label = gtk_label_new (NULL);
 701 	gtk_label_set_markup (GTK_LABEL (label), message);
 702 	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
 703 	g_free (message);
 704 
 705 	box = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar));
 706 	gtk_container_add (GTK_CONTAINER (box), label);
 707 
 708 	g_signal_connect (G_OBJECT (info_bar), "response",
 709 			  G_CALLBACK (cd_error_info_bar_response_cb), source);
 710 	show_info_bar (source, info_bar);
 711 }
 712 
 713 
 714 static void
 715 apply_musicbrainz_release (RBAudioCdSource *source, RBMusicBrainzData *release)
 716 {
 717 	RBMusicBrainzData *medium;
 718 	RhythmDB *db;
 719 	GList *l;
 720 	const char *value;
 721 	int disc_num = 0;
 722 	gulong release_date = 0;
 723 	const char *album;
 724 	const char *album_id;
 725 	const char *album_artist;
 726 	const char *album_artist_id;
 727 	const char *album_artist_sortname;
 728 
 729 	medium = rb_musicbrainz_data_find_child (release,
 730 						 "disc-id",
 731 						 source->priv->disc_info->musicbrainz_disc_id);
 732 	g_assert (medium != NULL);
 733 
 734 	/* set album stuff in widgets */
 735 	album = rb_musicbrainz_data_get_attr_value (release, RB_MUSICBRAINZ_ATTR_ALBUM);
 736 	if (album != NULL) {
 737 		rb_debug ("album title: %s", album);
 738 		gtk_entry_set_text (GTK_ENTRY (source->priv->album_entry), album);
 739 		g_object_set (source, "name", album, NULL);
 740 	}
 741 
 742 	album_artist = rb_musicbrainz_data_get_attr_value (release, RB_MUSICBRAINZ_ATTR_ALBUM_ARTIST);
 743 	if (album_artist != NULL) {
 744 		rb_debug ("album artist: %s", album_artist);
 745 		gtk_entry_set_text (GTK_ENTRY (source->priv->artist_entry), album_artist);
 746 	}
 747 
 748 	album_artist_sortname = rb_musicbrainz_data_get_attr_value (release, RB_MUSICBRAINZ_ATTR_ALBUM_ARTIST_SORTNAME);
 749 	if (album_artist_sortname != NULL) {
 750 		rb_debug ("album artist sortname: %s", album_artist_sortname);
 751 		gtk_entry_set_text (GTK_ENTRY (source->priv->artist_sort_entry), album_artist_sortname);
 752 	}
 753 
 754 	value = rb_musicbrainz_data_get_attr_value (release, RB_MUSICBRAINZ_ATTR_DATE);
 755 	if (value != NULL) {
 756 		int year = 1;
 757 		int month = 1;
 758 		int day = 1;
 759 
 760 		if (sscanf (value, "%u-%u-%u", &year, &month, &day) > 0) {
 761 			GDate date;
 762 			char *year_text;
 763 
 764 			year_text = g_strdup_printf ("%d", year);
 765 			gtk_entry_set_text (GTK_ENTRY (source->priv->year_entry), year_text);
 766 			g_free (year_text);
 767 
 768 			g_date_set_dmy (&date,
 769 					(day == 0) ? 1 : day,
 770 					(month == 0) ? 1 : month,
 771 					year);
 772 			release_date = g_date_get_julian (&date);
 773 		} else {
 774 			rb_debug ("unable to parse release date: %s", value);
 775 		}
 776 	}
 777 
 778 	value = rb_musicbrainz_data_get_attr_value (medium, RB_MUSICBRAINZ_ATTR_DISC_NUMBER);
 779 	if (value != NULL) {
 780 		disc_num = strtol (value, NULL, 10);	/* 0 is ok if this fails */
 781 		gtk_entry_set_text (GTK_ENTRY (source->priv->disc_number_entry), value);
 782 		rb_debug ("disc number %d", disc_num);
 783 	}
 784 
 785 	album_id = rb_musicbrainz_data_get_attr_value (release, RB_MUSICBRAINZ_ATTR_ALBUM_ID);
 786 	rb_debug ("musicbrainz_albumid: %s", album_id);
 787 
 788 	album_artist_id = rb_musicbrainz_data_get_attr_value (release, RB_MUSICBRAINZ_ATTR_ALBUM_ARTIST_ID);
 789 	rb_debug ("musicbrainz_albumartistid: %s", album_artist_id);
 790 
 791 	db = get_db_for_source (source);
 792 
 793 	/* apply things to tracks */
 794 	l = rb_musicbrainz_data_get_children (medium);
Value stored to 'l' is never read
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

795 for (l = rb_musicbrainz_data_get_children (medium); l != NULL; l = l->next) { 796 RhythmDBEntry *entry; 797 RBMusicBrainzData *mb_track = l->data; 798 GList *tl; 799 GValue value = {0, }; 800 const char *attr; 801 int mb_track_num; 802 803 attr = rb_musicbrainz_data_get_attr_value (mb_track, RB_MUSICBRAINZ_ATTR_TRACK_NUMBER); 804 rb_debug ("processing musicbrainz track %s", attr); 805 mb_track_num = strtol (attr, 0, 10); 806 807 /* find matching track */ 808 entry = NULL; 809 for (tl = source->priv->tracks; tl != NULL; tl = tl->next) { 810 gulong tn; 811 tn = rhythmdb_entry_get_ulong (tl->data, RHYTHMDB_PROP_TRACK_NUMBER); 812 if (tn == mb_track_num) { 813 entry = tl->data; 814 break; 815 } 816 } 817 818 if (entry == NULL) { 819 g_warning ("couldn't find track entry for musicbrainz track %d", 820 mb_track_num); 821 continue; 822 } 823 824 /* apply release stuff */ 825 entry_set_string_prop (db, entry, RHYTHMDB_PROP_ALBUM, FALSE, album); 826 entry_set_string_prop (db, entry, RHYTHMDB_PROP_MUSICBRAINZ_ALBUMID, TRUE, album_id); 827 entry_set_string_prop (db, entry, RHYTHMDB_PROP_MUSICBRAINZ_ALBUMARTISTID, TRUE, album_artist_id); 828 entry_set_string_prop (db, entry, RHYTHMDB_PROP_ALBUM_ARTIST, TRUE, album_artist); 829 entry_set_string_prop (db, entry, RHYTHMDB_PROP_ALBUM_ARTIST_SORTNAME, TRUE, album_artist_sortname); 830 831 if (release_date != 0) { 832 g_value_init (&value, G_TYPE_ULONG); 833 g_value_set_ulong (&value, release_date); 834 rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_DATE, &value); 835 g_value_unset (&value); 836 } 837 838 /* apply medium stuff */ 839 if (disc_num != 0) { 840 g_value_init (&value, G_TYPE_ULONG); 841 g_value_set_ulong (&value, disc_num); 842 rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_DISC_NUMBER, &value); 843 g_value_unset (&value); 844 } 845 846 /* apply track stuff */ 847 attr = rb_musicbrainz_data_get_attr_value (mb_track, RB_MUSICBRAINZ_ATTR_TITLE); 848 rb_debug ("title: %s", attr); 849 entry_set_string_prop (db, entry, RHYTHMDB_PROP_TITLE, FALSE, attr); 850 851 attr = rb_musicbrainz_data_get_attr_value (mb_track, RB_MUSICBRAINZ_ATTR_TRACK_ID); 852 rb_debug ("musicbrainz track id: %s", attr); 853 entry_set_string_prop (db, entry, RHYTHMDB_PROP_MUSICBRAINZ_TRACKID, TRUE, attr); 854 855 attr = rb_musicbrainz_data_get_attr_value (mb_track, RB_MUSICBRAINZ_ATTR_ARTIST); 856 rb_debug ("artist: %s", attr); 857 entry_set_string_prop (db, entry, RHYTHMDB_PROP_ARTIST, FALSE, attr); 858 859 attr = rb_musicbrainz_data_get_attr_value (mb_track, RB_MUSICBRAINZ_ATTR_ARTIST_SORTNAME); 860 rb_debug ("artist sortname: %s", attr); 861 entry_set_string_prop (db, entry, RHYTHMDB_PROP_ARTIST_SORTNAME, TRUE, attr); 862 863 attr = rb_musicbrainz_data_get_attr_value (mb_track, RB_MUSICBRAINZ_ATTR_ARTIST_ID); 864 rb_debug ("musicbrainz_artistid: %s", attr); 865 entry_set_string_prop (db, entry, RHYTHMDB_PROP_MUSICBRAINZ_ARTISTID, TRUE, attr); 866 } 867 868 rhythmdb_commit (db); 869 870 g_object_unref (db); 871 } 872 873 static void 874 album_combo_changed_cb (GtkWidget *combo, RBAudioCdSource *source) 875 { 876 GList *l; 877 int active; 878 879 active = gtk_combo_box_get_active (GTK_COMBO_BOX (combo)); 880 if (active == -1) 881 return; 882 883 l = g_list_nth (source->priv->releases, active); 884 if (l != NULL) { 885 apply_musicbrainz_release (source, l->data); 886 } 887 } 888 889 static void 890 show_multiple_release_info_bar (RBAudioCdSource *source) 891 { 892 GtkWidget *info_bar; 893 GtkWidget *label; 894 GtkWidget *box; 895 GtkWidget *combo; 896 GList *l; 897 898 rb_debug ("showing musicbrainz multiple release info bar"); 899 900 info_bar = gtk_info_bar_new (); 901 902 label = gtk_label_new (_("This disc matches multiple albums. Select the correct album.")); 903 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); 904 box = gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar)); 905 gtk_container_add (GTK_CONTAINER (box), label); 906 907 combo = gtk_combo_box_text_new (); 908 for (l = source->priv->releases; l != NULL; l = l->next) { 909 const char *artist; 910 const char *album; 911 const char *country; 912 char *text; 913 914 artist = rb_musicbrainz_data_get_attr_value (l->data, RB_MUSICBRAINZ_ATTR_ALBUM_ARTIST); 915 album = rb_musicbrainz_data_get_attr_value (l->data, RB_MUSICBRAINZ_ATTR_ALBUM); 916 country = rb_musicbrainz_data_get_attr_value (l->data, RB_MUSICBRAINZ_ATTR_COUNTRY); 917 text = g_strdup_printf ("%s - %s (%s)", artist, album, country); 918 gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), NULL, text); 919 g_free (text); 920 } 921 922 g_signal_connect (combo, "changed", G_CALLBACK (album_combo_changed_cb), source); 923 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0); 924 925 box = gtk_info_bar_get_action_area (GTK_INFO_BAR (info_bar)); 926 gtk_container_add (GTK_CONTAINER (box), combo); 927 928 show_info_bar (source, info_bar); 929 } 930 931 static void 932 musicbrainz_lookup_cb (GObject *obj, GAsyncResult *result, RBAudioCdSource **source_ptr) 933 { 934 RBAudioCdSource *source; 935 GError *error = NULL; 936 GList *l; 937 938 source = *source_ptr; 939 if (source == NULL) { 940 rb_debug ("cd source was destroyed"); 941 g_free (source_ptr); 942 return; 943 } 944 g_object_remove_weak_pointer (G_OBJECT (source), (gpointer *)source_ptr); 945 g_free (source_ptr); 946 947 if (source->priv->releases != NULL) { 948 g_list_free (source->priv->releases); 949 source->priv->releases = NULL; 950 } 951 if (source->priv->mb_data != NULL) { 952 rb_musicbrainz_data_free (source->priv->mb_data); 953 } 954 955 g_object_set (source, "load-status", RB_SOURCE_LOAD_STATUS_LOADED, NULL); 956 957 source->priv->mb_data = rb_musicbrainz_lookup_finish (result, &error); 958 if (error != NULL) { 959 if (error->domain == G_IO_ERROR && 960 error->code == G_IO_ERROR_CANCELLED) { 961 /* do nothing */ 962 } else if (error->domain == RB_MUSICBRAINZ_ERROR && 963 error->code == RB_MUSICBRAINZ_ERROR_NOT_FOUND) { 964 show_submit_info_bar (source); 965 } else { 966 show_lookup_error_info_bar (source, error); 967 } 968 g_clear_error (&error); 969 return; 970 } 971 972 /* find the release and medium matching the disc id */ 973 l = rb_musicbrainz_data_get_children (source->priv->mb_data); 974 if (l == NULL) { 975 show_submit_info_bar (source); 976 return; 977 } 978 979 for (; l != NULL; l = l->next) { 980 RBMusicBrainzData *m; 981 982 m = rb_musicbrainz_data_find_child (l->data, 983 "disc-id", 984 source->priv->disc_info->musicbrainz_disc_id); 985 if (m == NULL) 986 continue; 987 988 source->priv->releases = g_list_append (source->priv->releases, l->data); 989 } 990 991 if (source->priv->releases == NULL) { 992 show_submit_info_bar (source); 993 } else if (g_list_length (source->priv->releases) > 1) { 994 show_multiple_release_info_bar (source); 995 } else { 996 apply_musicbrainz_release (source, source->priv->releases->data); 997 } 998 } 999 1000 static gboolean 1001 rb_audiocd_source_load_metadata (RBAudioCdSource *source) 1002 { 1003 RBAudioCdSource **source_ptr; 1004 const char *disc_includes[] = { "recordings", "artist-credits", NULL }; 1005 1006 if (source->priv->disc_info->musicbrainz_disc_id == NULL) { 1007 rb_debug ("not doing musicbrainz lookup as we don't have a disc id"); 1008 return FALSE; 1009 } 1010 1011 source_ptr = g_new0 (RBAudioCdSource *, 1); 1012 *source_ptr = source; 1013 g_object_add_weak_pointer (G_OBJECT (source), (gpointer *)source_ptr); 1014 rb_debug ("looking up musicbrainz data for disc %s", 1015 source->priv->disc_info->musicbrainz_disc_id); 1016 rb_musicbrainz_lookup ("discid", 1017 source->priv->disc_info->musicbrainz_disc_id, 1018 disc_includes, 1019 source->priv->cancel_disc_info, 1020 (GAsyncReadyCallback) musicbrainz_lookup_cb, 1021 source_ptr); 1022 return TRUE; 1023 } 1024 1025 static void 1026 reload_metadata_cmd (GtkAction *action, RBAudioCdSource *source) 1027 { 1028 g_return_if_fail (RB_IS_AUDIOCD_SOURCE (source)); 1029 1030 rb_audiocd_source_load_metadata (source); 1031 } 1032 1033 static void 1034 disc_info_cb (GObject *obj, GAsyncResult *result, RBAudioCdSource **source_ptr) 1035 { 1036 RBAudioCdSource *source; 1037 GError *error = NULL; 1038 RhythmDB *db; 1039 int i; 1040 1041 source = *source_ptr; 1042 if (source == NULL) { 1043 rb_debug ("cd source was destroyed"); 1044 g_free (source_ptr); 1045 return; 1046 } 1047 g_object_remove_weak_pointer (G_OBJECT (source), (gpointer *)source_ptr); 1048 g_free (source_ptr); 1049 1050 source->priv->disc_info = rb_audiocd_info_finish (result, &error); 1051 if (error != NULL) { 1052 if (error->domain == G_IO_ERROR && 1053 error->code == G_IO_ERROR_CANCELLED) { 1054 /* do nothing */ 1055 } else { 1056 show_cd_error_info_bar (source, error); 1057 } 1058 g_clear_error (&error); 1059 1060 g_object_set (source, "load-status", RB_SOURCE_LOAD_STATUS_LOADED, NULL); 1061 return; 1062 } 1063 1064 if (source->priv->disc_info->album_artist != NULL) { 1065 gtk_entry_set_text (GTK_ENTRY (source->priv->artist_entry), source->priv->disc_info->album_artist); 1066 } 1067 if (source->priv->disc_info->album != NULL) { 1068 gtk_entry_set_text (GTK_ENTRY (source->priv->album_entry), source->priv->disc_info->album); 1069 g_object_set (source, "name", source->priv->disc_info->album, NULL); 1070 } 1071 if (source->priv->disc_info->genre != NULL) { 1072 gtk_entry_set_text (GTK_ENTRY (source->priv->genre_entry), source->priv->disc_info->genre); 1073 } 1074 1075 db = get_db_for_source (source); 1076 for (i = 0; i < source->priv->disc_info->num_tracks; i++) { 1077 RhythmDBEntry *entry; 1078 char *audio_path; 1079 GValue value = {0, }; 1080 gchar *str; 1081 RhythmDBEntryType *entry_type; 1082 RBAudioCDEntryData *extra_data; 1083 RBAudioCDTrack *track = &source->priv->disc_info->tracks[i]; 1084 1085 /* ignore data tracks */ 1086 if (track->is_audio == FALSE) { 1087 rb_debug ("ignoring non-audio track %d", track->track_num); 1088 continue; 1089 } 1090 1091 audio_path = g_strdup_printf ("cdda://%s#%d", source->priv->disc_info->device, track->track_num); 1092 1093 g_object_get (source, "entry-type", &entry_type, NULL); 1094 rb_debug ("creating entry for track %d from %s", track->track_num, source->priv->disc_info->device); 1095 entry = rhythmdb_entry_new (db, entry_type, audio_path); 1096 g_object_unref (entry_type); 1097 if (entry == NULL) { 1098 g_warning ("unable to create entry %s", audio_path); 1099 g_free (audio_path); 1100 continue; 1101 } 1102 1103 g_value_init (&value, G_TYPE_ULONG); 1104 g_value_set_ulong (&value, track->track_num); 1105 rhythmdb_entry_set (db, entry, 1106 RHYTHMDB_PROP_TRACK_NUMBER, 1107 &value); 1108 g_value_unset (&value); 1109 1110 g_value_init (&value, G_TYPE_STRING); 1111 str = g_strdup_printf (_("Track %u"), track->track_num); 1112 g_value_take_string (&value, str); 1113 rhythmdb_entry_set (db, entry, 1114 RHYTHMDB_PROP_TITLE, 1115 &value); 1116 g_value_unset (&value); 1117 1118 g_value_init (&value, G_TYPE_ULONG); 1119 g_value_set_ulong (&value, track->duration / 1000); 1120 rhythmdb_entry_set (db, entry, 1121 RHYTHMDB_PROP_DURATION, 1122 &value); 1123 g_value_unset (&value); 1124 1125 entry_set_string_prop (db, entry, RHYTHMDB_PROP_ARTIST, FALSE, track->artist); 1126 entry_set_string_prop (db, entry, RHYTHMDB_PROP_TITLE, FALSE, track->title); 1127 entry_set_string_prop (db, entry, RHYTHMDB_PROP_ALBUM, FALSE, source->priv->disc_info->album); 1128 entry_set_string_prop (db, entry, RHYTHMDB_PROP_ALBUM_ARTIST, FALSE, source->priv->disc_info->album_artist); 1129 entry_set_string_prop (db, entry, RHYTHMDB_PROP_GENRE, FALSE, source->priv->disc_info->genre); 1130 entry_set_string_prop (db, entry, RHYTHMDB_PROP_MEDIA_TYPE, TRUE, "audio/x-raw-int"); 1131 1132 extra_data = RHYTHMDB_ENTRY_GET_TYPE_DATA (entry, RBAudioCDEntryData); 1133 extra_data->extract = TRUE; 1134 1135 rhythmdb_commit (db); 1136 g_free (audio_path); 1137 1138 source->priv->tracks = g_list_prepend (source->priv->tracks, entry); 1139 } 1140 1141 g_object_unref (db); 1142 1143 if (rb_audiocd_source_load_metadata (source) == FALSE) { 1144 g_object_set (source, "load-status", RB_SOURCE_LOAD_STATUS_LOADED, NULL); 1145 } 1146 } 1147 1148 static void 1149 rb_audiocd_source_load_disc_info (RBAudioCdSource *source) 1150 { 1151 RBAudioCdSource **source_ptr; 1152 1153 source_ptr = g_new0 (RBAudioCdSource *, 1); 1154 *source_ptr = source; 1155 g_object_add_weak_pointer (G_OBJECT (source), (gpointer *)source_ptr); 1156 rb_audiocd_info_get (source->priv->device_path, 1157 source->priv->cancel_disc_info, 1158 (GAsyncReadyCallback) disc_info_cb, 1159 source_ptr); 1160 } 1161 1162 static void 1163 impl_delete_thyself (RBDisplayPage *page) 1164 { 1165 RhythmDB *db; 1166 RhythmDBEntryType *entry_type; 1167 RBAudioCdSource *source = RB_AUDIOCD_SOURCE (page); 1168 1169 rb_debug ("audio cd ejected"); 1170 1171 if (source->priv->cancel_disc_info) { 1172 g_cancellable_cancel (source->priv->cancel_disc_info); 1173 } 1174 1175 db = get_db_for_source (source); 1176 1177 g_object_get (page, "entry-type", &entry_type, NULL); 1178 rhythmdb_entry_delete_by_type (db, entry_type); 1179 g_object_unref (entry_type); 1180 1181 rhythmdb_commit (db); 1182 g_object_unref (db); 1183 } 1184 1185 gboolean 1186 rb_audiocd_is_mount_audiocd (GMount *mount) 1187 { 1188 gboolean result = FALSE; 1189 char **types; 1190 guint i; 1191 GError *error = NULL; 1192 1193 types = g_mount_guess_content_type_sync (mount, FALSE, NULL, &error); 1194 if (types == NULL) { 1195 rb_debug ("error guessing content type: %s", error->message); 1196 g_clear_error (&error); 1197 } else { 1198 for (i = 0; types[i] != NULL; i++) { 1199 if (g_str_equal (types[i], "x-content/audio-cdda") != FALSE) { 1200 result = TRUE; 1201 break; 1202 } 1203 } 1204 g_strfreev (types); 1205 } 1206 return result; 1207 } 1208 1209 static gboolean 1210 impl_show_popup (RBDisplayPage *page) 1211 { 1212 _rb_display_page_show_popup (page, "/AudioCdSourcePopup"); 1213 return TRUE; 1214 } 1215 1216 static guint 1217 impl_want_uri (RBSource *source, const char *uri) 1218 { 1219 GVolume *volume; 1220 GMount *mount; 1221 GFile *file; 1222 int retval; 1223 1224 retval = 0; 1225 1226 file = g_file_new_for_uri (uri); 1227 if (g_file_has_uri_scheme (file, "cdda") == FALSE) { 1228 g_object_unref (file); 1229 return 0; 1230 } 1231 1232 g_object_get (G_OBJECT (source), 1233 "volume", &volume, 1234 NULL); 1235 if (volume == NULL) 1236 return 0; 1237 1238 mount = g_volume_get_mount (volume); 1239 if (mount) { 1240 GFile *root; 1241 1242 root = g_mount_get_root (mount); 1243 retval = g_file_equal (root, file) ? 100 : 0; 1244 g_object_unref (mount); 1245 g_object_unref (root); 1246 } 1247 g_object_unref (file); 1248 1249 return retval; 1250 } 1251 1252 static RBEntryView * 1253 impl_get_entry_view (RBSource *source) 1254 { 1255 RBAudioCdSource *cdsource = RB_AUDIOCD_SOURCE (source); 1256 return cdsource->priv->entry_view; 1257 } 1258 1259 static gboolean 1260 impl_uri_is_source (RBSource *source, const char *uri) 1261 { 1262 if (impl_want_uri (source, uri) == 100) 1263 return TRUE; 1264 return FALSE; 1265 } 1266 1267 static void 1268 update_tracks (RBAudioCdSource *source, RhythmDBPropType property, GValue *value) 1269 { 1270 RhythmDB *db; 1271 GList *i; 1272 1273 db = get_db_for_source (source); 1274 1275 for (i = source->priv->tracks; i != NULL; i = i->next) { 1276 rhythmdb_entry_set (db, i->data, property, value); 1277 } 1278 1279 rhythmdb_commit (db); 1280 g_object_unref (db); 1281 } 1282 1283 static void 1284 update_tracks_string (RBAudioCdSource *source, RhythmDBPropType property, const char *str) 1285 { 1286 GValue v = {0, }; 1287 g_value_init (&v, G_TYPE_STRING); 1288 g_value_set_string (&v, str); 1289 update_tracks (source, property, &v); 1290 g_value_unset (&v); 1291 } 1292 1293 static gboolean 1294 update_artist_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source) 1295 { 1296 update_tracks_string (source, RHYTHMDB_PROP_ALBUM_ARTIST, gtk_entry_get_text (GTK_ENTRY (widget))); 1297 return FALSE; 1298 } 1299 1300 static gboolean 1301 update_artist_sort_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source) 1302 { 1303 update_tracks_string (source, RHYTHMDB_PROP_ALBUM_ARTIST_SORTNAME, gtk_entry_get_text (GTK_ENTRY (widget))); 1304 return FALSE; 1305 } 1306 1307 static gboolean 1308 update_album_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source) 1309 { 1310 update_tracks_string (source, RHYTHMDB_PROP_ALBUM, gtk_entry_get_text (GTK_ENTRY (widget))); 1311 return FALSE; 1312 } 1313 1314 static gboolean 1315 update_genre_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source) 1316 { 1317 update_tracks_string (source, RHYTHMDB_PROP_GENRE, gtk_entry_get_text (GTK_ENTRY (widget))); 1318 return FALSE; 1319 } 1320 1321 static gboolean 1322 update_year_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source) 1323 { 1324 const char *text; 1325 int year; 1326 GDate date; 1327 GValue v = {0, }; 1328 1329 text = gtk_entry_get_text (GTK_ENTRY (widget)); 1330 if (text[0] == '\0') { 1331 return FALSE; 1332 } 1333 1334 year = strtol (text, NULL, 10); 1335 g_date_clear (&date, 1); 1336 g_date_set_dmy (&date, 1, 1, year); 1337 1338 g_value_init (&v, G_TYPE_ULONG); 1339 g_value_set_ulong (&v, g_date_get_julian (&date)); 1340 update_tracks (source, RHYTHMDB_PROP_DATE, &v); 1341 g_value_unset (&v); 1342 1343 return FALSE; 1344 } 1345 1346 static gboolean 1347 update_disc_number_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source) 1348 { 1349 GValue v = {0, }; 1350 1351 g_value_init (&v, G_TYPE_ULONG); 1352 g_value_set_ulong (&v, strtoul (gtk_entry_get_text (GTK_ENTRY (widget)), NULL, 10)); 1353 update_tracks (source, RHYTHMDB_PROP_DISC_NUMBER, &v); 1354 g_value_unset (&v); 1355 1356 return FALSE; 1357 } 1358 1359 static void 1360 extract_cell_data_func (GtkTreeViewColumn *column, 1361 GtkCellRenderer *renderer, 1362 GtkTreeModel *tree_model, 1363 GtkTreeIter *iter, 1364 RBAudioCdSource *source) 1365 { 1366 RBAudioCDEntryData *extra_data; 1367 RhythmDBEntry *entry; 1368 1369 entry = rhythmdb_query_model_iter_to_entry (RHYTHMDB_QUERY_MODEL (tree_model), iter); 1370 if (entry != NULL) { 1371 extra_data = RHYTHMDB_ENTRY_GET_TYPE_DATA (entry, RBAudioCDEntryData); 1372 gtk_cell_renderer_toggle_set_active (GTK_CELL_RENDERER_TOGGLE (renderer), extra_data->extract); 1373 rhythmdb_entry_unref (entry); 1374 } 1375 } 1376 1377 static void 1378 extract_toggled_cb (GtkCellRendererToggle *renderer, char *path_str, RBAudioCdSource *source) 1379 { 1380 RhythmDBQueryModel *model; 1381 GtkTreePath *path; 1382 GtkTreeIter iter; 1383 1384 g_object_get (source, "query-model", &model, NULL); 1385 1386 path = gtk_tree_path_new_from_string (path_str); 1387 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path)) { 1388 RhythmDBEntry *entry; 1389 1390 entry = rhythmdb_query_model_iter_to_entry (model, &iter); 1391 if (entry != NULL) { 1392 RBAudioCDEntryData *extra_data; 1393 1394 extra_data = RHYTHMDB_ENTRY_GET_TYPE_DATA (entry, RBAudioCDEntryData); 1395 extra_data->extract = !extra_data->extract; 1396 rhythmdb_entry_unref (entry); 1397 1398 gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter); 1399 } 1400 } 1401 gtk_tree_path_free (path); 1402 g_object_unref (model); 1403 } 1404 1405 1406 static gboolean 1407 set_extract (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) 1408 { 1409 RBAudioCDEntryData *extra_data; 1410 RhythmDBEntry *entry; 1411 1412 entry = rhythmdb_query_model_iter_to_entry (RHYTHMDB_QUERY_MODEL (model), 1413 iter); 1414 if (entry != NULL) { 1415 extra_data = RHYTHMDB_ENTRY_GET_TYPE_DATA (entry, RBAudioCDEntryData); 1416 extra_data->extract = GPOINTER_TO_INT (data); 1417 1418 gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, iter); 1419 rhythmdb_entry_unref (entry); 1420 } 1421 return FALSE; 1422 } 1423 1424 static void 1425 extract_column_clicked_cb (GtkTreeViewColumn *column, RBAudioCdSource *source) 1426 { 1427 RhythmDBQueryModel *model; 1428 gboolean extract; 1429 GtkWidget *checkbox; 1430 1431 /* toggle the state of the checkbox in the header */ 1432 checkbox = gtk_tree_view_column_get_widget (column); 1433 1434 g_object_get (checkbox, "active", &extract, NULL); 1435 extract = !extract; 1436 g_object_set (checkbox, "active", extract, NULL); 1437 1438 /* set the extraction state for all tracks to match */ 1439 g_object_get (source, "query-model", &model, NULL); 1440 gtk_tree_model_foreach (GTK_TREE_MODEL (model), set_extract, GINT_TO_POINTER (extract)); 1441 g_object_unref (model); 1442 } 1443 1444 static gboolean 1445 copy_entry (RhythmDBQueryModel *model, 1446 GtkTreePath *path, 1447 GtkTreeIter *iter, 1448 GList **list) 1449 { 1450 RBAudioCDEntryData *extra_data; 1451 RhythmDBEntry *entry; 1452 GList *l; 1453 1454 entry = rhythmdb_query_model_iter_to_entry (model, iter); 1455 extra_data = RHYTHMDB_ENTRY_GET_TYPE_DATA (entry, RBAudioCDEntryData); 1456 if (extra_data->extract) { 1457 rb_debug ("adding track %s to transfer list", 1458 rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); 1459 l = g_list_append (*list, entry); 1460 *list = l; 1461 } else { 1462 rb_debug ("skipping track %s", 1463 rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); 1464 rhythmdb_entry_unref (entry); 1465 } 1466 return FALSE; 1467 } 1468 1469 static void 1470 copy_tracks_cmd (GtkAction *action, RBAudioCdSource *source) 1471 { 1472 RBShell *shell; 1473 RBSource *library; 1474 RhythmDBQueryModel *model; 1475 GList *list = NULL; 1476 1477 g_object_get (source, "shell", &shell, NULL); 1478 g_object_get (shell, "library-source", &library, NULL); 1479 g_object_unref (shell); 1480 1481 g_object_get (source, "query-model", &model, NULL); 1482 1483 gtk_tree_model_foreach (GTK_TREE_MODEL (model), (GtkTreeModelForeachFunc)copy_entry, &list); 1484 if (list != NULL) { 1485 rb_source_paste (library, list); 1486 g_list_free (list); 1487 } 1488 1489 g_object_unref (model); 1490 g_object_unref (library); 1491 } 1492 1493 void 1494 _rb_audiocd_source_register_type (GTypeModule *module) 1495 { 1496 rb_audiocd_source_register_type (module); 1497 rb_audiocd_entry_type_register_type (module); 1498 }