[rhythmbox] audioscrobbler: add popup menus to list items in profile source
- From: Jonathan Matthew <jmatthew src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rhythmbox] audioscrobbler: add popup menus to list items in profile source
- Date: Tue, 21 Sep 2010 10:50:11 +0000 (UTC)
commit 569af632c26a2a88cc0c5698704ec2fe169a0d6f
Author: Jamie Nicol <jamie thenicols net>
Date: Wed Jun 30 12:38:33 2010 +0100
audioscrobbler: add popup menus to list items in profile source
Menus have option to view the item in a web browser
.../rb-audioscrobbler-profile-source.c | 313 ++++++++++++++------
plugins/audioscrobbler/rb-audioscrobbler-user.c | 21 +-
plugins/audioscrobbler/rb-audioscrobbler-user.h | 4 +-
3 files changed, 225 insertions(+), 113 deletions(-)
---
diff --git a/plugins/audioscrobbler/rb-audioscrobbler-profile-source.c b/plugins/audioscrobbler/rb-audioscrobbler-profile-source.c
index aa2be7b..323eba2 100644
--- a/plugins/audioscrobbler/rb-audioscrobbler-profile-source.c
+++ b/plugins/audioscrobbler/rb-audioscrobbler-profile-source.c
@@ -85,6 +85,9 @@ struct _RBAudioscrobblerProfileSourcePrivate {
GtkWidget *top_artists_table;
GtkWidget *recommended_artists_area;
GtkWidget *recommended_artists_table;
+
+ GHashTable *button_to_popup_menu_map;
+ GHashTable *popup_menu_to_data_map;
};
#define RB_AUDIOSCROBBLER_PROFILE_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_AUDIOSCROBBLER_PROFILE_SOURCE, RBAudioscrobblerProfileSourcePrivate))
@@ -134,9 +137,6 @@ static void rb_audioscrobbler_profile_source_scrobbler_statistics_changed_cb (RB
static void rb_audioscrobbler_profile_source_user_info_updated_cb (RBAudioscrobblerUser *user,
RBAudioscrobblerUserData *info,
gpointer user_data);
-static void rb_audioscrobbler_profile_source_set_user_list (RBAudioscrobblerProfileSource *source,
- GtkWidget *list_table,
- GPtrArray *list_data);
static void rb_audioscrobbler_profile_source_recent_tracks_updated_cb (RBAudioscrobblerUser *user,
GPtrArray *recent_tracks,
gpointer user_data);
@@ -152,12 +152,25 @@ static void rb_audioscrobbler_profile_source_top_artists_updated_cb (RBAudioscro
static void rb_audioscrobbler_profile_source_recommended_artists_updated_cb (RBAudioscrobblerUser *user,
GPtrArray *recommended_artists,
gpointer user_data);
+
+static void rb_audioscrobbler_profile_source_set_user_list (RBAudioscrobblerProfileSource *source,
+ GtkWidget *list_table,
+ GPtrArray *list_data);
+static GtkWidget *rb_audioscrobbler_profile_source_create_list_button (RBAudioscrobblerProfileSource *source,
+ RBAudioscrobblerUserData *data);
+static GtkWidget *rb_audioscrobbler_profile_source_create_popup_menu (RBAudioscrobblerProfileSource *source,
+ RBAudioscrobblerUserData *data);
+static void rb_audioscrobbler_profile_source_list_item_clicked_cb (GtkButton *button, gpointer user_data);
+static void rb_audioscrobbler_profile_source_list_item_view_url_activated_cb (GtkMenuItem *menuitem,
+ gpointer user_data);
static void rb_audioscrobbler_profile_source_list_table_pack_start (GtkTable *list_table, GtkWidget *item);
void rb_audioscrobbler_profile_source_list_layout_size_allocate_cb (GtkWidget *layout,
GtkAllocation *allocation,
gpointer user_data);
+
+
enum {
PROP_0,
PROP_SERVICE
@@ -236,6 +249,9 @@ static void
rb_audioscrobbler_profile_source_init (RBAudioscrobblerProfileSource *source)
{
source->priv = RB_AUDIOSCROBBLER_PROFILE_SOURCE_GET_PRIVATE (source);
+
+ source->priv->button_to_popup_menu_map = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
+ source->priv->popup_menu_to_data_map = g_hash_table_new (g_direct_hash, g_direct_equal);
}
static void
@@ -358,6 +374,16 @@ rb_audioscrobbler_profile_source_dispose (GObject* object)
source->priv->scrobbling_enabled_notification_id = 0;
}
+ if (source->priv->button_to_popup_menu_map != NULL) {
+ g_hash_table_unref (source->priv->button_to_popup_menu_map);
+ source->priv->button_to_popup_menu_map = NULL;
+ }
+
+ if (source->priv->popup_menu_to_data_map != NULL) {
+ g_hash_table_unref (source->priv->popup_menu_to_data_map);
+ source->priv->popup_menu_to_data_map = NULL;
+ }
+
G_OBJECT_CLASS (rb_audioscrobbler_profile_source_parent_class)->dispose (object);
}
@@ -697,100 +723,6 @@ rb_audioscrobbler_profile_source_scrobbler_statistics_changed_cb (RBAudioscrobbl
}
static void
-rb_audioscrobbler_profile_source_set_user_list (RBAudioscrobblerProfileSource *source,
- GtkWidget *list_table,
- GPtrArray *list_data)
-{
- int i;
- GList *button_node;
-
- /* delete all existing buttons */
- for (button_node = gtk_container_get_children (GTK_CONTAINER (list_table));
- button_node != NULL;
- button_node = g_list_next (button_node)) {
- gtk_widget_destroy (button_node->data);
- }
-
- /* add a new button for each item in the list */
- for (i = 0; i < list_data->len; i++) {
- GtkWidget *button;
- RBAudioscrobblerUserData *data;
- char *button_text;
- GtkWidget *label;
- GtkWidget *label_alignment;
- GtkWidget *button_contents;
-
- button = gtk_button_new ();
- gtk_button_set_alignment (GTK_BUTTON (button),
- 0, 0.5);
- gtk_button_set_focus_on_click (GTK_BUTTON (button),
- FALSE);
- gtk_button_set_relief (GTK_BUTTON (button),
- GTK_RELIEF_NONE);
-
- data = g_ptr_array_index (list_data, i);
-
- button_text = NULL;
- if (data->type == RB_AUDIOSCROBBLER_USER_DATA_TYPE_TRACK) {
- char *escaped_title_text;
- char *escaped_artist_text;
-
- escaped_title_text = g_markup_escape_text (data->track.title, -1);
- escaped_artist_text = g_markup_escape_text (data->track.artist, -1);
- button_text = g_strdup_printf ("%s\n<small>%s</small>",
- escaped_title_text,
- escaped_artist_text);
-
- g_free (escaped_title_text);
- g_free (escaped_artist_text);
-
- } else if (data->type == RB_AUDIOSCROBBLER_USER_DATA_TYPE_ARTIST) {
- button_text = g_markup_escape_text (data->artist.name, -1);
- }
-
- label = gtk_label_new ("");
- gtk_label_set_markup (GTK_LABEL (label), button_text);
- g_free (button_text);
-
- label_alignment = gtk_alignment_new (0, 0.5, 0, 0);
- gtk_container_add (GTK_CONTAINER (label_alignment), label);
-
- button_contents = gtk_hbox_new (FALSE, 4);
- if (data->image != NULL) {
- GtkWidget *image;
- GtkWidget *viewport;
- GtkWidget *alignment;
-
- image = gtk_image_new_from_pixbuf (data->image);
-
- viewport = gtk_viewport_new (NULL, NULL);
- gtk_container_add (GTK_CONTAINER (viewport), image);
-
- alignment = gtk_alignment_new (0, 0.5, 0, 0);
- gtk_container_add (GTK_CONTAINER (alignment), viewport);
-
- gtk_box_pack_start (GTK_BOX (button_contents),
- alignment,
- FALSE, FALSE, 0);
-
-
- gtk_alignment_set_padding (GTK_ALIGNMENT (label_alignment),
- 0, 0,
- LIST_ITEM_IMAGE_SIZE - gdk_pixbuf_get_width (data->image), 0);
- } else {
- gtk_alignment_set_padding (GTK_ALIGNMENT (label_alignment), 0, 0, LIST_ITEM_IMAGE_SIZE + 4, 0);
- }
-
- gtk_box_pack_start (GTK_BOX (button_contents),
- label_alignment,
- FALSE, FALSE, 0);
- gtk_container_add (GTK_CONTAINER (button), button_contents);
-
- rb_audioscrobbler_profile_source_list_table_pack_start (GTK_TABLE (list_table), button);
- }
-}
-
-static void
rb_audioscrobbler_profile_source_user_info_updated_cb (RBAudioscrobblerUser *user,
RBAudioscrobblerUserData *data,
gpointer user_data)
@@ -807,7 +739,7 @@ rb_audioscrobbler_profile_source_user_info_updated_cb (RBAudioscrobblerUser *use
playcount_text);
gtk_link_button_set_uri (GTK_LINK_BUTTON (source->priv->view_profile_link),
- data->user_info.url);
+ data->url);
gtk_image_set_from_pixbuf (GTK_IMAGE (source->priv->profile_image), data->image);
@@ -895,6 +827,191 @@ rb_audioscrobbler_profile_source_recommended_artists_updated_cb (RBAudioscrobble
}
static void
+rb_audioscrobbler_profile_source_set_user_list (RBAudioscrobblerProfileSource *source,
+ GtkWidget *list_table,
+ GPtrArray *list_data)
+{
+ int i;
+ GList *button_node;
+
+ /* delete all existing buttons */
+ for (button_node = gtk_container_get_children (GTK_CONTAINER (list_table));
+ button_node != NULL;
+ button_node = g_list_next (button_node)) {
+ GtkMenu *menu;
+ menu = g_hash_table_lookup (source->priv->button_to_popup_menu_map, button_node->data);
+ g_hash_table_remove (source->priv->button_to_popup_menu_map, button_node->data);
+ g_hash_table_remove (source->priv->popup_menu_to_data_map, menu);
+ gtk_widget_destroy (button_node->data);
+ }
+
+ /* add a new button for each item in the list */
+ for (i = 0; i < list_data->len; i++) {
+ RBAudioscrobblerUserData *data;
+ GtkWidget *button;
+ GtkWidget *menu;
+
+ data = g_ptr_array_index (list_data, i);
+ button = rb_audioscrobbler_profile_source_create_list_button (source, data);
+ menu = rb_audioscrobbler_profile_source_create_popup_menu (source, data);
+
+ g_hash_table_insert (source->priv->button_to_popup_menu_map, button, g_object_ref_sink (menu));
+ g_hash_table_insert (source->priv->popup_menu_to_data_map, menu, data);
+
+ rb_audioscrobbler_profile_source_list_table_pack_start (GTK_TABLE (list_table), button);
+ }
+}
+
+static GtkWidget *
+rb_audioscrobbler_profile_source_create_list_button (RBAudioscrobblerProfileSource *source,
+ RBAudioscrobblerUserData *data)
+{
+ GtkWidget *button;
+ GtkWidget *button_contents;
+ char *button_text;
+ GtkWidget *label;
+ GtkWidget *label_alignment;
+
+ button = gtk_button_new ();
+ gtk_button_set_alignment (GTK_BUTTON (button),
+ 0, 0.5);
+ gtk_button_set_focus_on_click (GTK_BUTTON (button),
+ FALSE);
+ gtk_button_set_relief (GTK_BUTTON (button),
+ GTK_RELIEF_NONE);
+
+ button_contents = gtk_hbox_new (FALSE, 4);
+ gtk_container_add (GTK_CONTAINER (button), button_contents);
+
+ button_text = NULL;
+ if (data->type == RB_AUDIOSCROBBLER_USER_DATA_TYPE_TRACK) {
+ char *escaped_title_text;
+ char *escaped_artist_text;
+
+ escaped_title_text = g_markup_escape_text (data->track.title, -1);
+ escaped_artist_text = g_markup_escape_text (data->track.artist, -1);
+ button_text = g_strdup_printf ("%s\n<small>%s</small>",
+ escaped_title_text,
+ escaped_artist_text);
+
+ g_free (escaped_title_text);
+ g_free (escaped_artist_text);
+
+ } else if (data->type == RB_AUDIOSCROBBLER_USER_DATA_TYPE_ARTIST) {
+ button_text = g_markup_escape_text (data->artist.name, -1);
+ }
+
+ label = gtk_label_new ("");
+ gtk_label_set_markup (GTK_LABEL (label), button_text);
+ g_free (button_text);
+
+ label_alignment = gtk_alignment_new (0, 0.5, 0, 0);
+ gtk_container_add (GTK_CONTAINER (label_alignment), label);
+
+ if (data->image != NULL) {
+ GtkWidget *image;
+ GtkWidget *viewport;
+ GtkWidget *alignment;
+
+ image = gtk_image_new_from_pixbuf (data->image);
+
+ viewport = gtk_viewport_new (NULL, NULL);
+ gtk_container_add (GTK_CONTAINER (viewport), image);
+
+ alignment = gtk_alignment_new (0, 0.5, 0, 0);
+ gtk_container_add (GTK_CONTAINER (alignment), viewport);
+
+ gtk_box_pack_start (GTK_BOX (button_contents),
+ alignment,
+ FALSE, FALSE, 0);
+
+ gtk_alignment_set_padding (GTK_ALIGNMENT (label_alignment),
+ 0, 0,
+ LIST_ITEM_IMAGE_SIZE - gdk_pixbuf_get_width (data->image), 0);
+ } else {
+ gtk_alignment_set_padding (GTK_ALIGNMENT (label_alignment), 0, 0, LIST_ITEM_IMAGE_SIZE + 4, 0);
+ }
+
+ gtk_box_pack_start (GTK_BOX (button_contents),
+ label_alignment,
+ FALSE, FALSE, 0);
+
+ g_signal_connect (button,
+ "clicked",
+ (GCallback) rb_audioscrobbler_profile_source_list_item_clicked_cb,
+ source);
+
+ return button;
+}
+
+static GtkWidget *
+rb_audioscrobbler_profile_source_create_popup_menu (RBAudioscrobblerProfileSource *source,
+ RBAudioscrobblerUserData *data)
+{
+ GtkWidget *menu;
+
+ menu = gtk_menu_new ();
+
+ if (data->url != NULL && data->url[0] != '\0') {
+ GtkWidget *view_url_item;
+ char *item_text;
+
+ item_text = g_strdup_printf (_("_View on %s"),
+ rb_audioscrobbler_service_get_name (source->priv->service));
+ view_url_item = gtk_menu_item_new_with_mnemonic (item_text);
+ g_signal_connect (view_url_item,
+ "activate",
+ (GCallback) rb_audioscrobbler_profile_source_list_item_view_url_activated_cb,
+ source);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), view_url_item);
+ g_free (item_text);
+ }
+
+ gtk_widget_show_all (menu);
+
+ return menu;
+}
+
+static void
+rb_audioscrobbler_profile_source_list_item_clicked_cb (GtkButton *button, gpointer user_data)
+{
+ RBAudioscrobblerProfileSource *source;
+ GtkWidget *menu;
+
+ source = RB_AUDIOSCROBBLER_PROFILE_SOURCE (user_data);
+ menu = g_hash_table_lookup (source->priv->button_to_popup_menu_map, button);
+
+ /* show menu if it has any items in it */
+ if (g_list_length (gtk_container_get_children (GTK_CONTAINER (menu))) != 0) {
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ());
+ }
+}
+
+static void
+rb_audioscrobbler_profile_source_list_item_view_url_activated_cb (GtkMenuItem *menuitem,
+ gpointer user_data)
+{
+ RBAudioscrobblerProfileSource *source;
+ GtkWidget *menu;
+ RBAudioscrobblerUserData *data;
+
+ source = RB_AUDIOSCROBBLER_PROFILE_SOURCE (user_data);
+ menu = gtk_widget_get_parent (GTK_WIDGET (menuitem));
+ data = g_hash_table_lookup (source->priv->popup_menu_to_data_map, menu);
+
+ /* some urls are given to us without the http:// prefix */
+ if (g_str_has_prefix (data->url, "http://") == TRUE) {
+ gtk_show_uri (NULL, data->url, GDK_CURRENT_TIME, NULL);
+ } else {
+ char *url;
+ url = g_strdup_printf ("%s%s", "http://", data->url);
+ gtk_show_uri (NULL, url, GDK_CURRENT_TIME, NULL);
+ g_free (url);
+ }
+}
+
+static void
rb_audioscrobbler_profile_source_list_table_pack_start (GtkTable *list_table, GtkWidget *item)
{
int num_columns;
diff --git a/plugins/audioscrobbler/rb-audioscrobbler-user.c b/plugins/audioscrobbler/rb-audioscrobbler-user.c
index c621611..fd8ffc8 100644
--- a/plugins/audioscrobbler/rb-audioscrobbler-user.c
+++ b/plugins/audioscrobbler/rb-audioscrobbler-user.c
@@ -47,21 +47,19 @@ rb_audioscrobbler_user_data_copy (RBAudioscrobblerUserData *data)
if (data->image != NULL) {
d->image = g_object_ref (data->image);
}
+ d->url = g_strdup (data->url);
switch (d->type) {
case RB_AUDIOSCROBBLER_USER_DATA_TYPE_USER_INFO:
d->user_info.username = g_strdup (data->user_info.username);
- d->user_info.url = g_strdup (data->user_info.url);
d->user_info.playcount = g_strdup (data->user_info.playcount);
break;
case RB_AUDIOSCROBBLER_USER_DATA_TYPE_TRACK:
d->track.title = g_strdup (data->track.title);
d->track.artist = g_strdup (data->track.artist);
- d->track.url = g_strdup (data->track.url);
break;
case RB_AUDIOSCROBBLER_USER_DATA_TYPE_ARTIST:
d->artist.name = g_strdup (data->artist.name);
- d->artist.url = g_strdup (data->artist.url);
break;
}
@@ -74,20 +72,19 @@ rb_audioscrobbler_user_data_free (RBAudioscrobblerUserData *data)
if (data->image != NULL) {
g_object_unref (data->image);
}
+ g_free (data->url);
+
switch (data->type) {
case RB_AUDIOSCROBBLER_USER_DATA_TYPE_USER_INFO:
g_free (data->user_info.username);
- g_free (data->user_info.url);
g_free (data->user_info.playcount);
break;
case RB_AUDIOSCROBBLER_USER_DATA_TYPE_TRACK:
g_free (data->track.title);
g_free (data->track.artist);
- g_free (data->track.url);
break;
case RB_AUDIOSCROBBLER_USER_DATA_TYPE_ARTIST:
g_free (data->artist.name);
- g_free (data->artist.url);
break;
}
@@ -679,8 +676,8 @@ rb_audioscrobbler_user_parse_user_info (RBAudioscrobblerUser *user, const char *
user_info = g_slice_new0 (RBAudioscrobblerUserData);
user_info->type = RB_AUDIOSCROBBLER_USER_DATA_TYPE_USER_INFO;
user_info->user_info.username = g_strdup (json_object_get_string_member (user_object, "name"));
- user_info->user_info.url = g_strdup (json_object_get_string_member (user_object, "url"));
user_info->user_info.playcount = g_strdup (json_object_get_string_member (user_object, "playcount"));
+ user_info->url = g_strdup (json_object_get_string_member (user_object, "url"));
user_info->image = gdk_pixbuf_new_from_file_at_size (rb_audioscrobbler_user_calculate_cached_image_path (user, user_info),
USER_PROFILE_IMAGE_SIZE, -1, NULL);
@@ -817,7 +814,7 @@ rb_audioscrobbler_user_parse_recent_tracks (RBAudioscrobblerUser *user, const ch
track->track.title = g_strdup (json_object_get_string_member (track_object, "name"));
artist_object = json_object_get_object_member (track_object, "artist");
track->track.artist = g_strdup (json_object_get_string_member (artist_object, "#text"));
- track->track.url = g_strdup (json_object_get_string_member (track_object, "url"));
+ track->url = g_strdup (json_object_get_string_member (track_object, "url"));
g_ptr_array_add (recent_tracks, track);
@@ -957,7 +954,7 @@ rb_audioscrobbler_user_parse_top_tracks (RBAudioscrobblerUser *user, const char
track->track.title = g_strdup (json_object_get_string_member (track_object, "name"));
artist_object = json_object_get_object_member (track_object, "artist");
track->track.artist = g_strdup (json_object_get_string_member (artist_object, "name"));
- track->track.url = g_strdup (json_object_get_string_member (track_object, "url"));
+ track->url = g_strdup (json_object_get_string_member (track_object, "url"));
g_ptr_array_add (top_tracks, track);
@@ -1097,7 +1094,7 @@ rb_audioscrobbler_user_parse_loved_tracks (RBAudioscrobblerUser *user, const cha
track->track.title = g_strdup (json_object_get_string_member (track_object, "name"));
artist_object = json_object_get_object_member (track_object, "artist");
track->track.artist = g_strdup (json_object_get_string_member (artist_object, "name"));
- track->track.url = g_strdup (json_object_get_string_member (track_object, "url"));
+ track->url = g_strdup (json_object_get_string_member (track_object, "url"));
g_ptr_array_add (loved_tracks, track);
@@ -1234,7 +1231,7 @@ rb_audioscrobbler_user_parse_top_artists (RBAudioscrobblerUser *user, const char
artist = g_slice_new0 (RBAudioscrobblerUserData);
artist->type = RB_AUDIOSCROBBLER_USER_DATA_TYPE_ARTIST;
artist->artist.name = g_strdup (json_object_get_string_member (artist_object, "name"));
- artist->artist.url = g_strdup (json_object_get_string_member (artist_object, "url"));
+ artist->url = g_strdup (json_object_get_string_member (artist_object, "url"));
g_ptr_array_add (top_artists, artist);
@@ -1389,7 +1386,7 @@ rb_audioscrobbler_user_parse_recommended_artists (RBAudioscrobblerUser *user, co
artist = g_slice_new0 (RBAudioscrobblerUserData);
artist->type = RB_AUDIOSCROBBLER_USER_DATA_TYPE_ARTIST;
artist->artist.name = g_strdup (json_object_get_string_member (artist_object, "name"));
- artist->artist.url = g_strdup (json_object_get_string_member (artist_object, "url"));
+ artist->url = g_strdup (json_object_get_string_member (artist_object, "url"));
g_ptr_array_add (recommended_artists, artist);
diff --git a/plugins/audioscrobbler/rb-audioscrobbler-user.h b/plugins/audioscrobbler/rb-audioscrobbler-user.h
index ad8b2bc..8aaa591 100644
--- a/plugins/audioscrobbler/rb-audioscrobbler-user.h
+++ b/plugins/audioscrobbler/rb-audioscrobbler-user.h
@@ -46,23 +46,21 @@ typedef struct {
} type;
GdkPixbuf *image;
+ char *url;
union {
struct {
char *username;
- char *url;
char *playcount;
} user_info;
struct {
char *title;
char *artist;
- char *url;
} track;
struct {
char *name;
- char *url;
} artist;
};
} RBAudioscrobblerUserData;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]