banshee r3743 - in trunk/banshee: . src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.Playlist src/Core/Banshee.Services/Banshee.ServiceStack src/Core/Banshee.Services/Banshee.Sources src/Core/Banshee.ThickClient/Banshee.Sources.Gui src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue src/Libraries/Hyena/Hyena.Collections src/Libraries/Hyena/Hyena.Data.Sqlite



Author: gburt
Date: Thu Apr 10 05:21:35 2008
New Revision: 3743
URL: http://svn.gnome.org/viewvc/banshee?rev=3743&view=rev

Log:
2008-04-09  Gabriel Burt  <gabriel burt gmail com>

	This commit makes adding and deleting from a PrimarySource async, and pops
	up UserJobs if those operations take very long.  Very importantly, it also
	adds the ability to copy the track model selection so slow running jobs
	can process it w/o risking it changing on them.

	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs:
	Handle having no artist or album model gracefully.

	* src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs: Fixed up
	Add/Delete methods.

	* src/Core/Banshee.Services/Banshee.ServiceStack/UserJob.cs: Handle
	multiple Finish calls gracefully.

	* src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs: New
	AddAllTracks method for use by MergeSource method.

	* src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs: Change slow
	operations to use a new CachedList object instead of iterating over the
	model's Selection, since it or the model might change underneath us.  Add
	UserJobs for adding/deleting.

	* src/Core/Banshee.Services/Banshee.Sources/Source.cs: Don't raise
	UserNotifyUpdated if we're the active source.

	* src/Core/Banshee.Services/Makefile.am: New files

	* src/Core/Banshee.Services/Banshee.Collection.Database/CachedList.cs: New
	class that contains a SqliteModelCache, so it's backed by CoreCache and
	can be used to store info (eg the selected tracks from a source) so they
	can be operated on independent of the original selection/model.

	* src/Core/Banshee.Services/Banshee.ServiceStack/BatchUserJob.cs: UserJob
	convenience subclass.

	* src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView_DragAndDrop.cs:
	Do MergeSource operations in a thread.  Should probably be done in
	PrimarySource.

	* src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs:
	Whitespace.

	* src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs:
	Get rid of OnUserNotifyUpdated, this is done in DatabaseSource now.

	* src/Libraries/Hyena/Hyena.Collections/RangeCollection.cs: Add Count
	property to Range to avoid doing End - Start + 1 everywhere.

	* src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs: Make work
	without a Selection.


Added:
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/CachedList.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/BatchUserJob.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/UserJob.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/Source.cs
   trunk/banshee/src/Core/Banshee.Services/Makefile.am
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView_DragAndDrop.cs
   trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
   trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Collections/RangeCollection.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/CachedList.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/CachedList.cs	Thu Apr 10 05:21:35 2008
@@ -0,0 +1,123 @@
+//
+// CachedList.cs
+//
+// Author:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+using Hyena.Data;
+using Hyena.Collections;
+using Hyena.Data.Sqlite;
+
+using Banshee.Database;
+using Banshee.ServiceStack;
+
+namespace Banshee.Collection.Database
+{
+    public class CachedList<T> : IEnumerable<T> where T : ICacheableItem, new ()
+    {
+        private static object lock_obj = new object ();
+        private static int cache_id = 0;
+
+        private static string NextCacheId ()
+        {
+            lock (lock_obj) {
+                cache_id++;
+                return String.Format ("CachedList-{0}", cache_id);
+            }
+        }
+
+        private BansheeModelCache<T> cache;
+
+        public static CachedList<DatabaseTrackInfo> CreateFromModelSelection (DatabaseTrackListModel model)
+        {
+            CachedList<DatabaseTrackInfo> list = new CachedList<DatabaseTrackInfo> (DatabaseTrackInfo.Provider);
+
+            HyenaSqliteCommand add_range_command = new HyenaSqliteCommand (String.Format (@"
+                INSERT INTO CoreCache (ModelID, ItemID)
+                    SELECT ?, {0}", model.TrackIdsSql
+            ));
+
+            lock (model) {
+                foreach (RangeCollection.Range range in model.Selection.Ranges) {
+                    ServiceManager.DbConnection.Execute (add_range_command, list.CacheId, model.CacheId, range.Start, range.Count);
+                }
+            }
+
+            list.cache.UpdateAggregates ();
+
+            return list;
+        }
+
+        public CachedList (BansheeModelProvider<T> provider)
+        {
+            string uuid = NextCacheId ();
+            cache = new BansheeModelCache <T> (ServiceManager.DbConnection, uuid, CacheableDatabaseModel.Instance, provider);
+            Clear ();
+        }
+
+        public void Clear ()
+        {
+            ServiceManager.DbConnection.Execute ("DELETE FROM CoreCache WHERE ModelId = ?", CacheId);
+        }
+
+        public long CacheId {
+            get { return cache.CacheId; }
+        }
+
+        public long Count {
+            get { return cache.Count; }
+        }
+
+        public IEnumerator<T> GetEnumerator ()
+        {
+            for (long i = 0; i < cache.Count; i++) {
+                yield return cache.GetValue (i);
+            }
+        }
+        
+        IEnumerator IEnumerable.GetEnumerator ()
+        {
+            return GetEnumerator ();
+        }
+
+        private class CacheableDatabaseModel : ICacheableDatabaseModel
+        {
+            public static CacheableDatabaseModel Instance = new CacheableDatabaseModel ();
+            public int FetchCount { get { return 200; } }
+            public string ReloadFragment { get { return null; } }
+            public string SelectAggregates { get { return null; } }
+            public string JoinTable { get { return null; } }
+            public string JoinFragment { get { return null; } }
+            public string JoinPrimaryKey { get { return null; } }
+            public string JoinColumn { get { return null; } }
+            public bool CachesJoinTableEntries { get { return false; } }
+            public Selection Selection { get { return null; } }
+        }
+    }
+}

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs	Thu Apr 10 05:21:35 2008
@@ -90,6 +90,11 @@
         }
 
         private bool initialized = false;
+        public void Initialize ()
+        {
+            Initialize (null, null);
+        }
+
         public void Initialize (DatabaseArtistListModel artist_model, DatabaseAlbumListModel album_model)
         {
             if (initialized)
@@ -214,18 +219,20 @@
             } else {
                 ReloadWithoutArtistAlbumFilters ();
 
-                if (trigger == ReloadTrigger.Query) {
-                    artist_reloaded = true;
-                    artist_model.Reload (false);
-                }
+                if (artist_model != null && album_model != null) {
+                    if (trigger == ReloadTrigger.Query) {
+                        artist_reloaded = true;
+                        artist_model.Reload (false);
+                    }
 
-                album_reloaded = true;
-                album_model.Reload (false);
+                    album_reloaded = true;
+                    album_model.Reload (false);
 
-                // Unless both artist/album selections are "all" (eg unfiltered), reload
-                // the track model again with the artist/album filters now in place.
-                if (!artist_model.Selection.AllSelected || !album_model.Selection.AllSelected) {
-                    ReloadWithFilters ();
+                    // Unless both artist/album selections are "all" (eg unfiltered), reload
+                    // the track model again with the artist/album filters now in place.
+                    if (!artist_model.Selection.AllSelected || !album_model.Selection.AllSelected) {
+                        ReloadWithFilters ();
+                    }
                 }
             }
 
@@ -467,10 +474,10 @@
             get {
                 if (track_ids_sql == null) {
                     if (!CachesJoinTableEntries) {
-                        track_ids_sql = "SELECT ItemID FROM CoreCache WHERE ModelID = ? LIMIT ?, ?";
+                        track_ids_sql = "ItemID FROM CoreCache WHERE ModelID = ? LIMIT ?, ?";
                     } else {
                         track_ids_sql = String.Format (
-                            "SELECT {0} FROM {1} WHERE {2} IN (SELECT ItemID FROM CoreCache WHERE ModelID = ? LIMIT ?, ?)",
+                            "{0} FROM {1} WHERE {2} IN (SELECT ItemID FROM CoreCache WHERE ModelID = ? LIMIT ?, ?)",
                             JoinColumn, JoinTable, JoinPrimaryKey
                         );
                     }

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	Thu Apr 10 05:21:35 2008
@@ -119,26 +119,6 @@
             return base.AcceptsInputFromSource (source) && (Parent == null || source == Parent || source.Parent == Parent);
         }
         
-        public override void MergeSourceInput (Source from, SourceMergeType mergeType)
-        {
-            DatabaseSource source = from as DatabaseSource;
-            if (source == null || !(source.TrackModel is DatabaseTrackListModel)) {
-                return;
-            }
-            
-            DatabaseTrackListModel model = (DatabaseTrackListModel)source.TrackModel;
-            
-            switch (mergeType) {
-                case SourceMergeType.ModelSelection:
-                    AddSelectedTracks (from);
-                    break;
-                case SourceMergeType.Source:
-                    AddTrackRange (model, new RangeCollection.Range (0, model.Count));
-                    Reload ();
-                    break;
-            }
-        }
-        
         public override SourceMergeType SupportedMergeTypes {
             get { return SourceMergeType.All; }
         }
@@ -191,9 +171,11 @@
         }
 
         // Have our parent handle deleting tracks
-        public override void DeleteSelectedTracks (DatabaseTrackListModel model)
+        public override void DeleteSelectedTracks ()
         {
-            (Parent as DatabaseSource).DeleteSelectedTracks (model);
+            if (Parent is PrimarySource) {
+                (Parent as PrimarySource).DeleteSelectedTracksFromChild (this);
+            }
         }
 
 #endregion
@@ -233,16 +215,17 @@
             Reload ();
         }*/
         
-        public override void AddSelectedTracks (Source source)
+        public override bool AddSelectedTracks (Source source)
         {
             if (Parent == null || source == Parent || source.Parent == Parent) {
-                base.AddSelectedTracks (source);
+                return base.AddSelectedTracks (source);
             /*} else {
                 // Adding from a different primary source, so add to our primary source first
                 PrimarySource primary = Parent as PrimarySource;
                 primary.AddSelectedTracks (model);
                 // then add to us*/
             }
+            return false;
         }
 
         DatabaseTrackListModel last_add_range_from_model;
@@ -255,7 +238,7 @@
                     ? 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.End - range.Start + 1);
+            last_add_range_command.ApplyValues (DbId, from.CacheId, range.Start, range.Count);
             ServiceManager.DbConnection.Execute (last_add_range_command);
 
             last_add_range_from_model = from;
@@ -263,7 +246,7 @@
 
         protected override void RemoveTrackRange (DatabaseTrackListModel from, RangeCollection.Range range)
         {
-            remove_track_range_command.ApplyValues (DbId, from.CacheId, range.Start, range.End - range.Start + 1);
+            remove_track_range_command.ApplyValues (DbId, from.CacheId, range.Start, range.Count);
             ServiceManager.DbConnection.Execute (remove_track_range_command);
         }
 

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/BatchUserJob.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/BatchUserJob.cs	Thu Apr 10 05:21:35 2008
@@ -0,0 +1,74 @@
+// 
+// BatchUserJob.cs
+//
+// Author:
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+
+using Hyena.Data;
+
+namespace Banshee.ServiceStack
+{
+    public class BatchUserJob : UserJob
+    {
+        protected string status_format;
+        protected int completed;
+        protected int total;
+
+        public BatchUserJob (string title, string statusFormat, params string [] iconNames) : base (title, null, iconNames)
+        {
+            status_format = statusFormat;
+        }
+
+        public int Completed {
+            get { return completed; }
+            set {
+                completed = value;
+                UpdateProgress ();
+                if (total > 0 && completed == total)
+                    Finish ();
+            }
+        }
+
+        public int Total {
+            get { return total; }
+            set {
+                total = value;
+                UpdateProgress ();
+            }
+        }
+
+        protected void UpdateProgress ()
+        {
+            if (Total > 0) {
+                FreezeUpdate ();
+                Status = String.Format (status_format, completed, total);
+                Progress = (double)Completed / (double)Total;
+                ThawUpdate (true);
+            }
+        }
+    }
+}

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/UserJob.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/UserJob.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/UserJob.cs	Thu Apr 10 05:21:35 2008
@@ -82,8 +82,10 @@
         
         public void Finish ()
         {
-            is_finished = true;
-            OnFinished ();
+            if (!is_finished) {
+                is_finished = true;
+                OnFinished ();
+            }
         }
         
         protected void FreezeUpdate ()

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	Thu Apr 10 05:21:35 2008
@@ -205,20 +205,39 @@
             DeleteSelectedTracks (track_model);
         }
 
-        public virtual void DeleteSelectedTracks (DatabaseTrackListModel model)
+        protected virtual void DeleteSelectedTracks (DatabaseTrackListModel model)
         {
+            if (model == null)
+                return;
+
             WithTrackSelection (model, DeleteTrackRange);
             OnTracksDeleted ();
         }
 
-        public virtual void AddSelectedTracks (Source source)
+        public virtual bool AddSelectedTracks (Source source)
         {
             if (!AcceptsInputFromSource (source))
-                return;
+                return false;
 
             DatabaseTrackListModel model = (source as ITrackModelSource).TrackModel as DatabaseTrackListModel;
             WithTrackSelection (model, AddTrackRange);
             OnTracksAdded ();
+            OnUserNotifyUpdated ();
+            return true;
+        }
+
+        public virtual bool AddAllTracks (Source source)
+        {
+            if (!AcceptsInputFromSource (source) || source.Count == 0)
+                return false;
+
+            DatabaseTrackListModel model = (source as ITrackModelSource).TrackModel as DatabaseTrackListModel;
+            lock (model) {
+                AddTrackRange (model, new RangeCollection.Range (0, source.Count));
+            }
+            OnTracksAdded ();
+            OnUserNotifyUpdated ();
+            return true;
         }
 
         public virtual void RateSelectedTracks (int rating)
@@ -244,6 +263,15 @@
             get { return SourceMergeType.All; }
         }
 
+        public override void MergeSourceInput (Source source, SourceMergeType mergeType)
+        {
+            if (mergeType == SourceMergeType.Source) {
+                AddAllTracks (source);
+            } else if (mergeType == SourceMergeType.ModelSelection) {
+                AddSelectedTracks (source);
+            }
+        }
+
 #endregion
         
 #region Protected Methods
@@ -374,8 +402,8 @@
         protected HyenaSqliteCommand PruneCommand {
             get {
                 return prune_command ?? prune_command = new HyenaSqliteCommand (String.Format (
-                        @"DELETE FROM CoreCache WHERE ModelID = ? AND ItemID NOT IN (SELECT ArtistID FROM CoreTracks WHERE TrackID IN ({0}));
-                          DELETE FROM CoreCache WHERE ModelID = ? AND ItemID NOT IN (SELECT AlbumID FROM CoreTracks WHERE TrackID IN ({0}));",
+                        @"DELETE FROM CoreCache WHERE ModelID = ? AND ItemID NOT IN (SELECT ArtistID FROM CoreTracks WHERE TrackID IN (SELECT {0}));
+                          DELETE FROM CoreCache WHERE ModelID = ? AND ItemID NOT IN (SELECT AlbumID FROM CoreTracks WHERE TrackID IN (SELECT {0}));",
                         track_model.TrackIdsSql
                     ),
                     artist_model.CacheId, artist_model.CacheId, 0, artist_model.Count,

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	Thu Apr 10 05:21:35 2008
@@ -76,8 +76,13 @@
         protected bool error_source_visible = false;
 
         protected string remove_range_sql = @"
-            INSERT INTO CoreRemovedTracks SELECT ?, TrackID, Uri FROM CoreTracks WHERE TrackID IN ({0});
-            DELETE FROM CoreTracks WHERE TrackID IN ({0})";
+            INSERT INTO CoreRemovedTracks SELECT ?, TrackID, Uri FROM CoreTracks WHERE TrackID IN (SELECT {0});
+            DELETE FROM CoreTracks WHERE TrackID IN (SELECT {0})";
+
+        protected HyenaSqliteCommand remove_list_command = new HyenaSqliteCommand (@"
+            INSERT INTO CoreRemovedTracks SELECT ?, TrackID, Uri FROM CoreTracks WHERE TrackID IN (SELECT ItemID FROM CoreCache WHERE ModelID = ?);
+            DELETE FROM CoreTracks WHERE TrackID IN (SELECT ItemID FROM CoreCache WHERE ModelID = ?)
+        ");
 
         protected HyenaSqliteCommand prune_artists_albums_command = new HyenaSqliteCommand (@"
             DELETE FROM CoreArtists WHERE ArtistID NOT IN (SELECT ArtistID FROM CoreTracks);
@@ -279,13 +284,37 @@
             );
         }
 
-        protected override void DeleteTrackRange (DatabaseTrackListModel model, RangeCollection.Range range)
+        public void DeleteSelectedTracksFromChild (DatabaseSource source)
+        {
+            if (source.Parent != this)
+                return;
+
+            DeleteSelectedTracks (source.TrackModel as DatabaseTrackListModel);
+        }
+
+        protected override void DeleteSelectedTracks (DatabaseTrackListModel model)
+        {
+            ThreadAssist.SpawnFromMain (delegate {
+                if (model == null)
+                    return;
+
+                CachedList<DatabaseTrackInfo> list = CachedList<DatabaseTrackInfo>.CreateFromModelSelection (model);
+                DeleteTrackList (list);
+
+                OnTracksDeleted ();
+            });
+        }
+
+        protected virtual void DeleteTrackList (CachedList<DatabaseTrackInfo> list)
         {
+            DeleteTrackJob.Total += (int) list.Count;
+
             // Remove from file system
-            for (int i = range.Start; i <= range.End; i++) {
-                DatabaseTrackInfo track = model [i] as DatabaseTrackInfo;
-                if (track == null)
+            foreach (DatabaseTrackInfo track in list) {
+                if (track == null) {
+                    DeleteTrackJob.Completed++;
                     continue;
+                }
 
                 try {
                     DeleteTrack (track);
@@ -293,10 +322,16 @@
                     Log.Exception (e);
                     ErrorSource.AddMessage (e.Message, track.Uri.ToString ());
                 }
+                DeleteTrackJob.Completed++;
+            }
+
+            if (DeleteTrackJob.Total == DeleteTrackJob.Completed) {
+                delete_track_job.Finish ();
+                delete_track_job = null;
             }
 
             // Remove from database
-            RemoveTrackRange (model, range);
+            ServiceManager.DbConnection.Execute (remove_list_command, DateTime.Now, list.CacheId, list.CacheId);
         }
 
         protected virtual void DeleteTrack (DatabaseTrackInfo track)
@@ -309,23 +344,30 @@
             return base.AcceptsInputFromSource (source) && source.Parent != this;
         }
 
-        public override void MergeSourceInput (Source source, SourceMergeType mergeType)
+        public override bool AddSelectedTracks (Source source)
         {
-            AddSelectedTracks (source);
-            /*if (!(source is IImportSource) || mergeType != SourceMergeType.Source) {
-                return;
-            }
-            
-            ((IImportSource)source).Import ();
-            */
+            if (!AcceptsInputFromSource (source))
+                return false;
+
+            DatabaseTrackListModel model = (source as ITrackModelSource).TrackModel as DatabaseTrackListModel;
+
+            CachedList<DatabaseTrackInfo> cached_list = CachedList<DatabaseTrackInfo>.CreateFromModelSelection (model);
+            AddTrackList (cached_list);
+
+            OnTracksAdded ();
+            OnUserNotifyUpdated ();
+            return true;
         }
 
-        protected override void AddTrackRange (DatabaseTrackListModel model, RangeCollection.Range range)
+        protected virtual void AddTrackList (CachedList<DatabaseTrackInfo> list)
         {
-            for (int i = range.Start; i <= range.End; i++) {
-                DatabaseTrackInfo track = model [i] as DatabaseTrackInfo;
-                if (track == null)
+            AddTrackJob.Total += (int)list.Count;
+
+            foreach (DatabaseTrackInfo track in list) {
+                if (track == null) {
+                    AddTrackJob.Completed++;
                     continue;
+                }
 
                 try {
                     AddTrack (track);
@@ -333,6 +375,12 @@
                     Log.Exception (e);
                     ErrorSource.AddMessage (e.Message, track.Uri.ToString ());
                 }
+                AddTrackJob.Completed++;
+            }
+
+            if (AddTrackJob.Total == AddTrackJob.Completed) {
+                add_track_job.Finish ();
+                add_track_job = null;
             }
         }
 
@@ -346,5 +394,29 @@
             ServiceManager.DbConnection.Execute (prune_artists_albums_command);
             base.PruneArtistsAlbums ();
         }
+
+        private BatchUserJob add_track_job;
+        protected BatchUserJob AddTrackJob {
+            get {
+                if (add_track_job == null) {
+                    add_track_job = new BatchUserJob (String.Format (Catalog.GetString ("Adding Items to {0}"), Name), Catalog.GetString ("Adding {0} of {1}"), Properties.GetStringList ("Icon.Name"));
+                    add_track_job.DelayShow = true;
+                    add_track_job.Register ();
+                }
+                return add_track_job;
+            }
+        }
+
+        private BatchUserJob delete_track_job;
+        protected BatchUserJob DeleteTrackJob {
+            get {
+                if (delete_track_job == null) {
+                    delete_track_job = new BatchUserJob (String.Format (Catalog.GetString ("Deleting Items From {0}"), Name), Catalog.GetString ("Deleting {0} of {1}"), Properties.GetStringList ("Icon.Name"));
+                    delete_track_job.DelayShow = true;
+                    delete_track_job.Register ();
+                }
+                return delete_track_job;
+            }
+        }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/Source.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/Source.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/Source.cs	Thu Apr 10 05:21:35 2008
@@ -389,9 +389,11 @@
         
         protected virtual void OnUserNotifyUpdated ()
         {
-            EventHandler handler = UserNotifyUpdated;
-            if (handler != null) {
-                handler (this, EventArgs.Empty);
+            if (this != ServiceManager.SourceManager.ActiveSource) {
+                EventHandler handler = UserNotifyUpdated;
+                if (handler != null) {
+                    handler (this, EventArgs.Empty);
+                }
             }
         }
         

Modified: trunk/banshee/src/Core/Banshee.Services/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Makefile.am	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Makefile.am	Thu Apr 10 05:21:35 2008
@@ -5,6 +5,7 @@
 SOURCES =  \
 	Banshee.Base/RateLimiter.cs \
 	Banshee.Base/ThreadAssist.cs \
+	Banshee.Collection.Database/CachedList.cs \
 	Banshee.Collection.Database/DatabaseAlbumInfo.cs \
 	Banshee.Collection.Database/DatabaseAlbumListModel.cs \
 	Banshee.Collection.Database/DatabaseArtistInfo.cs \
@@ -116,6 +117,7 @@
 	Banshee.ServiceStack/ServiceManager.cs \
 	Banshee.ServiceStack/ServiceStartedHandler.cs \
 	Banshee.ServiceStack/TestUserJob.cs \
+	Banshee.ServiceStack/BatchUserJob.cs \
 	Banshee.ServiceStack/UserJob.cs \
 	Banshee.ServiceStack/UserJobEventHandler.cs \
 	Banshee.ServiceStack/UserJobManager.cs \

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView_DragAndDrop.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView_DragAndDrop.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView_DragAndDrop.cs	Thu Apr 10 05:21:35 2008
@@ -198,11 +198,14 @@
                 if (Gtk.Drag.GetSourceWidget (context) == this) {
                     DragDropList<Source> sources = selectionData;
                     if(sources.Count > 0) {
-                        drop_source.MergeSourceInput (sources[0], SourceMergeType.Source);
+                        Banshee.Base.ThreadAssist.SpawnFromMain (delegate {
+                            drop_source.MergeSourceInput (sources[0], SourceMergeType.Source);
+                        });
                     }
                 } else {   
-                    drop_source.MergeSourceInput (ServiceManager.SourceManager.ActiveSource, 
-                        SourceMergeType.ModelSelection);
+                    Banshee.Base.ThreadAssist.SpawnFromMain (delegate {
+                        drop_source.MergeSourceInput (ServiceManager.SourceManager.ActiveSource, SourceMergeType.ModelSelection);
+                    });
                 }
                 
                 Gtk.Drag.Finish (context, true, false, time);

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	Thu Apr 10 05:21:35 2008
@@ -28,7 +28,6 @@
 
 using System;
 using System.Collections.Generic;
-using System.Threading;
 using Mono.Unix;
 
 using Hyena;
@@ -73,9 +72,6 @@
             // TODO differentiate between Audio Players and normal Disks, and include the size, eg "2GB Audio Player"?
             //GenericName = Catalog.GetString ("Audio Player");
 
-            // TODO construct device-specific icon name as preferred icon
-            //Properties.SetStringList ("Icon.Name", "media-player");
-
             SetStatus (String.Format (Catalog.GetString ("Loading {0}"), Name), false);
             DatabaseImportManager importer = new DatabaseImportManager (this);
             importer.KeepUserJobHidden = true;
@@ -100,7 +96,7 @@
         }
 
         protected override bool IsMediaDevice {
-            get { return base.IsMediaDevice || Banshee.IO.File.Exists (new SafeUri (IsAudioPlayerPath)); }
+            get { return base.IsMediaDevice || File.Exists (new SafeUri (IsAudioPlayerPath)); }
         }
 
         protected string IsAudioPlayerPath {
@@ -128,7 +124,7 @@
                     // According to the HAL spec, the first folder listed in the audio_folders property
                     // is the folder to write files to.
                     if (MediaCapabilities != null && MediaCapabilities.AudioFolders.Length > 0) {
-                        write_path = System.IO.Path.Combine(write_path, MediaCapabilities.AudioFolders[0]);
+                        write_path = System.IO.Path.Combine (write_path, MediaCapabilities.AudioFolders[0]);
                     }
                 }
                 return write_path;
@@ -173,11 +169,13 @@
 
         protected override void Eject ()
         {
-            if (volume.CanUnmount)
+            if (volume.CanUnmount) {
                 volume.Unmount ();
+            }
 
-            if (volume.CanEject)
+            if (volume.CanEject) {
                 volume.Eject ();
+            }
         }
 
         protected int FolderDepth {

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	Thu Apr 10 05:21:35 2008
@@ -174,7 +174,6 @@
         private void OnAddToPlayQueue (object o, EventArgs args)
         {
             AddSelectedTracks (ServiceManager.SourceManager.ActiveSource);
-            OnUserNotifyUpdated ();
         }
         
         private void OnClearPlayQueue (object o, EventArgs args)

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Collections/RangeCollection.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Collections/RangeCollection.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Collections/RangeCollection.cs	Thu Apr 10 05:21:35 2008
@@ -87,6 +87,10 @@
                     : (Start + (End - Start)).CompareTo (
                         x.Start + (x.End - x.Start));
             }
+
+            public int Count {
+                get { return End - Start + 1; }
+            }
         }
 
         private const int MIN_CAPACITY = 16;

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs	Thu Apr 10 05:21:35 2008
@@ -94,7 +94,10 @@
             }
 
             uid = FindOrCreateCacheModelId (String.Format ("{0}-{1}", uuid, typeof(T).Name));
-            selection_uid = FindOrCreateCacheModelId (String.Format ("{0}-{1}-Selection", uuid, typeof(T).Name));
+
+            if (model.Selection != null) {
+                selection_uid = FindOrCreateCacheModelId (String.Format ("{0}-{1}-Selection", uuid, typeof(T).Name));
+            }
 
             if (model.CachesJoinTableEntries) {
                 select_range_command = new HyenaSqliteCommand (
@@ -172,19 +175,21 @@
                 )
             );
 
-            delete_selection_command = new HyenaSqliteCommand (String.Format (
-                "DELETE FROM {0} WHERE ModelID = {1}", CacheTableName, selection_uid
-            ));
-            
-            save_selection_command = new HyenaSqliteCommand (String.Format (
-                "INSERT INTO {0} (ModelID, ItemID) SELECT {1}, ItemID FROM {0} WHERE ModelID = {2} LIMIT ?, ?",
-                CacheTableName, selection_uid, uid
-            ));
+            if (model.Selection != null) {
+                delete_selection_command = new HyenaSqliteCommand (String.Format (
+                    "DELETE FROM {0} WHERE ModelID = {1}", CacheTableName, selection_uid
+                ));
+                
+                save_selection_command = new HyenaSqliteCommand (String.Format (
+                    "INSERT INTO {0} (ModelID, ItemID) SELECT {1}, ItemID FROM {0} WHERE ModelID = {2} LIMIT ?, ?",
+                    CacheTableName, selection_uid, uid
+                ));
 
-            get_selection_command = new HyenaSqliteCommand (String.Format (
-                "SELECT OrderID FROM {0} WHERE ModelID = {1} AND ItemID IN (SELECT ItemID FROM {0} WHERE ModelID = {2})",
-                CacheTableName, uid, selection_uid
-            ));
+                get_selection_command = new HyenaSqliteCommand (String.Format (
+                    "SELECT OrderID FROM {0} WHERE ModelID = {1} AND ItemID IN (SELECT ItemID FROM {0} WHERE ModelID = {2})",
+                    CacheTableName, uid, selection_uid
+                ));
+            }
         }
 
         private bool has_select_all_item = false;
@@ -245,9 +250,9 @@
         public override void Reload ()
         {
             lock (this) {
-                if (last_reload_fragment != model.ReloadFragment) {
+                if (last_reload_fragment != model.ReloadFragment || last_reload_command == null) {
                     last_reload_fragment = model.ReloadFragment;
-                    last_reload_command = new HyenaSqliteCommand (reload_sql + last_reload_fragment);
+                    last_reload_command = new HyenaSqliteCommand (String.Format ("{0}{1}", reload_sql, last_reload_fragment));
                 }
 
                 Clear ();
@@ -267,7 +272,9 @@
         private bool saved_selection = false;
         public void SaveSelection ()
         {
-            if (model.Selection.Count > 0 && !(has_select_all_item && model.Selection.AllSelected)) {
+            if (model.Selection != null && model.Selection.Count > 0 &&
+                !(has_select_all_item && model.Selection.AllSelected))
+            {
                 connection.Execute (delete_selection_command);
                 saved_selection = true;
 



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