banshee r3655 - in trunk/banshee: . build src/Backends/Banshee.Hal/Banshee.HalBackend src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Collection src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.Hardware src/Core/Banshee.Services/Banshee.Library src/Core/Banshee.Services/Banshee.PlayerMigration src/Core/Banshee.Services/Banshee.Sources src/Core/Banshee.ThickClient/Banshee.Collection.Gui src/Extensions src/Extensions/Banshee.Dap.MassStorage src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage src/Libraries/Hyena/Hyena.Data



Author: gburt
Date: Thu Apr  3 07:57:40 2008
New Revision: 3655
URL: http://svn.gnome.org/viewvc/banshee?rev=3655&view=rev

Log:
2008-04-03  Gabriel Burt  <gabriel burt gmail com>
	
	This patch adds the first support for DAPs to trunk.  It currently only
	support loading the songs/videos on a USB drive, but synching, adding,
	removing, transcoding etc are not implemented yet.

	* configure.ac:
	* build/build.environment.mk:
	* src/Extensions/Makefile.am:
	* src/Extensions/Extensions.mds: Add Banshee.Dap.MassStorage

	* src/Backends/Banshee.Hal/Banshee.HalBackend/Device.cs: Make Uuid virtual
	and HalDevice internal.

	* src/Backends/Banshee.Hal/Banshee.HalBackend/Volume.cs: Do not treat
	unmounted volumes as existing - intead, wait for them to be mounted and
	then notify they've been added.

	* src/Backends/Banshee.Hal/Banshee.HalBackend/HardwareManager.cs: Make
	method internal so Volume can access them.

	* src/Core/Banshee.Services/Banshee.Collection/ImportManager.cs: Add
	property to keep the user job hidden, used by MassStorageSource when
	loading its tracks.

	* src/Backends/Banshee.Hal/Banshee.HalBackend/BlockDevice.cs:
	* src/Core/Banshee.Services/Banshee.Hardware/IBlockDevice.cs: Add
	IsRemovable property.

	* src/Core/Banshee.Services/Banshee.Hardware/IVolume.cs: Remove IsMounted
	property, rename IsMountedReadOnly to IsReadOnly, and add ShouldIgnore and
	FileSystem properites.

	* src/Core/Banshee.Services/Banshee.Library/MusicLibrarySource.cs: Authors.

	* src/Core/Banshee.Services/Banshee.PlayerMigration/AmarokPlayerImportSource.cs:
	Call renamed ImportTrack method.

	* src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs: Lazy
	initialize the ErrorSource.

	* src/Core/Banshee.Services/Banshee.Library/LibraryImportManager.cs:
	Factor most everythign out into DatabaseImportManager so can be reused for
	all sorts of disk-based primary sources.

	* src/Core/Banshee.Services/Makefile.am:
	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs:
	Take most methods from LibraryImportManager, allow setting the ErrorSource
	and the method that chooses what primary source to put a DatabaseTrackInfo
	into.

	* src/Core/Banshee.Services/Banshee.Sources/Source.cs: Add SetStatus that
	gives access to every detail of the StatusMessage.

	* src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.addin.xml:
	* src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.mdp:
	* src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/DapService.cs:
	* src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/DapSource.cs:
	* src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs:
	* src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/RemovableSource.cs:
	* src/Extensions/Banshee.Dap.MassStorage/Makefile.am: New extension, first
	pass at loading disk-based volumes.  Currently only loads usb mass storage
	drives.  Adding and deleting tracks on these drives is not yet tested.

	* src/Libraries/Hyena/Hyena.Data/PropertyStore.cs: Handle set value == null.

	* src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ArtistListView.cs:
	Add todo for artist/browser context menu.


Added:
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs
   trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/
   trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/
   trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.addin.xml
   trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.mdp
   trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/DapService.cs
   trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/DapSource.cs
   trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
   trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/RemovableSource.cs
   trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Makefile.am
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/build/build.environment.mk
   trunk/banshee/configure.ac
   trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/BlockDevice.cs
   trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/Device.cs
   trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/HardwareManager.cs
   trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/Volume.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/ImportManager.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IBlockDevice.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IVolume.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Library/LibraryImportManager.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Library/MusicLibrarySource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.PlayerMigration/AmarokPlayerImportSource.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.Collection.Gui/ArtistListView.cs
   trunk/banshee/src/Extensions/Extensions.mds
   trunk/banshee/src/Extensions/Makefile.am
   trunk/banshee/src/Libraries/Hyena/Hyena.Data/PropertyStore.cs

Modified: trunk/banshee/build/build.environment.mk
==============================================================================
--- trunk/banshee/build/build.environment.mk	(original)
+++ trunk/banshee/build/build.environment.mk	Thu Apr  3 07:57:40 2008
@@ -134,6 +134,7 @@
 REF_EXTENSION_PLAYQUEUE = $(LINK_BANSHEE_THICKCLIENT_DEPS)
 REF_EXTENSION_LASTFM = $(LINK_BANSHEE_THICKCLIENT_DEPS) $(LINK_MONO_MEDIA) $(LINK_LASTFM) $(LINK_LASTFM_GUI)
 REF_EXTENSION_NOWPLAYING = $(LINK_BANSHEE_THICKCLIENT_DEPS)
+REF_EXTENSION_DAP_MASS_STORAGE = $(LINK_BANSHEE_SERVICES_DEPS)
 
 # Build rules
 # Ignoring 0278 due to a bug in gmcs: 

Modified: trunk/banshee/configure.ac
==============================================================================
--- trunk/banshee/configure.ac	(original)
+++ trunk/banshee/configure.ac	Thu Apr  3 07:57:40 2008
@@ -161,6 +161,7 @@
 src/Extensions/Banshee.AudioCd/Makefile
 src/Extensions/Banshee.Bookmarks/Makefile
 src/Extensions/Banshee.Daap/Makefile
+src/Extensions/Banshee.Dap.MassStorage/Makefile
 src/Extensions/Banshee.Lastfm/Makefile
 src/Extensions/Banshee.MultimediaKeys/Makefile
 src/Extensions/Banshee.NotificationArea/Makefile

Modified: trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/BlockDevice.cs
==============================================================================
--- trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/BlockDevice.cs	(original)
+++ trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/BlockDevice.cs	Thu Apr  3 07:57:40 2008
@@ -60,7 +60,11 @@
         public string DeviceNode {
             get { return HalDevice["block.device"]; }
         }
-        
+
+        public bool IsRemovable {
+            get { return HalDevice.GetPropertyBoolean ("storage.removable"); }
+        }
+
         public IEnumerable<IVolume> Volumes {
             get { return this; }
         }

Modified: trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/Device.cs
==============================================================================
--- trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/Device.cs	(original)
+++ trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/Device.cs	Thu Apr  3 07:57:40 2008
@@ -35,7 +35,7 @@
     public abstract class Device : IDevice
     {    
         private Hal.Device device;
-        protected Hal.Device HalDevice {
+        internal Hal.Device HalDevice {
             get { return device; }
         }
         
@@ -50,12 +50,22 @@
             this.device = device;
         }
         
-        public string Uuid {
+        public virtual string Uuid {
             get { return device.Udi; }
         }
 
+        private string name;
         public virtual string Name {
-            get { return device["info.product"]; }
+            get {
+                if (name == null) {
+                    name = device["info.product"];
+                    if (String.IsNullOrEmpty (name)) {
+                        name = device["volume.label"];
+                    }
+                }
+
+                return name;
+            }
         }
     }
 }

Modified: trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/HardwareManager.cs
==============================================================================
--- trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/HardwareManager.cs	(original)
+++ trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/HardwareManager.cs	Thu Apr  3 07:57:40 2008
@@ -37,7 +37,7 @@
     public sealed class HardwareManager : IHardwareManager
     {
         private Hal.Manager manager;
-        
+
         public event DeviceAddedHandler DeviceAdded;
         public event DeviceRemovedHandler DeviceRemoved;
         
@@ -46,6 +46,8 @@
             manager = new Hal.Manager ();
             manager.DeviceAdded += OnHalDeviceAdded;
             manager.DeviceRemoved += OnHalDeviceRemoved;
+
+            Volume.HardwareManager = this;
         }
         
         public void Dispose ()
@@ -76,23 +78,27 @@
         {
             return GetAllBlockDevices<IDiskDevice> ();
         }
-        
+
         private void OnHalDeviceAdded (object o, Hal.DeviceAddedArgs args)
         {
             if (!args.Device.QueryCapability ("block")) {
                 return;
             }
-            
+
             IDevice device = BlockDevice.Resolve<IBlockDevice> (manager, args.Device);
             if (device == null) {
                 device = Volume.Resolve (null, manager, args.Device);
             }
-            
+            OnHalDeviceAdded (device);
+        }
+
+        internal void OnHalDeviceAdded (IDevice device)
+        {
             if (device != null) {
                 OnDeviceAdded (device);
             }
         }
-        
+
         private void OnHalDeviceRemoved (object o, Hal.DeviceRemovedArgs args)
         {
             OnDeviceRemoved (args.Udi);
@@ -106,7 +112,7 @@
             }
         }
         
-        private void OnDeviceRemoved (string uuid)
+        internal void OnDeviceRemoved (string uuid)
         {
             DeviceRemovedHandler handler = DeviceRemoved;
             if (handler != null) {

Modified: trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/Volume.cs
==============================================================================
--- trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/Volume.cs	(original)
+++ trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/Volume.cs	Thu Apr  3 07:57:40 2008
@@ -27,6 +27,7 @@
 //
 
 using System;
+using System.Collections.Generic;
 
 using Banshee.Hardware;
 
@@ -34,6 +35,11 @@
 {
     public class Volume : Device, IVolume
     {
+        private static Dictionary<Hal.Device, Volume> mounted_volumes = new Dictionary<Hal.Device, Volume> ();
+        private static Dictionary<Hal.Device, Volume> unmounted_volumes = new Dictionary<Hal.Device, Volume> ();
+
+        internal static HardwareManager HardwareManager;
+        
         private const string method_names_property = "org.freedesktop.Hal.Device.Volume.method_names";
         
         public static Volume Resolve (BlockDevice parent, Hal.Manager manager, Hal.Device device)
@@ -42,9 +48,11 @@
                 return null;
             }
             
-            return (parent is ICdromDevice || (parent == null && device.QueryCapability ("volume.disc")))
+            Volume volume = (parent is ICdromDevice || (parent == null && device.QueryCapability ("volume.disc")))
                 ? DiscVolume.Resolve (parent, manager, device)
                 : new Volume (parent, manager, device);
+
+            return CheckVolumeMounted (volume) ? volume : null;
         }
         
         private BlockDevice parent;
@@ -67,11 +75,23 @@
             get { return HalDevice["volume.mount_point"]; }
         }
 
+        public string FileSystem {
+            get { return HalDevice["volume.fstype"]; }
+        }
+
+        public override string Uuid {
+            get { return String.IsNullOrEmpty (HalDevice["volume.uuid"]) ? base.Uuid : HalDevice["volume.uuid"]; }
+        }
+
         public bool IsMounted {
             get { return HalDevice.GetPropertyBoolean ("volume.is_mounted"); }
         }
 
-        public bool IsMountedReadOnly {
+        public bool ShouldIgnore {
+            get { return HalDevice.GetPropertyBoolean ("volume.ignore"); }
+        }
+
+        public bool IsReadOnly {
             get { return HalDevice.GetPropertyBoolean ("volume.is_mounted_read_only"); }
         }
 
@@ -127,10 +147,59 @@
         {
             if (IsMounted) {
                 return String.Format ("`{0}': mounted {1} volume at {2} with {3} bytes free (of {4})", 
-                    Name, IsMountedReadOnly ? "read only" : "read/write", MountPoint, Available, Capacity);
+                    Name, IsReadOnly ? "read only" : "read/write", MountPoint, Available, Capacity);
             }
             
             return String.Format ("`{0}': not mounted (capacity: {1} bytes)", Name, Capacity);
         }
+
+        private static bool CheckVolumeMounted (Volume volume)
+        {
+            if (volume != null && !(volume is IDiscVolume)) {
+                lock (mounted_volumes) {
+                    if (mounted_volumes.ContainsKey (volume.HalDevice)) {
+                        return true;
+                    } else if (unmounted_volumes.ContainsKey (volume.HalDevice)) {
+                        return false;
+                    }
+
+                    volume.HalDevice.PropertyModified += HandleVolumeChanged;
+
+                    if (!volume.IsMounted) {
+                        unmounted_volumes[volume.HalDevice] = volume;
+                        return false;
+                    } else {
+                        mounted_volumes[volume.HalDevice] = volume;
+                    }
+                }
+            }
+            return true;
+        }
+
+        private static void HandleVolumeChanged (object o, Hal.PropertyModifiedArgs args)
+        {
+            Hal.Device device = o as Hal.Device;
+            if (device == null) {
+                return;
+            }
+
+            lock (mounted_volumes) {
+                if (mounted_volumes.ContainsKey (device)) {
+                    Volume volume = mounted_volumes[device];
+                    if (!volume.IsMounted) {
+                        mounted_volumes.Remove (device);
+                        unmounted_volumes[device] = volume;
+                        HardwareManager.OnDeviceRemoved (volume.Uuid);
+                    }
+                } else if (unmounted_volumes.ContainsKey (device)) {
+                    Volume volume = unmounted_volumes[device];
+                    if (volume.IsMounted) {
+                        unmounted_volumes.Remove (device);
+                        mounted_volumes[device] = volume;
+                        HardwareManager.OnHalDeviceAdded (volume);
+                    }
+                }
+            }
+        }
     }
 }

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseImportManager.cs	Thu Apr  3 07:57:40 2008
@@ -0,0 +1,208 @@
+// 
+// DatabaseImportManager.cs
+//
+// Authors:
+//   Aaron Bockover <abockover novell com>
+//   Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2007-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.Generic;
+using System.IO;
+
+using Mono.Unix;
+
+using Hyena;
+using Hyena.Data.Sqlite;
+
+using Banshee.Base;
+using Banshee.Sources;
+using Banshee.Collection;
+using Banshee.Collection.Database;
+using Banshee.ServiceStack;
+using Banshee.Streaming;
+
+namespace Banshee.Collection.Database
+{
+    public class DatabaseImportManager : ImportManager
+    {
+        // This is a list of known media files that we may encounter. The extensions
+        // in this list do not mean they are actually supported - this list is just
+        // used to see if we should allow the file to be processed by TagLib. The
+        // point is to rule out, at the path level, files that we won't support.
+        
+        private static readonly string [] white_list_file_extensions = new string [] {
+            "3g2",   "3gp",  "3gp2", "3gpp", "aac",  "ac3",  "aif",  "aifc", 
+            "aiff",  "al",   "alaw", "ape",  "asf",  "asx",  "au",   "avi", 
+            "cda",   "cdr",  "divx", "dv",   "flac", "flv",  "gvi",  "gvp", 
+            "m1v",   "m21",  "m2p",  "m2v",  "m4a",  "m4b",  "m4e",  "m4p",  
+            "m4u",   "m4v",  "mp+",  "mid",  "midi", "mjp",  "mkv",  "moov",
+            "mov",   "movie","mp1",  "mp2",  "mp21", "mp3",  "mp4",  "mpa",
+            "mpc",   "mpe",  "mpeg", "mpg",  "mpp",  "mpu",  "mpv",  "mpv2",
+            "ogg",   "ogm",  "omf",  "qt",   "ra",   "ram",  "raw",  "rm",
+            "rmvb",  "rts",  "smil", "swf",  "tivo", "u",    "vfw",  "vob",
+            "wav",   "wave", "wax",  "wm",   "wma",  "wmd",  "wmv",  "wmx",
+            "wv",    "wvc",  "wvx",  "yuv",
+            "f4v",   "f4a",  "f4b",
+        };
+
+        static DatabaseImportManager ()
+        {
+            Array.Sort<string> (white_list_file_extensions);
+        }
+
+        public static bool IsWhiteListedFile (string path)
+        {
+            if (String.IsNullOrEmpty (path)) {
+                return false;
+            }
+            
+            int index = path.LastIndexOf ('.');
+            if (index < 0 || index == path.Length || index == path.Length - 1) {
+                return false;
+            }
+            
+            return Array.BinarySearch<string> (white_list_file_extensions, 
+                path.Substring (index + 1).ToLower ()) >= 0;
+        }
+
+        public delegate PrimarySource TrackPrimarySourceChooser (DatabaseTrackInfo track);
+
+        private TrackPrimarySourceChooser trackPrimarySourceChooser;
+        protected bool can_copy_to_library = false;
+        private Dictionary<int, int> counts;
+        private ErrorSource error_source;
+    
+        public DatabaseImportManager (PrimarySource psource) : this (psource.ErrorSource, delegate { return psource; })
+        {
+        }
+
+        public DatabaseImportManager (ErrorSource error_source, TrackPrimarySourceChooser chooser) : this (chooser)
+        {
+            this.error_source = error_source;
+        }
+
+        public DatabaseImportManager (TrackPrimarySourceChooser chooser)
+        {
+            trackPrimarySourceChooser = chooser;
+            counts = new Dictionary<int, int> ();
+        }
+
+        protected virtual ErrorSource ErrorSource { 
+            get { return error_source; }
+        }
+
+        protected override void OnImportRequested (string path)
+        {
+            if (!IsWhiteListedFile (path)) {
+                IncrementProcessedCount (null);
+                return;
+            }
+
+            try {            
+                DatabaseTrackInfo track = ImportTrack (path);
+                if (track != null && track.TrackId > 0) {
+                    IncrementProcessedCount (String.Format ("{0} - {1}", 
+                        track.DisplayArtistName, track.DisplayTrackTitle));
+                }
+            } catch (Exception e) {
+                LogError (path, e);
+                IncrementProcessedCount (null);
+            }
+        }
+        
+        public DatabaseTrackInfo ImportTrack (string path)
+        {
+            return ImportTrack (new SafeUri (path));
+        }
+
+        public DatabaseTrackInfo ImportTrack (SafeUri uri)
+        {
+            DatabaseTrackInfo track = null;
+            
+            if (DatabaseTrackInfo.ContainsUri (uri)) {
+                IncrementProcessedCount (null);
+                return null;
+            }
+
+            ServiceManager.DbConnection.BeginTransaction ();
+            try {
+                TagLib.File file = StreamTagger.ProcessUri (uri);
+                track = new DatabaseTrackInfo ();
+                StreamTagger.TrackInfoMerge (track, file);
+                
+                if (can_copy_to_library) {
+                    SafeUri newpath = track.CopyToLibrary ();
+                    if (newpath != null) {
+                        track.Uri = newpath;
+                    }
+                }
+
+                track.DateAdded = DateTime.Now;
+
+                track.PrimarySource = trackPrimarySourceChooser (track);
+                counts[track.PrimarySourceId] = counts.ContainsKey (track.PrimarySourceId) ? counts[track.PrimarySourceId] + 1 : 1;
+
+                track.Save (false);
+
+                ServiceManager.DbConnection.CommitTransaction ();
+
+                if (counts[track.PrimarySourceId] % 250 == 0) {
+                    track.PrimarySource.NotifyTracksAdded ();
+                }
+            } catch (Exception) {
+                ServiceManager.DbConnection.RollbackTransaction ();
+                throw;
+            }
+
+            return track;
+        }
+
+        private void LogError (string path, Exception e)
+        {
+            LogError (path, e.Message);
+
+            if (!(e is TagLib.CorruptFileException) && !(e is TagLib.UnsupportedFormatException)) {
+                Log.DebugFormat ("Full import exception: {0}", e.ToString ());
+            }
+        }
+
+        private void LogError (string path, string msg)
+        {
+            ErrorSource.AddMessage (Path.GetFileName (path), msg);
+            Log.Error (path, msg, false);
+        }
+
+        protected override void OnImportFinished ()
+        {
+            foreach (int primary_source_id in counts.Keys) {
+                PrimarySource.GetById (primary_source_id).NotifyTracksAdded ();
+            }
+
+            counts.Clear ();
+
+            base.OnImportFinished ();
+        }
+    }
+}

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	Thu Apr  3 07:57:40 2008
@@ -65,6 +65,12 @@
         public bool IsImportInProgress {
             get { return processing_queue; }
         }
+
+        private bool keep_user_job_hidden = false;
+        public bool KeepUserJobHidden {
+            get { return keep_user_job_hidden; }
+            set { keep_user_job_hidden = value; }
+        }
         
         private void CreateUserJob ()
         {
@@ -77,7 +83,10 @@
                 user_job.IconNames = new string [] { "system-search", "gtk-find" };
                 user_job.CancelMessage = CancelMessage;
                 user_job.CanCancel = true;
-                user_job.Register ();
+
+                if (!KeepUserJobHidden) {
+                    user_job.Register ();
+                }
                 
                 total_count = 0;
                 processed_count = 0;

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IBlockDevice.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IBlockDevice.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IBlockDevice.cs	Thu Apr  3 07:57:40 2008
@@ -35,5 +35,6 @@
     {
         string DeviceNode { get; }
         IEnumerable<IVolume> Volumes { get; }
+        bool IsRemovable { get; }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IVolume.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IVolume.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IVolume.cs	Thu Apr  3 07:57:40 2008
@@ -34,11 +34,13 @@
     {
         string DeviceNode { get; }
         string MountPoint { get; }
-        bool IsMounted { get; }
-        bool IsMountedReadOnly { get; }
+        bool IsReadOnly { get; }
         ulong Capacity { get; }
         long Available { get; }
         new IBlockDevice Parent { get; }
+
+        bool ShouldIgnore { get; }
+        string FileSystem { get; }
         
         bool CanEject { get; }
         void Eject ();

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	Thu Apr  3 07:57:40 2008
@@ -1,8 +1,9 @@
 // 
 // LibraryImportManager.cs
 //
-// Author:
+// Authors:
 //   Aaron Bockover <abockover novell com>
+//   Gabriel Burt <gburt novell com>
 //
 // Copyright (C) 2007-2008 Novell, Inc.
 //
@@ -27,6 +28,7 @@
 //
 
 using System;
+using System.Collections.Generic;
 using System.IO;
 
 using Mono.Unix;
@@ -43,158 +45,24 @@
 
 namespace Banshee.Library
 {
-    public class LibraryImportManager : ImportManager, IService
+    public class LibraryImportManager : DatabaseImportManager, IService
     {
-        // This is a list of known media files that we may encounter. The extensions
-        // in this list do not mean they are actually supported - this list is just
-        // used to see if we should allow the file to be processed by TagLib. The
-        // point is to rule out, at the path level, files that we won't support.
-        
-        private static string [] white_list_file_extensions = new string [] {
-            "3g2",   "3gp",  "3gp2", "3gpp", "aac",  "ac3",  "aif",  "aifc", 
-            "aiff",  "al",   "alaw", "ape",  "asf",  "asx",  "au",   "avi", 
-            "cda",   "cdr",  "divx", "dv",   "flac", "flv",  "gvi",  "gvp", 
-            "m1v",   "m21",  "m2p",  "m2v",  "m4a",  "m4b",  "m4e",  "m4p",  
-            "m4u",   "m4v",  "mp+",  "mid",  "midi", "mjp",  "mkv",  "moov",
-            "mov",   "movie","mp1",  "mp2",  "mp21", "mp3",  "mp4",  "mpa",
-            "mpc",   "mpe",  "mpeg", "mpg",  "mpp",  "mpu",  "mpv",  "mpv2",
-            "ogg",   "ogm",  "omf",  "qt",   "ra",   "ram",  "raw",  "rm",
-            "rmvb",  "rts",  "smil", "swf",  "tivo", "u",    "vfw",  "vob",
-            "wav",   "wave", "wax",  "wm",   "wma",  "wmd",  "wmv",  "wmx",
-            "wv",    "wvc",  "wvx",  "yuv",
-            "f4v",   "f4a",  "f4b",
-        };
-
-        static LibraryImportManager ()
-        {
-            Array.Sort<string> (white_list_file_extensions);
-        }
-        
-        public static bool IsWhiteListedFile (string path)
-        {
-            if (String.IsNullOrEmpty (path)) {
-                return false;
-            }
-            
-            int index = path.LastIndexOf ('.');
-            if (index < 0 || index == path.Length || index == path.Length - 1) {
-                return false;
-            }
-            
-            return Array.BinarySearch<string> (white_list_file_extensions, 
-                path.Substring (index + 1).ToLower ()) >= 0;
-        }
-    
-        public LibraryImportManager ()
-        {
-        }
-        
-        protected override void OnImportRequested (string path)
-        {
-            if (!IsWhiteListedFile (path)) {
-                IncrementProcessedCount (null);
-                return;
-            }
-
-            try {            
-                DatabaseTrackInfo track = AddTrackToLibrary (path);
-                if (track != null && track.TrackId > 0) {
-                    IncrementProcessedCount (String.Format ("{0} - {1}", 
-                        track.DisplayArtistName, track.DisplayTrackTitle));
-                }
-            } catch (Exception e) {
-                LogError (path, e);
-                IncrementProcessedCount (null);
-            }
-        }
-        
-        public DatabaseTrackInfo AddTrackToLibrary (string path)
-        {
-            return AddTrackToLibrary (new SafeUri (path));
-        }
-        
-        private int music_count = 0;
-        private int video_count = 0;
-
-        public DatabaseTrackInfo AddTrackToLibrary (SafeUri uri)
+        public LibraryImportManager () : base (DefaultTrackPrimarySourceChooser)
         {
-            DatabaseTrackInfo track = null;
-            
-            if (DatabaseTrackInfo.ContainsUri (uri)) {
-                IncrementProcessedCount (null);
-                return null;
-            }
-
-            ServiceManager.DbConnection.BeginTransaction ();
-            try {
-                TagLib.File file = StreamTagger.ProcessUri (uri);
-                track = new DatabaseTrackInfo ();
-                StreamTagger.TrackInfoMerge (track, file);
-                
-                SafeUri newpath = track.CopyToLibrary ();
-                if (newpath != null) {
-                    track.Uri = newpath;
-                }
-
-                track.DateAdded = DateTime.Now;
-
-                if ((track.MediaAttributes & TrackMediaAttributes.VideoStream) != 0) {
-                    track.PrimarySource = ServiceManager.SourceManager.VideoLibrary;
-                    video_count++;
-                } else {
-                    track.PrimarySource = ServiceManager.SourceManager.MusicLibrary;
-                    music_count++;
-                }
-
-                track.Save (false);
-
-                ServiceManager.DbConnection.CommitTransaction ();
-            } catch (Exception) {
-                ServiceManager.DbConnection.RollbackTransaction ();
-                throw;
-            }
-
-            if (music_count > 0 && music_count % 250 == 0) {
-                ServiceManager.SourceManager.MusicLibrary.NotifyTracksAdded ();
-            }
-
-            if (video_count > 0 && video_count % 250 == 0) {
-                ServiceManager.SourceManager.VideoLibrary.NotifyTracksAdded ();
-            }
-            
-            return track;
+            can_copy_to_library = true;
         }
 
-        private void LogError (string path, Exception e)
-        {
-            LogError (path, e.Message);
-
-            if (!(e is TagLib.CorruptFileException) && !(e is TagLib.UnsupportedFormatException)) {
-                Log.DebugFormat ("Full import exception: {0}", e.ToString ());
-            }
+        protected override ErrorSource ErrorSource {
+            get { return ServiceManager.SourceManager.MusicLibrary.ErrorSource; }
         }
 
-        private void LogError (string path, string msg)
+        protected static PrimarySource DefaultTrackPrimarySourceChooser (DatabaseTrackInfo track)
         {
-            ErrorSource error_source = ServiceManager.SourceManager.MusicLibrary.ErrorSource;
-            error_source.AddMessage (Path.GetFileName (path), msg);
-            
-            Log.Error (path, msg, false);
-        }
-
-        protected override void OnImportFinished ()
-        {
-            if (music_count > 0) {
-                ServiceManager.SourceManager.MusicLibrary.NotifyTracksAdded ();
-            }
-
-            if (video_count > 0) {
-                ServiceManager.SourceManager.VideoLibrary.NotifyTracksAdded ();
+            if ((track.MediaAttributes & TrackMediaAttributes.VideoStream) != 0) {
+                return ServiceManager.SourceManager.VideoLibrary;
+            } else {
+                return ServiceManager.SourceManager.MusicLibrary;
             }
-
-            music_count = 0;
-            video_count = 0;
-            base.OnImportFinished ();
         }
         
         string IService.ServiceName {

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Library/MusicLibrarySource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Library/MusicLibrarySource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Library/MusicLibrarySource.cs	Thu Apr  3 07:57:40 2008
@@ -1,7 +1,7 @@
 //
 // MusicLibrarySource.cs
 //
-// Author:
+// Authors:
 //   Aaron Bockover <abockover novell com>
 //   Gabriel Burt <gburt novell com>
 //

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.PlayerMigration/AmarokPlayerImportSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.PlayerMigration/AmarokPlayerImportSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.PlayerMigration/AmarokPlayerImportSource.cs	Thu Apr  3 07:57:40 2008
@@ -166,7 +166,7 @@
                          UpdateUserJob (processed, count, artist, title);
                      
                          try {
-                             DatabaseTrackInfo track = import_manager.AddTrackToLibrary (uri);
+                             DatabaseTrackInfo track = import_manager.ImportTrack (uri);
                             
                              if (track == null) {
                                  throw new Exception (String.Format ("Unable to import track: {0}", uri.AbsoluteUri));

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  3 07:57:40 2008
@@ -69,7 +69,7 @@
 
     public abstract class PrimarySource : DatabaseSource
     {
-        protected ErrorSource error_source = new ErrorSource (Catalog.GetString ("Import Errors"));
+        protected ErrorSource error_source;
         protected bool error_source_visible = false;
 
         protected string remove_range_sql = @"
@@ -87,7 +87,14 @@
         }
 
         public ErrorSource ErrorSource {
-            get { return error_source; }
+            get {
+                if (error_source == null) {
+                    error_source = new ErrorSource (Catalog.GetString ("Import Errors"));
+                    ErrorSource.Updated += OnErrorSourceUpdated;
+                    OnErrorSourceUpdated (null, null);
+                }
+                return error_source;
+            }
         }
 
         public delegate void TrackEventHandler (Source sender, TrackEventArgs args);
@@ -110,8 +117,6 @@
             }
 
             track_model.Condition = String.Format ("CoreTracks.PrimarySourceID = {0}", dbid);
-            error_source.Updated += OnErrorSourceUpdated;
-            OnErrorSourceUpdated (null, null);
 
             primary_sources[dbid] = this;
         }

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  3 07:57:40 2008
@@ -212,6 +212,11 @@
         
         protected virtual void SetStatus (string message, bool error)
         {
+            SetStatus (message, !error, !error, error ? "dialog-error" : null);
+        }
+
+        protected virtual void SetStatus (string message, bool can_close, bool is_spinning, string icon_name)
+        {
             if (status_message == null) {
                 status_message = new SourceMessage (this);
                 PushMessage (status_message);
@@ -221,9 +226,9 @@
             
             status_message.FreezeNotify ();
             status_message.Text = String.Format (GLib.Markup.EscapeText (message), status_name);
-            status_message.CanClose = !error;
-            status_message.IsSpinning = !error;
-            status_message.SetIconName (error ? "dialog-error" : null);
+            status_message.CanClose = can_close;
+            status_message.IsSpinning = is_spinning;
+            status_message.SetIconName (icon_name);
             status_message.ClearActions ();
             
             status_message.ThawNotify ();
@@ -412,12 +417,12 @@
             get { return false; }
         }
 
-        public string Name {
+        public virtual string Name {
             get { return properties.GetString ("Name"); }
             set { properties.SetString ("Name", value); }
         }
 
-        public string GenericName {
+        public virtual string GenericName {
             get { return properties.GetString ("GenericName"); }
             set { properties.SetString ("GenericName", value); }
         }

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  3 07:57:40 2008
@@ -14,6 +14,7 @@
 	Banshee.Collection.Database/ArtistListDatabaseModel.cs \
 	Banshee.Collection.Database/DatabaseAlbumInfo.cs \
 	Banshee.Collection.Database/DatabaseArtistInfo.cs \
+	Banshee.Collection.Database/DatabaseImportManager.cs \
 	Banshee.Collection.Database/DatabaseTrackInfo.cs \
 	Banshee.Collection.Database/TrackListDatabaseModel.cs \
 	Banshee.Collection/AlbumListModel.cs \

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ArtistListView.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ArtistListView.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Collection.Gui/ArtistListView.cs	Thu Apr  3 07:57:40 2008
@@ -53,6 +53,15 @@
             };
         }
 
+        // TODO add context menu for artists/albums...probably need a Banshee.Gui/ArtistActions.cs file.  Should
+        // make TrackActions.cs more generic with regards to the TrackSelection stuff, using the new properties
+        // set on the sources themselves that give us access to the IListView<T>.
+        /*protected override bool OnPopupMenu ()
+        {
+            ServiceManager.Get<InterfaceActionService> ().TrackActions["TrackContextMenuAction"].Activate ();
+            return true;
+        }*/
+
         protected override bool OnFocusInEvent(Gdk.EventFocus evnt)
         {
             ServiceManager.Get<InterfaceActionService> ().TrackActions.SuppressSelectActions ();

Added: trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.addin.xml
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.addin.xml	Thu Apr  3 07:57:40 2008
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Addin 
+    id="Banshee.Dap.MassStorage"
+    version="1.0"
+    compatVersion="1.0"
+    copyright="Â 2008 Novell Inc. Licensed under the MIT X11 license."
+    name="Mass Storage Digital Audio Player Support"
+    category="Hardware"
+    description="Provides support for Digital Audio Players that use USB Mass Storage."
+    author="Gabriel Burt"
+    url="http://banshee-project.org/";
+    defaultEnabled="true">
+
+  <Dependencies>
+    <Addin id="Banshee.Services" version="1.0"/>
+  </Dependencies>
+
+  <Extension path="/Banshee/ServiceManager/Service">
+    <Service class="Banshee.Dap.MassStorage.DapService"/>
+  </Extension>
+
+</Addin>

Added: trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.mdp
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.mdp	Thu Apr  3 07:57:40 2008
@@ -0,0 +1,33 @@
+<Project name="Banshee.Dap.MassStorage" fileversion="2.0" language="C#" clr-version="Net_2_0" ctype="DotNetProject">
+  <Configurations active="Debug">
+    <Configuration name="Debug" ctype="DotNetProjectConfiguration">
+      <Output directory="../../../bin" assemblyKeyFile="." assembly="Banshee.AudioCd" />
+      <Build debugmode="True" target="Library" />
+      <Execution runwithwarnings="True" consolepause="True" runtime="MsNet" clr-version="Net_2_0" />
+      <CodeGeneration compiler="Mcs" warninglevel="4" optimize="True" unsafecodeallowed="False" generateoverflowchecks="True" generatexmldocumentation="False" ctype="CSharpCompilerParameters" />
+    </Configuration>
+  </Configurations>
+  <Contents>
+    <File name="Banshee.Dap.MassStorage/MassStorageSource.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.Dap.MassStorage/DapSource.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.Dap.MassStorage/RemovableSource.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.Dap.MassStorage/DapService.cs" subtype="Code" buildaction="Compile" />
+    <File name="Banshee.Dap.MassStorage.addin.xml" subtype="Code" buildaction="EmbedAsResource" />
+  </Contents>
+  <References>
+    <ProjectReference type="Project" localcopy="True" refto="Banshee.Core" />
+    <ProjectReference type="Project" localcopy="True" refto="Banshee.Services" />
+    <ProjectReference type="Project" localcopy="True" refto="Hyena" />
+    <ProjectReference type="Gac" localcopy="True" refto="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+    <ProjectReference type="Project" localcopy="True" refto="MusicBrainz" />
+  </References>
+  <MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="True" RelativeMakefileName="./Makefile.am">
+    <BuildFilesVar Sync="True" Name="SOURCES" />
+    <DeployFilesVar />
+    <ResourcesVar Sync="True" Name="RESOURCES" />
+    <OthersVar />
+    <GacRefVar />
+    <AsmRefVar />
+    <ProjectRefVar />
+  </MonoDevelop.Autotools.MakefileInfo>
+</Project>

Added: trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/DapService.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/DapService.cs	Thu Apr  3 07:57:40 2008
@@ -0,0 +1,136 @@
+//
+// DapService.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.Generic;
+using System.Threading;
+using Mono.Unix;
+
+using Hyena;
+using Banshee.Base;
+using Banshee.ServiceStack;
+using Banshee.Sources;
+using Banshee.Collection;
+using Banshee.Collection.Database;
+using Banshee.Hardware;
+
+namespace Banshee.Dap.MassStorage
+{
+    public class DapService : IExtensionService, IDisposable
+    {
+        private Dictionary<string, DapSource> sources;
+        
+        public DapService ()
+        {
+        }
+        
+        public void Initialize ()
+        {
+            lock (this) {
+                sources = new Dictionary<string, DapSource> ();
+                
+                foreach (IDiskDevice device in ServiceManager.HardwareManager.GetAllDiskDevices ()) {
+                    MapDiskDevice (device);
+                }
+                
+                ServiceManager.HardwareManager.DeviceAdded += OnHardwareDeviceAdded;
+                ServiceManager.HardwareManager.DeviceRemoved += OnHardwareDeviceRemoved;
+            }
+        }
+        
+        public void Dispose ()
+        {
+            lock (this) {
+                ServiceManager.HardwareManager.DeviceAdded -= OnHardwareDeviceAdded;
+                ServiceManager.HardwareManager.DeviceRemoved -= OnHardwareDeviceRemoved;
+                
+                foreach (DapSource source in sources.Values) {
+                    ServiceManager.SourceManager.RemoveSource (source);
+                }
+                
+                sources.Clear ();
+                sources = null;
+            }
+        }
+        
+        private void MapDiskDevice (IDiskDevice device)
+        {
+            lock (this) {
+                foreach (IVolume volume in device) {
+                    MapDiskVolume (volume);
+                }
+            }
+        }
+        
+        private void MapDiskVolume (IVolume volume)
+        {
+            lock (this) {
+                if (!volume.ShouldIgnore && volume.Parent.IsRemovable && !sources.ContainsKey (volume.Uuid)) {
+                    Log.DebugFormat ("Mapping disk device ({0}, mount point: {1})", volume.Uuid, volume.MountPoint);
+                    MassStorageSource source = new MassStorageSource (volume);
+                    sources.Add (volume.Uuid, source);
+                    ServiceManager.SourceManager.AddSource (source);
+                }
+            }
+        }
+        
+        internal void UnmapDiskVolume (string uuid)
+        {
+            lock (this) {
+                if (sources.ContainsKey (uuid)) {
+                    Log.DebugFormat ("Unmapping DAP source ({0})", uuid);
+                    DapSource source = sources[uuid];
+                    ServiceManager.SourceManager.RemoveSource (source);
+                    sources.Remove (uuid);
+                }
+            }
+        }
+        
+        private void OnHardwareDeviceAdded (object o, DeviceAddedArgs args)
+        {
+            lock (this) {
+                if (args.Device is IVolume) {
+                    if ((args.Device as IVolume).Parent is IDiskDevice) {
+                        MapDiskVolume ((IVolume)args.Device);
+                    }
+                }
+            }
+        }
+        
+        private void OnHardwareDeviceRemoved (object o, DeviceRemovedArgs args)
+        {
+            lock (this) {
+                UnmapDiskVolume (args.DeviceUuid);
+            }
+        }
+        
+        string IService.ServiceName {
+            get { return "DapService"; }
+        }
+    }
+}

Added: trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/DapSource.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/DapSource.cs	Thu Apr  3 07:57:40 2008
@@ -0,0 +1,51 @@
+//
+// DapSource.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.Generic;
+using System.Threading;
+using Mono.Unix;
+
+using Hyena;
+using Banshee.Base;
+using Banshee.ServiceStack;
+using Banshee.Sources;
+using Banshee.Collection;
+using Banshee.Collection.Database;
+using Banshee.Hardware;
+
+namespace Banshee.Dap.MassStorage
+{
+    public abstract class DapSource : RemovableSource
+    {
+        public DapSource (string name, string generic_name, string uuid) : base (generic_name, name, uuid)
+        {
+            Properties.SetStringList ("Icon.Name", "multimedia-player");
+        }
+    }
+}

Added: trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs	Thu Apr  3 07:57:40 2008
@@ -0,0 +1,85 @@
+//
+// MassStorageSource.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.Generic;
+using System.Threading;
+using Mono.Unix;
+
+using Hyena;
+using Banshee.Base;
+using Banshee.ServiceStack;
+using Banshee.Sources;
+using Banshee.Collection;
+using Banshee.Collection.Database;
+using Banshee.Hardware;
+
+namespace Banshee.Dap.MassStorage
+{
+    public class MassStorageSource : DapSource
+    {
+        protected IVolume volume;
+        public IVolume Volume {
+            get { return volume; }
+        }
+
+        public MassStorageSource (IVolume volume) : base (Catalog.GetString ("Media"), volume.Name ?? "Media" , volume.Uuid)
+        {
+            this.volume = volume;
+
+            Properties.SetStringList ("Icon.Name", "harddrive");
+
+            // 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");
+
+            ThreadPool.QueueUserWorkItem (delegate {
+                DatabaseImportManager importer = new DatabaseImportManager (this);
+                importer.KeepUserJobHidden = true;
+                SetStatus (String.Format (Catalog.GetString ("Loading {0}"), Name), false);
+                importer.ImportFinished += delegate  { HideStatus (); };
+                importer.QueueSource (new string [] { volume.MountPoint });
+            });
+        }
+
+        protected override bool IsReadOnly {
+            get { return volume.IsReadOnly; }
+        }
+
+        protected override void Eject ()
+        {
+            if (volume.CanUnmount)
+                volume.Unmount ();
+
+            if (volume.CanEject)
+                volume.Eject ();
+        }
+    }
+}

Added: trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/RemovableSource.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/RemovableSource.cs	Thu Apr  3 07:57:40 2008
@@ -0,0 +1,131 @@
+//
+// RemovableSource.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.Generic;
+using System.Threading;
+using Mono.Unix;
+
+using Hyena;
+using Banshee.Base;
+using Banshee.ServiceStack;
+using Banshee.Sources;
+using Banshee.Collection;
+using Banshee.Collection.Database;
+using Banshee.Hardware;
+
+namespace Banshee.Dap.MassStorage
+{
+    public abstract class RemovableSource : PrimarySource, IUnmapableSource, IDisposable
+    {
+        public RemovableSource (string name, string generic_name, string uuid) : base (generic_name, name, uuid, 175)
+        {
+            Name = name;
+
+            Properties.SetString ("UnmapSourceActionIconName", "media-eject");
+            AfterInitialized ();
+        }
+
+        public override string GenericName {
+            get { return base.GenericName; }
+            set {
+                base.GenericName = value;
+                Properties.SetString ("DeleteTracksActionLabel", String.Format (Catalog.GetString ("Delete From {0}"), value));
+                Properties.SetString ("UnmapSourceActionLabel", String.Format (Catalog.GetString ("Eject {0}"), value));
+            }
+        }
+
+        public void Dispose ()
+        {
+            ServiceManager.SourceManager.RemoveSource (this);
+        }
+        
+        public override bool CanRemoveTracks {
+            get { return !IsReadOnly; }
+        }
+
+        public override bool CanDeleteTracks {
+            get { return !IsReadOnly; }
+        }
+
+        /*public double DiskUsageFraction {
+            get { return (double)device.StorageUsed / (double)device.StorageCapacity; }
+        }*/
+
+#region IUnmapableSource Implementation
+
+        public bool Unmap ()
+        {
+            DatabaseTrackInfo track = ServiceManager.PlayerEngine.CurrentTrack as DatabaseTrackInfo;
+            if (track != null && track.PrimarySourceId == this.DbId) {
+                ServiceManager.PlayerEngine.Close ();
+            }
+            
+            SetStatus (String.Format (Catalog.GetString ("Ejecting {0}..."), GenericName), false);
+        
+            ThreadPool.QueueUserWorkItem (delegate {
+                try {
+                    Eject ();
+
+                    ThreadAssist.ProxyToMain (delegate {
+                        Dispose ();
+                    });
+                } catch (Exception e) {
+                    ThreadAssist.ProxyToMain (delegate {
+                        SetStatus (String.Format (Catalog.GetString ("Could not eject {0}: {1}"), GenericName, e.Message), true);
+                    });
+                    
+                    Log.Exception (e);
+                }
+            });
+            
+            return true;
+        }
+
+        public bool CanUnmap {
+            get { return true; }
+        }
+
+        public bool ConfirmBeforeUnmap {
+            get { return false; }
+        }
+
+#endregion
+
+#region Members Subclasses Should Override
+
+        protected virtual void Eject ()
+        {
+        }
+
+        protected abstract bool IsReadOnly { get; }
+
+#endregion
+
+    }
+}

Added: trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Extensions/Banshee.Dap.MassStorage/Makefile.am	Thu Apr  3 07:57:40 2008
@@ -0,0 +1,15 @@
+ASSEMBLY = Banshee.Dap.MassStorage
+TARGET = library
+LINK = $(REF_EXTENSION_DAP_MASS_STORAGE)
+INSTALL_DIR = $(EXTENSIONS_INSTALL_DIR)
+
+SOURCES = \
+	Banshee.Dap.MassStorage/MassStorageSource.cs \
+	Banshee.Dap.MassStorage/DapService.cs \
+	Banshee.Dap.MassStorage/DapSource.cs \
+	Banshee.Dap.MassStorage/RemovableSource.cs
+
+RESOURCES = Banshee.Dap.MassStorage.addin.xml
+
+include $(top_srcdir)/build/build.mk
+

Modified: trunk/banshee/src/Extensions/Extensions.mds
==============================================================================
--- trunk/banshee/src/Extensions/Extensions.mds	(original)
+++ trunk/banshee/src/Extensions/Extensions.mds	Thu Apr  3 07:57:40 2008
@@ -9,6 +9,7 @@
       <Entry build="True" name="Banshee.PlayQueue" configuration="Debug" />
       <Entry build="True" name="Banshee.AudioCd" configuration="Debug" />
       <Entry build="True" name="Banshee.Daap" configuration="Debug" />
+      <Entry build="True" name="Banshee.Dap.MassStorage" configuration="Debug" />
     </Configuration>
   </Configurations>
   <StartMode single="True">
@@ -20,6 +21,7 @@
     <Execute type="None" entry="Banshee.NowPlaying" />
     <Execute type="None" entry="Banshee.Bookmarks" />
     <Execute type="None" entry="Banshee.AudioCd" />
+    <Execute type="None" entry="Banshee.Dap.MassStorage" />
   </StartMode>
   <Entries>
     <Entry filename="Banshee.Daap/Banshee.Daap.mdp" />
@@ -30,5 +32,6 @@
     <Entry filename="Banshee.NowPlaying/Banshee.NowPlaying.mdp" />
     <Entry filename="Banshee.Bookmarks/Banshee.Bookmarks.mdp" />
     <Entry filename="Banshee.AudioCd/Banshee.AudioCd.mdp" />
+    <Entry filename="Banshee.Dap.MassStorage/Banshee.Dap.MassStorage.mdp" />
   </Entries>
 </Combine>
\ No newline at end of file

Modified: trunk/banshee/src/Extensions/Makefile.am
==============================================================================
--- trunk/banshee/src/Extensions/Makefile.am	(original)
+++ trunk/banshee/src/Extensions/Makefile.am	Thu Apr  3 07:57:40 2008
@@ -3,6 +3,7 @@
 SUBDIRS = \
 	Banshee.AudioCd \
 	Banshee.Bookmarks \
+	Banshee.Dap.MassStorage \
 	Banshee.Lastfm \
 	Banshee.MultimediaKeys \
 	Banshee.NotificationArea \

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data/PropertyStore.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data/PropertyStore.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data/PropertyStore.cs	Thu Apr  3 07:57:40 2008
@@ -136,7 +136,7 @@
 
                 if(object_store.ContainsKey(name)) {
                     old_value = (T)object_store[name];
-                    if (value.Equals (old_value))
+                    if ((value == null && old_value == null) || value.Equals (old_value))
                         return;
                     object_store[name] = value;
                 } else {



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