? shell/iradio.xml
Index: rhythmdb/rhythmdb-marshal.list
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb-marshal.list,v
retrieving revision 1.1
diff -u -r1.1 rhythmdb-marshal.list
--- rhythmdb/rhythmdb-marshal.list	14 Jul 2004 04:27:16 -0000	1.1
+++ rhythmdb/rhythmdb-marshal.list	29 Jul 2005 15:33:39 -0000
@@ -1,3 +1,5 @@
 VOID:STRING,STRING
+VOID:POINTER,POINTER
 VOID:POINTER,INT,POINTER,POINTER
+VOID:POINTER
 
Index: rhythmdb/rhythmdb-property-model.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb-property-model.c,v
retrieving revision 1.19
diff -u -r1.19 rhythmdb-property-model.c
--- rhythmdb/rhythmdb-property-model.c	16 Sep 2004 19:15:44 -0000	1.19
+++ rhythmdb/rhythmdb-property-model.c	29 Jul 2005 15:33:41 -0000
@@ -52,9 +52,9 @@
 						     RhythmDBPropType prop, const GValue *old,
 						     const GValue *new,
 						     RhythmDBPropertyModel *propmodel);
-static void rhythmdb_property_model_row_deleted_cb (GtkTreeModel *model,
-						    GtkTreePath *path,
-						    RhythmDBPropertyModel *propmodel);
+static void rhythmdb_property_model_entry_removed_cb (RhythmDBQueryModel *model,
+						      RhythmDBEntry *entry,
+						      RhythmDBPropertyModel *propmodel);
 static void rhythmdb_property_model_insert (RhythmDBPropertyModel *model, RhythmDBEntry *entry);
 static void rhythmdb_property_model_delete (RhythmDBPropertyModel *model,
 					    RhythmDBEntry *entry);
@@ -251,7 +251,7 @@
 							      G_CALLBACK (rhythmdb_property_model_row_inserted_cb),
 							      model);
 			g_signal_handlers_disconnect_by_func (G_OBJECT (model->priv->query_model),
-							      G_CALLBACK (rhythmdb_property_model_row_deleted_cb),
+							      G_CALLBACK (rhythmdb_property_model_entry_removed_cb),
 							      model);
 			g_signal_handlers_disconnect_by_func (G_OBJECT (model->priv->query_model),
 							      G_CALLBACK (rhythmdb_property_model_prop_changed_cb),
@@ -268,8 +268,8 @@
 						 model,
 						 0);
 			g_signal_connect_object (G_OBJECT (model->priv->query_model),
-						 "row_deleted",
-						 G_CALLBACK (rhythmdb_property_model_row_deleted_cb),
+						 "entry-removed",
+						 G_CALLBACK (rhythmdb_property_model_entry_removed_cb),
 						 model,
 						 0);
 			g_signal_connect_object (G_OBJECT (model->priv->query_model),
@@ -381,18 +381,6 @@
 	return entry;
 }
 
-static RhythmDBEntry *
-entry_from_tree_path (GtkTreeModel *model, GtkTreePath *path)
-{
-	GtkTreeIter entry_iter;
-	RhythmDBEntry *entry;
-
-	gtk_tree_model_get_iter (model, &entry_iter, path);
-	gtk_tree_model_get (model, &entry_iter, 0,
-			    &entry, -1);
-	return entry;
-}
-
 static void
 rhythmdb_property_model_row_inserted_cb (GtkTreeModel *model,
 					 GtkTreePath *path,
@@ -417,11 +405,10 @@
 }
 
 static void
-rhythmdb_property_model_row_deleted_cb (GtkTreeModel *model,
-					GtkTreePath *path,
-					RhythmDBPropertyModel *propmodel)
+rhythmdb_property_model_entry_removed_cb (RhythmDBQueryModel *model,
+					  RhythmDBEntry *entry,
+					  RhythmDBPropertyModel *propmodel)
 {
-	RhythmDBEntry *entry = entry_from_tree_path (model, path);
 	rhythmdb_property_model_delete (propmodel, entry);
 }
 
Index: rhythmdb/rhythmdb-query-model.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb-query-model.c,v
retrieving revision 1.72
diff -u -r1.72 rhythmdb-query-model.c
--- rhythmdb/rhythmdb-query-model.c	18 Jul 2005 12:45:22 -0000	1.72
+++ rhythmdb/rhythmdb-query-model.c	29 Jul 2005 15:33:45 -0000
@@ -62,11 +62,12 @@
 static void rhythmdb_query_model_entry_added_cb (RhythmDB *db, RhythmDBEntry *entry,
 						 RhythmDBQueryModel *model);
 static void rhythmdb_query_model_entry_changed_cb (RhythmDB *db, RhythmDBEntry *entry,
-						   RhythmDBPropType prop, const GValue *old,
-						   const GValue *new, RhythmDBQueryModel *model);
+						   GSList *changes, RhythmDBQueryModel *model);
 static void rhythmdb_query_model_entry_deleted_cb (RhythmDB *db, RhythmDBEntry *entry,
 						   RhythmDBQueryModel *model);
 
+static void rhythmdb_query_model_filter_out_entry (RhythmDBQueryModel *model,
+						   RhythmDBEntry *entry);
 static void rhythmdb_query_model_do_reorder (RhythmDBQueryModel *model, RhythmDBEntry *entry);
 static gboolean rhythmdb_query_model_drag_data_get (RbTreeDragSource *dragsource,
 							  GList *paths,
@@ -183,6 +184,7 @@
 {
 	COMPLETE,
 	ENTRY_PROP_CHANGED,
+	ENTRY_REMOVED,
 	LAST_SIGNAL
 };
 
@@ -265,6 +267,14 @@
 			      rhythmdb_marshal_VOID__POINTER_INT_POINTER_POINTER,
 			      G_TYPE_NONE, 4, G_TYPE_POINTER,
 			      G_TYPE_INT, G_TYPE_POINTER, G_TYPE_POINTER);
+	rhythmdb_query_model_signals[ENTRY_REMOVED] =
+		g_signal_new ("entry-removed",
+			      RHYTHMDB_TYPE_QUERY_MODEL,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RhythmDBQueryModelClass, entry_removed),
+			      NULL, NULL,
+			      rhythmdb_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
 	rhythmdb_query_model_signals[COMPLETE] =
 		g_signal_new ("complete",
 			      RHYTHMDB_TYPE_QUERY_MODEL,
@@ -570,42 +580,47 @@
 
 static void
 rhythmdb_query_model_entry_changed_cb (RhythmDB *db, RhythmDBEntry *entry,
-				       RhythmDBPropType prop, const GValue *old,
-				       const GValue *new, RhythmDBQueryModel *model)
+				       GSList *changes, RhythmDBQueryModel *model)
 {
 	gboolean hidden = FALSE;
+	GSList *t;
 
-	if (!model->priv->connected) {
+	if (!model->priv->connected)
 		return;
-	}
+
 
 	hidden = rhythmdb_entry_get_boolean (entry, RHYTHMDB_PROP_HIDDEN);
 
-	if (g_hash_table_lookup (model->priv->reverse_map, entry) != NULL) {
-		if (hidden != FALSE) {
-			rhythmdb_query_model_remove_entry (model, entry);
-			return;
+	if (g_hash_table_lookup (model->priv->reverse_map, entry) == NULL) {
+		if (hidden == FALSE) {
+			/* the changed entry may now satisfy the query 
+			 * so we test it */
+			rhythmdb_query_model_entry_added_cb (db, entry, model);
 		}
+		return;
+	}
 
-		if (model->priv->query &&
-		    !rhythmdb_evaluate_query (db, model->priv->query, entry)) {
-			rhythmdb_query_model_remove_entry (model, entry);
-			return;
-		}
+	if (hidden) {
+		rhythmdb_query_model_remove_entry (model, entry);
+		return;
+	}
 
+	/* emit separate change signals for each property */
+	for (t = changes; t; t = t->next) {
+		RhythmDBEntryChange *change = t->data;
 		g_signal_emit (G_OBJECT (model),
 			       rhythmdb_query_model_signals[ENTRY_PROP_CHANGED], 0,
-			       entry, prop, old, new);
+			       entry, change->prop, &change->old, &change->new);
+	}
 
-		/* it may have moved, so we can't just emit a changed entry */
-		rhythmdb_query_model_do_reorder (model, entry);
-	} else {
-		if (hidden == FALSE) {
-			/* the changed entry may now satisfy the query 
-			 * so we test it */
-			rhythmdb_query_model_entry_added_cb (db, entry, model);
-		}
+	if (model->priv->query &&
+	    !rhythmdb_evaluate_query (db, model->priv->query, entry)) {
+		rhythmdb_query_model_filter_out_entry (model, entry);
+		return;
 	}
+
+	/* it may have moved, so we can't just emit a changed entry */
+	rhythmdb_query_model_do_reorder (model, entry);
 }
 
 static void
@@ -913,8 +928,9 @@
 	rhythmdb_query_model_update_limited_entries (model);
 }
 
-void
-rhythmdb_query_model_remove_entry (RhythmDBQueryModel *model, RhythmDBEntry *entry)
+static void
+rhythmdb_query_model_filter_out_entry (RhythmDBQueryModel *model,
+				       RhythmDBEntry *entry)
 {
 	GSequencePtr ptr;
 
@@ -932,6 +948,21 @@
 		return;
 	}
 }
+				
+
+void
+rhythmdb_query_model_remove_entry (RhythmDBQueryModel *model, 
+				   RhythmDBEntry *entry)
+{
+	/* emit entry-removed, so listeners know the
+	 * entry has actually been removed, rather than filtered
+	 * out.
+	 */
+	g_signal_emit (G_OBJECT (model),
+		       rhythmdb_query_model_signals[ENTRY_REMOVED], 0,
+		       entry);
+	rhythmdb_query_model_filter_out_entry (model, entry);
+}
 
 static gboolean
 idle_poll_model (RhythmDBQueryModel *model)
Index: rhythmdb/rhythmdb-query-model.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb-query-model.h,v
retrieving revision 1.12
diff -u -r1.12 rhythmdb-query-model.h
--- rhythmdb/rhythmdb-query-model.h	14 Jul 2004 03:13:03 -0000	1.12
+++ rhythmdb/rhythmdb-query-model.h	29 Jul 2005 15:33:45 -0000
@@ -56,6 +56,7 @@
 	void	(*complete)		(void);
 	void	(*entry_prop_changed)	(RhythmDBEntry *entry, RhythmDBPropType prop,
 					 const GValue *old, const GValue *new);
+	void    (*entry_removed)        (RhythmDBEntry *entry);
 
 } RhythmDBQueryModelClass;
 
Index: rhythmdb/rhythmdb.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.c,v
retrieving revision 1.102
diff -u -r1.102 rhythmdb.c
--- rhythmdb/rhythmdb.c	27 Jul 2005 16:44:41 -0000	1.102
+++ rhythmdb/rhythmdb.c	29 Jul 2005 15:33:55 -0000
@@ -90,7 +90,7 @@
 	gboolean no_update;
 
 	GList *added_entries;
-	GList *changed_entries;
+	GHashTable *changed_entries;
 
 	GHashTable *propname_map;
 
@@ -116,14 +116,6 @@
 	gboolean cancel;
 };
 
-struct RhythmDBEntryChangeData
-{
-	RhythmDBEntry *entry;
-	RhythmDBPropType prop;
-	GValue old;
-	GValue new;
-};
-
 struct RhythmDBAddThreadData
 {
 	RhythmDB *db;
@@ -165,10 +157,10 @@
 	RBMetaData *metadata;
 	/* QUERY_COMPLETE */
 	RhythmDBQueryModel *model;
-	/* ENTRY_RESTORED */
+	/* ENTRY_RESTORED / ENTRY_SET */
 	RhythmDBEntry *entry;
 	/* ENTRY_SET */
-	struct RhythmDBEntryChangeData change;
+	RhythmDBEntryChange change;
 };
 
 G_DEFINE_ABSTRACT_TYPE(RhythmDB, rhythmdb, G_TYPE_OBJECT)
@@ -204,6 +196,9 @@
 static void rhythmdb_volume_unmounted_cb (GnomeVFSVolumeMonitor *monitor,
  					  GnomeVFSVolume *volume, 
  					  gpointer data);
+static gboolean free_entry_changes (RhythmDBEntry *entry, 
+				    GSList *changes,
+				    RhythmDB *db);
 
 enum
 {
@@ -296,9 +291,9 @@
 			      G_SIGNAL_RUN_LAST,
 			      G_STRUCT_OFFSET (RhythmDBClass, entry_changed),
 			      NULL, NULL,
-			      rhythmdb_marshal_VOID__POINTER_INT_POINTER_POINTER,
-			      G_TYPE_NONE, 4, G_TYPE_POINTER,
-			      G_TYPE_INT, G_TYPE_POINTER, G_TYPE_POINTER);
+			      rhythmdb_marshal_VOID__POINTER_POINTER,
+			      G_TYPE_NONE, 2, 
+			      G_TYPE_POINTER, G_TYPE_POINTER);
 
 	rhythmdb_signals[LOAD_COMPLETE] =
 		g_signal_new ("load_complete",
@@ -517,6 +512,8 @@
 								 (GDestroyNotify) g_free,
 								 NULL);
 
+	db->priv->changed_entries = g_hash_table_new (NULL, NULL);
+	
 	db->priv->event_poll_id = g_idle_add ((GSourceFunc) rhythmdb_idle_poll_events, db);
 
 	rhythmdb_thread_create (db, (GThreadFunc) action_thread_main, db);
@@ -766,46 +763,49 @@
 			       0, FALSE);
 }
 
-static void
-emit_changed_signals (RhythmDB *db, gboolean commit)
+static gboolean
+free_entry_changes (RhythmDBEntry *entry, GSList *changes, RhythmDB *db)
 {
-	GList *tem;
-	GHashTable *queued_entry_changes = g_hash_table_new (NULL, NULL);
+	GSList *t;
+	for (t = changes; t; t = t->next) {
+		RhythmDBEntryChange *change = t->data;
+		g_value_unset (&change->old);
+		g_value_unset (&change->new);
+		g_free (change);
+	}
+	g_slist_free (changes);
+	return TRUE;
+}
 
-	for (tem = db->priv->changed_entries; tem; tem = tem->next) {
-		struct RhythmDBEntryChangeData *data = tem->data;
-		if (commit) {
-			struct RhythmDBAction *action;
+static void
+emit_entry_changed (RhythmDBEntry *entry, GSList *changes, RhythmDB *db)
+{
+	if (rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TYPE) == RHYTHMDB_ENTRY_TYPE_SONG) {
+		GSList *t;
+		gboolean sync = FALSE;
+		for (t = changes; t; t = t->next) {
 			RBMetaDataField field;
-
-			if (rhythmdb_entry_get_ulong (data->entry, RHYTHMDB_PROP_TYPE) == RHYTHMDB_ENTRY_TYPE_SONG
-			    && !g_hash_table_lookup (queued_entry_changes, data->entry)
-			    && metadata_field_from_prop (data->prop, &field)) {
-				action = g_new0 (struct RhythmDBAction, 1);
+			RhythmDBEntryChange *change = t->data;
+			if (metadata_field_from_prop (change->prop, &field)) {
+				struct RhythmDBAction *action = g_new0 (struct RhythmDBAction, 1);
 				action->type = RHYTHMDB_ACTION_SYNC;
-				action->uri = g_strdup (data->entry->location);
-
-				g_hash_table_insert (queued_entry_changes, data->entry, action);
+				action->uri = g_strdup (entry->location);
 				g_async_queue_push (db->priv->action_queue, action);
 			}
-			g_signal_emit (G_OBJECT (db), rhythmdb_signals[ENTRY_CHANGED], 0, data->entry,
-				       data->prop, &data->old, &data->new);
 		}
-		g_value_unset (&data->old);
-		g_value_unset (&data->new);
-		g_free (data);
 	}
-	g_list_free (db->priv->changed_entries);
-	db->priv->changed_entries = NULL;
-	g_hash_table_destroy (queued_entry_changes);
+	
+	g_signal_emit (G_OBJECT (db), rhythmdb_signals[ENTRY_CHANGED], 0, entry, changes);
 }
 
 static void
 rhythmdb_commit_internal (RhythmDB *db, gboolean signal_changed)
 {
-       GList *tem;
+	GList *tem;
 
-	emit_changed_signals (db, signal_changed);
+	if (signal_changed)
+		g_hash_table_foreach (db->priv->changed_entries, (GHFunc) emit_entry_changed, db);
+	g_hash_table_foreach_remove (db->priv->changed_entries, (GHRFunc) free_entry_changes, db);
 
 	for (tem = db->priv->added_entries; tem; tem = tem->next) {
 		RhythmDBEntry *entry = tem->data;
@@ -1382,7 +1382,7 @@
 rhythmdb_process_queued_entry_set_event (RhythmDB *db, 
 					 struct RhythmDBEvent *event)
 {
-	rhythmdb_entry_set_internal (db, event->change.entry, 
+	rhythmdb_entry_set_internal (db, event->entry, 
 			    event->change.prop, 
 			    &event->change.new);
 	/* Don't run rhythmdb_commit right now in case there 
@@ -1886,10 +1886,10 @@
 rhythmdb_entry_sync (RhythmDB *db, RhythmDBEntry *entry,
 		     guint propid, GValue *value)
 {
-	struct RhythmDBEntryChangeData *changedata;
+	RhythmDBEntryChange *changedata;
+	GSList *changelist;
 
-	changedata = g_new0 (struct RhythmDBEntryChangeData, 1);
-	changedata->entry = entry;
+	changedata = g_new0 (RhythmDBEntryChange, 1);
 	changedata->prop = propid;
 
 	/* Copy a temporary gvalue, since _entry_get uses
@@ -1905,7 +1905,9 @@
 	g_value_init (&changedata->new, G_VALUE_TYPE (value));
 	g_value_copy (value, &changedata->new);
 
-	db->priv->changed_entries = g_list_append (db->priv->changed_entries, changedata);
+	changelist = g_hash_table_lookup (db->priv->changed_entries, entry);
+	changelist = g_slist_append (changelist, changedata);
+	g_hash_table_insert (db->priv->changed_entries, entry, changelist);
 
 	rhythmdb_entry_set_internal (db, entry, propid, value);
 }
@@ -2054,7 +2056,7 @@
 
 		rb_debug ("queuing RHYTHMDB_ACTION_ENTRY_SET");
 
-		result->change.entry = entry;
+		result->entry = entry;
 		result->change.prop = propid;
 		g_value_init (&result->change.new, G_VALUE_TYPE (value));
 		g_value_copy (value, &result->change.new);
Index: rhythmdb/rhythmdb.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.h,v
retrieving revision 1.41
diff -u -r1.41 rhythmdb.h
--- rhythmdb/rhythmdb.h	5 Jul 2005 09:15:43 -0000	1.41
+++ rhythmdb/rhythmdb.h	29 Jul 2005 15:34:00 -0000
@@ -169,6 +169,11 @@
 	gboolean hidden;
 } RhythmDBEntry;
 
+typedef struct {
+	RhythmDBPropType prop;
+	GValue old;
+	GValue new;
+} RhythmDBEntryChange;
 
 G_INLINE_FUNC const char *rhythmdb_entry_get_string	(RhythmDBEntry *entry, RhythmDBPropType propid);
 G_INLINE_FUNC gboolean rhythmdb_entry_get_boolean	(RhythmDBEntry *entry, RhythmDBPropType propid);
@@ -325,8 +330,7 @@
 	/* signals */
 	void	(*entry_added)		(RhythmDBEntry *entry);
 	void	(*entry_restored)	(RhythmDBEntry *entry);
-	void	(*entry_changed)	(RhythmDBEntry *entry, RhythmDBPropType prop,
-					 const GValue *old, const GValue *new);
+	void	(*entry_changed)	(RhythmDBEntry *entry, GSList *changes); /* list of RhythmDBEntryChanges */
 	void	(*entry_deleted)	(RhythmDBEntry *entry);
 	void	(*load_complete)	(void);
 	void	(*save_complete)	(void);
Index: sources/rb-iradio-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-iradio-source.c,v
retrieving revision 1.74
diff -u -r1.74 rb-iradio-source.c
--- sources/rb-iradio-source.c	26 Jul 2005 14:07:29 -0000	1.74
+++ sources/rb-iradio-source.c	29 Jul 2005 15:34:08 -0000
@@ -84,6 +84,7 @@
 static void rb_iradio_source_state_prefs_sync (RBIRadioSource *source);
 static void genre_selected_cb (RBPropertyView *propview, const char *name,
 			       RBIRadioSource *iradio_source);
+static void genre_selection_reset_cb (RBPropertyView *propview, RBIRadioSource *iradio_source);
 static void rb_iradio_source_songs_view_sort_order_changed_cb (RBEntryView *view, RBIRadioSource *source);
 
 /* source methods */
@@ -377,6 +378,10 @@
 				 "property-selected",
 				 G_CALLBACK (genre_selected_cb),
 				 source, 0);
+	g_signal_connect_object (G_OBJECT (source->priv->genres),
+				 "property-selection-reset",
+				 G_CALLBACK (genre_selection_reset_cb),
+				 source, 0);
 
 	g_object_set (G_OBJECT (source->priv->genres), "vscrollbar_policy",
 		      GTK_POLICY_AUTOMATIC, NULL);
@@ -696,6 +701,17 @@
 }
 
 static void
+genre_selection_reset_cb (RBPropertyView *propview, RBIRadioSource *iradio_source)
+{
+	g_free (iradio_source->priv->selected_genre);
+	iradio_source->priv->selected_genre = NULL;
+
+	rb_iradio_source_do_query (iradio_source, RB_IRADIO_QUERY_TYPE_GENRE);
+
+	rb_source_notify_filter_changed (RB_SOURCE (iradio_source));
+}
+
+static void
 rb_iradio_source_show_browser (RBIRadioSource *source,
 			       gboolean show)
 {
