[rhythmbox] audiocd: add album info UI, hide 'album' column



commit d7dc14b15febb17315f690b0007bf96fcd72af85
Author: Jonathan Matthew <jonathan d14n org>
Date:   Fri Jun 19 14:26:13 2009 +1000

    audiocd: add album info UI, hide 'album' column
    
    The album info UI is mostly copied from sound-juicer, with the addition
    of the album artist sortname.

 plugins/audiocd/album-info.ui       |  196 +++++++++++++++++++++++++++++++++
 plugins/audiocd/rb-audiocd-source.c |  202 +++++++++++++++++++++++++++++++++--
 2 files changed, 391 insertions(+), 7 deletions(-)
---
diff --git a/plugins/audiocd/album-info.ui b/plugins/audiocd/album-info.ui
new file mode 100644
index 0000000..471f0f3
--- /dev/null
+++ b/plugins/audiocd/album-info.ui
@@ -0,0 +1,196 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- interface-requires gtk+ 2.12 -->
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkTable" id="album_info">
+    <property name="visible">True</property>
+    <property name="border_width">6</property>
+    <property name="n_rows">4</property>
+    <property name="n_columns">2</property>
+    <property name="column_spacing">12</property>
+    <property name="row_spacing">6</property>
+    <child>
+      <object class="GtkLabel" id="album_label">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">A_lbum:</property>
+        <property name="use_markup">True</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">album_entry</property>
+      </object>
+      <packing>
+        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+        <property name="y_options"></property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="artist_label">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">_Artist:</property>
+        <property name="use_markup">True</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">artist_entry</property>
+      </object>
+      <packing>
+        <property name="top_attach">1</property>
+        <property name="bottom_attach">2</property>
+        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+        <property name="y_options"></property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkEntry" id="album_entry">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">&#x25CF;</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHBox" id="hbox1">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">12</property>
+        <child>
+          <object class="GtkEntry" id="genre_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="invisible_char">&#x25CF;</property>
+          </object>
+          <packing>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="year_label">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">_Year:</property>
+            <property name="use_markup">True</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">year_entry</property>
+            <accessibility>
+              <relation type="label-for" target="year_entry"/>
+            </accessibility>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="year_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="max_length">4</property>
+            <property name="invisible_char">&#x25CF;</property>
+            <property name="width_chars">4</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="disc_number_label">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">_Disc:</property>
+            <property name="use_markup">True</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">disc_number_entry</property>
+            <accessibility>
+              <relation type="label-for" target="disc_number_entry"/>
+            </accessibility>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="disc_number_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="invisible_char">&#x25CF;</property>
+            <property name="width_chars">2</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="top_attach">3</property>
+        <property name="bottom_attach">4</property>
+        <property name="x_options">GTK_FILL</property>
+        <property name="y_options">GTK_SHRINK | GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="genre_label">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">_Genre:</property>
+        <property name="use_markup">True</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">genre_entry</property>
+      </object>
+      <packing>
+        <property name="top_attach">3</property>
+        <property name="bottom_attach">4</property>
+        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="artist_sort_label">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">Artist s_ort order:</property>
+        <property name="use_markup">True</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">artist_sort_entry</property>
+      </object>
+      <packing>
+        <property name="top_attach">2</property>
+        <property name="bottom_attach">3</property>
+        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkEntry" id="artist_sort_entry">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">&#x25CF;</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="top_attach">2</property>
+        <property name="bottom_attach">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkEntry" id="artist_entry">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">&#x25CF;</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="top_attach">1</property>
+        <property name="bottom_attach">2</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/plugins/audiocd/rb-audiocd-source.c b/plugins/audiocd/rb-audiocd-source.c
index 1d1de18..b38d585 100644
--- a/plugins/audiocd/rb-audiocd-source.c
+++ b/plugins/audiocd/rb-audiocd-source.c
@@ -63,6 +63,7 @@ enum
 };
 
 static void rb_audiocd_source_dispose (GObject *object);
+static void rb_audiocd_source_finalize (GObject *object);
 static GObject *rb_audiocd_source_constructor (GType type, guint n_construct_properties,
 					        GObjectConstructParam *construct_properties);
 static void impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
@@ -75,10 +76,17 @@ static gboolean impl_uri_is_source (RBSource *source, const char *uri);
 static void impl_delete_thyself (RBSource *source);
 static GList* impl_get_ui_actions (RBSource *source);
 
+static void impl_pack_paned (RBBrowserSource *source, GtkWidget *paned);
+
 static gpointer rb_audiocd_load_songs (RBAudioCdSource *source);
 static void rb_audiocd_load_metadata (RBAudioCdSource *source, RhythmDB *db);
 static void rb_audiocd_load_metadata_cancel (RBAudioCdSource *source);
 
+static gboolean update_album_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
+static gboolean update_genre_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
+static gboolean update_year_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
+static gboolean update_disc_number_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
+
 typedef struct
 {
 	gchar *device_path;
@@ -88,6 +96,14 @@ typedef struct
 	GstElement *cdda;
 	GstElement *fakesink;
 
+	GtkWidget *box;
+	GtkWidget *artist_entry;
+	GtkWidget *artist_sort_entry;
+	GtkWidget *album_entry;
+	GtkWidget *year_entry;
+	GtkWidget *genre_entry;
+	GtkWidget *disc_number_entry;
+
 #ifdef HAVE_SJ_METADATA_GETTER
 	SjMetadataGetter *metadata;
 #endif
@@ -104,9 +120,11 @@ rb_audiocd_source_class_init (RBAudioCdSourceClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
+	RBBrowserSourceClass *browser_source_class = RB_BROWSER_SOURCE_CLASS (klass);
 
 	object_class->constructor = rb_audiocd_source_constructor;
 	object_class->dispose = rb_audiocd_source_dispose;
+	object_class->finalize = rb_audiocd_source_finalize;
 	object_class->set_property = impl_set_property;
 	object_class->get_property = impl_get_property;
 
@@ -123,6 +141,9 @@ rb_audiocd_source_class_init (RBAudioCdSourceClass *klass)
 	source_class->impl_try_playlist = (RBSourceFeatureFunc) rb_true_function;	/* shouldn't need this. */
 	source_class->impl_want_uri = impl_want_uri;
 
+	/* add the browser below the album info section */
+	browser_source_class->impl_pack_paned = impl_pack_paned;
+
 	g_object_class_override_property (object_class,
 					  PROP_SEARCH_TYPE,
 					  "search-type");
@@ -133,11 +154,10 @@ rb_audiocd_source_class_init (RBAudioCdSourceClass *klass)
 static void
 rb_audiocd_source_init (RBAudioCdSource *self)
 {
-
 }
 
 static void
-rb_audiocd_source_dispose (GObject *object)
+rb_audiocd_source_finalize (GObject *object)
 {
 	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (object);
 
@@ -147,6 +167,15 @@ rb_audiocd_source_dispose (GObject *object)
 		g_list_free (priv->tracks);
 		priv->tracks = NULL;
 	}
+
+	G_OBJECT_CLASS (rb_audiocd_source_parent_class)->finalize (object);
+}
+
+static void
+rb_audiocd_source_dispose (GObject *object)
+{
+	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (object);
+
 	if (priv->pipeline) {
 		gst_object_unref (GST_OBJECT (priv->pipeline));
 		priv->pipeline = NULL;
@@ -162,6 +191,8 @@ rb_audiocd_source_constructor (GType type,
 {
 	RBAudioCdSource *source;
 	RBEntryView *entry_view;
+	RBPlugin *plugin;
+	char *ui_file;
 
 	source = RB_AUDIOCD_SOURCE (G_OBJECT_CLASS (rb_audiocd_source_parent_class)->
 			constructor (type, n_construct_properties, construct_properties));
@@ -172,6 +203,46 @@ rb_audiocd_source_constructor (GType type,
 	entry_view = rb_source_get_entry_view (RB_SOURCE (source));
 	rb_entry_view_set_sorting_order (entry_view, "Track", GTK_SORT_ASCENDING);
 
+	/* hide the 'album' column */
+	gtk_tree_view_column_set_visible (rb_entry_view_get_column (entry_view, RB_ENTRY_VIEW_COL_ALBUM), FALSE);
+
+	/* set up the album info widgets */
+	g_object_get (source, "plugin", &plugin, NULL);
+	ui_file = rb_plugin_find_file (plugin, "album-info.ui");
+	g_object_unref (plugin);
+
+	if (ui_file == NULL) {
+		g_warning ("couldn't find album-info.ui");
+	} else {
+		RBAudioCdSourcePrivate *priv;
+		GtkWidget *table;
+		GtkBuilder *builder;
+
+		priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
+
+		builder = rb_builder_load (ui_file, NULL);
+		g_free (ui_file);
+
+		table = GTK_WIDGET (gtk_builder_get_object (builder, "album_info"));
+		g_assert (table != NULL);
+
+		priv->artist_entry = GTK_WIDGET (gtk_builder_get_object (builder, "artist_entry"));
+		priv->artist_sort_entry = GTK_WIDGET (gtk_builder_get_object (builder, "artist_sort_entry"));
+		priv->album_entry = GTK_WIDGET (gtk_builder_get_object (builder, "album_entry"));
+		priv->year_entry = GTK_WIDGET (gtk_builder_get_object (builder, "year_entry"));
+		priv->genre_entry = GTK_WIDGET (gtk_builder_get_object (builder, "genre_entry"));
+		priv->disc_number_entry = GTK_WIDGET (gtk_builder_get_object (builder, "disc_number_entry"));
+
+		g_signal_connect_object (priv->album_entry, "focus-out-event", G_CALLBACK (update_album_cb), source, 0);
+		g_signal_connect_object (priv->genre_entry, "focus-out-event", G_CALLBACK (update_genre_cb), source, 0);
+		g_signal_connect_object (priv->year_entry, "focus-out-event", G_CALLBACK (update_year_cb), source, 0);
+		g_signal_connect_object (priv->disc_number_entry, "focus-out-event", G_CALLBACK (update_disc_number_cb), source, 0);
+
+		gtk_box_pack_start (GTK_BOX (priv->box), table, FALSE, FALSE, 0);
+		gtk_box_reorder_child (GTK_BOX (priv->box), table, 0);
+		g_object_unref (builder);
+	}
+
 	g_object_ref (G_OBJECT (source));
 	g_thread_create ((GThreadFunc)rb_audiocd_load_songs, source, FALSE, NULL);
 
@@ -243,6 +314,16 @@ impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *ps
 	}
 }
 
+static void
+impl_pack_paned (RBBrowserSource *source, GtkWidget *paned)
+{
+	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
+
+	priv->box = gtk_vbox_new (FALSE, 6);
+	gtk_widget_show_all (priv->box);
+	gtk_container_add (GTK_CONTAINER (source), priv->box);
+	gtk_box_pack_start (GTK_BOX (priv->box), paned, TRUE, TRUE, 0);
+}
 
 static void
 entry_set_string_prop (RhythmDB *db,
@@ -579,7 +660,37 @@ metadata_cb (SjMetadataGetter *metadata,
 		return;
 	}
 
+	if (album->artist != NULL) {
+		gtk_entry_set_text (GTK_ENTRY (priv->artist_entry), album->artist);
+	}
+	if (album->artist_sortname != NULL) {
+		gtk_entry_set_text (GTK_ENTRY (priv->artist_sort_entry), album->artist_sortname);
+	}
+	if (album->title != NULL) {
+		gtk_entry_set_text (GTK_ENTRY (priv->album_entry), album->title);
+	}
+	if (album->release_date != NULL) {
+		char *year;
+		year = g_strdup_printf ("%d", g_date_get_year (album->release_date));
+		gtk_entry_set_text (GTK_ENTRY (priv->year_entry), year);
+		g_free (year);
+	}
+	if (album->disc_number != 0) {
+		char *num;
+		num = g_strdup_printf ("%d", album->disc_number);
+		gtk_entry_set_text (GTK_ENTRY (priv->disc_number_entry), num);
+		g_free (num);
+	}
+	if (album->genre != NULL) {
+		gtk_entry_set_text (GTK_ENTRY (priv->genre_entry), album->genre);
+	}
+
 	g_object_set (G_OBJECT (source), "name", album->title, NULL);
+	rb_debug ("musicbrainz_albumid: %s", album->album_id);
+	rb_debug ("musicbrainz_albumartistid: %s", album->artist_id);
+	rb_debug ("album artist: %s", album->artist);
+	rb_debug ("disc number: %d", album->disc_number);
+	rb_debug ("genre: %s", album->genre);
 
 	while (album->tracks && cd_track) {
 		TrackDetails *track = (TrackDetails*)album->tracks->data;
@@ -588,12 +699,9 @@ metadata_cb (SjMetadataGetter *metadata,
 
 		rb_debug ("storing metadata for %s - %s - %s", track->artist, album->title, track->title);
 
-		rb_debug ("genre: %s", album->genre);
 		rb_debug ("musicbrainz_trackid: %s", track->track_id);
 		rb_debug ("musicbrainz_artistid: %s", track->artist_id);
-		rb_debug ("musicbrainz_albumid: %s", album->album_id);
-		rb_debug ("musicbrainz_albumartistid: %s", album->artist_id);
-		rb_debug ("album sortname: %s", album->artist_sortname);
+		rb_debug ("artist sortname: %s", track->artist_sortname);
 
 		/* record track info in entry*/
 		entry_set_string_prop (db, entry, TRUE, RHYTHMDB_PROP_TITLE, track->title);
@@ -604,13 +712,20 @@ metadata_cb (SjMetadataGetter *metadata,
 		entry_set_string_prop (db, entry, TRUE, RHYTHMDB_PROP_MUSICBRAINZ_ARTISTID, track->artist_id);
 		entry_set_string_prop (db, entry, TRUE, RHYTHMDB_PROP_MUSICBRAINZ_ALBUMID, album->album_id);
 		entry_set_string_prop (db, entry, TRUE, RHYTHMDB_PROP_MUSICBRAINZ_ALBUMARTISTID, album->artist_id);
-		entry_set_string_prop (db, entry, TRUE, RHYTHMDB_PROP_ARTIST_SORTNAME, album->artist_sortname);
+		entry_set_string_prop (db, entry, TRUE, RHYTHMDB_PROP_ARTIST_SORTNAME, track->artist_sortname);
 
 		g_value_init (&value, G_TYPE_ULONG);
 		g_value_set_ulong (&value, track->duration);
 		rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_DURATION, &value);
 		g_value_unset (&value);
 
+		if (album->disc_number != 0) {
+			g_value_init (&value, G_TYPE_ULONG);
+			g_value_set_ulong (&value, album->disc_number);
+			rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_DISC_NUMBER, &value);
+			g_value_unset (&value);
+		}
+
 		/*album->release_date (could potentially have multiple values)*/
 		/* in current sj-structures.h, however, it does not */
 
@@ -851,3 +966,76 @@ impl_uri_is_source (RBSource *source, const char *uri)
 	return FALSE;
 }
 
+static void
+update_tracks (RBAudioCdSource *source, RhythmDBPropType property, GValue *value)
+{
+	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
+	RhythmDB *db;
+	GList *i;
+
+	db = get_db_for_source (source);
+
+	for (i = priv->tracks; i != NULL; i = i->next) {
+		rhythmdb_entry_set (db, i->data, property, value);
+	}
+
+	rhythmdb_commit (db);
+	g_object_unref (db);
+}
+
+static void
+update_tracks_string (RBAudioCdSource *source, RhythmDBPropType property, const char *str)
+{
+	GValue v = {0, };
+	g_value_init (&v, G_TYPE_STRING);
+	g_value_set_string (&v, str);
+	update_tracks (source, property, &v);
+	g_value_unset (&v);
+}
+
+static gboolean
+update_album_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source)
+{
+	update_tracks_string (source, RHYTHMDB_PROP_ALBUM, gtk_entry_get_text (GTK_ENTRY (widget)));
+	return FALSE;
+}
+
+static gboolean
+update_genre_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source)
+{
+	update_tracks_string (source, RHYTHMDB_PROP_GENRE, gtk_entry_get_text (GTK_ENTRY (widget)));
+	return FALSE;
+}
+
+static gboolean
+update_year_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source)
+{
+	int year;
+	GDate date;
+	GValue v = {0, };
+
+	year = strtol (gtk_entry_get_text (GTK_ENTRY (widget)), NULL, 10);
+	g_date_clear (&date, 1);
+	g_date_set_dmy (&date, 1, 1, year);
+
+	g_value_init (&v, G_TYPE_ULONG);
+	g_value_set_ulong (&v, g_date_get_julian (&date));
+	update_tracks (source, RHYTHMDB_PROP_DATE, &v);
+	g_value_unset (&v);
+
+	return FALSE;
+}
+
+static gboolean
+update_disc_number_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source)
+{
+	GValue v = {0, };
+
+	g_value_init (&v, G_TYPE_ULONG);
+	g_value_set_ulong (&v, strtoul (gtk_entry_get_text (GTK_ENTRY (widget)), NULL, 10));
+	update_tracks (source, RHYTHMDB_PROP_DISC_NUMBER, &v);
+	g_value_unset (&v);
+
+	return FALSE;
+}
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]