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);
(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 }