banshee r3863 - in trunk/banshee: . src/Core/Banshee.Services/Banshee.Collection src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.Configuration src/Core/Banshee.Services/Banshee.Playlist src/Core/Banshee.Services/Banshee.Sources src/Core/Banshee.ThickClient/Banshee.Gui src/Core/Banshee.ThickClient/Banshee.Gui.Widgets src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue src/Libraries/Hyena.Gui/Hyena.Widgets src/Libraries/Hyena/Hyena src/Libraries/Hyena/Hyena.Data.Sqlite src/Libraries/Hyena/Hyena.Query src/Libraries/Lastfm/Lastfm tests/Hyena



Author: gburt
Date: Fri May  2 19:07:48 2008
New Revision: 3863
URL: http://svn.gnome.org/viewvc/banshee?rev=3863&view=rev

Log:
2008-05-02  Gabriel Burt  <gabriel burt gmail com>

	* src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmSource.cs: Set
	SourceManager.Dispose property to true so that the SourceManager knows to
	Dispose us, even though we're an extension source.

	* src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmActions.cs:
	Listen to the PlaybackController.SourceChanged event, and disable
	shuffle/repeat when switching to a StationSource, and restore when
	switching away and Disposing (so that the original state is not
	overwritten in gconf).  Fixes BGO #526033.

	* src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs:
	Fix silly bug that caused the playback source to switch to the Music
	Library erroneously.

	* src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs:
	Load the tracks in the LoadFromDevice method, and turn threading off on
	the importer since LoadFromDevice is already called from a thread.

	* src/Core/Banshee.ThickClient/Banshee.Gui/GlobalActions.cs: Comment out
	ImportPlaylist stuff that's not done.

	* src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackShuffleActions.cs:
	* src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackRepeatActions.cs: Add
	Sensitive override that triggers the Changed event.

	* src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/RepeatActionButton.cs:
	* src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/NextButton.cs:
	Set the sensitivity of the button to the ActionGroup's sensitivity.

	* src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs: Fix bug
	where we had a SqliteModelProvider created for every DatabaseSource
	instead of sharing one.

	* src/Core/Banshee.Services/Banshee.Sources/SourceManager.cs: Dispose
	extension sources that have the property SourceManager.Dispose == true.

	* tests/Hyena/QueryTests.cs: 
	* src/Libraries/Hyena/Hyena.Query/FileSizeQueryValue.cs:
	* src/Libraries/Hyena/Hyena.Query/TimeSpanQueryValue.cs:
	* src/Core/Banshee.Services/Banshee.Sources/DurationStatusFormatters.cs:
	* src/Libraries/Hyena/Hyena/StringUtil.cs:
	Renamed FormatDouble to DoubleToTenthsPrecision.  Also changed it to use
	Math.Round and fixed bug where 14.96 would show up as 15.0 instead of 15.
	Also changed it to use the N string formatter, which causes separators to
	be shown, eg 1,000

	* src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs: Remove
	superflous assignment. 

	* src/Core/Banshee.Services/Banshee.Collection/ImportManager.cs: Add a
	Threaded bool property, and if false don't use the ThreadPool.

	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs:
	* src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs:
	* src/Core/Banshee.Services/Banshee.Configuration/DatabaseConfigurationClient.cs:
	* src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs:
	Do not explicitly call ApplyValues, but pass the values in the Query or
	Execute method calls.

	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs:
	Comment out use of transactions for now; were causing deadlock;

	* src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs: Comment
	out unfinished playlist import code.

	* tests/Hyena/StringUtilTests.cs: Add tests for DoubleToTenthsPrecision
	and DoubleToPluralInt methods.

	* src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteCommand.cs: Make
	ApplyValues an internal method, accessibly implicitly by passing params to
	the Query or Execute methods.

	* src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteConnection.cs: Lock the
	command before calling ApplyValues.  Comment out the transaction methods,
	since they can cause deadlock.

	* src/Libraries/Lastfm/Lastfm/AudioscrobblerConnection.cs: Better logging.

	* src/Libraries/Hyena.Gui/Hyena.Widgets/MenuButton.cs: Rename member,
	add protected Arrow and ToggleButton properties so that their sensitivity
	can be changed, etc.


Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/ImportManager.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Configuration/DatabaseConfigurationClient.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DurationStatusFormatters.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/SourceManager.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/NextButton.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/RepeatActionButton.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/GlobalActions.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackRepeatActions.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackShuffleActions.cs
   trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
   trunk/banshee/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmActions.cs
   trunk/banshee/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmSource.cs
   trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/MenuButton.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteCommand.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteConnection.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Query/FileSizeQueryValue.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Query/TimeSpanQueryValue.cs
   trunk/banshee/src/Libraries/Hyena/Hyena/StringUtil.cs
   trunk/banshee/src/Libraries/Lastfm/Lastfm/AudioscrobblerConnection.cs
   trunk/banshee/tests/Hyena/QueryTests.cs
   trunk/banshee/tests/Hyena/StringUtilTests.cs

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs	Fri May  2 19:07:48 2008
@@ -161,7 +161,9 @@
                 return null;
             }
 
-            ServiceManager.DbConnection.BeginTransaction ();
+            // TODO note, there is deadlock potential here b/c of locking of shared commands and blocking
+            // because of transactions.  Needs to be fixed in HyenaDatabaseConnection.
+            //ServiceManager.DbConnection.BeginTransaction ();
             try {
                 TagLib.File file = StreamTagger.ProcessUri (uri);
                 track = new DatabaseTrackInfo ();
@@ -175,18 +177,18 @@
                 }
 
                 track.Save (false);
-                counts[track.PrimarySourceId] = counts.ContainsKey (track.PrimarySourceId) ? counts[track.PrimarySourceId] + 1 : 1;
 
-                ServiceManager.DbConnection.CommitTransaction ();
-
-                if (counts[track.PrimarySourceId] % 250 == 0) {
-                    track.PrimarySource.NotifyTracksAdded ();
-                }
+                //ServiceManager.DbConnection.CommitTransaction ();
             } catch (Exception) {
-                ServiceManager.DbConnection.RollbackTransaction ();
+                //ServiceManager.DbConnection.RollbackTransaction ();
                 throw;
             }
 
+            counts[track.PrimarySourceId] = counts.ContainsKey (track.PrimarySourceId) ? counts[track.PrimarySourceId] + 1 : 1;
+            if (counts[track.PrimarySourceId] % 250 == 0) {
+                track.PrimarySource.NotifyTracksAdded ();
+            }
+
             return track;
         }
 

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs	Fri May  2 19:07:48 2008
@@ -56,11 +56,11 @@
 
     public class DatabaseTrackInfo : TrackInfo, ICacheableItem
     {
-        private static BansheeModelProvider<DatabaseTrackInfo> provider = new BansheeModelProvider<DatabaseTrackInfo> (
-            ServiceManager.DbConnection, "CoreTracks"
+        private static DatabaseTrackModelProvider<DatabaseTrackInfo> provider = new DatabaseTrackModelProvider<DatabaseTrackInfo> (
+            ServiceManager.DbConnection
         );
 
-        public static BansheeModelProvider<DatabaseTrackInfo> Provider {
+        public static DatabaseTrackModelProvider<DatabaseTrackInfo> Provider {
             get { return provider; }
         }
 
@@ -445,17 +445,20 @@
 
         public static int GetTrackIdForUri (string relative_path, int [] primary_sources)
         {
-            return ServiceManager.DbConnection.Query<int> (check_command.ApplyValues (primary_sources, relative_path, relative_path));
+            return ServiceManager.DbConnection.Query<int> (check_command,
+                primary_sources, relative_path, relative_path);
         }
         
         public static bool ContainsUri (string relative_path, int [] primary_sources)
         {
-            return ServiceManager.DbConnection.Query<int> (check_command.ApplyValues (primary_sources, relative_path, relative_path)) > 0;
+            return ServiceManager.DbConnection.Query<int> (check_command,
+                primary_sources, relative_path, relative_path) > 0;
         }
 
         public static bool ContainsUri (SafeUri uri, string relative_path, int [] primary_sources)
         {
-            return ServiceManager.DbConnection.Query<int> (check_command.ApplyValues (primary_sources, relative_path, uri.AbsoluteUri)) > 0;
+            return ServiceManager.DbConnection.Query<int> (check_command,
+                primary_sources, relative_path, uri.AbsoluteUri) > 0;
         }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/ImportManager.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/ImportManager.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/ImportManager.cs	Fri May  2 19:07:48 2008
@@ -158,7 +158,12 @@
         public void QueueSource (UriList uris)
         {
             CreateUserJob ();
-            ThreadPool.QueueUserWorkItem (ThreadedQueueSource, uris);
+
+            if (Threaded) {
+                ThreadPool.QueueUserWorkItem (ThreadedQueueSource, uris);
+            } else {
+                ThreadedQueueSource (uris);
+            }
         }
         
         public void QueueSource (string source)
@@ -300,5 +305,11 @@
             get { return progress_message; }
             set { progress_message = value; }
         }
+
+        private bool threaded = true;
+        public bool Threaded {
+            get { return threaded; }
+            set { threaded = value; }
+        }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Configuration/DatabaseConfigurationClient.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Configuration/DatabaseConfigurationClient.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Configuration/DatabaseConfigurationClient.cs	Fri May  2 19:07:48 2008
@@ -95,8 +95,7 @@
         
         private IDataReader Get (string namespce, string key)
         {
-            return connection.Query (
-                select_value_command.ApplyValues (MakeKey (namespce, key)));
+            return connection.Query (select_value_command, MakeKey (namespce, key));
         }
 
         public void Set <T> (SchemaEntry<T> entry, T value)
@@ -111,14 +110,10 @@
 
         public void Set <T> (string namespce, string key, T value)
         {
-            if (connection.Query<int> (select_id_command.ApplyValues (MakeKey (namespce, key))) > 0) {
-                connection.Execute (
-                    update_command.ApplyValues (value.ToString (), MakeKey (namespce, key))
-                );
+            if (connection.Query<int> (select_id_command, MakeKey (namespce, key)) > 0) {
+                connection.Execute (update_command, value.ToString (), MakeKey (namespce, key));
             } else {
-                connection.Execute (
-                    insert_command.ApplyValues (MakeKey (namespce, key), value.ToString ())
-                );
+                connection.Execute (insert_command, MakeKey (namespce, key), value.ToString ());
             }
         }
         

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistFileUtil.cs	Fri May  2 19:07:48 2008
@@ -146,7 +146,7 @@
         }
     }
     
-    public class ImportPlaylistWorker
+    /*public class ImportPlaylistWorker
     {
         private string [] uris;
         private string name;
@@ -172,17 +172,24 @@
         
         private void CreatePlaylist ()
         {
-            PlaylistSource playlist = new PlaylistSource (name, ServiceManager.SourceManager.MusicLibrary.DbId);
-            playlist.Save ();
+            try {
+                PlaylistSource playlist = new PlaylistSource (name, ServiceManager.SourceManager.MusicLibrary.DbId);
+                playlist.Save ();
 
-            HyenaSqliteCommand command = new HyenaSqliteCommand (
-                @"INSERT INTO CorePlaylistEntries (PlaylistID, TrackID)
-                    VALUES (?, (SELECT TrackID FROM CoreTracks WHERE Uri = ?))"
-            );
+                HyenaSqliteCommand command = new HyenaSqliteCommand (
+                    @"INSERT INTO CorePlaylistEntries (PlaylistID, TrackID)
+                        VALUES (?, (SELECT TrackID FROM CoreTracks WHERE Uri = ?))"
+                );
 
-            foreach (string uri in uris) {
-                command.ApplyValues (playlist.DbId, uri);
+                ServiceManager.DbConnection.BeginTransaction ();
+                foreach (string uri in uris) {
+                    ServiceManager.DbConnection.Execute (command, playlist.DbId, uri);
+                }
+                ServiceManager.DbConnection.CommitTransaction ();
+            } catch (Exception e) {
+                Log.Exception (e);
+                ServiceManager.DbConnection.RollbackTransaction ();
             }
         }
-    }
+    }*/
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs	Fri May  2 19:07:48 2008
@@ -219,8 +219,7 @@
 
         protected void AddTrack (int track_id)
         {
-            add_track_command.ApplyValues (DbId, track_id);
-            ServiceManager.DbConnection.Execute (add_track_command);
+            ServiceManager.DbConnection.Execute (add_track_command, DbId, track_id);
             OnTracksAdded ();
         }
         
@@ -253,16 +252,15 @@
                     ? last_add_range_command
                     : new HyenaSqliteCommand (String.Format (add_track_range_from_joined_model_sql, from.JoinTable, from.JoinPrimaryKey));
 
-            last_add_range_command.ApplyValues (DbId, from.CacheId, range.Start, range.Count);
-            ServiceManager.DbConnection.Execute (last_add_range_command);
+            ServiceManager.DbConnection.Execute (last_add_range_command, DbId, from.CacheId, range.Start, range.Count);
 
             last_add_range_from_model = from;
         }
 
         protected override void RemoveTrackRange (DatabaseTrackListModel from, RangeCollection.Range range)
         {
-            remove_track_range_command.ApplyValues (DbId, from.CacheId, range.Start, range.Count);
-            ServiceManager.DbConnection.Execute (remove_track_range_command);
+            ServiceManager.DbConnection.Execute (remove_track_range_command,
+                DbId, from.CacheId, range.Start, range.Count);
         }
 
         protected override void HandleTracksChanged (Source sender, TrackEventArgs args)

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs	Fri May  2 19:07:48 2008
@@ -105,14 +105,8 @@
             set { track_cache = value; }
         }
 
-
-        private DatabaseTrackModelProvider<DatabaseTrackInfo> track_provider;
         protected DatabaseTrackModelProvider<DatabaseTrackInfo> TrackProvider {
-            get {
-                return track_provider ?? track_provider = new DatabaseTrackModelProvider<DatabaseTrackInfo> (
-                    ServiceManager.DbConnection
-                );
-            }
+            get { return DatabaseTrackInfo.Provider; }
         }
 
         private void DatabaseSourceInitialize ()
@@ -441,8 +435,8 @@
 
         protected virtual void RateTrackRange (DatabaseTrackListModel model, RangeCollection.Range range, int rating)
         {
-            RateTrackRangeCommand.ApplyValues (rating, DateTime.Now, range.Start, range.End - range.Start + 1);
-            ServiceManager.DbConnection.Execute (RateTrackRangeCommand);
+            ServiceManager.DbConnection.Execute (RateTrackRangeCommand,
+                rating, DateTime.Now, range.Start, range.End - range.Start + 1);
         }
 
         protected void WithTrackSelection (DatabaseTrackListModel model, TrackRangeHandler handler)

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DurationStatusFormatters.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DurationStatusFormatters.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DurationStatusFormatters.cs	Fri May  2 19:07:48 2008
@@ -51,15 +51,15 @@
             if (span.Days > 0) {
                 double days = span.Days + (span.Hours / 24.0);
                 builder.AppendFormat (Catalog.GetPluralString ("{0} day", "{0} days", 
-                    StringUtil.DoubleToPluralInt (days)), StringUtil.FormatDouble (days));
+                    StringUtil.DoubleToPluralInt (days)), StringUtil.DoubleToTenthsPrecision (days));
             } else if (span.Hours > 0) {
                 double hours = span.Hours + (span.Minutes / 60.0);
                 builder.AppendFormat (Catalog.GetPluralString ("{0} hour", "{0} hours", 
-                    StringUtil.DoubleToPluralInt (hours)), StringUtil.FormatDouble (hours));
+                    StringUtil.DoubleToPluralInt (hours)), StringUtil.DoubleToTenthsPrecision (hours));
             } else {
                 double minutes = span.Minutes + (span.Seconds / 60.0);
                 builder.AppendFormat (Catalog.GetPluralString ("{0} minute", "{0} minutes", 
-                    StringUtil.DoubleToPluralInt (minutes)), StringUtil.FormatDouble (minutes));
+                    StringUtil.DoubleToPluralInt (minutes)), StringUtil.DoubleToTenthsPrecision (minutes));
             }
         }
         

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs	Fri May  2 19:07:48 2008
@@ -144,7 +144,6 @@
 
         protected PrimarySource (string generic_name, string name, string id, int order) : base (generic_name, name, id, order)
         {
-            type_unique_id = id;
             PrimarySourceInitialize ();
         }
 

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/SourceManager.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/SourceManager.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/SourceManager.cs	Fri May  2 19:07:48 2008
@@ -84,7 +84,9 @@
             lock (this) {
                 // Do not dispose extension sources
                 foreach (Source source in extension_sources.Values) {
-                    RemoveSource (source, false);
+                    // Only dispose extension sources that explicitly tell us to, otherwise
+                    // assume their Service or somesuch will Dispose them.
+                    RemoveSource (source, source.Properties.Get<bool> ("SourceManager.Dispose"));
                 }
 
                 // But do dispose non-extension sources

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/NextButton.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/NextButton.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/NextButton.cs	Fri May  2 19:07:48 2008
@@ -36,11 +36,28 @@
 {
     public class NextButton : MenuButton
     {
+        PlaybackShuffleActions shuffle_actions;
+        Menu menu;
+        Widget button;
+
         public NextButton (InterfaceActionService actionService)
         {
-            Widget button = actionService.PlaybackActions["NextAction"].CreateToolItem ();
-            Menu menu = actionService.PlaybackActions.ShuffleActions.CreateMenu ();
+            shuffle_actions = actionService.PlaybackActions.ShuffleActions;
+
+            button = actionService.PlaybackActions["NextAction"].CreateToolItem ();
+            menu = shuffle_actions.CreateMenu ();
             Construct (button, menu, true);
+
+            shuffle_actions.Changed += OnActionsChanged;
+        }
+
+        private void OnActionsChanged (object o, EventArgs args)
+        {
+            menu.Sensitive = shuffle_actions.Sensitive;
+            ToggleButton.Sensitive = shuffle_actions.Sensitive;
+            if (Arrow != null) {
+                Arrow.Sensitive = shuffle_actions.Sensitive;
+            }
         }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/RepeatActionButton.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/RepeatActionButton.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/RepeatActionButton.cs	Fri May  2 19:07:48 2008
@@ -54,9 +54,6 @@
             label.UseUnderline = true;
             image.IconSize = (int)IconSize.Menu;
             
-            actions.Changed += delegate { OnActionChanged (); };
-            OnActionChanged ();
-            
             box.PackStart (image, false, false, (uint)(iconOnly ? 4 : 0));
             if (!iconOnly) {
                 box.PackStart (label, true, true, 0);
@@ -64,11 +61,16 @@
             
             button = new MenuButton (box, actions.CreateMenu (), false);
             Add (button);
+
+            actions.Changed += OnActionChanged;
+            OnActionChanged (null, null);
+
             ShowAll ();
         }
         
-        private void OnActionChanged ()
+        private void OnActionChanged (object o, EventArgs args)
         {
+            button.Sensitive = image.Sensitive = label.Sensitive = actions.Sensitive;
             image.IconName = actions.Active.IconName;
             label.TextWithMnemonic = actions.Active.Label;
         }

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/GlobalActions.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/GlobalActions.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/GlobalActions.cs	Fri May  2 19:07:48 2008
@@ -53,9 +53,9 @@
                     Catalog.GetString ("Import _Media..."), "<control>I",
                     Catalog.GetString ("Import media from a variety of sources"), OnImport),
 
-                new ActionEntry ("ImportPlaylistAction", null,
+                /*new ActionEntry ("ImportPlaylistAction", null,
                     Catalog.GetString ("Import Playlist..."), null,
-                    Catalog.GetString ("Import a playlist"), OnImportPlaylist),
+                    Catalog.GetString ("Import a playlist"), OnImportPlaylist),*/
 
                 new ActionEntry ("OpenLocationAction", null, 
                     Catalog.GetString ("Open _Location..."), "<control>L",
@@ -165,7 +165,7 @@
             }
         }
 
-        private void OnImportPlaylist (object o, EventArgs args)
+        /*private void OnImportPlaylist (object o, EventArgs args)
         {
             // Prompt user for location of the playlist.
             Banshee.Gui.Dialogs.FileChooserDialog chooser = new Banshee.Gui.Dialogs.FileChooserDialog(
@@ -226,7 +226,7 @@
                 md.Destroy();
                 return;
             }
-        }
+        }*/
         
         private void OnQuit (object o, EventArgs args)
         {

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackRepeatActions.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackRepeatActions.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackRepeatActions.cs	Fri May  2 19:07:48 2008
@@ -51,10 +51,19 @@
                 active_action = value;
                 RepeatMode.Set (active_action == null ? String.Empty : ActionNameToConfigId (active_action.Name));
                 ServiceManager.PlaybackController.RepeatMode = (PlaybackRepeatMode)active_action.Value;
+                OnChanged ();
+            }
+        }
+        
+        public new bool Sensitive {
+            get { return base.Sensitive; }
+            set {
+                base.Sensitive = value;
+                OnChanged ();
             }
         }
 
-        public event ChangedHandler Changed;
+        public event EventHandler Changed;
         
         public PlaybackRepeatActions (InterfaceActionService actionService) : base ("PlaybackRepeat")
         {
@@ -82,7 +91,7 @@
                     Catalog.GetString ("Repeat Singl_e"), null,
                     Catalog.GetString ("Repeat the current playing song"),
                     (int)PlaybackRepeatMode.RepeatSingle)
-            }, 0, OnChanged);
+            }, 0, OnActionChanged);
 
             this["RepeatNoneAction"].IconName = "media-repeat-none";
             this["RepeatAllAction"].IconName = "media-repeat-all";
@@ -98,13 +107,16 @@
             Active.Activate ();
         }
 
-        private void OnChanged (object o, ChangedArgs args)
+        private void OnActionChanged (object o, ChangedArgs args)
         {
             Active = args.Current;
-            
-            ChangedHandler handler = Changed;
+        }
+        
+        private void OnChanged ()
+        {
+            EventHandler handler = Changed;
             if (handler != null) {
-                handler (o, args);
+                handler (this, EventArgs.Empty);
             }
         }
         

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackShuffleActions.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackShuffleActions.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackShuffleActions.cs	Fri May  2 19:07:48 2008
@@ -52,10 +52,19 @@
                 active_action = value;
                 ShuffleMode.Set (active_action == null ? String.Empty : ActionNameToConfigId (active_action.Name));
                 ServiceManager.PlaybackController.ShuffleMode = (PlaybackShuffleMode)active_action.Value;
+                OnChanged ();
             }
         }
 
-        public event ChangedHandler Changed;
+        public new bool Sensitive {
+            get { return base.Sensitive; }
+            set {
+                base.Sensitive = value;
+                OnChanged ();
+            }
+        }
+
+        public event EventHandler Changed;
         
         public PlaybackShuffleActions (InterfaceActionService actionService, PlaybackActions playbackActions)
             : base ("PlaybackShuffle")
@@ -90,7 +99,7 @@
                     Catalog.GetString ("Shuffle by A_lbum"), null,
                     Catalog.GetString ("Play all songs from an album, then randomly choose another album"),
                     (int)PlaybackShuffleMode.Album)
-            }, 0, OnChanged);
+            }, 0, OnActionChanged);
                 
             this["ShuffleOffAction"].IconName = "media-skip-forward";
             this["ShuffleSongAction"].IconName = "media-playlist-shuffle";
@@ -109,15 +118,17 @@
             Active.Activate ();
         }
 
-        private void OnChanged (object o, ChangedArgs args)
+        private void OnActionChanged (object o, ChangedArgs args)
         {
             Active = args.Current;
-            
+        }
+
+        private void OnChanged ()
+        {
             playback_actions["NextAction"].IconName = Active.IconName;
-            
-            ChangedHandler handler = Changed;
+            EventHandler handler = Changed;
             if (handler != null) {
-                handler (o, args);
+                handler (this, EventArgs.Empty);
             }
         }
         

Modified: trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs	Fri May  2 19:07:48 2008
@@ -70,11 +70,14 @@
 
             // TODO differentiate between Audio Players and normal Disks, and include the size, eg "2GB Audio Player"?
             //GenericName = Catalog.GetString ("Audio Player");
+        }
 
-            SetStatus (String.Format (Catalog.GetString ("Loading {0}"), Name), false);
+        // WARNING: This will be called from a thread!
+        protected override void LoadFromDevice ()
+        {
             DatabaseImportManager importer = new DatabaseImportManager (this);
             importer.KeepUserJobHidden = true;
-            importer.ImportFinished += delegate  { HideStatus (); };
+            importer.Threaded = false; // We're already threaded
             importer.QueueSource (BaseDirectory);
         }
 

Modified: trunk/banshee/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmActions.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmActions.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmActions.cs	Fri May  2 19:07:48 2008
@@ -45,6 +45,7 @@
 using Banshee.ServiceStack;
 using Banshee.Gui;
 using Banshee.Collection;
+using Banshee.PlaybackController;
 
 using Browser = Banshee.Web.Browser;
 
@@ -62,10 +63,6 @@
             action_service = ServiceManager.Get<InterfaceActionService> ();
             this.lastfm = lastfm;
             
-            ServiceManager.PlayerEngine.ConnectEvent (OnPlayerEvent, 
-                PlayerEvent.StartOfStream | 
-                PlayerEvent.EndOfStream);
-
             AddImportant (
                 new ActionEntry (
                     "LastfmAddAction", Stock.Add,
@@ -189,25 +186,22 @@
             );
 
             actions_id = action_service.UIManager.AddUiFromResource ("GlobalUI.xml");
+            action_service.AddActionGroup (this);
 
             lastfm.Connection.StateChanged += HandleConnectionStateChanged;
-            
-            this["LastfmLoveAction"].Visible = false;
-            this["LastfmHateAction"].Visible = false;
-            this["LastfmLoveAction"].IsImportant = true;
-            this["LastfmHateAction"].IsImportant = true;
-
-            UpdateActions ();
-
             action_service.SourceActions ["SourcePropertiesAction"].Activated += OnSourceProperties;
-
-            action_service.AddActionGroup (this);
+            ServiceManager.PlaybackController.SourceChanged += OnPlaybackSourceChanged;
+            ServiceManager.PlayerEngine.ConnectEvent (OnPlayerEvent, 
+                PlayerEvent.StartOfStream | 
+                PlayerEvent.EndOfStream);
+            UpdateActions ();
         }
 
         public override void Dispose ()
         {
             action_service.UIManager.RemoveUi (actions_id);
             action_service.RemoveActionGroup (this);
+            RestoreShuffleRepeat ();
             base.Dispose ();
         }
 
@@ -399,12 +393,7 @@
 
         private void OnPlayerEvent (PlayerEventArgs args)
         { 
-            if (args.Event == PlayerEvent.EndOfStream || args.Event == PlayerEvent.StartOfStream) {
-                TrackInfo current_track = ServiceManager.PlayerEngine.CurrentTrack;
-                this["LastfmLoveAction"].Visible = current_track is LastfmTrackInfo;
-                this["LastfmHateAction"].Visible = current_track is LastfmTrackInfo;
-                this["LastfmAddAction"].IsImportant = !(current_track is LastfmTrackInfo);
-            }
+            UpdateActions ();
         }
 
         private void HandleConnectionStateChanged (object sender, ConnectionStateChangedArgs args)
@@ -422,11 +411,58 @@
             }
 
             bool have_user = (lastfm.Account.UserName != null);
+            this["LastfmAddAction"].IsImportant = ServiceManager.PlaybackController.Source is LastfmSource;
             this["LastfmAddAction"].Sensitive = have_user;
             this["LastfmSortAction"].Sensitive = have_user;
             this["LastfmConnectAction"].Visible = lastfm.Connection.State == ConnectionState.Disconnected;
 
+            TrackInfo current_track = ServiceManager.PlayerEngine.CurrentTrack;
+            this["LastfmLoveAction"].Visible = current_track is LastfmTrackInfo;
+            this["LastfmHateAction"].Visible = current_track is LastfmTrackInfo;
+
             updating = false;
         }
+
+        private RadioAction old_shuffle;
+        private RadioAction old_repeat;
+        private bool was_lastfm = false;
+        private void OnPlaybackSourceChanged (object o, EventArgs args)
+        {
+            if (action_service == null || action_service.PlaybackActions == null || ServiceManager.PlaybackController == null)
+                return;
+
+            UpdateActions ();
+
+            bool is_lastfm = ServiceManager.PlaybackController.Source is StationSource;
+            action_service.PlaybackActions["PreviousAction"].Sensitive = !is_lastfm;
+            PlaybackRepeatActions repeat_actions = action_service.PlaybackActions.RepeatActions;
+            PlaybackShuffleActions shuffle_actions = action_service.PlaybackActions.ShuffleActions;
+
+            // Save/clear or restore shuffle/repeat values when we first switch to a Last.fm station
+            if (is_lastfm && !was_lastfm) {
+                old_repeat = repeat_actions.Active;
+                repeat_actions.Active = repeat_actions["RepeatNoneAction"] as RadioAction;
+                
+                old_shuffle = shuffle_actions.Active;
+                shuffle_actions.Active = shuffle_actions["ShuffleOffAction"] as RadioAction;
+            } else {
+                RestoreShuffleRepeat ();
+            }
+            
+            // Set sensitivity
+            shuffle_actions.Sensitive = !is_lastfm;
+            repeat_actions.Sensitive = !is_lastfm;
+
+            was_lastfm = is_lastfm;
+        }
+
+        private void RestoreShuffleRepeat ()
+        {
+            if (action_service != null && action_service.PlaybackActions != null && old_repeat != null) {
+                action_service.PlaybackActions.RepeatActions.Active = old_repeat;
+                action_service.PlaybackActions.ShuffleActions.Active = old_shuffle;
+            }
+            old_repeat = old_shuffle = null;
+        }
     }
 }

Modified: trunk/banshee/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmSource.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmSource.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/LastfmSource.cs	Fri May  2 19:07:48 2008
@@ -99,6 +99,8 @@
             Connection.StateChanged += HandleConnectionStateChanged;
             UpdateUI ();
 
+            Properties.Set<bool> ("SourceManager.Dispose", true);
+
             Properties.SetString ("ActiveSourceUIResource", "ActiveSourceUI.xml");
             Properties.SetString ("GtkActionPath", "/LastfmSourcePopup");
             Properties.SetString ("Icon.Name", "lastfm-audioscrobbler");

Modified: trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs	Fri May  2 19:07:48 2008
@@ -114,7 +114,7 @@
             ServiceManager.SourceManager.VideoLibrary.TracksDeleted += HandleTracksDeleted;
             
             TrackModel.Reloaded += delegate {
-                if (Count == 0) {
+                if (this == ServiceManager.PlaybackController.Source && Count == 0) {
                     ServiceManager.PlaybackController.Source = (ITrackModelSource)ServiceManager.SourceManager.DefaultSource;
                 }
             };

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/MenuButton.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/MenuButton.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Widgets/MenuButton.cs	Fri May  2 19:07:48 2008
@@ -33,7 +33,7 @@
 {
     public class MenuButton : Container
     {
-        private ToggleButton button = new ToggleButton ();
+        private ToggleButton toggle_button = new ToggleButton ();
         private HBox box = new HBox ();
         private Alignment alignment;
         private Arrow arrow;
@@ -56,13 +56,13 @@
             
             button_widget = buttonWidget;
             this.menu = menu;
-            menu.Deactivated += delegate { button.Active = false; };
+            menu.Deactivated += delegate { toggle_button.Active = false; };
             
-            button.Parent = this;
-            button.FocusOnClick = false;
-            button.Relief = ReliefStyle.None;
-            button.Pressed += delegate { button.Active = true; ShowMenu (); };
-            button.Activated += delegate { ShowMenu (); };
+            toggle_button.Parent = this;
+            toggle_button.FocusOnClick = false;
+            toggle_button.Relief = ReliefStyle.None;
+            toggle_button.Pressed += delegate { toggle_button.Active = true; ShowMenu (); };
+            toggle_button.Activated += delegate { ShowMenu (); };
             
             box.Parent = this;
             
@@ -74,8 +74,8 @@
                 box.PackStart (alignment, false, false, 5);
                 size_widget = box;
             } else {
-                button.Add (button_widget);
-                size_widget = button;
+                toggle_button.Add (button_widget);
+                size_widget = toggle_button;
             }
             
             ShowAll ();
@@ -89,6 +89,14 @@
             get { return menu; }
         }
         
+        protected ToggleButton ToggleButton {
+            get { return toggle_button; }
+        }
+        
+        protected Arrow Arrow {
+            get { return arrow; }
+        }
+        
         protected override void OnSizeRequested (ref Requisition requisition)
         {
             requisition = size_widget.SizeRequest ();
@@ -97,13 +105,13 @@
         protected override void OnSizeAllocated (Rectangle allocation)
         {
             box.SizeAllocate (allocation);
-            button.SizeAllocate (allocation);
+            toggle_button.SizeAllocate (allocation);
             base.OnSizeAllocated (allocation);
         }
         
         protected override void ForAll (bool include_internals, Callback callback)
         {
-            callback (button);
+            callback (toggle_button);
             callback (box);
         }
         

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteCommand.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteCommand.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteCommand.cs	Fri May  2 19:07:48 2008
@@ -135,7 +135,7 @@
             return ret;
         }
 
-        public HyenaSqliteCommand ApplyValues (params object [] param_values)
+        internal HyenaSqliteCommand ApplyValues (params object [] param_values)
         {
             if (command_format == null) {
                 CreateParameters ();

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteConnection.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteConnection.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/HyenaSqliteConnection.cs	Fri May  2 19:07:48 2008
@@ -97,7 +97,9 @@
 
         public IDataReader Query (HyenaSqliteCommand command, params object [] param_values)
         {
-            return Query (command.ApplyValues (param_values));
+            lock (command) {
+                return Query (command.ApplyValues (param_values));
+            }
         }
 
         public IDataReader Query (string command_str, params object [] param_values)
@@ -125,7 +127,9 @@
 
         public T Query<T> (HyenaSqliteCommand command, params object [] param_values)
         {
-            return Query<T> (command.ApplyValues (param_values));
+            lock (command) {
+                return Query<T> (command.ApplyValues (param_values));
+            }
         }
 
         public T Query<T> (string command_str, params object [] param_values)
@@ -150,7 +154,9 @@
 
         public int Execute (HyenaSqliteCommand command, params object [] param_values)
         {
-            return Execute (command.ApplyValues (param_values));
+            lock (command) {
+                return Execute (command.ApplyValues (param_values));
+            }
         }
 
         public int Execute (string command_str, params object [] param_values)
@@ -167,7 +173,11 @@
 
 #region Public Utility Methods
         
-        public void BeginTransaction ()
+        // FIXME these are commented out because they can cause deadlock if one thread
+        // starts a transaction, then another one tries to execute command A (which locks A) but
+        // waits for the transaction to finish while holding the lock on A.  If the transaction thread
+        // then tries to execute/lock A, it can't.
+        /*public void BeginTransaction ()
         {
             if (transaction_thread == Thread.CurrentThread) {
                 throw new Exception ("Can't start a recursive transaction");
@@ -219,7 +229,7 @@
                 // Let any other threads continue
                 transaction_signal.Set (); 
             }
-        }
+        }*/
 
         public bool TableExists (string tableName)
         {

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs	Fri May  2 19:07:48 2008
@@ -269,9 +269,9 @@
             }
         }
         
-        protected virtual void PrepareInsertCommand (T target)
+        protected virtual object [] GetInsertParams (T target)
         {
-            // TODO create an instance variable object array and reuse it?
+            // TODO create an instance variable object array and reuse it? beware threading issues
             object [] values = new object [columns.Count - 1];
             int j = 0;
             for (int i = 0; i < columns.Count; i++) {
@@ -280,18 +280,17 @@
                     j++;
                 }
             }
-            InsertCommand.ApplyValues (values);
+            return values;
         }
         
         protected int Insert (T target)
         {
-            PrepareInsertCommand (target);
-            return connection.Execute (InsertCommand);
+            return connection.Execute (InsertCommand, GetInsertParams (target));
         }
 
-        protected virtual void PrepareUpdateCommand (T target)
+        protected object [] GetUpdateParams (T target)
         {
-            // TODO create an instance variable object array and reuse it?
+            // TODO create an instance variable object array and reuse it? beware threading issues
             object [] values = new object [columns.Count];
             int j = 0;
             for (int i = 0; i < columns.Count; i++) {
@@ -301,13 +300,12 @@
                 }
             }
             values[j] = key.GetValue (target);
-            UpdateCommand.ApplyValues (values);
+            return values;
         }
         
         protected void Update (T target)
         {
-            PrepareUpdateCommand (target);
-            connection.Execute (UpdateCommand);
+            connection.Execute (UpdateCommand, GetUpdateParams (target));
         }
         
         public T Load (IDataReader reader)
@@ -340,13 +338,8 @@
             }
         }
         
-        protected virtual void PrepareSelectCommand ()
-        {
-        }
-        
         public IEnumerable<T> FetchAll ()
         {
-            PrepareSelectCommand ();
             using (IDataReader reader = connection.Query (SelectCommand)) {
                 while (reader.Read ()) {
                     yield return Load (reader);
@@ -356,7 +349,6 @@
 
         public T FetchFirstMatching (string condition)
         {
-            PrepareSelectCommand ();
             HyenaSqliteCommand fetch_matching_command = new HyenaSqliteCommand (String.Format ("{0} AND {1}", SelectCommand.Text, condition));
             using (IDataReader reader = connection.Query (fetch_matching_command)) {
                 if (reader.Read ()) {
@@ -368,7 +360,6 @@
         
         public IEnumerable<T> FetchAllMatching (string condition)
         {
-            PrepareSelectCommand ();
             HyenaSqliteCommand fetch_matching_command = new HyenaSqliteCommand (String.Format ("{0} AND {1}", SelectCommand.Text, condition));
             using (IDataReader reader = connection.Query (fetch_matching_command)) {
                 while (reader.Read ()) {
@@ -377,26 +368,15 @@
             }
         }
         
-        protected virtual void PrepareSelectRangeCommand (int offset, int limit)
-        {
-            SelectRangeCommand.ApplyValues (offset, limit);
-        }
-        
         public IEnumerable<T> FetchRange (int offset, int limit)
         {
-            PrepareSelectRangeCommand (offset, limit);
-            using (IDataReader reader = connection.Query (SelectRangeCommand)) {
+            using (IDataReader reader = connection.Query (SelectRangeCommand, offset, limit)) {
                 while (reader.Read ()) {
                     yield return Load (reader);
                 }
             }
         }
         
-        protected virtual void PrepareSelectSingleCommand (object id)
-        {
-            SelectSingleCommand.ApplyValues (id);
-        }
-        
         public T FetchSingle (int id)
         {
             return FetchSingle ((long) id);
@@ -404,8 +384,7 @@
         
         public T FetchSingle (long id)
         {
-            PrepareSelectSingleCommand (id);
-            using (IDataReader reader = connection.Query (SelectSingleCommand)) {
+            using (IDataReader reader = connection.Query (SelectSingleCommand, id)) {
                 if (reader.Read ()) {
                     return Load (reader);
                 }
@@ -420,7 +399,7 @@
         
         public void Delete (long id)
         {
-            connection.Execute (delete_command.ApplyValues (id));
+            connection.Execute (delete_command, id);
         }
         
         public void Delete (T item)
@@ -439,7 +418,7 @@
             }
             
             if (ids.Count > 0)
-                connection.Execute (delete_command.ApplyValues (ids.ToArray ()));
+                connection.Execute (delete_command, ids.ToArray ());
         }
 
         public bool Refresh (T item)
@@ -451,8 +430,7 @@
             if (id < 1)
                 return false;
 
-            PrepareSelectSingleCommand (id);
-            using (IDataReader reader = connection.Query (SelectSingleCommand)) {
+            using (IDataReader reader = connection.Query (SelectSingleCommand, id)) {
                 if (reader.Read ()) {
                     Load (reader);
                     return true;

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Query/FileSizeQueryValue.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Query/FileSizeQueryValue.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Query/FileSizeQueryValue.cs	Fri May  2 19:07:48 2008
@@ -117,7 +117,7 @@
             if (factor != FileSizeFactor.None) {
                 return String.Format (
                     "{0} {1}",
-                    IntValue == 0 ? "0" : StringUtil.FormatDouble (((double)IntValue / (double)factor)),
+                    IntValue == 0 ? "0" : StringUtil.DoubleToTenthsPrecision (((double)IntValue / (double)factor)),
                     factor.ToString ()
                 );
             } else {

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Query/TimeSpanQueryValue.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Query/TimeSpanQueryValue.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Query/TimeSpanQueryValue.cs	Fri May  2 19:07:48 2008
@@ -169,7 +169,7 @@
                 default: return null;
             }
 
-            return String.Format (translated, StringUtil.FormatDouble (count));
+            return String.Format (translated, StringUtil.DoubleToTenthsPrecision (count));
         }
     }
 }

Modified: trunk/banshee/src/Libraries/Hyena/Hyena/StringUtil.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena/StringUtil.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena/StringUtil.cs	Fri May  2 19:07:48 2008
@@ -113,15 +113,15 @@
             return builder.ToString ();
         }
 
-        public static string FormatDouble (double num)
+        public static string DoubleToTenthsPrecision (double num)
         {
-            // Don't show x.0
-            if (num - (int)num < 0.1)
-                return Convert.ToString ((int)num);
-            else
-                return String.Format ("{0:0.0}", num);
+            num = Math.Round (num, 1, MidpointRounding.ToEven);
+            return String.Format (
+                num == (int)num ? "{0:N0}" : "{0:N1}", num
+            );
         }
         
+        // This method helps us pluralize doubles. Probably a horrible i18n idea.
         public static int DoubleToPluralInt (double num)
         {
             if (num == (int)num)

Modified: trunk/banshee/src/Libraries/Lastfm/Lastfm/AudioscrobblerConnection.cs
==============================================================================
--- trunk/banshee/src/Libraries/Lastfm/Lastfm/AudioscrobblerConnection.cs	(original)
+++ trunk/banshee/src/Libraries/Lastfm/Lastfm/AudioscrobblerConnection.cs	Fri May  2 19:07:48 2008
@@ -281,10 +281,8 @@
 
             try {
                 stream = current_web_req.EndGetRequestStream (ar);
-            }
-            catch (Exception e) {
-                Hyena.Log.Warning ("Failed to get the request stream", e.ToString (), false);
-
+            } catch (Exception e) {
+                Log.Exception ("Failed to get the request stream", e);
                 state = State.Idle;
                 next_interval = DateTime.Now + new TimeSpan (0, 0, RETRY_SECONDS);
                 return;

Modified: trunk/banshee/tests/Hyena/QueryTests.cs
==============================================================================
--- trunk/banshee/tests/Hyena/QueryTests.cs	(original)
+++ trunk/banshee/tests/Hyena/QueryTests.cs	Fri May  2 19:07:48 2008
@@ -30,7 +30,7 @@
 
         qv = new FileSizeQueryValue (); qv.ParseUserQuery ("2048 KB");
         Assert.AreEqual (2097152, qv.Value);
-        Assert.AreEqual ("2048 KB", qv.ToUserQuery ());
+        Assert.AreEqual ("2.048 KB", qv.ToUserQuery ());
         Assert.AreEqual ("2097152", qv.ToSql ());
 
         // TODO this will break once an it_IT translation for "days ago" etc is committed

Modified: trunk/banshee/tests/Hyena/StringUtilTests.cs
==============================================================================
--- trunk/banshee/tests/Hyena/StringUtilTests.cs	(original)
+++ trunk/banshee/tests/Hyena/StringUtilTests.cs	Fri May  2 19:07:48 2008
@@ -58,4 +58,32 @@
             Assert.AreEqual (map.Under, StringUtil.CamelCaseToUnderCase (map.Camel));
         }
     }
+
+    [Test]
+    public void TestDoubleToTenthsPrecision ()
+    {
+        // Note we are testing with locale = it_IT, hence the commas
+        Assert.AreEqual ("15",      StringUtil.DoubleToTenthsPrecision (15.0));
+        Assert.AreEqual ("15",      StringUtil.DoubleToTenthsPrecision (15.0334));
+        Assert.AreEqual ("15,1",    StringUtil.DoubleToTenthsPrecision (15.052));
+        Assert.AreEqual ("15,5",    StringUtil.DoubleToTenthsPrecision (15.5234));
+        Assert.AreEqual ("15",      StringUtil.DoubleToTenthsPrecision (14.9734));
+        Assert.AreEqual ("14,9",    StringUtil.DoubleToTenthsPrecision (14.92));
+        Assert.AreEqual ("0,4",     StringUtil.DoubleToTenthsPrecision (0.421));
+        Assert.AreEqual ("0",       StringUtil.DoubleToTenthsPrecision (0.01));
+        Assert.AreEqual ("1.000,3", StringUtil.DoubleToTenthsPrecision (1000.32));
+        Assert.AreEqual ("9.233",   StringUtil.DoubleToTenthsPrecision (9233));
+    }
+
+    [Test]
+    public void TestDoubleToPluralInt ()
+    {
+        // This method helps us pluralize doubles. Probably a horrible i18n idea.
+        Assert.AreEqual (0,     StringUtil.DoubleToPluralInt (0));
+        Assert.AreEqual (1,     StringUtil.DoubleToPluralInt (1));
+        Assert.AreEqual (2,     StringUtil.DoubleToPluralInt (2));
+        Assert.AreEqual (1,     StringUtil.DoubleToPluralInt (0.5));
+        Assert.AreEqual (2,     StringUtil.DoubleToPluralInt (1.8));
+        Assert.AreEqual (22,    StringUtil.DoubleToPluralInt (21.3));
+    }
 }



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