banshee r3772 - in trunk/banshee: . src/Backends/Banshee.Hal/Banshee.HalBackend src/Backends/Banshee.Unix/Banshee.IO.Unix src/Clients/Nereid/Nereid src/Core/Banshee.Core/Banshee.Collection src/Core/Banshee.Core/Banshee.IO src/Core/Banshee.Core/Banshee.Streaming src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.Database src/Core/Banshee.Services/Banshee.Hardware src/Core/Banshee.Services/Banshee.Sources src/Core/Banshee.ThickClient/Banshee.Gui src/Core/Banshee.ThickClient/Banshee.Sources.Gui src/Dap/Banshee.Dap.Mtp src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp src/Dap/Banshee.Dap/Banshee.Dap src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView src/Libraries/Hyena/Hyena src/Libraries/Mtp/Mtp tests tests/Banshee.Core



Author: gburt
Date: Sat Apr 12 11:02:15 2008
New Revision: 3772
URL: http://svn.gnome.org/viewvc/banshee?rev=3772&view=rev

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

	This commit adds usable MTP device support.  Still no transcoding for any
	DAPs, but that's next.

	* src/Backends/Banshee.Hal/Banshee.HalBackend/Device.cs: If usb.serial
	property exists on the device, use it for the Uuid.  Used for matching Mtp
	devices to the libmtp device list.

	* src/Clients/Nereid/Nereid/PlayerInterface.cs:
	* src/Clients/Nereid/Nereid/ViewContainer.cs: Add a disk usage
	label/progres bar and display it when the source implements
	IDiskUsageReporter.  Also, show the source context menu when the source's
	title in the view container is right clicked.

	* src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs: Set the default
	MediaAttributes to Default.

	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs:
	Add GetTrackIdForUri method, used by Mtp support to associate existing
	tracks when mtp device entries.

	* src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs:
	Change CorePrimarySource entries for Library/VideoLibrary to use UniqueId.

	* src/Backends/Banshee.Hal/Banshee.HalBackend/HardwareManager.cs:
	* src/Core/Banshee.Services/Banshee.Hardware/HardwareManager.cs:
	* src/Core/Banshee.Services/Banshee.Hardware/IHardwareManager.cs: Add
	GetAllDevices call.

	* src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs: Use UniqueId
	to identify primary sources, not TypeUniqueId.  Add user notify calls when
	deleting items.  And every 10 items added or deleted, refresh.

	* src/Core/Banshee.Services/Banshee.Sources/Source.cs: Use String.Format
	instead of concat.

	* src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpSource.cs: Implement track
	loading, adding, and deleting.  Implement disk usage, and eject, and
	renaming.

	* src/Core/Banshee.Services/Makefile.am:
	* src/Core/Banshee.Services/Banshee.Sources/IDiskUsageReporter.cs: New
	interface for sources that want disk usage info displayed (eg DAPs).

	* src/Dap/Banshee.Dap.Mtp/Makefile.am:
	* src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpDapTrackInfo.cs:
	* src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpTrackInfo.cs: Fixes to
	property mapping, renamed, added to build.

	* src/Dap/Banshee.Dap/Banshee.Dap/DapService.cs: Listen for DapSources
	being removed by the SourceManager and remove them from the map. Also,
	when unmapping them, call Dispose on them.

	* src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs:  Override AddChildSourc
	with warning about how they aren't saved to the device (yet).  Add
	internal Device property.

	* src/Dap/Banshee.Dap/Banshee.Dap/RemovableSource.cs: Implement
	IDiskUsageReporter.

	* src/Libraries/Mtp/Mtp/Track.cs: Style fixes.

	* Makefile.am: 
	* tests/Makefile.am: Change make test instead of make run-test

	* tests/Banshee.Core/TaglibReadWriteTests.cs: Add unit tests to make sure
	Banshee.IO.System and Banshee.IO.Unix read and write tags properly.

	* src/Backends/Banshee.Unix/Banshee.IO.Unix/DemuxVfs.cs: Fix major bug
	where writing metadata to file wasn't working in trunk if you were using
	Banshee.IO.Unix (which most/all people are).


Added:
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/IDiskUsageReporter.cs
   trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpTrackInfo.cs   (contents, props changed)
      - copied, changed from r3767, /trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpDapTrackInfo.cs
Removed:
   trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpDapTrackInfo.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/Makefile.am
   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.Unix/Banshee.IO.Unix/DemuxVfs.cs
   trunk/banshee/src/Clients/Nereid/Nereid/PlayerInterface.cs
   trunk/banshee/src/Clients/Nereid/Nereid/ViewContainer.cs
   trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs
   trunk/banshee/src/Core/Banshee.Core/Banshee.IO/Provider.cs
   trunk/banshee/src/Core/Banshee.Core/Banshee.Streaming/SaveTrackMetadataJob.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/HardwareManager.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IHardwareManager.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.Gui/SourceActions.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView.cs
   trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpSource.cs
   trunk/banshee/src/Dap/Banshee.Dap.Mtp/Makefile.am
   trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapService.cs
   trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs
   trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/RemovableSource.cs
   trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs
   trunk/banshee/src/Libraries/Hyena/Hyena/StringUtil.cs
   trunk/banshee/src/Libraries/Mtp/Mtp/Track.cs
   trunk/banshee/tests/Banshee.Core/TaglibReadWriteTests.cs
   trunk/banshee/tests/Makefile.am

Modified: trunk/banshee/Makefile.am
==============================================================================
--- trunk/banshee/Makefile.am	(original)
+++ trunk/banshee/Makefile.am	Sat Apr 12 11:02:15 2008
@@ -66,7 +66,7 @@
 
 test:
 	@pushd tests; \
-	make run-test \
+	make test \
 	popd;
 
 clean-local:

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	Sat Apr 12 11:02:15 2008
@@ -33,8 +33,8 @@
 
 namespace Banshee.HalBackend
 {
-    public abstract class Device : IDevice
-    {    
+    public class Device : IDevice
+    {
         private Hal.Device device;
         internal Hal.Device HalDevice {
             get { return device; }
@@ -45,14 +45,14 @@
             get { return manager; }
         }
 
-        protected Device (Hal.Manager manager, Hal.Device device)
+        public Device (Hal.Manager manager, Hal.Device device)
         {
             this.manager = manager;
             this.device = device;
         }
         
         public virtual string Uuid {
-            get { return device.Udi; }
+            get { return String.IsNullOrEmpty (HalDevice["usb.serial"]) ? device.Udi : HalDevice["usb.serial"]; }
         }
 
         private string 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	Sat Apr 12 11:02:15 2008
@@ -53,6 +53,17 @@
         public void Dispose ()
         {
         }
+
+        public IEnumerable<IDevice> GetAllDevices ()
+        {
+            IDevice device;
+            foreach (string udi in manager.GetAllDevices ()) {
+                device = Resolve (new Hal.Device (udi));
+                if (device != null) {
+                    yield return device;
+                }
+            }
+        }
         
         private IEnumerable<T> GetAllBlockDevices<T> () where T : IBlockDevice
         {
@@ -81,15 +92,21 @@
 
         private void OnHalDeviceAdded (object o, Hal.DeviceAddedArgs args)
         {
-            if (!args.Device.QueryCapability ("block")) {
-                return;
-            }
+            OnHalDeviceAdded (Resolve (args.Device));
+        }
 
-            IDevice device = BlockDevice.Resolve<IBlockDevice> (manager, args.Device);
-            if (device == null) {
-                device = Volume.Resolve (null, manager, args.Device);
-            }
-            OnHalDeviceAdded (device);
+        private IDevice Resolve (Hal.Device hal_device)
+        {
+            if (!hal_device.QueryCapability ("block") && !hal_device.QueryCapability ("portable_audio_player"))
+                return null;
+
+            IDevice device = BlockDevice.Resolve<IBlockDevice> (manager, hal_device);
+            if (device == null)
+                device = Volume.Resolve (null, manager, hal_device);
+                if (device == null)
+                    device = new Device (manager, hal_device);
+
+            return device;
         }
 
         internal void OnHalDeviceAdded (IDevice device)

Modified: trunk/banshee/src/Backends/Banshee.Unix/Banshee.IO.Unix/DemuxVfs.cs
==============================================================================
--- trunk/banshee/src/Backends/Banshee.Unix/Banshee.IO.Unix/DemuxVfs.cs	(original)
+++ trunk/banshee/src/Backends/Banshee.Unix/Banshee.IO.Unix/DemuxVfs.cs	Sat Apr 12 11:02:15 2008
@@ -58,7 +58,7 @@
         }
         
         public Stream WriteStream {
-            get { return file_info.Open (FileMode.Create, FileAccess.ReadWrite); }
+            get { return file_info.Open (FileMode.Open, FileAccess.ReadWrite); }
         }
    
         public bool IsReadable {

Modified: trunk/banshee/src/Clients/Nereid/Nereid/PlayerInterface.cs
==============================================================================
--- trunk/banshee/src/Clients/Nereid/Nereid/PlayerInterface.cs	(original)
+++ trunk/banshee/src/Clients/Nereid/Nereid/PlayerInterface.cs	Sat Apr 12 11:02:15 2008
@@ -210,7 +210,7 @@
                 Source source = ServiceManager.SourceManager.ActiveSource;
                 if (source != null) {
                     source.CycleStatusFormat ();
-                    UpdateStatusBar ();
+                    UpdateSourceInformation ();
                 }
             };
             status_label = new Label ();
@@ -342,15 +342,17 @@
 
             view_container.Header.Visible = source.Properties.Contains ("Nereid.SourceContents.HeaderVisible") ?
                 source.Properties.Get<bool> ("Nereid.SourceContents.HeaderVisible") : true;
+
+            view_container.DiskUsageVisible = (source is IDiskUsageReporter);
             
-            UpdateStatusBar ();
+            UpdateSourceInformation ();
             view_container.SearchEntry.Ready = true;
         }
 
         private void OnSourceUpdated (SourceEventArgs args)
         {
             if (args.Source == ServiceManager.SourceManager.ActiveSource) {
-                UpdateStatusBar ();
+                UpdateSourceInformation ();
                 view_container.Title = args.Source.Name;
             }
         }
@@ -479,7 +481,7 @@
 
         private void HandleTrackModelReloaded (object sender, EventArgs args)
         {
-            UpdateStatusBar ();
+            UpdateSourceInformation ();
         }
 
         private void SetPlaybackControllerSource (Source source)
@@ -493,14 +495,31 @@
             ServiceManager.PlaybackController.Source = (ITrackModelSource)source;    
         }
 
-        private void UpdateStatusBar ()
+        private void UpdateSourceInformation ()
         {
-            if (ServiceManager.SourceManager.ActiveSource == null) {
+            Source source = ServiceManager.SourceManager.ActiveSource;
+            if (source == null) {
                 status_label.Text = String.Empty;
                 return;
             }
 
-            status_label.Text = ServiceManager.SourceManager.ActiveSource.GetStatusText ();
+            if (source is IDiskUsageReporter) {
+                IDiskUsageReporter reporter = source as IDiskUsageReporter;
+
+                double fraction = (double)reporter.BytesUsed / (double)reporter.BytesCapacity;
+
+                view_container.DiskUsageBar.Fraction = fraction;
+                view_container.DiskUsageBar.Text = String.Format(
+                    Catalog.GetString("{0} of {1}"),
+                    new Hyena.Query.FileSizeQueryValue (reporter.BytesUsed).ToUserQuery (),
+                    new Hyena.Query.FileSizeQueryValue (reporter.BytesCapacity).ToUserQuery ()
+                );
+
+                //string tooltip = dapSource.DiskUsageString + " (" + dapSource.DiskAvailableString + ")";
+                //toolTips.SetTip (dapDiskUsageBar, tooltip, tooltip);
+            }
+
+            status_label.Text = source.GetStatusText ();
         }
 
 #endregion

Modified: trunk/banshee/src/Clients/Nereid/Nereid/ViewContainer.cs
==============================================================================
--- trunk/banshee/src/Clients/Nereid/Nereid/ViewContainer.cs	(original)
+++ trunk/banshee/src/Clients/Nereid/Nereid/ViewContainer.cs	Sat Apr 12 11:02:15 2008
@@ -47,6 +47,8 @@
         private HBox header;
         private Label title_label;
         private Label search_label;
+        private Label disk_usage_label;
+        private ProgressBar disk_usage_bar;
         
         private ISourceContents content;
         
@@ -62,16 +64,35 @@
         {
             header = new HBox ();
             
+            EventBox title_box = new EventBox ();
             title_label = new Label ();
             title_label.Xalign = 0.0f;
             title_label.Ellipsize = Pango.EllipsizeMode.End;
+
+            title_box.Add (title_label);
+
+            // Show the source context menu when the title is right clicked
+            title_box.PopupMenu += delegate {
+                ServiceManager.Get<InterfaceActionService> ().SourceActions ["SourceContextMenuAction"].Activate ();
+            };
+
+            title_box.ButtonPressEvent += delegate (object o, ButtonPressEventArgs press) {
+                if (press.Event.Button == 3) {
+                    ServiceManager.Get<InterfaceActionService> ().SourceActions ["SourceContextMenuAction"].Activate ();
+                }
+            };
+
+            disk_usage_label = new Label (Catalog.GetString ("Disk Usage:"));
+            disk_usage_bar = new ProgressBar ();
             
             BuildSearchEntry ();
             
             search_label = new Label (Catalog.GetString ("_Search:"));
             search_label.MnemonicWidget = search_entry.InnerEntry;
             
-            header.PackStart (title_label, true, true, 0);
+            header.PackStart (title_box, true, true, 0);
+            header.PackStart (disk_usage_label, false, false, 5);
+            header.PackStart (disk_usage_bar, false, false, 5);
             header.PackStart (search_label, false, false, 5);
             header.PackStart (search_entry, false, false, 0);
             
@@ -129,6 +150,10 @@
         public SearchEntry SearchEntry {
             get { return search_entry; }
         }
+
+        public ProgressBar DiskUsageBar {
+            get { return disk_usage_bar; }
+        }
         
         public ISourceContents Content {
             get { return content; }
@@ -163,5 +188,13 @@
                 search_label.Visible = value;
             }
         }
+
+        public bool DiskUsageVisible {
+            get { return disk_usage_bar.Visible; }
+            set {
+                disk_usage_label.Visible = value;
+                disk_usage_bar.Visible = value;
+            }
+        }
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Collection/TrackInfo.cs	Sat Apr 12 11:02:15 2008
@@ -306,7 +306,7 @@
             set { can_play = value; }
         }
         
-        private TrackMediaAttributes media_attributes;
+        private TrackMediaAttributes media_attributes = TrackMediaAttributes.Default;
         public virtual TrackMediaAttributes MediaAttributes {
             get { return media_attributes; }
             set { media_attributes = value; }

Modified: trunk/banshee/src/Core/Banshee.Core/Banshee.IO/Provider.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Banshee.IO/Provider.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.IO/Provider.cs	Sat Apr 12 11:02:15 2008
@@ -36,7 +36,7 @@
 
 namespace Banshee.IO
 {
-    internal static class Provider
+    public static class Provider
     {
         private static IProvider provider;
         private static IDirectory directory;
@@ -68,21 +68,26 @@
                 file = (IFile)Activator.CreateInstance (provider.FileProvider);
             }
         }
+
+        public static void SetProvider (IProvider customProvider)
+        {
+            provider = customProvider;
+        }
         
-        public static IDirectory Directory {
+        internal static IDirectory Directory {
             get { return directory; }
         }
         
-        public static IFile File {
+        internal static IFile File {
             get { return file; }
         }
         
-        public static IDemuxVfs CreateDemuxVfs (string file)
+        internal static IDemuxVfs CreateDemuxVfs (string file)
         {
             return (IDemuxVfs)Activator.CreateInstance (provider.DemuxVfsProvider, new object [] { file });
         }
         
-        public static readonly SchemaEntry<string> ProviderSchema = new SchemaEntry<string> (
+        internal static readonly SchemaEntry<string> ProviderSchema = new SchemaEntry<string> (
             "core", "io_provider",
             "Banshee.IO.Unix.Provider",
             "Set the IO provider backend in Banshee",

Modified: trunk/banshee/src/Core/Banshee.Core/Banshee.Streaming/SaveTrackMetadataJob.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Core/Banshee.Streaming/SaveTrackMetadataJob.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Core/Banshee.Streaming/SaveTrackMetadataJob.cs	Sat Apr 12 11:02:15 2008
@@ -39,24 +39,27 @@
         private TrackInfo track;
         
         public string Name {
-            get { return String.Format(Catalog.GetString("Saving tags for {0}"), track.TrackTitle); }
+            get { return String.Format (Catalog.GetString ("Saving tags for {0}"), track.TrackTitle); }
         }
         
-        public SaveTrackMetadataJob(TrackInfo track)
+        public SaveTrackMetadataJob (TrackInfo track)
         {
             this.track = track;
         }
     
-        public void Run()
+        public void Run ()
         {
-            if(!LibrarySchema.WriteMetadata.Get()) {
-                Console.WriteLine("Skipping scheduled metadata write, preference disabled after scheduling");
+            Console.WriteLine ("in metadata write");
+            if (!LibrarySchema.WriteMetadata.Get ()) {
+                Console.WriteLine ("Skipping scheduled metadata write, preference disabled after scheduling");
                 return;
             }
+            Console.WriteLine ("doing metadata write, artist = {0}", track.ArtistName);
         
             // Note: this should be kept in sync with the metadata read in StreamTagger.cs
-            TagLib.File file = StreamTagger.ProcessUri(track.Uri);
+            TagLib.File file = StreamTagger.ProcessUri (track.Uri);
             file.Tag.Performers = new string [] { track.ArtistName };
+            Console.WriteLine ("Performers is set to {0}", file.Tag.Performers[0]);
             file.Tag.Album = track.AlbumTitle;
             file.Tag.Genres = new string [] { track.Genre };
             file.Tag.Title = track.TrackTitle;

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	Sat Apr 12 11:02:15 2008
@@ -440,9 +440,19 @@
         }
 
         private static HyenaSqliteCommand check_command = new HyenaSqliteCommand (
-            "SELECT COUNT(*) FROM CoreTracks WHERE PrimarySourceId IN (?) AND (Uri = ? OR Uri = ?)"
+            "SELECT TrackID FROM CoreTracks WHERE PrimarySourceId IN (?) AND (Uri = ? OR Uri = ?) LIMIT 1"
         );
+
+        public static int GetTrackIdForUri (string relative_path, int [] primary_sources)
+        {
+            return ServiceManager.DbConnection.Query<int> (check_command.ApplyValues (primary_sources, relative_path, relative_path));
+        }
         
+        public static bool ContainsUri (string relative_path, int [] primary_sources)
+        {
+            return ServiceManager.DbConnection.Query<int> (check_command.ApplyValues (primary_sources, relative_path, relative_path)) > 0;
+        }
+
         public static bool ContainsUri (SafeUri uri, string relative_path, int [] primary_sources)
         {
             return ServiceManager.DbConnection.Query<int> (check_command.ApplyValues (primary_sources, relative_path, uri.AbsoluteUri)) > 0;

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs	Sat Apr 12 11:02:15 2008
@@ -61,7 +61,7 @@
         // NOTE: Whenever there is a change in ANY of the database schema,
         //       this version MUST be incremented and a migration method
         //       MUST be supplied to match the new version number
-        protected const int CURRENT_VERSION = 6;
+        protected const int CURRENT_VERSION = 7;
         protected const int CURRENT_METADATA_VERSION = 1;
         
         protected class DatabaseVersionAttribute : Attribute 
@@ -310,6 +310,16 @@
             return true;
         }
 
+        [DatabaseVersion (7)]
+        private bool Migrate_7 ()
+        {
+            Execute ("UPDATE CorePrimarySources SET StringID = 'MusicLibrarySource-Library' WHERE StringID = 'Library'");
+            Execute ("UPDATE CorePrimarySources SET StringID = 'VideoLibrarySource-VideoLibrary' WHERE StringID = 'VideoLibrary'");
+            Execute ("UPDATE CorePrimarySources SET StringID = 'PodcastSource-podcasting' WHERE StringID = 'podcasting'");
+            Execute ("DELETE FROM CoreCache; DELETE FROM CoreCacheModels");
+            return true;
+        }
+
 #pragma warning restore 0169
         
         private void InitializeFreshDatabase()

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/HardwareManager.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/HardwareManager.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/HardwareManager.cs	Sat Apr 12 11:02:15 2008
@@ -75,6 +75,11 @@
         {
             manager.Dispose ();
         }
+
+        public IEnumerable<IDevice> GetAllDevices ()
+        {
+            return manager.GetAllDevices ();
+        }
         
         public IEnumerable<IBlockDevice> GetAllBlockDevices ()
         {

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IHardwareManager.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IHardwareManager.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IHardwareManager.cs	Sat Apr 12 11:02:15 2008
@@ -36,6 +36,7 @@
         event DeviceAddedHandler DeviceAdded;
         event DeviceRemovedHandler DeviceRemoved;
     
+        IEnumerable<IDevice> GetAllDevices ();
         IEnumerable<IBlockDevice> GetAllBlockDevices ();
         IEnumerable<ICdromDevice> GetAllCdromDevices ();
         IEnumerable<IDiskDevice> GetAllDiskDevices ();

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/IDiskUsageReporter.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/IDiskUsageReporter.cs	Sat Apr 12 11:02:15 2008
@@ -0,0 +1,36 @@
+//
+// IDiskUsageReporter.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.
+//
+
+namespace Banshee.Sources
+{
+    public interface IDiskUsageReporter
+    {
+        long BytesUsed { get; }
+        long BytesCapacity { get; }
+    }
+}

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	Sat Apr 12 11:02:15 2008
@@ -170,9 +170,9 @@
 
         private void PrimarySourceInitialize ()
         {
-            dbid = ServiceManager.DbConnection.Query<int> ("SELECT PrimarySourceID FROM CorePrimarySources WHERE StringID = ?", TypeUniqueId);
+            dbid = ServiceManager.DbConnection.Query<int> ("SELECT PrimarySourceID FROM CorePrimarySources WHERE StringID = ?", UniqueId);
             if (dbid == 0) {
-                dbid = ServiceManager.DbConnection.Execute ("INSERT INTO CorePrimarySources (StringID) VALUES (?)", TypeUniqueId);
+                dbid = ServiceManager.DbConnection.Execute ("INSERT INTO CorePrimarySources (StringID) VALUES (?)", UniqueId);
             }
 
             track_model.Condition = String.Format ("CoreTracks.PrimarySourceID = {0}", dbid);
@@ -302,11 +302,16 @@
                 DeleteTrackList (list);
 
                 OnTracksDeleted ();
+                OnUserNotifyUpdated ();
+                ThreadAssist.ProxyToMain (delegate {
+                    OnUpdated ();
+                });
             });
         }
 
         protected virtual void DeleteTrackList (CachedList<DatabaseTrackInfo> list)
         {
+            is_deleting = true;
             DeleteTrackJob.Total += (int) list.Count;
 
             // Remove from file system
@@ -322,9 +327,15 @@
                     Log.Exception (e);
                     ErrorSource.AddMessage (e.Message, track.Uri.ToString ());
                 }
+
                 DeleteTrackJob.Completed++;
+                if (DeleteTrackJob.Completed % 10 == 0 && !DeleteTrackJob.IsFinished) {
+                    OnTracksDeleted ();
+                }
             }
 
+            is_deleting = false;
+
             if (DeleteTrackJob.Total == DeleteTrackJob.Completed) {
                 delete_track_job.Finish ();
                 delete_track_job = null;
@@ -359,8 +370,19 @@
             return true;
         }
 
+        private bool is_adding;
+        public bool IsAdding {
+            get { return is_adding; }
+        }
+
+        private bool is_deleting;
+        public bool IsDeleting {
+            get { return is_deleting; }
+        }
+
         protected virtual void AddTrackList (CachedList<DatabaseTrackInfo> list)
         {
+            is_adding = true;
             AddTrackJob.Total += (int)list.Count;
 
             foreach (DatabaseTrackInfo track in list) {
@@ -375,8 +397,13 @@
                     Log.Exception (e);
                     ErrorSource.AddMessage (e.Message, track.Uri.ToString ());
                 }
+
                 AddTrackJob.Completed++;
+                if (AddTrackJob.Completed % 10 == 0 && !AddTrackJob.IsFinished) {
+                    OnTracksAdded ();
+                }
             }
+            is_adding = false;
 
             if (AddTrackJob.Total == AddTrackJob.Completed) {
                 add_track_job.Finish ();

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	Sat Apr 12 11:02:15 2008
@@ -35,6 +35,7 @@
 
 using Mono.Unix;
 
+using Hyena;
 using Hyena.Data;
 using Hyena.Query;
 
@@ -543,15 +544,15 @@
                     if (span.Days > 0) {
                         double days = span.Days + (span.Hours / 24.0);
                         builder.AppendFormat (Catalog.GetPluralString ("{0} day", "{0} days", 
-                            DoubleToPluralInt (days)), FormatDouble (days));
+                            StringUtil.DoubleToPluralInt (days)), StringUtil.FormatDouble (days));
                     } else if (span.Hours > 0) {
                         double hours = span.Hours + (span.Minutes / 60.0);
                         builder.AppendFormat (Catalog.GetPluralString ("{0} hour", "{0} hours", 
-                            DoubleToPluralInt (hours)), FormatDouble (hours));
+                            StringUtil.DoubleToPluralInt (hours)), StringUtil.FormatDouble (hours));
                     } else {
                         double minutes = span.Minutes + (span.Seconds / 60.0);
                         builder.AppendFormat (Catalog.GetPluralString ("{0} minute", "{0} minutes", 
-                            DoubleToPluralInt (minutes)), FormatDouble (minutes));
+                            StringUtil.DoubleToPluralInt (minutes)), StringUtil.FormatDouble (minutes));
                     }
                 } else if (format == 1) {
                     if (span.Days > 0) {
@@ -588,25 +589,9 @@
             
             return builder.ToString ();
         }
-
-        private static string FormatDouble (double num)
-        {
-            if (num == (int)num)
-                return Convert.ToString ((int)num);
-            else
-                return String.Format ("{0:0.0}", num);
-        }
-        
-        private static int DoubleToPluralInt (double num)
-        {
-            if (num == (int)num)
-                return (int)num;
-            else
-                return (int)num + 1;
-        }
         
         string IService.ServiceName {
-            get { return DBusServiceManager.MakeDBusSafeString (Name) + "Source"; }
+            get { return String.Format ("{0}{1}", DBusServiceManager.MakeDBusSafeString (Name), "Source"); }
         }
         
         IDBusExportable IDBusExportable.Parent {

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	Sat Apr 12 11:02:15 2008
@@ -125,6 +125,7 @@
 	Banshee.SmartPlaylist/SmartPlaylistSource.cs \
 	Banshee.Sources/DatabaseSource.cs \
 	Banshee.Sources/ErrorSource.cs \
+	Banshee.Sources/IDiskUsageReporter.cs \
 	Banshee.Sources/IDurationAggregator.cs \
 	Banshee.Sources/IFileSizeAggregator.cs \
 	Banshee.Sources/IImportable.cs \

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/SourceActions.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/SourceActions.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/SourceActions.cs	Sat Apr 12 11:02:15 2008
@@ -238,7 +238,7 @@
                 UpdateActions ();
             };
         }
-            
+
         private void OnImportSource (object o, EventArgs args)
         {
             (ActionSource as IImportSource).Import ();

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Sources.Gui/SourceView.cs	Sat Apr 12 11:02:15 2008
@@ -410,14 +410,10 @@
             source.ChildSourceRemoved += OnSourceChildSourceRemoved;
             source.UserNotifyUpdated += OnSourceUserNotifyUpdated;
            
-            if (source.Expanded || (source.AutoExpand != null && source.AutoExpand.Value)) {
+            if (source.Expanded || source.AutoExpand == true) {
                 Expand (iter);
-            }
-            
-            if (source.Parent != null) {
-                if (source.Parent.AutoExpand == true) {
-                    Expand (FindSource (source.Parent));
-                }
+            } else if (source.Parent != null && source.Parent.AutoExpand == true) {
+                Expand (FindSource (source.Parent));
             }
             
             UpdateView ();

Modified: trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpSource.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpSource.cs	Sat Apr 12 11:02:15 2008
@@ -52,6 +52,7 @@
 
 		private MtpDevice mtp_device;
         //private bool supports_jpegs = false;
+        private Dictionary<int, Track> track_map;
 
         public MtpSource () : base ()
         {
@@ -59,9 +60,7 @@
 
         protected override bool Initialize (IDevice device)
         {
-            Log.DebugFormat ("MTP testing device {0}", device.Uuid);
             if (MediaCapabilities == null || !MediaCapabilities.IsType ("mtp")) {
-                Log.DebugFormat ("FAILED");
                 return false;
             }
 
@@ -75,8 +74,6 @@
 				return false;
             }
 
-            string serial = "";//hal_device ["usb.serial"];
-
 			List<MtpDevice> devices = null;
 			try {
 				devices = MtpDevice.Detect ();
@@ -89,6 +86,7 @@
 				return false;
 			} catch (Exception e) {
                 Log.Exception (e);
+                Log.Debug (e.ToString ());
 				//ShowGeneralExceptionDialog (e);
 				return false;
 			}
@@ -100,8 +98,8 @@
                 );
             } else {
                 string mtp_serial = devices[0].SerialNumber;
-                if (!String.IsNullOrEmpty (mtp_serial) && !String.IsNullOrEmpty (serial)) {
-                    if (mtp_serial.Contains (serial)) {
+                if (!String.IsNullOrEmpty (mtp_serial)) {
+                    if (mtp_serial.Contains (device.Uuid)) {
                         mtp_device = devices[0];
                         mtp_source = this;
                     }
@@ -120,66 +118,153 @@
                 return false;
             }
 
-			/*Log.Debug ("Loading MTP Device",
-                String.Format ("Name: {0}, ProductID: {1}, VendorID: {2}, Serial: {3}",
-                    hal_name, product_id, vendor_id, serial
-                )
-            );*/
-
+            Name = mtp_device.Name;
             Initialize ();
 
-            // TODO differentiate between Audio Players and normal Disks, and include the size, eg "2GB Audio Player"?
-            //GenericName = Catalog.GetString ("Audio Player");
+            //ServiceManager.DbConnection.Execute ("
 
-            // TODO construct device-specific icon name as preferred icon
-            //Properties.SetStringList ("Icon.Name", "media-player");
-
-            //SetStatus (String.Format (Catalog.GetString ("Loading {0}"), Name), false);
-            /*DatabaseImportManager importer = new DatabaseImportManager (this);
-            importer.KeepUserJobHidden = true;
-            importer.ImportFinished += delegate  { HideStatus (); };
-            importer.QueueSource (BaseDirectory);*/
+            ThreadPool.QueueUserWorkItem (delegate {
+                track_map = new Dictionary<int, Track> ();
+                SetStatus (String.Format (Catalog.GetString ("Loading {0}"), Name), false);
+                try {
+                    List<Track> files = mtp_device.GetAllTracks (delegate (ulong current, ulong total, IntPtr data) {
+                        //user_event.Progress = (double)current / total;
+                        SetStatus (String.Format (Catalog.GetString ("Loading {0} - {1} of {2}"), Name, current, total), false);
+                        return 0;
+                    });
+                    
+                    /*if (user_event.IsCancelRequested) {
+                        return;
+                    }*/
+                    
+                    int [] source_ids = new int [] { DbId };
+                    foreach (Track mtp_track in files) {
+                        int track_id;
+                        if ((track_id = DatabaseTrackInfo.GetTrackIdForUri (MtpTrackInfo.GetPathFromMtpTrack (mtp_track), source_ids)) > 0) {
+                            track_map[track_id] = mtp_track;
+                        } else {
+                            MtpTrackInfo track = new MtpTrackInfo (mtp_track);
+                            track.PrimarySource = this;
+                            track.Save (false);
+                            track_map[track.TrackId] = mtp_track;
+                        }
+                    }
+                } catch (Exception e) {
+                    Log.Exception (e);
+                }
+                OnTracksAdded ();
+                HideStatus ();
+            });
 
             return true;
         }
 
         public override void Import ()
         {
+            Log.Information ("Import to Library is not implemented for MTP devices yet", true);
             //new LibraryImportManager (true).QueueSource (BaseDirectory);
         }
 
+        public override bool CanRename {
+            get { return !(IsAdding || IsDeleting); }
+        }
+
+        protected override void OnTracksDeleted ()
+        {
+            // Hack to get the disk usage indicate to be accurate, which seems to
+            // only be updated when tracks are added, not removed.
+            SafeUri empty_file = new SafeUri (Paths.Combine (Paths.ApplicationCache, "mtp.mp3"));
+            try {
+                using (System.IO.TextWriter writer = new System.IO.StreamWriter (Banshee.IO.File.OpenWrite (empty_file, true))) {
+                    writer.Write ("foo");
+                }
+                Track mtp_track = new Track (System.IO.Path.GetFileName (empty_file.LocalPath), 3);
+                mtp_device.UploadTrack (empty_file.AbsolutePath, mtp_track);
+                mtp_device.Remove (mtp_track);
+            } finally {
+                Banshee.IO.File.Delete (empty_file);
+            }
+
+            base.OnTracksDeleted ();
+        }
+
+        public override void Rename (string newName)
+        {
+            base.Rename (newName);
+            mtp_device.Name = newName;
+
+            Console.WriteLine ("BytesUsed = {0}", BytesUsed);
+        }
+
         public override long BytesUsed {
-            //get { return BytesCapacity - volume.Available; }
-            get { return 0; }
+            get {
+				long count = 0;
+				foreach (DeviceStorage s in mtp_device.GetStorage ()) {
+					count += (long) s.MaxCapacity - (long) s.FreeSpaceInBytes;
+                }
+				return count;
+            }
         }
         
         public override long BytesCapacity {
-            //get { return (long) volume.Capacity; }
-            get { return 0; }
+            get {
+				long count = 0;
+				foreach (DeviceStorage s in mtp_device.GetStorage ()) {
+					count += (long) s.MaxCapacity;
+                }
+				return count;
+            }
         }
 
         protected override bool IsReadOnly {
-            //get { return volume.IsReadOnly; }
             get { return false; }
         }
 
+        protected override void AddTrack (DatabaseTrackInfo track)
+        {
+            if (track.PrimarySourceId == DbId)
+                return;
+
+            Track mtp_track = TrackInfoToMtpTrack (track);
+            mtp_device.UploadTrack (track.Uri.AbsolutePath, mtp_track);
+
+            MtpTrackInfo new_track = new MtpTrackInfo (mtp_track);
+            new_track.PrimarySource = this;
+            new_track.Save (false);
+            track_map[new_track.TrackId] = mtp_track;
+        }
+
         protected override void DeleteTrack (DatabaseTrackInfo track)
         {
-            /*try {
-                Banshee.IO.Utilities.DeleteFileTrimmingParentDirectories (track.Uri);
-            } catch (System.IO.FileNotFoundException) {
-            } catch (System.IO.DirectoryNotFoundException) {
-            }*/
+            mtp_device.Remove (track_map [track.TrackId]);
+            track_map.Remove (track.TrackId);
         }
 
-        protected override void Eject ()
+        public Track TrackInfoToMtpTrack (TrackInfo track)
+        {
+			Track f = new Track (System.IO.Path.GetFileName (track.Uri.LocalPath), (ulong) track.FileSize);
+			f.Album = track.AlbumTitle;
+			f.Artist = track.ArtistName;
+			f.Duration = (uint)track.Duration.TotalMilliseconds;
+			f.Genre = track.Genre;
+			f.Rating = (ushort)(track.Rating * 20);
+			f.Title = track.TrackTitle;
+			f.TrackNumber = (ushort)track.TrackNumber;
+			f.UseCount = (uint)track.PlayCount;
+            f.ReleaseDate = track.Year + "0101T0000.0";
+            return f;
+		}
+
+        public override void Dispose ()
         {
-            /*if (volume.CanUnmount)
-                volume.Unmount ();
+			base.Dispose ();
+			mtp_device.Dispose ();
+            mtp_source = null;
+        }
 
-            if (volume.CanEject)
-                volume.Eject ();
-                */
+        protected override void Eject ()
+        {
+            Dispose ();
         }
     }
 }

Copied: trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpTrackInfo.cs (from r3767, /trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpDapTrackInfo.cs)
==============================================================================
--- /trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpDapTrackInfo.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpTrackInfo.cs	Sat Apr 12 11:02:15 2008
@@ -1,5 +1,5 @@
 /***************************************************************************
- *  MtpDapTrackInfo.cs
+ *  MtpTrackInfo.cs
  *
  *  Copyright (C) 2006-2007 Novell and Patrick van Staveren
  *  Written by Patrick van Staveren (trick vanstaveren us)
@@ -30,48 +30,52 @@
 using System.IO;
 
 using Banshee.Base;
-using Banshee.Dap;
+using Banshee.Collection.Database;
 
 using Mtp;
 
 namespace Banshee.Dap.Mtp
 {
-    public sealed class MtpDapTrackInfo : DapTrackInfo
+    public class MtpTrackInfo : DatabaseTrackInfo
     {
-        private MtpDevice camera;
         private Track file;
         
-        public Track OriginalFile
-        {
+        public Track OriginalFile {
             get { return file; }
         }
+
+        public static string GetPathFromMtpTrack (Track track)
+        {
+            return String.Format ("mtp://{0}/{1}", track.FileId, track.FileName);
+        }
         
-        public MtpDapTrackInfo(MtpDevice camera, Track file) : base()
+        public MtpTrackInfo (Track file) : base()
 		{
-            this.camera = camera;
             this.file = file;
 			
-			Album = file.Album;
-            Artist = file.Artist;
-            Duration = TimeSpan.FromMilliseconds(file.Duration);
+			AlbumTitle = file.Album;
+            ArtistName = file.Artist;
+            Duration = TimeSpan.FromMilliseconds (file.Duration);
             Genre = file.Genre;
-            PlayCount = file.UseCount < 0 ? (uint)0 : (uint)file.UseCount;
-            Rating = file.Rating < 0 ? (uint) 0 : (uint) (file.Rating / 20);
-            Title = file.Title;
-            TrackNumber = file.TrackNumber < 0 ? (uint)0 : file.TrackNumber;
-            Year = (file.Date != null && file.Date.Length >= 4) ? int.Parse(file.Date.Substring(0, 4)) : 0;
-            //Filesize = file.Filesize; // Unfortunately this info is currently stat'd when needed
+            PlayCount = file.UseCount < 0 ? 0 : (int) file.UseCount;
+            Rating = file.Rating < 0 ? 0 : (file.Rating / 20);
+            TrackTitle = file.Title;
+            TrackNumber = file.TrackNumber < 0 ? 0 : (int)file.TrackNumber;
+            Year = (file.ReleaseDate != null && file.ReleaseDate.Length >= 4) ? Int32.Parse (file.ReleaseDate.Substring(0, 4)) : 0;
+            FileSize = (long)file.FileSize;
 
             // This can be implemented if there's enough people requesting it
-            CanPlay = false;             
+            CanPlay = false;
             CanSaveToDatabase = true;
-            NeedSync = false;
+            //NeedSync = false;
+
+            // TODO detect if this is a video file and set the MediaAttributes appropriately?
 
 			// Set a URI even though it's not actually accessible through normal API's.
-			uri = new SafeUri(String.Format ("mtp://{0}", file.Filename));
+			Uri = new SafeUri (GetPathFromMtpTrack (file));
         }
         
-        public override bool Equals (object o)
+        /*public override bool Equals (object o)
         {
             MtpDapTrackInfo dapInfo = o as MtpDapTrackInfo;
             return dapInfo == null ? false : Equals(dapInfo);
@@ -97,16 +101,11 @@
             if(title != null) result ^= title.GetHashCode();
             
             return result;
-        }
+        }*/
         
-        public bool OnCamera(MtpDevice camera)
-        {
-            return this.camera == camera;
-        }
-		
-		protected override void WriteUpdate ()
+		/*protected override void WriteUpdate ()
 		{
 			OnChanged();
-		}
+		}*/
     }
 }

Modified: trunk/banshee/src/Dap/Banshee.Dap.Mtp/Makefile.am
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap.Mtp/Makefile.am	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap.Mtp/Makefile.am	Sat Apr 12 11:02:15 2008
@@ -3,7 +3,9 @@
 LINK = $(REF_DAP_MTP)
 INSTALL_DIR = $(EXTENSIONS_INSTALL_DIR)
 
-SOURCES = Banshee.Dap.Mtp/MtpSource.cs
+SOURCES = \
+	Banshee.Dap.Mtp/MtpSource.cs \
+	Banshee.Dap.Mtp/MtpTrackInfo.cs
 
 RESOURCES = Banshee.Dap.Mtp.addin.xml
 

Modified: trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapService.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapService.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapService.cs	Sat Apr 12 11:02:15 2008
@@ -59,6 +59,7 @@
             AddinManager.AddExtensionNodeHandler ("/Banshee/Dap/DeviceClass", OnExtensionChanged);
             ServiceManager.HardwareManager.DeviceAdded += OnHardwareDeviceAdded;
             ServiceManager.HardwareManager.DeviceRemoved += OnHardwareDeviceRemoved;
+            ServiceManager.SourceManager.SourceRemoved += OnSourceRemoved;
         }
 
         private void OnExtensionChanged (object o, ExtensionNodeEventArgs args) {
@@ -68,11 +69,8 @@
                 supported_dap_types.Add (node);
 
                 // See if any existing devices are handled by this new DAP support
-                foreach (IBlockDevice device in ServiceManager.HardwareManager.GetAllBlockDevices ()) {
+                foreach (IDevice device in ServiceManager.HardwareManager.GetAllDevices ()) {
                     MapDevice (device);
-                    foreach (IVolume volume in device.Volumes) {
-                        MapDevice (volume);
-                    }
                 }
             } else {
                 // TODO remove/dispose all loaded DAPs of this type?
@@ -85,13 +83,17 @@
             lock (this) {
                 ServiceManager.HardwareManager.DeviceAdded -= OnHardwareDeviceAdded;
                 ServiceManager.HardwareManager.DeviceRemoved -= OnHardwareDeviceRemoved;
+                ServiceManager.SourceManager.SourceRemoved -= OnSourceRemoved;
                 
-                foreach (DapSource source in sources.Values) {
-                    ServiceManager.SourceManager.RemoveSource (source);
-                }
-                
-                sources.Clear ();
-                sources = null;
+                ThreadPool.QueueUserWorkItem (delegate {
+                    List<DapSource> dap_sources = new List<DapSource> (sources.Values);
+                    foreach (DapSource source in dap_sources) {
+                        UnmapDevice (source.Device.Uuid);
+                    }
+                    
+                    sources.Clear ();
+                    sources = null;
+                });
             }
         }
         
@@ -107,6 +109,9 @@
                 if (device is IVolume && (device as IVolume).ShouldIgnore)
                     return;
 
+                if (device.MediaCapabilities == null && !(device is IBlockDevice) && !(device is IVolume))
+                    return;
+
                 DapSource source = FindDeviceType (device);
                 if (source != null) {
                     Log.DebugFormat ("Found DAP support for device {0}", source.Name);
@@ -123,9 +128,21 @@
             lock (this) {
                 if (sources.ContainsKey (uuid)) {
                     Log.DebugFormat ("Unmapping DAP source ({0})", uuid);
+
                     DapSource source = sources[uuid];
-                    ServiceManager.SourceManager.RemoveSource (source);
+                    source.Dispose ();
                     sources.Remove (uuid);
+                    ServiceManager.SourceManager.RemoveSource (source);
+                }
+            }
+        }
+
+        private void OnSourceRemoved (SourceEventArgs args)
+        {
+            DapSource dap_source = args.Source as DapSource;
+            if (dap_source != null) {
+                lock (this) {
+                    UnmapDevice (dap_source.Device.Uuid);
                 }
             }
         }

Modified: trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs	Sat Apr 12 11:02:15 2008
@@ -45,6 +45,10 @@
     {
         protected IDevice device;
 
+        internal IDevice Device {
+            get { return device; }
+        }
+
         protected DapSource () : base ()
         {
         }
@@ -60,14 +64,19 @@
                 Properties.SetStringList ("Icon.Name", FallbackIcon);
             }
 
+            if (String.IsNullOrEmpty (Name)) Name = device.Name;
             GenericName = IsMediaDevice ? Catalog.GetString ("Audio Player") : Catalog.GetString ("Media Device");
         }
 
+        bool initialized = false;
+
         public bool Resolve (IDevice device)
         {
             this.device = device;
             type_unique_id = device.Uuid;
-            return Initialize (device);
+            bool ret = Initialize (device);
+            initialized = true;
+            return ret;
         }
 
         protected abstract bool Initialize (IDevice device);
@@ -83,5 +92,13 @@
         protected IDeviceMediaCapabilities MediaCapabilities {
             get { return device.MediaCapabilities; }
         }
+
+        public override void AddChildSource (Source child)
+        {
+            if (initialized && child is Banshee.Playlist.AbstractPlaylistSource) {
+                Log.Information ("Note: playlists added to digital audio players within Banshee are not yet saved to the device.", true);
+            }
+            base.AddChildSource (child);
+        }
     }
 }

Modified: trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/RemovableSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/RemovableSource.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/RemovableSource.cs	Sat Apr 12 11:02:15 2008
@@ -41,7 +41,7 @@
 
 namespace Banshee.Dap
 {
-    public abstract class RemovableSource : PrimarySource, IUnmapableSource, Banshee.Library.IImportSource
+    public abstract class RemovableSource : PrimarySource, IUnmapableSource, Banshee.Library.IImportSource, IDiskUsageReporter
     {
         protected RemovableSource () : base ()
         {
@@ -82,10 +82,6 @@
             get { return true; }
         }
 
-        public double StorageUsageFraction {
-            get { return (double) BytesUsed / (double) BytesCapacity; }
-        }
-
 #region IUnmapableSource Implementation
 
         public bool Unmap ()

Modified: trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs	Sat Apr 12 11:02:15 2008
@@ -160,6 +160,9 @@
         
         private void PaintHeaderCell (Rectangle area, Rectangle clip, int ci, bool dragging)
         {
+            if (ci < 0 || column_cache.Length <= ci)
+                return;
+
             if (dragging) {
                 Theme.DrawColumnHighlight (cairo_context, area, 
                     CairoExtensions.ColorShade (Theme.Colors.GetWidgetColor (GtkColorClass.Dark, StateType.Normal), 0.9));
@@ -175,7 +178,7 @@
                 cairo_context.LineTo (area.Right - 0.5, area.Bottom);
                 cairo_context.Stroke ();
             }
-            
+
             ColumnCell cell = column_cache[ci].Column.HeaderCell;
             
             if (cell != null) {

Modified: trunk/banshee/src/Libraries/Hyena/Hyena/StringUtil.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena/StringUtil.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena/StringUtil.cs	Sat Apr 12 11:02:15 2008
@@ -112,5 +112,21 @@
 
             return builder.ToString ();
         }
+
+        public static string FormatDouble (double num)
+        {
+            if (num == (int)num)
+                return Convert.ToString ((int)num);
+            else
+                return String.Format ("{0:0.0}", num);
+        }
+        
+        public static int DoubleToPluralInt (double num)
+        {
+            if (num == (int)num)
+                return (int)num;
+            else
+                return (int)num + 1;
+        }
     }
 }

Modified: trunk/banshee/src/Libraries/Mtp/Mtp/Track.cs
==============================================================================
--- trunk/banshee/src/Libraries/Mtp/Mtp/Track.cs	(original)
+++ trunk/banshee/src/Libraries/Mtp/Mtp/Track.cs	Sat Apr 12 11:02:15 2008
@@ -37,106 +37,103 @@
 		internal TrackStruct trackStruct;
 		private MtpDevice device;
 		
-		internal uint FileId
-		{
+		public uint FileId {
 			get { return trackStruct.item_id; }
 		}
 		
-		public string Album
-		{
+		public string Album {
 			get { return trackStruct.album; }
 			set { trackStruct.album = value;}
 		}
-		public string Artist
-		{
+
+		public string Artist {
 			get { return trackStruct.artist; }
 			set { trackStruct.artist = value; }
 		}
-		public uint Bitrate
-		{
+
+		public uint Bitrate {
 			get { return trackStruct.bitrate; }
 		}
-		public ushort BitrateType
-		{
+
+		public ushort BitrateType {
 			get { return trackStruct.bitratetype; }
 		}
-		public string Date
-		{
+
+		public string ReleaseDate {
 			get { return trackStruct.date; }
 			set { trackStruct.date = value; }
 		}
-		public uint Duration
-		{
+
+		public uint Duration {
 			get { return trackStruct.duration; }
 			set { trackStruct.duration = value; }
 		}
-		public string Filename
-		{
+
+		public string FileName {
 			get { return trackStruct.filename; }
 			set { trackStruct.filename = value; }
 		}
-		public ulong Filesize
-		{
+
+		public ulong FileSize {
 			get { return trackStruct.filesize; }
 			set { trackStruct.filesize = value; }
 		}
-		public FileType Filetype
-		{
+
+		public FileType FileType {
 			get { return trackStruct.filetype; }
 			set { trackStruct.filetype = value; }
 		}
-		public string Genre
-		{
+
+		public string Genre {
 			get { return trackStruct.genre; }
 			set { trackStruct.genre = value; }
 		}
-		public ushort NoChannels
-		{
+
+		public ushort NoChannels {
 			get { return trackStruct.nochannels; }
 			set { trackStruct.nochannels = value; }
 		}
-		public ushort Rating  // 0 -> 100
-		{
+
+        // 0 to 100
+		public ushort Rating {
 			get { return trackStruct.rating; }
-			set
-			{
+			set {
 				if (value < 0 || value > 100)
-					throw new ArgumentOutOfRangeException("Rating", "Rating must be between zero and 100");
+					throw new ArgumentOutOfRangeException ("Rating", "Rating must be between zero and 100");
 				trackStruct.rating = value;
 			}
 		}
-		public uint SampleRate
-		{
+
+		public uint SampleRate {
 			get { return trackStruct.samplerate; }
 			set { trackStruct.samplerate = value; }
 		}
-		public string Title
-		{
+
+		public string Title {
 			get { return trackStruct.title; }
 			set { trackStruct.title = value; }
 		}
+
 		public ushort TrackNumber
 		{
 			get { return trackStruct.tracknumber; }
 			set { trackStruct.tracknumber = value; }
 		}
-		public uint WaveCodec
-		{
+
+		public uint WaveCodec {
 			get { return trackStruct.wavecodec; }
 		}
-		public uint UseCount
-		{
+
+		public uint UseCount {
 			get { return trackStruct.usecount; }
 			set { trackStruct.usecount = value; }
 		}
-		
 
-		public Track (string filename, ulong filesize)
-			: this(new TrackStruct(), null)
+		public Track (string filename, ulong filesize) : this (new TrackStruct (), null)
 		{
 			this.trackStruct.filename = filename;
 			this.trackStruct.filesize = filesize;
-			this.trackStruct.filetype = DetectFiletype(this);
+			this.trackStruct.filetype = DetectFileType (this);
 		}
 		
 		internal Track (TrackStruct track, MtpDevice device)
@@ -145,57 +142,57 @@
 			this.trackStruct = track;
 		}
 		
-		public void Download(string path)
+		public void Download (string path)
 		{
-			Download(path, null);
+			Download (path, null);
 		}
 		
-		public void Download (string path, ProgressFunction callback)
+		public void Download  (string path, ProgressFunction callback)
 		{
-			if (string.IsNullOrEmpty(path))
+			if (String.IsNullOrEmpty (path))
 				throw new ArgumentException ("Cannot be null or empty", "path");
 			
 			GetTrack (device.Handle, trackStruct.item_id, path, callback, IntPtr.Zero);
 		}
 		
-		public void UpdateMetadata()
+		public void UpdateMetadata ()
 		{
-			UpdateTrackMetadata(device.Handle, ref trackStruct);
+			UpdateTrackMetadata (device.Handle, ref trackStruct);
 		}
 		
-		private static FileType DetectFiletype(Track track)
+		private static FileType DetectFileType (Track track)
 		{
-			if(track.Filename.EndsWith(".asf", System.StringComparison.OrdinalIgnoreCase))
+			if(track.FileName.EndsWith(".asf", System.StringComparison.OrdinalIgnoreCase))
 				return FileType.ASF;
 			
-			if(track.Filename.EndsWith(".avi", System.StringComparison.OrdinalIgnoreCase))
+			if(track.FileName.EndsWith(".avi", System.StringComparison.OrdinalIgnoreCase))
 				return  FileType.AVI;
 			
-			if(track.Filename.EndsWith(".BMP", System.StringComparison.OrdinalIgnoreCase))
+			if(track.FileName.EndsWith(".BMP", System.StringComparison.OrdinalIgnoreCase))
 				return  FileType.BMP;
 			
-			if(track.Filename.EndsWith(".JPEG", System.StringComparison.OrdinalIgnoreCase)
-			   || track.Filename.EndsWith(".JPG", System.StringComparison.OrdinalIgnoreCase))
+			if(track.FileName.EndsWith(".JPEG", System.StringComparison.OrdinalIgnoreCase)
+			   || track.FileName.EndsWith(".JPG", System.StringComparison.OrdinalIgnoreCase))
 				return FileType.JPEG;
 			
-			if(track.Filename.EndsWith(".MP3", System.StringComparison.OrdinalIgnoreCase))
+			if(track.FileName.EndsWith(".MP3", System.StringComparison.OrdinalIgnoreCase))
 				return FileType.MP3;
 			
-			if(track.Filename.EndsWith(".MPG", System.StringComparison.OrdinalIgnoreCase)
-			   || track.Filename.EndsWith(".MPEG", System.StringComparison.OrdinalIgnoreCase))
+			if(track.FileName.EndsWith(".MPG", System.StringComparison.OrdinalIgnoreCase)
+			   || track.FileName.EndsWith(".MPEG", System.StringComparison.OrdinalIgnoreCase))
 				return FileType.MPEG;
 			
-			if(track.Filename.EndsWith(".OGG", System.StringComparison.OrdinalIgnoreCase)
-			   || track.Filename.EndsWith(".OGM", System.StringComparison.OrdinalIgnoreCase))
+			if(track.FileName.EndsWith(".OGG", System.StringComparison.OrdinalIgnoreCase)
+			   || track.FileName.EndsWith(".OGM", System.StringComparison.OrdinalIgnoreCase))
 				return  FileType.OGG;
 						
-			if(track.Filename.EndsWith(".PNG", System.StringComparison.OrdinalIgnoreCase))
+			if(track.FileName.EndsWith(".PNG", System.StringComparison.OrdinalIgnoreCase))
 				return  FileType.PNG;
 			
-			if(track.Filename.EndsWith(".WAV", System.StringComparison.OrdinalIgnoreCase))
+			if(track.FileName.EndsWith(".WAV", System.StringComparison.OrdinalIgnoreCase))
 				return FileType.WAV;
 									
-			if(track.Filename.EndsWith(".WMA", System.StringComparison.OrdinalIgnoreCase))
+			if(track.FileName.EndsWith(".WMA", System.StringComparison.OrdinalIgnoreCase))
 				return FileType.WMA;
 
 			return  FileType.UNKNOWN;
@@ -210,29 +207,29 @@
 		{
 			if (LIBMTP_Get_Track_To_File (handle, trackId, destPath, callback, data) != 0)
 			{
-				LibMtpException.CheckErrorStack(handle);
+				LibMtpException.CheckErrorStack (handle);
 				throw new LibMtpException (ErrorCode.General, "Could not download track from the device");
 			}
 		}
 
 		internal static IntPtr GetTrackListing (MtpDeviceHandle handle, ProgressFunction function, IntPtr data)
 		{
-			return LIBMTP_Get_Tracklisting_With_Callback(handle, function, data);
+			return LIBMTP_Get_Tracklisting_With_Callback (handle, function, data);
 		}
 
 		internal static void SendTrack (MtpDeviceHandle handle, string path, ref TrackStruct metadata, ProgressFunction callback, IntPtr data, uint parent)
 		{
 			if (LIBMTP_Send_Track_From_File (handle, path, ref metadata, callback, data, parent) != 0)
 			{
-				LibMtpException.CheckErrorStack(handle);
+				LibMtpException.CheckErrorStack (handle);
 				throw new LibMtpException (ErrorCode.General, "Could not upload the track");
 			}
 		}
 
-		internal static void UpdateTrackMetadata(MtpDeviceHandle handle, ref TrackStruct metadata)
+		internal static void UpdateTrackMetadata (MtpDeviceHandle handle, ref TrackStruct metadata)
 		{
 			if (LIBMTP_Update_Track_Metadata (handle, ref metadata) != 0)
-				throw new LibMtpException(ErrorCode.General);
+				throw new LibMtpException (ErrorCode.General);
 		}
 		
 		//[DllImport("libmtp.dll")]

Modified: trunk/banshee/tests/Banshee.Core/TaglibReadWriteTests.cs
==============================================================================
--- trunk/banshee/tests/Banshee.Core/TaglibReadWriteTests.cs	(original)
+++ trunk/banshee/tests/Banshee.Core/TaglibReadWriteTests.cs	Sat Apr 12 11:02:15 2008
@@ -10,67 +10,47 @@
 [TestFixture]
 public class TaglibReadWriteTests
 {
-    /*
-    static string [] files, blank_files;
+    static string [] files;
     static string pwd;
 
     static TaglibReadWriteTests () {
+        Hyena.Log.Debugging = true;
+
         pwd = Mono.Unix.UnixDirectoryInfo.GetCurrentDirectory ();
         AddinManager.Initialize (pwd + "/../bin/");
         Banshee.Configuration.ConfigurationClient.Initialize ();
 
         files = new string [] {
-            pwd + "/data/test1.ogg",
-            // TODO this flac file doesn't have metadata yet
-            //"data/test2.flac",
-            pwd + "/data/test3.mp3",
-        };
-
-        blank_files = new string [] {
-            pwd + "/data/no_metadata1.ogg",
-            // TODO this flac file doesn't have metadata yet
-            //"data/test2.flac",
-            pwd + "/data/no_metadata3.mp3",
+            pwd + "/data/test.mp3",
         };
     }
 
     [Test]
-    public void ReadMetadata ()
-    {
-        QueryTests.AssertForEach<string> (files, delegate (string uri) {
-            VerifyRead (new SafeUri (uri));
-        });
-    }
-
-    [Test]
-    public void UpdateMetadata ()
+    public void TestSystemIO ()
     {
-        WriteMetadata (files, true);
+        Banshee.IO.Provider.SetProvider (new Banshee.IO.SystemIO.Provider ());
+        WriteMetadata (files);
     }
 
     [Test]
-    public void CreateMetadata ()
+    public void TestUnixIO ()
     {
-        WriteMetadata (blank_files, false);
+        Banshee.IO.Provider.SetProvider (new Banshee.IO.Unix.Provider ());
+        WriteMetadata (files);
     }
 
-    private static void WriteMetadata (string [] files, bool verify_start_state)
+    private static void WriteMetadata (string [] files)
     {
         SafeUri newuri = null;
         bool write_metadata = LibrarySchema.WriteMetadata.Get();
         LibrarySchema.WriteMetadata.Set (true);
         try {
             QueryTests.AssertForEach<string> (files, delegate (string uri) {
-                string [] p = uri.Split ('.');
-                string extension = p[p.Length - 1];
+                string extension = System.IO.Path.GetExtension (uri);
                 newuri = new SafeUri (pwd + "/data/test_write." + extension);
 
                 Banshee.IO.File.Copy (new SafeUri (uri), newuri, true);
 
-                if (verify_start_state) {
-                    VerifyRead (newuri);
-                }
-
                 ChangeAndVerify (newuri);
             });
         } finally {
@@ -82,21 +62,6 @@
 
 #region Utility methods
 
-    private static void VerifyRead (SafeUri uri)
-    {
-        TagLib.File file = StreamTagger.ProcessUri (uri);
-        TrackInfo track = new TrackInfo ();
-        StreamTagger.TrackInfoMerge (track, file);
-
-        Assert.AreEqual ("TestTitle", track.TrackTitle);
-        Assert.AreEqual ("TestArtist", track.ArtistName);
-        Assert.AreEqual ("TestAlbum", track.AlbumTitle);
-        Assert.AreEqual ("TestGenre", track.Genre);
-        Assert.AreEqual (2, track.TrackNumber);
-        Assert.AreEqual (2, track.Disc);
-        Assert.AreEqual (2001, track.Year);
-    }
-
     private static void ChangeAndVerify (SafeUri uri)
     {
         TagLib.File file = StreamTagger.ProcessUri (uri);
@@ -131,6 +96,5 @@
     }
 
 #endregion
-    */
 
 }

Modified: trunk/banshee/tests/Makefile.am
==============================================================================
--- trunk/banshee/tests/Makefile.am	(original)
+++ trunk/banshee/tests/Makefile.am	Sat Apr 12 11:02:15 2008
@@ -25,7 +25,7 @@
 	ConsoleUi.cs
 
 $(ASSEMBLY): $(ASSEMBLY_CSFILES)
-	$(MCS) $(MCS_FLAGS) $(NUNIT_FLAGS) -out:$@ -target:library -r:System.Xml $(LINK_HYENA_DEPS) $(LINK_BANSHEE_THICKCLIENT_DEPS) $(ASSEMBLY_CSFILES)
+	$(MCS) $(MCS_FLAGS) $(NUNIT_FLAGS) -out:$@ -target:library -r:System.Xml $(LINK_HYENA_DEPS) $(LINK_BANSHEE_CORE_DEPS) $(LINK_BANSHEE_THICKCLIENT_DEPS) $(ASSEMBLY_CSFILES) $(REF_BACKEND_UNIX) -r:$(DIR_BIN)/Banshee.Unix.dll
 
 $(NUNIT_TESTER): $(NUNIT_TESTER_CSFILES)
 	$(MCS) $(MCS_FLAGS) -out:$@ $(NUNIT_FLAGS) $(NUNIT_TESTER_CSFILES)
@@ -33,7 +33,7 @@
 if ENABLE_TESTS
 all: $(ASSEMBLY)
 
-run-test: $(NUNIT_TESTER) $(ASSEMBLY)
+test: $(NUNIT_TESTER) $(ASSEMBLY)
 	LANG=it_IT MONO_PATH="$(top_builddir)/bin" mono --debug $(NUNIT_TESTER) $(ASSEMBLY)
 endif
 



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