banshee r4151 - in trunk/banshee: . build/m4/shamrock data src/Clients src/Clients/Halie/Halie src/Core src/Core/Banshee.Core src/Core/Banshee.Core/Banshee.Base src/Core/Banshee.Core/Banshee.IO src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Base src/Core/Banshee.Services/Banshee.Collection src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.Library src/Core/Banshee.Services/Banshee.ServiceStack src/Core/Banshee.ThickClient/Banshee.Gui.Widgets src/Core/Banshee.ThickClient/Banshee.Library.Gui src/Dap src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage src/Extensions/Banshee.FileSystemQueue/Banshee.FileSystemQueue src/Extensions/Banshee.Podcasting/Banshee.Podcasting src/Libraries src/Libraries/Hyena src/Libraries/Hyena/Hyena.Collections src/Libraries/Hyena/Hyena.Collections/Tests src/Libraries/Hyena/Hyena.CommandLine



Author: abock
Date: Mon Jun 16 20:32:09 2008
New Revision: 4151
URL: http://svn.gnome.org/viewvc/banshee?rev=4151&view=rev

Log:
2008-06-16  Aaron Bockover  <abock gnome org>

* src/Extensions/Banshee.FileSystemQueue/Banshee.FileSystemQueue/FileSystemQueueSource.cs:
Lots of bug fixes with FSQ behavior around starting a new instance with
items in the queue, queueing items remotely, and playing back from the
queue automaticaly when --play-enqueued is passed

* src/Core/Banshee.Services/Banshee.Collection/ImportManager.cs: Major
update to use the new QueuePipeline and DirectoryScannerPipelineElement
for improved parallelism, fixed threading issues, and more readable and
reliable code

* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs:
Added an ImportResult event; small API cleanup

* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportResultHandler.cs:
New delegate and args class that the DatabaseImportManager uses for the
new result event

* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs:
Remove unnecessary casting

* src/Libraries/Hyena/Hyena.Collections/QueuePipeline.cs: Container class
for the async queue pipeline; links elements together

* src/Libraries/Hyena/Hyena.Collections/QueuePipelineElement.cs: Base
element class for the pipeline; items pushed into the element's queue are
processed async and then pushed to the downstream element in the pipeline,
which may run in its own thread; this allows for good parallelism in an
easy, safe way (i.e. walk a directory tree while processing results from
earlier in the walk at the same time)

* src/Libraries/Hyena/Hyena.Collections/WriteLineElement.cs: A simple
sync element that dumps results to stdout

* src/Libraries/Hyena/Hyena.Collections/Tests/QueuePipelineTests.cs:
Some unit tests for QP/QPE

* src/Core/Banshee.Services/Banshee.Library/HomeDirectoryImportSource.cs:
* src/Core/Banshee.Services/Banshee.Library/LibraryImportManager.cs:
* src/Core/Banshee.ThickClient/Banshee.Library.Gui/FileImportSource.cs:
* src/Core/Banshee.ThickClient/Banshee.Library.Gui/FolderImportSource.cs:
* src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs:
* src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastImportManager.cs:
Updated to reflect small API changes in base ImportManager class

* src/Core/Banshee.Services/Banshee.Base/ThreadAssist.cs: 
* src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/ConnectedMessageBar.cs:
* src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs: Remove
EventHandler override for doing Invoke/ProxyToMain; just use InvokeHandler

* src/Core/Banshee.Core/Banshee.IO/DirectoryScannerPipelineElement.cs:
Moved the directory scanning code from ImportManager to a nice
QueuePipelineElement so it can be reused inside threaded queue pipelines

* src/Core/Banshee.Core/Banshee.Base/ApplicationContext.cs:
* src/Libraries/Hyena/Hyena.CommandLine/CommandLineParser.cs: Remove the
notion of --enqueue and just assume anything that does not start with --
is a 'file'

* src/Clients/Halie/Halie/Client.cs: handle files after all commands are
handled, so the remote process can get an idea of what is coming

* src/Clients/banshee-1.in: Added --redirect-log argument that dumps
stdin/error to ~/.config/banshee-1/log; sort of a hack job

* data/banshee-1.desktop.in.in: Pass --redirect-log and remove --enqueue

* build/m4/shamrock/nunit.m4: Fix nunit detection


Added:
   trunk/banshee/src/Core/Banshee.Core/Banshee.IO/DirectoryScannerPipelineElement.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportResultHandler.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipeline.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipelineElement.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Collections/Tests/QueuePipelineTests.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Collections/WriteLineElement.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/build/m4/shamrock/nunit.m4
   trunk/banshee/data/banshee-1.desktop.in.in
   trunk/banshee/src/Clients/Halie/Halie/Client.cs
   trunk/banshee/src/Clients/banshee-1.in
   trunk/banshee/src/Core/Banshee.Core/Banshee.Base/ApplicationContext.cs
   trunk/banshee/src/Core/Banshee.Core/Banshee.Core.mdp
   trunk/banshee/src/Core/Banshee.Core/Makefile.am
   trunk/banshee/src/Core/Banshee.Services/Banshee.Base/ThreadAssist.cs
   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.Library/HomeDirectoryImportSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Library/LibraryImportManager.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp
   trunk/banshee/src/Core/Banshee.Services/Makefile.am
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/ConnectedMessageBar.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Library.Gui/FileImportSource.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Library.Gui/FolderImportSource.cs
   trunk/banshee/src/Core/Core.mds
   trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
   trunk/banshee/src/Dap/Dap.mds
   trunk/banshee/src/Extensions/Banshee.FileSystemQueue/Banshee.FileSystemQueue/FileSystemQueueSource.cs
   trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastImportManager.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.CommandLine/CommandLineParser.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.mdp
   trunk/banshee/src/Libraries/Hyena/Makefile.am
   trunk/banshee/src/Libraries/Libraries.mds

Modified: trunk/banshee/build/m4/shamrock/nunit.m4
==============================================================================
--- trunk/banshee/build/m4/shamrock/nunit.m4	(original)
+++ trunk/banshee/build/m4/shamrock/nunit.m4	Mon Jun 16 20:32:09 2008
@@ -2,7 +2,7 @@
 [
 	NUNIT_REQUIRED=2.4.7
 
-	PKG_CHECK_MODULES(NUNIT, nunit >= NUNIT_REQUIRED, 
+	PKG_CHECK_MODULES(NUNIT, nunit >= $NUNIT_REQUIRED, 
 		do_tests="yes", do_tests="no")
 	
 	AC_SUBST(NUNIT_LIBS)

Modified: trunk/banshee/data/banshee-1.desktop.in.in
==============================================================================
--- trunk/banshee/data/banshee-1.desktop.in.in	(original)
+++ trunk/banshee/data/banshee-1.desktop.in.in	Mon Jun 16 20:32:09 2008
@@ -4,7 +4,7 @@
 _Name=Banshee Media Player
 _GenericName=Media Player
 Comment=Play and organize your media collection
-Exec=banshee-1 --play-enqueued --enqueue %U
+Exec=banshee-1 --redirect-log --play-enqueued %U
 Icon=media-player-banshee
 StartupNotify=true
 Terminal=false

Modified: trunk/banshee/src/Clients/Halie/Halie/Client.cs
==============================================================================
--- trunk/banshee/src/Clients/Halie/Halie/Client.cs	(original)
+++ trunk/banshee/src/Clients/Halie/Halie/Client.cs	Mon Jun 16 20:32:09 2008
@@ -72,9 +72,9 @@
             command = DBusServiceManager.FindInstance<DBusCommandService> ("/DBusCommandService");
             hide_field = ApplicationContext.CommandLine.Contains ("hide-field");
             
-            HandleFiles ();
             bool present = HandlePlayerCommands ();
             HandleWindowCommands (present);
+            HandleFiles ();
         }
         
         private static void HandleWindowCommands (bool present)

Modified: trunk/banshee/src/Clients/banshee-1.in
==============================================================================
--- trunk/banshee/src/Clients/banshee-1.in	(original)
+++ trunk/banshee/src/Clients/banshee-1.in	Mon Jun 16 20:32:09 2008
@@ -25,6 +25,10 @@
     case "x--profile=" in ("x${arg:0:10}")
         BANSHEE_PROFILE=$arg
     esac
+
+	case "x--redirect-log" in ("x$arg")
+		BANSHEE_REDIRECT_LOG="$HOME/.config/banshee-1/log"
+	esac
 done
 
 if [ -n "$BANSHEE_DEBUG" -o -n "$BANSHEE_TRACE" -o -n "$BANSHEE_PROFILE" ]; then
@@ -33,5 +37,12 @@
 fi
 
 # Finally - environment is set up, time to run our beloved
-exec -a banshee-1 mono $MONO_OPTIONS $MONO_EXE "$@"
+exec_args="-a banshee-1 mono $MONO_OPTIONS $MONO_EXE $@"
+
+if [ -z "$BANSHEE_REDIRECT_LOG" ]; then
+	exec $exec_args
+else
+	exec $exec_args &> $BANSHEE_REDIRECT_LOG
+fi
+
 

Modified: trunk/banshee/src/Core/Banshee.Core/Banshee.Base/ApplicationContext.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Banshee.Base/ApplicationContext.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Base/ApplicationContext.cs	Mon Jun 16 20:32:09 2008
@@ -33,6 +33,8 @@
 
 namespace Banshee.Base
 {
+    public delegate void InvokeHandler ();
+
     public static class ApplicationContext
     {
         static ApplicationContext () 
@@ -40,7 +42,7 @@
             Log.Debugging = Debugging;
         }
     
-        private static CommandLineParser command_line = new CommandLineParser ("enqueue");
+        private static CommandLineParser command_line = new CommandLineParser ();
         public static CommandLineParser CommandLine {
             set { command_line = value; }
             get { return command_line; }

Modified: trunk/banshee/src/Core/Banshee.Core/Banshee.Core.mdp
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Banshee.Core.mdp	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Core.mdp	Mon Jun 16 20:32:09 2008
@@ -71,6 +71,7 @@
     <File name="Banshee.Base/Tests/TaglibReadWriteTests.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Kernel/DelegateJob.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Collection/CacheableItem.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.IO/DirectoryScannerPipelineElement.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Project" localcopy="False" refto="Hyena" />

Added: trunk/banshee/src/Core/Banshee.Core/Banshee.IO/DirectoryScannerPipelineElement.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.IO/DirectoryScannerPipelineElement.cs	Mon Jun 16 20:32:09 2008
@@ -0,0 +1,90 @@
+//
+// DirectoryScannerPipelineElement.cs
+//
+// Author:
+//   Aaron Bockover <abockover 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.IO;
+
+using Hyena.Collections;
+
+using Banshee.Base;
+
+namespace Banshee.IO
+{  
+    public class DirectoryScannerPipelineElement : QueuePipelineElement<string>
+    {
+        protected override string ProcessItem (string item)
+        {
+            ScanForFiles (item);
+            return null;
+        }
+        
+        private void ScanForFiles (string source)
+        {
+            CheckForCanceled ();
+            
+            bool is_regular_file = false;
+            bool is_directory = false;
+            
+            SafeUri source_uri = new SafeUri (source);
+            
+            try {
+                is_regular_file = Banshee.IO.File.Exists (source_uri);
+                is_directory = !is_regular_file && Banshee.IO.Directory.Exists (source);
+            } catch {
+                return;
+            }
+            
+            if (is_regular_file) {
+                try {
+                    if (!Path.GetFileName (source).StartsWith (".")) {
+                        EnqueueDownstream (source);
+                    }
+                } catch (System.ArgumentException) {
+                    // If there are illegal characters in path
+                }
+            } else if (is_directory) {
+                try {
+                    if (!Path.GetFileName (Path.GetDirectoryName (source)).StartsWith (".")) {
+                        try {
+                            foreach (string file in Banshee.IO.Directory.GetFiles (source)) {
+                                ScanForFiles (file);
+                            }
+
+                            foreach (string directory in Banshee.IO.Directory.GetDirectories (source)) {
+                                ScanForFiles (directory);
+                            }
+                        } catch {
+                        }
+                    }
+                } catch (System.ArgumentException) {
+                    // If there are illegal characters in path
+                }
+            }
+        }
+    }
+}

Modified: trunk/banshee/src/Core/Banshee.Core/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Makefile.am	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Makefile.am	Mon Jun 16 20:32:09 2008
@@ -42,6 +42,7 @@
 	Banshee.IO.SystemIO/Provider.cs \
 	Banshee.IO/DemuxVfs.cs \
 	Banshee.IO/Directory.cs \
+	Banshee.IO/DirectoryScannerPipelineElement.cs \
 	Banshee.IO/File.cs \
 	Banshee.IO/IDemuxVfs.cs \
 	Banshee.IO/IDirectory.cs \

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Base/ThreadAssist.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Base/ThreadAssist.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Base/ThreadAssist.cs	Mon Jun 16 20:32:09 2008
@@ -50,12 +50,12 @@
             }
         }
         
-        public static void ProxyToMain (EventHandler handler)
+        public static void ProxyToMain (InvokeHandler handler)
         {
             if (!InMainThread) {
                 Banshee.ServiceStack.Application.Invoke (handler);
             } else {
-                handler (null, EventArgs.Empty);
+                handler ();
             }
         }
 

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	Mon Jun 16 20:32:09 2008
@@ -92,16 +92,19 @@
         private TrackPrimarySourceChooser trackPrimarySourceChooser;
         private Dictionary<int, int> counts;
         private ErrorSource error_source;
-        protected int [] primary_source_ids;
-        protected string base_directory;
-        protected bool force_copy;
+        private int [] primary_source_ids;
+        private string base_directory;
+        private bool force_copy;
+        
+        public event DatabaseImportResultHandler ImportResult;
     
         public DatabaseImportManager (PrimarySource psource) :
             this (psource.ErrorSource, delegate { return psource; }, new int [] {psource.DbId}, psource.BaseDirectory)
         {
         }
 
-        public DatabaseImportManager (ErrorSource error_source, TrackPrimarySourceChooser chooser, int [] primarySourceIds, string baseDirectory) : this (chooser)
+        public DatabaseImportManager (ErrorSource error_source, TrackPrimarySourceChooser chooser, 
+            int [] primarySourceIds, string baseDirectory) : this (chooser)
         {
             this.error_source = error_source;
             primary_source_ids = primarySourceIds;
@@ -120,28 +123,46 @@
 
         protected virtual int [] PrimarySourceIds {
             get { return primary_source_ids; }
+            set { primary_source_ids = value; }
         }
 
         protected virtual string BaseDirectory {
             get { return base_directory; }
+            set { base_directory = value; }
+        }
+        
+        protected virtual bool ForceCopy {
+            get { return force_copy; }
+            set { force_copy = value; }
         }
 
         protected override void OnImportRequested (string path)
         {
             if (!IsWhiteListedFile (path)) {
-                IncrementProcessedCount (null);
+                UpdateProgress (null);
                 return;
             }
 
             try {
                 DatabaseTrackInfo track = ImportTrack (path);
                 if (track != null && track.TrackId > 0) {
-                    IncrementProcessedCount (String.Format ("{0} - {1}", 
+                    UpdateProgress (String.Format ("{0} - {1}", 
                         track.DisplayArtistName, track.DisplayTrackTitle));
                 }
+                
+                OnImportResult (track, path, null);
             } catch (Exception e) {
                 LogError (path, e);
-                IncrementProcessedCount (null);
+                UpdateProgress (null);
+                OnImportResult (null, path, e);
+            }
+        }
+        
+        protected virtual void OnImportResult (DatabaseTrackInfo track, string path, Exception error)
+        {
+            DatabaseImportResultHandler handler = ImportResult;
+            if (handler != null) {
+                handler (this, new DatabaseImportResultArgs (track, path, error));
             }
         }
         
@@ -157,7 +178,7 @@
             if (DatabaseTrackInfo.ContainsUri (uri, Paths.MakePathRelative (uri.AbsolutePath, BaseDirectory) ?? uri.AbsoluteUri, PrimarySourceIds)) {
                 // TODO add DatabaseTrackInfo.SyncedStamp property, and if the file has been
                 // updated since the last sync, fetch its metadata into the db.
-                IncrementProcessedCount (null);
+                UpdateProgress (null);
                 return null;
             }
 

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportResultHandler.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportResultHandler.cs	Mon Jun 16 20:32:09 2008
@@ -0,0 +1,60 @@
+//
+// DatabaseImportResultHandler.cs
+//
+// Author:
+//   Aaron Bockover <abockover 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;
+
+namespace Banshee.Collection.Database
+{
+    public delegate void DatabaseImportResultHandler (object o, DatabaseImportResultArgs args);
+
+    public sealed class DatabaseImportResultArgs : EventArgs
+    {
+        private DatabaseTrackInfo track;
+        private string path;
+        private Exception error;
+
+        public DatabaseImportResultArgs (DatabaseTrackInfo track, string path, Exception error)
+        {
+            this.track = track;
+            this.path = path;
+            this.error = error;
+        }
+                
+        public string Path {
+            get { return path; }
+        }
+        
+        public DatabaseTrackInfo Track {
+            get { return track; }
+        }
+
+        public Exception Error {
+            get { return error; }
+        }
+    }
+}

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	Mon Jun 16 20:32:09 2008
@@ -99,11 +99,11 @@
 
         public override bool TrackEqual (TrackInfo track)
         {
-            if (!(track is DatabaseTrackInfo)) {
+            DatabaseTrackInfo db_track = track as DatabaseTrackInfo;
+            if (db_track == null) {
                 return base.TrackEqual (track);
             }
             
-            DatabaseTrackInfo db_track = (DatabaseTrackInfo)track;
             return db_track.TrackId == TrackId && db_track.CacheModelId == CacheModelId && 
                 db_track.CacheEntryId == CacheEntryId;
         }

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	Mon Jun 16 20:32:09 2008
@@ -27,43 +27,113 @@
 //
 
 using System;
-using System.IO;
-using System.Collections.Generic;
-using System.Threading;
+using System.Globalization;
 using Mono.Unix;
 
 using Hyena;
+using Hyena.Collections;
+
 using Banshee.IO;
 using Banshee.Base;
 using Banshee.ServiceStack;
 
 namespace Banshee.Collection
 {
-    public class ImportManager
+    public class ImportManager : QueuePipeline<string>
     {
-        private class ImportCanceledException : ApplicationException
+
+#region Importing Pipeline Element
+
+        private class ImportElement : QueuePipelineElement<string>
         {
+            private ImportManager manager;
+            
+            public ImportElement (ImportManager manager)
+            {
+                this.manager = manager;
+            }
+        
+            private int processed_count;
+            public int ProcessedCount {
+                get { return processed_count; }
+            }
+            
+            private int total_count;
+            public int TotalCount {
+                get { return total_count; }
+            }
+            
+            public override void Enqueue (string item)
+            {
+                total_count++;
+                manager.UpdateScannerProgress ();
+                base.Enqueue (item);
+            }
+        
+            protected override string ProcessItem (string item)
+            {
+                manager.OnImportRequested (item);
+                processed_count++;
+                return null;   
+            }
+            
+            protected override void OnFinished ()
+            {
+                base.OnFinished ();
+                manager.DestroyUserJob ();
+                manager.OnImportFinished ();
+            }
+            
+            public void Reset ()
+            {
+                processed_count = 0;
+                total_count = 0;
+            }
         }
         
-        private readonly object user_job_mutex = new object ();
-        private UserJob user_job;
+#endregion
         
-        private Queue<string> path_queue = new Queue<string> ();
-        private bool processing_queue = false;
+        private static NumberFormatInfo number_format = new NumberFormatInfo ();
         
-        private int total_count;
-        private int processed_count;
-        private int scan_ref_count = 0;
+        private DirectoryScannerPipelineElement scanner_element;
+        private ImportElement import_element;
+        
+        private readonly object user_job_mutex = new object ();
+        private UserJob user_job;
+        private uint timer_id;
         
         public event ImportEventHandler ImportRequested;
         public event EventHandler ImportFinished;
         
         public ImportManager ()
         {
+            AddElement (scanner_element = new DirectoryScannerPipelineElement ());
+            AddElement (import_element = new ImportElement (this));
+        }
+        
+#region Public API
+                      
+        public virtual void Enqueue (UriList uris)
+        {
+            CreateUserJob ();
+            
+            foreach (string path in uris.LocalPaths) {
+                base.Enqueue (path);
+            }
+        }
+        
+        public override void Enqueue (string source)
+        {
+            Enqueue (new UriList (source));
+        }
+        
+        public void Enqueue (string [] paths)
+        {
+            Enqueue (new UriList (paths));
         }
         
         public bool IsImportInProgress {
-            get { return processing_queue; }
+            get { return import_element.Processing; }
         }
 
         private bool keep_user_job_hidden = false;
@@ -72,6 +142,10 @@
             set { keep_user_job_hidden = value; }
         }
         
+#endregion
+        
+#region User Job / Interaction
+        
         private void CreateUserJob ()
         {
             lock (user_job_mutex) {
@@ -79,17 +153,19 @@
                     return;
                 }
                 
+                timer_id = Log.DebugTimerStart ();
+                
                 user_job = new UserJob (Title, Catalog.GetString ("Scanning for media"));
                 user_job.IconNames = new string [] { "system-search", "gtk-find" };
                 user_job.CancelMessage = CancelMessage;
                 user_job.CanCancel = true;
+                user_job.CancelRequested += OnCancelRequested;
 
                 if (!KeepUserJobHidden) {
                     user_job.Register ();
                 }
                 
-                total_count = 0;
-                processed_count = 0;
+                import_element.Reset ();
             }
         }
         
@@ -100,186 +176,58 @@
                     return;
                 }
                 
+                Log.DebugTimerPrint (timer_id, Title + " duration: {0}");
+                
+                user_job.CancelRequested -= OnCancelRequested;
                 user_job.Finish ();
                 user_job = null;
                     
-                total_count = 0;
-                processed_count = 0;
-                scan_ref_count = 0;
+                import_element.Reset ();
             }
         }
         
-        protected void IncrementProcessedCount (string message)
+        private void OnCancelRequested (object o, EventArgs args)
+        {
+            scanner_element.Cancel ();
+        }
+        
+        protected void UpdateProgress (string message)
         {
             CreateUserJob ();
-            processed_count++;
             
-            double new_progress = (double)processed_count / (double)total_count;
+            double new_progress = (double)import_element.ProcessedCount / (double)import_element.TotalCount;
             double old_progress = user_job.Progress;
             
             if (new_progress >= 0.0 && new_progress <= 1.0 && Math.Abs (new_progress - old_progress) > 0.001) {
-                string disp_progress = String.Format (ProgressMessage, processed_count, total_count);
-                
-                user_job.Title = disp_progress;
-                user_job.Status = String.IsNullOrEmpty (message) ? Catalog.GetString ("Scanning...") : message;
-                user_job.Progress = new_progress;
-            }
-        }
-        
-        private void CheckForCanceled ()
-        {
-            lock (user_job_mutex) {
-                if (user_job != null && user_job.IsCancelRequested) {
-                    throw new ImportCanceledException ();  
+                lock (number_format) {
+                    string disp_progress = String.Format (ProgressMessage, 
+                        import_element.ProcessedCount.ToString ("N", number_format), 
+                        import_element.TotalCount.ToString ("N", number_format));
+                    
+                    user_job.Title = disp_progress;
+                    user_job.Status = String.IsNullOrEmpty (message) ? Catalog.GetString ("Scanning...") : message;
+                    user_job.Progress = new_progress;
                 }
             }
         }
         
-        private void FinalizeImport ()
-        {
-            path_queue.Clear ();
-            processing_queue = false;
-            DestroyUserJob ();
-            OnImportFinished ();
-        }
-        
         private DateTime last_enqueue_display = DateTime.Now;
-        private static System.Globalization.NumberFormatInfo nfi = new System.Globalization.NumberFormatInfo ();
         
-        private void Enqueue (string path)
+        private void UpdateScannerProgress ()
         {
-            if (path_queue.Contains (path)) {
-                return;
-            }
-            
-            total_count++;
-            
             if (DateTime.Now - last_enqueue_display > TimeSpan.FromMilliseconds (400)) {
-                lock (nfi) {
-                    nfi.NumberDecimalDigits = 0;
+                lock (number_format) {
+                    number_format.NumberDecimalDigits = 0;
                     user_job.Status = String.Format (Catalog.GetString ("Scanning ({0} files)..."), 
-                        total_count.ToString ("N", nfi));
+                        import_element.TotalCount.ToString ("N", number_format));
                     last_enqueue_display = DateTime.Now;
                 }
             }
-            
-            lock (path_queue) {
-                path_queue.Enqueue (path);
-            }
         }
         
-        public void QueueSource (UriList uris)
-        {
-            CreateUserJob ();
-
-            if (Threaded) {
-                ThreadPool.QueueUserWorkItem (ThreadedQueueSource, uris);
-            } else {
-                ThreadedQueueSource (uris);
-            }
-        }
-        
-        public void QueueSource (string source)
-        {
-            QueueSource (new UriList (source));
-        }
-        
-        public void QueueSource (string [] paths)
-        {
-            QueueSource (new UriList (paths));
-        }
-
-        private void ThreadedQueueSource (object o)
-        {
-            UriList uris = (UriList)o;
-
-            try {
-                foreach (string path in uris.LocalPaths) {
-                    Interlocked.Increment (ref scan_ref_count);
-                    ScanForFiles (path);
-                    Interlocked.Decrement (ref scan_ref_count);
-                }
-                
-                if(scan_ref_count == 0) {
-                    ProcessQueue ();
-                }
-            } catch (ImportCanceledException) {
-                FinalizeImport ();
-            }
-        }
+#endregion
         
-        private void ScanForFiles (string source)
-        {
-            CheckForCanceled ();
-            Interlocked.Increment (ref scan_ref_count);
-            
-            bool is_regular_file = false;
-            bool is_directory = false;
-            
-            SafeUri source_uri = new SafeUri (source);
-            
-            try {
-                is_regular_file = Banshee.IO.File.Exists (source_uri);
-                is_directory = !is_regular_file && Banshee.IO.Directory.Exists (source);
-            } catch {
-                Interlocked.Decrement (ref scan_ref_count);
-                return;
-            }
-            
-            if (is_regular_file) {
-                try {
-                    if (!Path.GetFileName (source).StartsWith (".")) {
-                        Enqueue (source);
-                    }
-                } catch (System.ArgumentException) {
-                    // If there are illegal characters in path
-                }
-            } else if (is_directory) {
-                try {
-                    if (!Path.GetFileName (Path.GetDirectoryName (source)).StartsWith (".")) {
-                        try {
-                            foreach (string file in Banshee.IO.Directory.GetFiles (source)) {
-                                ScanForFiles (file);
-                            }
-
-                            foreach (string directory in Banshee.IO.Directory.GetDirectories (source)) {
-                                ScanForFiles (directory);
-                            }
-                        } catch {
-                        }
-                    }
-                } catch (System.ArgumentException) {
-                    // If there are illegal characters in path
-                }
-            }
-
-            Interlocked.Decrement (ref scan_ref_count);
-        }
-
-        private void ProcessQueue ()
-        {
-            if (processing_queue) {
-                return;
-            }
-            
-            processing_queue = true;
-            uint timer_id = Log.DebugTimerStart ();
-            
-            while (path_queue.Count > 0) {
-                CheckForCanceled ();
-                OnImportRequested (path_queue.Dequeue ());
-            }
-            
-            Log.DebugTimerPrint (timer_id, Title + " duration: {0}");
-            
-            path_queue.Clear ();
-            processing_queue = false;
-            
-            if (scan_ref_count == 0) {
-                DestroyUserJob ();
-                OnImportFinished ();
-            }
-        }
+#region Protected Import Hooks
         
         protected virtual void OnImportRequested (string path)
         {
@@ -287,9 +235,9 @@
             if (handler != null && path != null) {
                 ImportEventArgs args = new ImportEventArgs (path);
                 handler (this, args);
-                IncrementProcessedCount (args.ReturnMessage);
+                UpdateProgress (args.ReturnMessage);
             } else {
-                IncrementProcessedCount (null);
+                UpdateProgress (null);
             }
         }
         
@@ -301,13 +249,18 @@
             }
         }
         
+#endregion
+
+#region Properties
+        
         private string title = Catalog.GetString ("Importing Media");
         public string Title {
             get { return title; }
             set { title = value; }
         }
 
-        private string cancel_message = Catalog.GetString ("The import process is currently running. Would you like to stop it?");
+        private string cancel_message = Catalog.GetString (
+            "The import process is currently running. Would you like to stop it?");
         public string CancelMessage {
             get { return cancel_message; }
             set { cancel_message = value; }
@@ -319,10 +272,11 @@
             set { progress_message = value; }
         }
 
-        private bool threaded = true;
         public bool Threaded {
-            get { return threaded; }
-            set { threaded = value; }
+            set { import_element.Threaded = scanner_element.Threaded = value; }
         }
+        
+#endregion
+
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Library/HomeDirectoryImportSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Library/HomeDirectoryImportSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Library/HomeDirectoryImportSource.cs	Mon Jun 16 20:32:09 2008
@@ -39,7 +39,7 @@
 
         public void Import ()
         {
-            Banshee.ServiceStack.ServiceManager.Get<LibraryImportManager> ().QueueSource (
+            Banshee.ServiceStack.ServiceManager.Get<LibraryImportManager> ().Enqueue (
                 Environment.GetFolderPath (Environment.SpecialFolder.Personal)
             );
         }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Library/LibraryImportManager.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Library/LibraryImportManager.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Library/LibraryImportManager.cs	Mon Jun 16 20:32:09 2008
@@ -53,7 +53,7 @@
 
         public LibraryImportManager (bool force_copy) : base (DefaultTrackPrimarySourceChooser)
         {
-            this.force_copy = force_copy;
+            ForceCopy = force_copy;
         }
 
         protected override ErrorSource ErrorSource {
@@ -62,12 +62,14 @@
 
         protected override int [] PrimarySourceIds {
             get {
-                if (primary_source_ids == null) {
-                    primary_source_ids = new int [] {
-                        ServiceManager.SourceManager.VideoLibrary.DbId, ServiceManager.SourceManager.MusicLibrary.DbId
+                if (base.PrimarySourceIds == null) {
+                    base.PrimarySourceIds = new int [] {
+                        ServiceManager.SourceManager.VideoLibrary.DbId, 
+                        ServiceManager.SourceManager.MusicLibrary.DbId
                     };
                 }
-                return primary_source_ids;
+                
+                return base.PrimarySourceIds;
             }
         }
 

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs	Mon Jun 16 20:32:09 2008
@@ -36,13 +36,13 @@
 using Banshee.Playlist;
 using Banshee.SmartPlaylist;
 using Banshee.Sources;
+using Banshee.Base;
 
 namespace Banshee.ServiceStack
 {    
     public delegate bool ShutdownRequestHandler ();
     public delegate bool TimeoutHandler ();
     public delegate bool IdleHandler ();
-    public delegate void InvokeHandler ();
     public delegate bool IdleTimeoutRemoveHandler (uint id);
     public delegate uint TimeoutImplementationHandler (uint milliseconds, TimeoutHandler handler); 
     public delegate uint IdleImplementationHandler (IdleHandler handler);
@@ -159,12 +159,7 @@
         {
             RunIdle (delegate { handler (); return false; });
         }
-        
-        public static void Invoke (EventHandler handler)
-        {
-            RunIdle (delegate { handler (null, EventArgs.Empty); return false; });
-        }
-        
+
         public static uint RunIdle (IdleHandler handler)
         {
             if (idle_handler == null) {

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Services.mdp	Mon Jun 16 20:32:09 2008
@@ -173,6 +173,7 @@
     <File name="Banshee.ServiceStack/DBusCommandService.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.ServiceStack/IDBusObjectName.cs" subtype="Code" buildaction="Compile" />
     <File name="Banshee.Hardware/IDiscDuplicator.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.Collection.Database/DatabaseImportResultHandler.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

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	Mon Jun 16 20:32:09 2008
@@ -12,6 +12,7 @@
 	Banshee.Collection.Database/DatabaseArtistListModel.cs \
 	Banshee.Collection.Database/DatabaseFilterListModel.cs \
 	Banshee.Collection.Database/DatabaseImportManager.cs \
+	Banshee.Collection.Database/DatabaseImportResultHandler.cs \
 	Banshee.Collection.Database/DatabaseTrackInfo.cs \
 	Banshee.Collection.Database/DatabaseTrackListModel.cs \
 	Banshee.Collection.Database/DatabaseTrackModelCache.cs \

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/ConnectedMessageBar.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/ConnectedMessageBar.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui.Widgets/ConnectedMessageBar.cs	Mon Jun 16 20:32:09 2008
@@ -85,7 +85,7 @@
             ThreadAssist.ProxyToMain (InnerUpdate);
         }
         
-        private void InnerUpdate (object o, EventArgs args)
+        private void InnerUpdate ()
         {
             if (source == null || source.CurrentMessage == null || source.CurrentMessage.IsHidden) {
                 Hide ();

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Library.Gui/FileImportSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Library.Gui/FileImportSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Library.Gui/FileImportSource.cs	Mon Jun 16 20:32:09 2008
@@ -51,9 +51,8 @@
             chooser.SelectMultiple = true;
             chooser.DefaultResponse = ResponseType.Ok;
             
-            if(chooser.Run() == (int)ResponseType.Ok) {
-                Banshee.ServiceStack.ServiceManager.Get<LibraryImportManager> ("LibraryImportManager").QueueSource (
-                    chooser.Uris);   
+            if (chooser.Run () == (int)ResponseType.Ok) {
+                Banshee.ServiceStack.ServiceManager.Get<LibraryImportManager> ().Enqueue (chooser.Uris);
             }
             
             chooser.Destroy ();

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Library.Gui/FolderImportSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Library.Gui/FolderImportSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Library.Gui/FolderImportSource.cs	Mon Jun 16 20:32:09 2008
@@ -49,9 +49,8 @@
             chooser.AddButton (Stock.Open, ResponseType.Ok);
             chooser.DefaultResponse = ResponseType.Ok;
             
-            if(chooser.Run () == (int)ResponseType.Ok) {
-                Banshee.ServiceStack.ServiceManager.Get<LibraryImportManager> ("LibraryImportManager").QueueSource (
-                    chooser.Uri);   
+            if (chooser.Run () == (int)ResponseType.Ok) {
+                Banshee.ServiceStack.ServiceManager.Get<LibraryImportManager> ().Enqueue (chooser.Uri);
             }
             
             chooser.Destroy ();

Modified: trunk/banshee/src/Core/Core.mds
==============================================================================
--- trunk/banshee/src/Core/Core.mds	(original)
+++ trunk/banshee/src/Core/Core.mds	Mon Jun 16 20:32:09 2008
@@ -7,7 +7,7 @@
       <Entry build="True" name="Banshee.ThickClient" configuration="Debug" />
     </Configuration>
   </Configurations>
-  <StartMode startupentry="Nereid" single="True">
+  <StartMode startupentry="Banshee.Widgets" single="True">
     <Execute type="None" entry="Banshee.Widgets" />
     <Execute type="None" entry="Banshee.Services" />
     <Execute type="None" entry="Banshee.Core" />

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	Mon Jun 16 20:32:09 2008
@@ -119,7 +119,7 @@
             importer.Threaded = false; // We are already threaded
 
             foreach (string audio_folder in BaseDirectories) {
-                importer.QueueSource (audio_folder);
+                importer.Enqueue (audio_folder);
             }
         }
 
@@ -134,7 +134,7 @@
         {
             LibraryImportManager importer = new LibraryImportManager (true);
             foreach (string audio_folder in BaseDirectories) {
-                importer.QueueSource (audio_folder);
+                importer.Enqueue (audio_folder);
             }
         }
 

Modified: trunk/banshee/src/Dap/Dap.mds
==============================================================================
--- trunk/banshee/src/Dap/Dap.mds	(original)
+++ trunk/banshee/src/Dap/Dap.mds	Mon Jun 16 20:32:09 2008
@@ -7,7 +7,7 @@
       <Entry build="True" name="Banshee.Dap.Ipod" configuration="Debug" />
     </Configuration>
   </Configurations>
-  <StartMode startupentry="Banshee.Dap.Ipod" single="True">
+  <StartMode startupentry="Banshee.Dap" single="True">
     <Execute type="None" entry="Banshee.Dap" />
     <Execute type="None" entry="Banshee.Dap.MassStorage" />
     <Execute type="None" entry="Banshee.Dap.Mtp" />

Modified: trunk/banshee/src/Extensions/Banshee.FileSystemQueue/Banshee.FileSystemQueue/FileSystemQueueSource.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.FileSystemQueue/Banshee.FileSystemQueue/FileSystemQueueSource.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.FileSystemQueue/Banshee.FileSystemQueue/FileSystemQueueSource.cs	Mon Jun 16 20:32:09 2008
@@ -48,6 +48,8 @@
         private DatabaseImportManager importer;
         private bool visible = false;
         private bool actions_loaded = false;
+        private bool play_enqueued = false;
+        private string path_to_play;
         
         protected override string TypeUniqueId {
             get { return "file-system-queue"; }
@@ -60,9 +62,6 @@
             Properties.Set<bool> ("AutoAddSource", false);
             IsLocal = true;
             
-            importer = new DatabaseImportManager (this);
-            importer.KeepUserJobHidden = true;
-            
             ServiceManager.Get<DBusCommandService> ().ArgumentPushed += OnCommandLineArgument;
             
             AfterInitialized ();
@@ -93,15 +92,11 @@
             ServiceManager.SourceManager.ActiveSourceChanged += delegate { UpdateActions (); };
             TrackModel.Reloaded += OnTrackModelReloaded;
 
-            Reload ();
-
+            play_enqueued = ApplicationContext.CommandLine.Contains ("play-enqueued");
+            
             foreach (string path in ApplicationContext.CommandLine.Files) {
                 Enqueue (path);
             }
-            
-            if (ApplicationContext.CommandLine.Contains ("play-enqueued")) {
-                PlayEnqueued ();
-            }
         }
         
         uint source_activate_id = 0;
@@ -109,7 +104,27 @@
         public void Enqueue (string path)
         {
             lock (this) {
-                importer.QueueSource (path);
+                if (importer == null) {
+                    importer = new DatabaseImportManager (this);
+                    importer.KeepUserJobHidden = true;
+                    importer.ImportResult += delegate (object o, DatabaseImportResultArgs args) {
+                        Banshee.ServiceStack.Application.Invoke (delegate {
+                            if (args.Error != null || path_to_play != null) {
+                                return;
+                            }
+                            
+                            path_to_play = args.Path;
+                            if (args.Track == null) {
+                                // Play immediately if the track is already in the source,
+                                // otherwise the call will be deferred until the track has
+                                // been imported and loaded into the cache
+                                PlayEnqueued ();
+                            }
+                        });
+                    };
+                }
+            
+                importer.Enqueue (path);
                 
                 if (source_activate_id == 0) {
                     source_activate_id = GLib.Timeout.Add (500, delegate {
@@ -121,6 +136,40 @@
             }
         }
         
+        private void PlayEnqueued ()
+        {
+            if (!play_enqueued || path_to_play == null) {
+                return;
+            }
+            
+            SafeUri uri = null;
+            play_enqueued = false;
+            
+            ServiceManager.PlaybackController.NextSource = this;
+            
+            try {
+                uri = new SafeUri (path_to_play);
+            } catch {
+            }
+            
+            if (uri == null) {
+                return;
+            }
+            
+            int id = DatabaseTrackInfo.GetTrackIdForUri (uri, Paths.MakePathRelative (
+                uri.AbsolutePath, BaseDirectory), new int [] { DbId });
+            
+            if (id >= 0) {
+                int index = (int)TrackCache.IndexOf ((long)id);
+                if (index >= 0) {
+                    TrackInfo track = TrackModel[index];
+                    if (track != null) {
+                        ServiceManager.PlayerEngine.OpenPlay (track);
+                    }
+                }
+            }
+        }
+        
         public override void Dispose ()
         {
             ServiceManager.Get<DBusCommandService> ().ArgumentPushed -= OnCommandLineArgument;
@@ -134,12 +183,13 @@
         {
             if (!isFile) {
                 if (argument == "play-enqueued") {
-                    PlayEnqueued ();
+                    play_enqueued = true;
+                    path_to_play = null;
                 }
                 return;
             }
             
-            Log.DebugFormat ("FileSystemQueueSource::Enqueue => {0}", argument);
+            Log.DebugFormat ("FSQ Enqueue: {0}", argument);
             
             try {
                 if (Banshee.IO.Directory.Exists (argument) || Banshee.IO.File.Exists (new SafeUri (argument))) {
@@ -149,12 +199,6 @@
             }
         }
         
-        private void PlayEnqueued ()
-        {
-            ServiceManager.PlaybackController.NextSource = this;
-            ServiceManager.PlayerEngine.Play ();
-        }
-        
         protected override void OnUpdated ()
         {
             base.OnUpdated ();
@@ -163,7 +207,16 @@
                 UpdateActions ();
             }
         }
-
+        
+        public override void Reload ()
+        {
+            base.Reload ();
+            
+            //if (Count > 0) {
+                PlayEnqueued ();
+          //  }
+        }
+        
         private void OnTrackModelReloaded (object sender, EventArgs args)
         {
             if (Count > 0 && !visible) {
@@ -172,6 +225,10 @@
             } else if (Count <= 0 && visible) {
                 ServiceManager.SourceManager.RemoveSource (this);
                 visible = false;
+            }            
+            
+            if (Count > 0) {
+                PlayEnqueued ();
             }
         }
         

Modified: trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastImportManager.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastImportManager.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Podcasting/Banshee.Podcasting/PodcastImportManager.cs	Mon Jun 16 20:32:09 2008
@@ -40,7 +40,7 @@
     {
         public PodcastImportManager (PodcastSource source) : base (source)
         {
-            force_copy = false;
+            ForceCopy = false;
         }
         
         public DatabaseTrackInfo ImportPodcast (string uri)

Added: trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipeline.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipeline.cs	Mon Jun 16 20:32:09 2008
@@ -0,0 +1,81 @@
+//
+// QueuePipeline.cs
+//
+// Author:
+//   Aaron Bockover <abockover 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;
+
+namespace Hyena.Collections
+{
+    public class QueuePipeline <T> where T : class
+    {
+        private QueuePipelineElement<T> first_element;
+        internal QueuePipelineElement<T> FirstElement {
+            get { return first_element; }
+        }
+        
+        public QueuePipeline ()
+        {
+        }
+        
+        public void AddElement (QueuePipelineElement<T> element)
+        {
+            lock (this) {
+                if (first_element == null) {
+                    first_element = element;
+                    return;
+                }
+            
+                QueuePipelineElement<T> current = first_element;
+                
+                while (current != null) {
+                    if (current.NextElement == null) {
+                        current.NextElement = element;
+                        break;
+                    }
+                    
+                    current = current.NextElement;
+                }
+            }
+        }
+        
+        public virtual void Enqueue (T item)
+        {
+            if (first_element == null) {
+                throw new InvalidOperationException ("There are no elements in this pipeline");
+            }
+            
+            first_element.Enqueue (item);
+        }
+        
+        public virtual void Cancel ()
+        {
+            if (first_element != null) {
+                first_element.Cancel ();
+            }
+        }
+    }
+}

Added: trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipelineElement.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Collections/QueuePipelineElement.cs	Mon Jun 16 20:32:09 2008
@@ -0,0 +1,183 @@
+//
+// QueuePipelineElement.cs
+//
+// Author:
+//   Aaron Bockover <abockover 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.Threading;
+using System.Collections.Generic;
+
+namespace Hyena.Collections
+{
+    public abstract class QueuePipelineElement<T> where T : class
+    {
+        private class ElementProcessCanceledException : ApplicationException
+        {
+        }
+    
+        private Queue<T> queue = new Queue<T> ();
+        private object monitor = new object ();
+        private AutoResetEvent thread_wait;
+        private bool processing = false;
+        private bool threaded = true;
+        private bool canceled = false;
+        
+        protected abstract T ProcessItem (T item);
+        
+        protected virtual void OnFinished ()
+        {
+            lock (this) {
+                canceled = false;
+            }
+            
+            Console.WriteLine ("Finished {0}", GetType ());
+        }
+        
+        protected virtual void OnCanceled ()
+        {
+            Console.WriteLine ("Canceled {0}", GetType ());
+        
+            lock (queue) {
+                queue.Clear ();
+            }
+        }
+        
+        public virtual void Enqueue (T item)
+        {
+            lock (this) {                
+                lock (queue) {
+                    queue.Enqueue (item);
+                }
+                
+                if (!threaded) {
+                    Processor (null);
+                    return;
+                }
+                
+                if (thread_wait == null) {
+                    thread_wait = new AutoResetEvent (false);
+                }
+                
+                if (Monitor.TryEnter (monitor)) {
+                    Monitor.Exit (monitor);
+                    ThreadPool.QueueUserWorkItem (Processor);
+                    thread_wait.WaitOne ();
+                }
+            }
+        }
+        
+        protected virtual void EnqueueDownstream (T item)
+        {
+            if (NextElement != null && item != null) {
+                NextElement.Enqueue (item);
+            }
+        }
+        
+        private void Processor (object state)
+        {
+            lock (monitor) {
+                if (threaded) {
+                    thread_wait.Set ();
+                }
+            
+                lock (this) {
+                    processing = true;
+                }
+                
+                try {
+                    while (queue.Count > 0) {
+                        CheckForCanceled ();
+                        
+                        T item = null;
+                        lock (queue) {
+                            item = queue.Dequeue ();
+                        }
+                        
+                        EnqueueDownstream (ProcessItem (item));
+                    }
+                } catch (ElementProcessCanceledException) {
+                    OnCanceled ();
+                }
+                
+                
+                lock (this) {
+                    processing = false;
+                    thread_wait.Close ();
+                    thread_wait = null;
+                }
+                
+                OnFinished ();
+            }
+        }
+        
+        protected virtual void CheckForCanceled ()
+        {
+            lock (this) {
+                if (canceled) {
+                    throw new ElementProcessCanceledException ();
+                }
+            }
+        }
+        
+        public void Cancel ()
+        {
+            lock (this) {
+                if (processing) {
+                    canceled = true;
+                }
+                
+                if (NextElement != null) {
+                    NextElement.Cancel ();
+                }
+            }
+        }
+        
+        public bool Processing {
+            get { lock (this) { return processing; } }
+        }
+        
+        public bool Threaded {
+            get { return threaded; }
+            set { 
+                if (processing) {
+                    throw new InvalidOperationException ("Cannot change threading model while the element is processing");
+                }
+                
+                threaded = value; 
+            }
+        }
+        
+        protected Queue<T> Queue {
+            get { return queue; }
+        }
+        
+        private QueuePipelineElement<T> next_element;
+        internal QueuePipelineElement<T> NextElement {
+            get { return next_element; }
+            set { next_element = value; }
+        }
+    }
+}

Added: trunk/banshee/src/Libraries/Hyena/Hyena.Collections/Tests/QueuePipelineTests.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Collections/Tests/QueuePipelineTests.cs	Mon Jun 16 20:32:09 2008
@@ -0,0 +1,141 @@
+//
+// ElementQueueProcessor.cs
+//
+// Author:
+//   Aaron Bockover <abockover 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.
+//
+
+#if ENABLE_TESTS
+
+using System;
+using System.Threading;
+using System.Collections.Generic;
+using NUnit.Framework;
+
+using Hyena.Collections;
+
+namespace Hyena.Collections.Tests
+{
+    [TestFixture]
+    public class QueuePipelineTests
+    {
+        private class FakeElement : QueuePipelineElement<object>
+        {
+            protected override object ProcessItem (object item)
+            {
+                return null;
+            }
+        }
+    
+        [Test]
+        public void BuildPipeline ()
+        {
+            BuildPipeline (1);
+            BuildPipeline (2);
+            BuildPipeline (3);
+            BuildPipeline (10);
+            BuildPipeline (1000);
+        }
+        
+        private void BuildPipeline (int count)
+        {
+            List<FakeElement> elements = new List<FakeElement> ();
+            for (int i = 0; i < count; i++) {
+                elements.Add (new FakeElement ());
+            }
+        
+            QueuePipeline<object> qp = new QueuePipeline<object> ();
+            foreach (FakeElement s in elements) {
+                qp.AddElement (s);
+            }
+            
+            Assert.AreEqual (elements[0], qp.FirstElement);
+            
+            int index = 0;
+            FakeElement element = (FakeElement)qp.FirstElement;
+            while (element != null) {
+                Assert.AreEqual (elements[index++], element);
+                element = (FakeElement)element.NextElement;
+            }
+        }
+        
+        [Test]
+        public void Blah ()
+        {
+            QueuePipeline<string> pipeline = new QueuePipeline<string> ();
+            pipeline.AddElement (new EvenFilterElement ());
+            pipeline.AddElement (new RandomFilterElement ());
+            pipeline.AddElement (new TerminationElement ());
+            
+            for (int i = 0; i < 1000; i++) {
+                pipeline.Enqueue (i.ToString ());
+            }
+            
+            Console.ReadLine ();
+        }
+        
+        private class EvenFilterElement : QueuePipelineElement<string>
+        {
+            private int index;
+            private Random random = new Random ();
+            
+            protected override string ProcessItem (string item)
+            {
+                System.Threading.Thread.Sleep (random.Next (0, 10));
+                return index++ % 2 == 0 ? item : null;
+            }
+        }
+        
+        private class RandomFilterElement : QueuePipelineElement<string>
+        {
+            private Random random = new Random ();
+        
+            public RandomFilterElement ()
+            {
+                Threaded = true;
+            }
+            
+            protected override string ProcessItem (string item)
+            {   
+                return random.Next () % 2 == 0 ? null : item;
+            }
+        }
+        
+        private class TerminationElement : QueuePipelineElement<string>
+        {
+            public TerminationElement ()
+            {
+                Threaded = true;
+            }
+        
+            protected override string ProcessItem (string item)
+            {
+                Console.WriteLine ("TerminationElement: {0}", item);
+                return null;
+            }
+        }
+    }
+}
+
+#endif

Added: trunk/banshee/src/Libraries/Hyena/Hyena.Collections/WriteLineElement.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Collections/WriteLineElement.cs	Mon Jun 16 20:32:09 2008
@@ -0,0 +1,46 @@
+//
+// WriteLineElement.cs
+//
+// Author:
+//   Aaron Bockover <abockover 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;
+
+namespace Hyena.Collections
+{
+    public class WriteLineElement<T> : QueuePipelineElement<T> where T : class
+    {
+        public WriteLineElement ()
+        {
+            Threaded = false;
+        }
+        
+        protected override T ProcessItem (T item)
+        {
+            Console.WriteLine (item);
+            return null;
+        }
+    }
+}

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.CommandLine/CommandLineParser.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.CommandLine/CommandLineParser.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.CommandLine/CommandLineParser.cs	Mon Jun 16 20:32:09 2008
@@ -49,23 +49,17 @@
         private int generation;
         private int sorted_args_generation;
         private int offset;
-        private string enqueue_arg;
         private string [] arguments;
         private KeyValuePair<string, Argument> [] sorted_args;
         private Dictionary<string, Argument> parsed_arguments = new Dictionary<string, Argument> ();
         private List<string> file_list = new List<string> ();
         
-        public CommandLineParser () : this (null, Environment.GetCommandLineArgs (), 1)
+        public CommandLineParser () : this (Environment.GetCommandLineArgs (), 1)
         {
         }
         
-        public CommandLineParser (string enqueueArgument) : this (enqueueArgument, Environment.GetCommandLineArgs (), 1)
+        public CommandLineParser (string [] arguments, int offset)
         {
-        }
-        
-        public CommandLineParser (string enqueueArgument, string [] arguments, int offset)
-        {
-            this.enqueue_arg = enqueueArgument;
             this.arguments = arguments;
             this.offset = offset;
             
@@ -74,21 +68,14 @@
         
         private void Parse ()
         {
-            bool enqueue_mode = false;
-            
             for (int i = offset; i < arguments.Length; i++) {
-                if (enqueue_mode || !IsOption (arguments[i])) {
+                if (!IsOption (arguments[i])) {
                     file_list.Add (arguments[i]);
                     continue;
                 }
                 
                 string name = OptionName (arguments[i]);
                 string value = String.Empty;
-                
-                if (name == enqueue_arg) {
-                    enqueue_mode = true;
-                    continue;
-                }
 
                 int eq_offset = name.IndexOf ('=');
                 if (eq_offset > 1) {

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.mdp
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.mdp	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.mdp	Mon Jun 16 20:32:09 2008
@@ -97,6 +97,10 @@
     <File name="Hyena/Tests/TestBase.cs" subtype="Code" buildaction="Compile" />
     <File name="Hyena.Data/ICacheableItem.cs" subtype="Code" buildaction="Compile" />
     <File name="Hyena.Collections/CollectionExtensions.cs" subtype="Code" buildaction="Compile" />
+    <File name="Hyena.Collections/QueuePipeline.cs" subtype="Code" buildaction="Compile" />
+    <File name="Hyena.Collections/Tests/QueuePipelineTests.cs" subtype="Code" buildaction="Compile" />
+    <File name="Hyena.Collections/QueuePipelineElement.cs" subtype="Code" buildaction="Compile" />
+    <File name="Hyena.Collections/WriteLineElement.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

Modified: trunk/banshee/src/Libraries/Hyena/Makefile.am
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Makefile.am	(original)
+++ trunk/banshee/src/Libraries/Hyena/Makefile.am	Mon Jun 16 20:32:09 2008
@@ -5,11 +5,15 @@
 	Hyena.Collections/CollectionExtensions.cs \
 	Hyena.Collections/IntervalHeap.cs \
 	Hyena.Collections/IStackProvider.cs \
+	Hyena.Collections/QueuePipeline.cs \
+	Hyena.Collections/QueuePipelineElement.cs \
 	Hyena.Collections/RangeCollection.cs \
 	Hyena.Collections/Selection.cs \
 	Hyena.Collections/SelectionProxy.cs \
 	Hyena.Collections/Tests/IntervalHeapTests.cs \
+	Hyena.Collections/Tests/QueuePipelineTests.cs \
 	Hyena.Collections/Tests/RangeCollectionTests.cs \
+	Hyena.Collections/WriteLineElement.cs \
 	Hyena.CommandLine/CommandLineParser.cs \
 	Hyena.CommandLine/Layout.cs \
 	Hyena.CommandLine/LayoutGroup.cs \

Modified: trunk/banshee/src/Libraries/Libraries.mds
==============================================================================
--- trunk/banshee/src/Libraries/Libraries.mds	(original)
+++ trunk/banshee/src/Libraries/Libraries.mds	Mon Jun 16 20:32:09 2008
@@ -11,7 +11,7 @@
       <Entry build="True" name="Migo" configuration="Debug" />
     </Configuration>
   </Configurations>
-  <StartMode startupentry="MusicBrainz" single="True">
+  <StartMode startupentry="Hyena" single="True">
     <Execute type="None" entry="Hyena" />
     <Execute type="None" entry="Hyena.Gui" />
     <Execute type="None" entry="Lastfm" />



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