banshee r3725 - in trunk/banshee: . build src/Backends/Banshee.Hal src/Backends/Banshee.Hal/Banshee.HalBackend src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.Hardware src/Core/Banshee.Services/Banshee.Library src/Core/Banshee.Services/Banshee.Playlist src/Core/Banshee.Services/Banshee.ServiceStack src/Core/Banshee.Services/Banshee.SmartPlaylist src/Core/Banshee.Services/Banshee.Sources src/Core/Banshee.ThickClient/Banshee.Gui src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp src/Dap/Banshee.Dap/Banshee.Dap src/Extensions/Banshee.AudioCd/Banshee.AudioCd src/Extensions/Banshee.Daap/Banshee.Daap src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue src/Libraries/Hyena/Hyena.Data.Sqlite



Author: gburt
Date: Wed Apr  9 08:11:10 2008
New Revision: 3725
URL: http://svn.gnome.org/viewvc/banshee?rev=3725&view=rev

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

	* build/build.environment.mk: Banshee.Dap.Mtp depends on Mtp library.

	* src/Backends/Banshee.Hal/Makefile.am:
	* src/Backends/Banshee.Hal/Banshee.HalBackend/DeviceMediaCapabilities.cs:
	* src/Core/Banshee.Services/Makefile.am:
	* src/Core/Banshee.Services/Banshee.Hardware/IDeviceMediaCapabilities.cs:
	New files for exposing portable_audio_player properties.

	* src/Backends/Banshee.Hal/Banshee.HalBackend/Device.cs:
	* src/Core/Banshee.Services/Banshee.Hardware/IDevice.cs: Add Product,
	Vendor, and MediaCapabilities properties.

	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs:
	Add copy ctor.

	* src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs: Add
	ShuttingDown bool property.

	* src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs:
	* src/Core/Banshee.Services/Banshee.Library/LibrarySource.cs:
	* src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs:
	* src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs: Add
	CanAddTracks and Merge-related overrides.

	* src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs: Add Dispose
	method, and override AddTrack/Merge methods.

	* src/Core/Banshee.ThickClient/Banshee.Gui/BansheeActionGroup.cs: Get rid
	of WriteLine.

	* src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs:
	Add the ability to add tracks to DAPs.  No transcoding yet, and doesn't
	respect FolderDepth yet.

	* src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpSource.cs: Copy more
	initialization code over.  Still far from usable.

	* src/Dap/Banshee.Dap/Banshee.Dap/DapService.cs: Call DapSource.Resolve
	instead of Initialize.

	* src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs: Add better defaults.

	* src/Dap/Banshee.Dap/Banshee.Dap/RemovableSource.cs: Move Dispose method
	up to PrimarySource.  Get rid of Merge/AcceptsInput overrides.

	* src/Core/Banshee.Services/Banshee.Sources/ITrackModelSource.cs:
	* src/Extensions/Banshee.AudioCd/Banshee.AudioCd/AudioCdSource.cs:
	* src/Extensions/Banshee.Daap/Banshee.Daap/DaapPlaylistSource.cs:
	* src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs: Add
	CanAddTracks property.

	* src/Extensions/Banshee.Daap/Banshee.Daap/DaapSource.cs: Call
	base.Dispose ().

	* src/Core/Banshee.ThickClient/Banshee.Gui/TrackActions.cs:
	* src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs:
	Use updated AddSelectedTracks method.

	* src/Libraries/Hyena/Hyena.Data.Sqlite/DatabaseColumn.cs: Add GetRawValue
	method for use in provider's Copy method.

	* src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs: Add Copy
	method for transferring all db fields (except pk) from one instance to another.


Added:
   trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/DeviceMediaCapabilities.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IDeviceMediaCapabilities.cs
Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/build/build.environment.mk
   trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/Device.cs
   trunk/banshee/src/Backends/Banshee.Hal/Makefile.am
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackInfo.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IDevice.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Library/LibrarySource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/ITrackModelSource.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/PrimarySource.cs
   trunk/banshee/src/Core/Banshee.Services/Makefile.am
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/BansheeActionGroup.cs
   trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/TrackActions.cs
   trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
   trunk/banshee/src/Dap/Banshee.Dap.Mtp/Banshee.Dap.Mtp/MtpSource.cs
   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/Extensions/Banshee.AudioCd/Banshee.AudioCd/AudioCdSource.cs
   trunk/banshee/src/Extensions/Banshee.Daap/Banshee.Daap/DaapPlaylistSource.cs
   trunk/banshee/src/Extensions/Banshee.Daap/Banshee.Daap/DaapSource.cs
   trunk/banshee/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs
   trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/DatabaseColumn.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs

Modified: trunk/banshee/build/build.environment.mk
==============================================================================
--- trunk/banshee/build/build.environment.mk	(original)
+++ trunk/banshee/build/build.environment.mk	Wed Apr  9 08:11:10 2008
@@ -128,7 +128,7 @@
 LINK_DAP = -r:$(DIR_BIN)/Banshee.Dap.dll
 LINK_DAP_DEPS = $(REF_DAP) $(LINK_DAP)
 REF_DAP_MASS_STORAGE = $(LINK_BANSHEE_SERVICES_DEPS) $(LINK_DAP_DEPS)
-REF_DAP_MTP = $(LINK_BANSHEE_SERVICES_DEPS) $(LINK_DAP_DEPS)
+REF_DAP_MTP = $(LINK_BANSHEE_SERVICES_DEPS) $(LINK_DAP_DEPS) $(LINK_MTP_DEPS)
 
 # Backends
 REF_BACKEND_GNOME = $(LINK_BANSHEE_SERVICES_DEPS) $(LINK_GCONF) $(LINK_GNOME)

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	Wed Apr  9 08:11:10 2008
@@ -69,8 +69,26 @@
                 return name;
             }
         }
+
+        public virtual string Product {
+            get { return device["info.product"]; }
+        }
+
+        public virtual string Vendor {
+            get { return device["info.vendor"]; }
+        }
+
+        protected IDeviceMediaCapabilities media_capabilities;
+        public IDeviceMediaCapabilities MediaCapabilities {
+            get {
+                if (media_capabilities == null && device.PropertyExists ("portable_audio_player.output_formats")) {
+                    media_capabilities = new DeviceMediaCapabilities (device);
+                }
+                return media_capabilities;
+            }
+        }
         
-       private static Stack<Hal.Device> CollectUsbDeviceStack(Hal.Device device)
+        private static Stack<Hal.Device> CollectUsbDeviceStack(Hal.Device device)
         {
             Stack<Hal.Device> device_stack = new Stack<Hal.Device>();
             int usb_vendor_id = -1;

Added: trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/DeviceMediaCapabilities.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Backends/Banshee.Hal/Banshee.HalBackend/DeviceMediaCapabilities.cs	Wed Apr  9 08:11:10 2008
@@ -0,0 +1,130 @@
+//
+// DeviceMediaCapabilities.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 Banshee.Hardware;
+
+namespace Banshee.HalBackend
+{
+    public class DeviceMediaCapabilities : IDeviceMediaCapabilities
+    {
+        private Hal.Device device;
+
+        public DeviceMediaCapabilities (Hal.Device device)
+        {
+            this.device = device;
+        }
+
+        private int? folder_depth;
+        public int FolderDepth {
+            get {
+                if (folder_depth == null) {
+                    if (device.PropertyExists("portable_audio_player.folder_depth")) {
+                        folder_depth = device.GetPropertyInteger("portable_audio_player.folder_depth");
+                    } else {
+                        folder_depth = -1;
+                    }
+                }
+                return folder_depth.Value;
+            }
+        }
+
+        private string [] audio_folders;
+        public string [] AudioFolders {
+            get {
+                if (audio_folders == null) {
+                    if (device.PropertyExists ("portable_audio_player.audio_folders")) {
+                        audio_folders = device.GetPropertyStringList ("portable_audio_player.audio_folders");
+                    } else {
+                        audio_folders = new string [0];
+                    }
+                }
+                return audio_folders;
+            }
+        }
+
+        private string [] playlist_formats;
+        public string [] PlaylistFormats {
+            get {
+                if (playlist_formats == null) {
+                    if (device.PropertyExists ("portable_audio_player.playlist_format")) {
+                        playlist_formats = device.GetPropertyStringList ("portable_audio_player.playlist_format");
+                    } else {
+                        playlist_formats = new string [0];
+                    }
+                }
+                return playlist_formats;
+            }
+        }
+
+        private string playlist_path;
+        public string PlaylistPath {
+            get {
+                if (playlist_path == null) {
+                    if (device.PropertyExists ("portable_audio_player.playlist_path")) {
+                        playlist_path = device["portable_audio_player.playlist_path"];
+                    }
+                }
+                return playlist_path;
+            }
+        }
+
+        private string [] playback_formats;
+        public string [] PlaybackMimeTypes {
+            get {
+                if (playback_formats == null) {
+                    if (device.PropertyExists ("portable_audio_player.output_formats")) {
+                        playback_formats = device.GetPropertyStringList ("portable_audio_player.output_formats");
+                    } else {
+                        playback_formats = new string [0];
+                    }
+                }
+                return playback_formats;
+            }
+        }
+
+        public bool IsType (string type)
+        {
+            if (device.PropertyExists ("portable_audio_player.type")) {
+                if (device ["portable_audio_player.type"] == type) {
+                    return true;
+                }
+            }
+
+            if (device.PropertyExists ("portable_audio_player.access_method.protocols")) {
+                if (Array.IndexOf (device.GetPropertyStringList ("portable_audio_player.access_method.protocols"), type) != -1) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+    }
+}

Modified: trunk/banshee/src/Backends/Banshee.Hal/Makefile.am
==============================================================================
--- trunk/banshee/src/Backends/Banshee.Hal/Makefile.am	(original)
+++ trunk/banshee/src/Backends/Banshee.Hal/Makefile.am	Wed Apr  9 08:11:10 2008
@@ -9,6 +9,7 @@
 	Banshee.HalBackend/Device.cs \
 	Banshee.HalBackend/DiscVolume.cs \
 	Banshee.HalBackend/DiskDevice.cs \
+	Banshee.HalBackend/DeviceMediaCapabilities.cs \
 	Banshee.HalBackend/HardwareManager.cs \
 	Banshee.HalBackend/Volume.cs \
 	Hal/Device.cs \

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	Wed Apr  9 08:11:10 2008
@@ -72,6 +72,11 @@
         {
         }
 
+        public DatabaseTrackInfo (DatabaseTrackInfo original) : base ()
+        {
+            Provider.Copy (original, this);
+        }
+
         public override void IncrementPlayCount ()
         {
             if (Provider.Refresh (this)) {
@@ -126,7 +131,10 @@
             }
             
             DateUpdated = DateTime.Now;
-            bool is_new = TrackId == 0;
+
+            bool is_new = (TrackId == 0);
+            if (is_new) DateAdded = DateUpdated;
+
             Provider.Save (this);
 
             if (notify) {
@@ -156,7 +164,7 @@
 
         public PrimarySource PrimarySource {
             get { return PrimarySource.GetById (primary_source_id); }
-            set { primary_source_id = value.DbId; }
+            set { PrimarySourceId = value.DbId; }
         }
 
         [DatabaseColumn ("ArtistID")]

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IDevice.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IDevice.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IDevice.cs	Wed Apr  9 08:11:10 2008
@@ -34,5 +34,10 @@
     {
         string Uuid { get; }
         string Name { get; }
+
+        string Product { get; }
+        string Vendor { get; }
+
+        IDeviceMediaCapabilities MediaCapabilities { get; }
     }
 }

Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IDeviceMediaCapabilities.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/IDeviceMediaCapabilities.cs	Wed Apr  9 08:11:10 2008
@@ -0,0 +1,43 @@
+//
+// IDeviceMediaCapabilities.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;
+
+namespace Banshee.Hardware
+{
+    public interface IDeviceMediaCapabilities
+    {
+        int FolderDepth { get; }
+        string [] AudioFolders { get; }
+        string [] PlaylistFormats { get; }
+        string PlaylistPath { get; }
+        string [] PlaybackMimeTypes { get; }
+        bool IsType (string type);
+    }
+}

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Library/LibrarySource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Library/LibrarySource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Library/LibrarySource.cs	Wed Apr  9 08:11:10 2008
@@ -66,18 +66,32 @@
             }
         }
 
-        public override bool AcceptsInputFromSource (Source source)
+        protected override void AddTrack (DatabaseTrackInfo track)
         {
-            return source is IImportSource;
-        }
+            // Ignore if already have it
+            if (track.PrimarySourceId == DbId)
+                return;
 
-        public override void MergeSourceInput (Source source, SourceMergeType mergeType)
-        {
-            if (!(source is IImportSource) || mergeType != SourceMergeType.Source) {
+            // Move it if its from another library source
+            if (track.PrimarySource is LibrarySource) {
+                PrimarySource old_primary = track.PrimarySource;
+                track.PrimarySource = this;
+                track.Save (false);
+                old_primary.NotifyTracksChanged ();
                 return;
             }
-            
-            ((IImportSource)source).Import ();
+
+            // Otherwise, copy it
+            if (track.PrimarySource is LibrarySource) {
+                // queue in importer or something?
+            }
+
+            /*try {
+                Banshee.IO.Utilities.DeleteFileTrimmingParentDirectories (track.Uri);
+            } catch (System.IO.FileNotFoundException) {
+            } catch (System.IO.DirectoryNotFoundException) {
+            }*/
         }
+
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Playlist/PlaylistSource.cs	Wed Apr  9 08:11:10 2008
@@ -116,8 +116,7 @@
 
         public override bool AcceptsInputFromSource (Source source)
         {
-            // TODO: Probably should be more restrictive than this
-            return source is DatabaseSource;
+            return base.AcceptsInputFromSource (source) && (Parent == null || source == Parent || source.Parent == Parent);
         }
         
         public override void MergeSourceInput (Source from, SourceMergeType mergeType)
@@ -131,7 +130,7 @@
             
             switch (mergeType) {
                 case SourceMergeType.ModelSelection:
-                    AddSelectedTracks (model);
+                    AddSelectedTracks (from);
                     break;
                 case SourceMergeType.Source:
                     AddTrackRange (model, new RangeCollection.Range (0, model.Count));
@@ -183,6 +182,14 @@
             }
         }
 
+        // We can add tracks only if our parent can
+        public override bool CanAddTracks {
+            get {
+                DatabaseSource ds = Parent as DatabaseSource;
+                return ds != null ? ds.CanAddTracks : base.CanAddTracks;
+            }
+        }
+
         // Have our parent handle deleting tracks
         public override void DeleteSelectedTracks (TrackListDatabaseModel model)
         {
@@ -226,19 +233,22 @@
             Reload ();
         }*/
         
-        public virtual void AddSelectedTracks (TrackListDatabaseModel from)
+        public override void AddSelectedTracks (Source source)
         {
-            if (from == track_model)
-                return;
-
-            WithTrackSelection (from, AddTrackRange);
-            Reload ();
-            OnUserNotifyUpdated ();
+            if (Parent == null || source == Parent || source.Parent == Parent) {
+                base.AddSelectedTracks (source);
+                Reload ();
+            /*} else {
+                // Adding from a different primary source, so add to our primary source first
+                PrimarySource primary = Parent as PrimarySource;
+                primary.AddSelectedTracks (model);
+                // then add to us*/
+            }
         }
 
         TrackListDatabaseModel last_add_range_from_model;
         HyenaSqliteCommand last_add_range_command = null;
-        protected virtual void AddTrackRange (TrackListDatabaseModel from, RangeCollection.Range range)
+        protected override void AddTrackRange (TrackListDatabaseModel from, RangeCollection.Range range)
         {
             last_add_range_command = (!from.CachesJoinTableEntries)
                 ? add_track_range_command

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.ServiceStack/Application.cs	Wed Apr  9 08:11:10 2008
@@ -53,6 +53,7 @@
         public static event ShutdownRequestHandler ShutdownRequested;
 
         private static Stack<Client> running_clients = new Stack<Client> ();
+        private static bool shutting_down;
 
         public static void Run ()
         {
@@ -71,12 +72,18 @@
             
             Banshee.Base.PlatformHacks.RestoreMonoJitSegv ();
         }
+
+        public static bool ShuttingDown {
+            get { return shutting_down; }
+        }
      
         public static void Shutdown ()
         {
+            shutting_down = true;
             if (Banshee.Kernel.Scheduler.IsScheduled (typeof (Banshee.Kernel.IInstanceCriticalJob)) ||
                 Banshee.Kernel.Scheduler.CurrentJob is Banshee.Kernel.IInstanceCriticalJob) {
                 if (shutdown_prompt_handler != null && !shutdown_prompt_handler ()) {
+                    shutting_down = false;
                     return;
                 }
             }
@@ -84,6 +91,7 @@
             if (OnShutdownRequested ()) {
                 Dispose ();
             }
+            shutting_down = false;
         }
         
         public static void PushClient (Client client)

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs	Wed Apr  9 08:11:10 2008
@@ -80,6 +80,10 @@
             get { return true; }
         }
 
+        public override bool CanAddTracks {
+            get { return false; }
+        }
+
         public override bool CanRemoveTracks {
             get { return false; }
         }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs	Wed Apr  9 08:11:10 2008
@@ -114,6 +114,10 @@
             }
         }
 
+        public virtual bool CanAddTracks {
+            get { return true; }
+        }
+
         public virtual bool CanRemoveTracks {
             get { return true; }
         }
@@ -146,6 +150,11 @@
             get { return true; }
         }
 
+        public override bool AcceptsInputFromSource (Source source)
+        {
+            return CanAddTracks && source != this;
+        }
+
 #endregion
 
 #region Public Methods
@@ -202,6 +211,16 @@
             OnTracksDeleted ();
         }
 
+        public virtual void AddSelectedTracks (Source source)
+        {
+            if (!AcceptsInputFromSource (source))
+                return;
+
+            TrackListDatabaseModel model = (source as ITrackModelSource).TrackModel as TrackListDatabaseModel;
+            WithTrackSelection (model, AddTrackRange);
+            OnTracksAdded ();
+        }
+
         public virtual void RateSelectedTracks (int rating)
         {
             RateSelectedTracks (track_model, rating);
@@ -221,6 +240,10 @@
             OnTracksChanged (BansheeQuery.RatingField);
         }
 
+        public override SourceMergeType SupportedMergeTypes {
+            get { return SourceMergeType.All; }
+        }
+
 #endregion
         
 #region Protected Methods
@@ -326,6 +349,11 @@
             throw new NotImplementedException(); 
         }
 
+        protected virtual void AddTrackRange (TrackListDatabaseModel model, RangeCollection.Range range)
+        {
+            throw new NotImplementedException(); 
+        }
+
         protected virtual void RateTrackRange (TrackListDatabaseModel model, RangeCollection.Range range, int rating)
         {
             RateTrackRangeCommand.ApplyValues (rating, DateTime.Now, range.Start, range.End - range.Start + 1);

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/ITrackModelSource.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/ITrackModelSource.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Sources/ITrackModelSource.cs	Wed Apr  9 08:11:10 2008
@@ -47,6 +47,7 @@
         void RemoveSelectedTracks ();
         void DeleteSelectedTracks ();
 
+        bool CanAddTracks { get; }
         bool CanRemoveTracks { get; }
         bool CanDeleteTracks { get; }
         bool ConfirmRemoveTracks { 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	Wed Apr  9 08:11:10 2008
@@ -70,7 +70,7 @@
         }
     }
 
-    public abstract class PrimarySource : DatabaseSource
+    public abstract class PrimarySource : DatabaseSource, IDisposable
     {
         protected ErrorSource error_source;
         protected bool error_source_visible = false;
@@ -92,7 +92,7 @@
         public ErrorSource ErrorSource {
             get {
                 if (error_source == null) {
-                    error_source = new ErrorSource (Catalog.GetString ("Import Errors"));
+                    error_source = new ErrorSource (Catalog.GetString ("Errors"));
                     ErrorSource.Updated += OnErrorSourceUpdated;
                     OnErrorSourceUpdated (null, null);
                 }
@@ -143,6 +143,20 @@
         {
         }
 
+        public virtual void Dispose ()
+        {
+            if (Application.ShuttingDown)
+                return;
+
+            DatabaseTrackInfo track = ServiceManager.PlayerEngine.CurrentTrack as DatabaseTrackInfo;
+            if (track != null && track.PrimarySourceId == this.DbId) {
+                ServiceManager.PlayerEngine.Close ();
+            }
+
+            ClearChildSources ();
+            ServiceManager.SourceManager.RemoveSource (this);
+        }
+
         protected override void Initialize ()
         {
             base.Initialize ();
@@ -290,6 +304,43 @@
             throw new Exception ("PrimarySource DeleteTrack method not implemented");
         }
 
+        public override bool AcceptsInputFromSource (Source source)
+        {
+            return base.AcceptsInputFromSource (source) && source.Parent != this;
+        }
+
+        public override void MergeSourceInput (Source source, SourceMergeType mergeType)
+        {
+            AddSelectedTracks (source);
+            /*if (!(source is IImportSource) || mergeType != SourceMergeType.Source) {
+                return;
+            }
+            
+            ((IImportSource)source).Import ();
+            */
+        }
+
+        protected override void AddTrackRange (TrackListDatabaseModel model, RangeCollection.Range range)
+        {
+            for (int i = range.Start; i <= range.End; i++) {
+                DatabaseTrackInfo track = model [i] as DatabaseTrackInfo;
+                if (track == null)
+                    continue;
+
+                try {
+                    AddTrack (track);
+                } catch (Exception e) {
+                    Log.Exception (e);
+                    ErrorSource.AddMessage (e.Message, track.Uri.ToString ());
+                }
+            }
+        }
+
+        protected virtual void AddTrack (DatabaseTrackInfo track)
+        {
+            throw new Exception ("PrimarySource DeleteTrack method not implemented");
+        }
+
         protected override void PruneArtistsAlbums ()
         {
             ServiceManager.DbConnection.Execute (prune_artists_albums_command);

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	Wed Apr  9 08:11:10 2008
@@ -39,6 +39,7 @@
 	Banshee.Hardware/IDiscVolume.cs \
 	Banshee.Hardware/IDiskDevice.cs \
 	Banshee.Hardware/IHardwareManager.cs \
+	Banshee.Hardware/IDeviceMediaCapabilities.cs \
 	Banshee.Hardware/IVolume.cs \
 	Banshee.Library/HomeDirectoryImportSource.cs \
 	Banshee.Library/IImportSource.cs \

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/BansheeActionGroup.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/BansheeActionGroup.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/BansheeActionGroup.cs	Wed Apr  9 08:11:10 2008
@@ -96,7 +96,6 @@
                 // to the original icon
                 string icon = source.Properties.GetString (String.Format ("{0}IconName", action_name)) ?? icons[action_name];
                 if (!String.IsNullOrEmpty (icon)) {
-                    Console.WriteLine ("Setting icon for {1} to {0}", icon, action_name);
                     action.IconName = icon;
                 }
             }

Modified: trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/TrackActions.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/TrackActions.cs	(original)
+++ trunk/banshee/src/Core/Banshee.ThickClient/Banshee.Gui/TrackActions.cs	Wed Apr  9 08:11:10 2008
@@ -331,14 +331,14 @@
             playlist.Save ();
             playlist.PrimarySource.AddChildSource (playlist);
             ThreadAssist.SpawnFromMain (delegate {
-                playlist.AddSelectedTracks (TrackSelector.TrackModel);
+                playlist.AddSelectedTracks (ActiveSource);
             });
         }
 
         private void OnAddToExistingPlaylist (object o, EventArgs args)
         {
             ThreadAssist.SpawnFromMain (delegate {
-                ((PlaylistMenuItem)o).Playlist.AddSelectedTracks (TrackSelector.TrackModel);
+                ((PlaylistMenuItem)o).Playlist.AddSelectedTracks (ActiveSource);
             });
         }
 

Modified: trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs	(original)
+++ trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs	Wed Apr  9 08:11:10 2008
@@ -34,6 +34,7 @@
 using Hyena;
 using Hyena.Collections;
 
+using Banshee.IO;
 using Banshee.Base;
 using Banshee.ServiceStack;
 using Banshee.Library;
@@ -52,24 +53,23 @@
         {
         }
 
-        public override bool Initialize (IDevice device)
+        protected override bool Initialize (IDevice device)
         {
             this.volume = device as IVolume;
             if (volume == null)
                 return false;
 
-            if (!System.IO.File.Exists (IsAudioPlayerPath))
+            // TODO set up a ui for selecting volumes we want mounted/shown within Banshee
+            // (so people don't have to touch .is_audio_player, and so we can give them a harddrive icon
+            // instead of pretending they are DAPs).
+            if (!IsMediaDevice)
                 return false;
 
-            type_unique_id = volume.Uuid;
             Name = volume.Name;
-            GenericName = Catalog.GetString ("Media");
+            mount_point = volume.MountPoint;
 
             Initialize ();
 
-            Properties.SetStringList ("Icon.Name", "harddrive");
-            mount_point = volume.MountPoint;
-
             // TODO differentiate between Audio Players and normal Disks, and include the size, eg "2GB Audio Player"?
             //GenericName = Catalog.GetString ("Audio Player");
 
@@ -99,6 +99,10 @@
             get { return mount_point; }
         }
 
+        protected override bool IsMediaDevice {
+            get { return base.IsMediaDevice || Banshee.IO.File.Exists (new SafeUri (IsAudioPlayerPath)); }
+        }
+
         protected string IsAudioPlayerPath {
             get { return System.IO.Path.Combine (volume.MountPoint, ".is_audio_player"); }
         }
@@ -111,8 +115,51 @@
             get { return (long) volume.Capacity; }
         }
 
+        private bool had_write_error = false;
         protected override bool IsReadOnly {
-            get { return volume.IsReadOnly; }
+            get { return volume.IsReadOnly || had_write_error; }
+        }
+
+        private string write_path = null;
+        protected string WritePath {
+            get {
+                if (write_path == null) {
+                    write_path = BaseDirectory;
+                    // According to the HAL spec, the first folder listed in the audio_folders property
+                    // is the folder to write files to.
+                    if (MediaCapabilities != null && MediaCapabilities.AudioFolders.Length > 0) {
+                        write_path = System.IO.Path.Combine(write_path, MediaCapabilities.AudioFolders[0]);
+                    }
+                }
+                return write_path;
+            }
+
+            set { write_path = value; }
+        }
+
+        protected override void AddTrack (DatabaseTrackInfo track)
+        {
+            if (track.PrimarySourceId == DbId)
+                return;
+
+            SafeUri new_uri = new SafeUri (GetTrackPath (track));
+            try {
+                // If it already is on the device but it's out of date, remove it
+                //if (File.Exists(new_uri) && File.GetLastWriteTime(track.Uri.LocalPath) > File.GetLastWriteTime(new_uri))
+                    //RemoveTrack(new MassStorageTrackInfo(new SafeUri(new_uri)));
+                if (!File.Exists (new_uri)) {
+                    Directory.Create (System.IO.Path.GetDirectoryName (new_uri.LocalPath));
+                    File.Copy (track.Uri, new_uri, false);
+
+                    DatabaseTrackInfo copied_track = new DatabaseTrackInfo (track);
+                    copied_track.PrimarySource = this;
+                    copied_track.Uri = new_uri;
+                    copied_track.Save (false);
+                }
+            } catch (System.IO.FileNotFoundException) {
+                had_write_error = true;
+                throw;
+            }
         }
 
         protected override void DeleteTrack (DatabaseTrackInfo track)
@@ -132,5 +179,56 @@
             if (volume.CanEject)
                 volume.Eject ();
         }
+
+        protected int FolderDepth {
+            get { return MediaCapabilities == null ? -1 : MediaCapabilities.FolderDepth; }
+        }
+
+        private string GetTrackPath (TrackInfo track)
+        {
+            string file_path = WritePath;
+
+            /*string artist = FileNamePattern.Escape (track.ArtistName);
+            string album = FileNamePattern.Escape (track.AlbumTitle);
+            string number_title = FileNamePattern.Escape (track.TrackNumberTitle);
+
+            // If the folder_depth property exists, we have to put the files in a hiearchy of
+            // the exact given depth (not including the mount point/audio_folder).
+            if (FolderDepth != -1) {
+                int depth = FolderDepth;
+
+                if (depth == 0) {
+                    // Artist - Album - 01 - Title
+                    file_path = System.IO.Path.Combine (file_path, String.Format ("{0} - {1} - {2}", artist, album, number_title));
+                } else if (depth == 1) {
+                    // Artist - Album/01 - Title
+                    file_path = System.IO.Path.Combine (file_path, String.Format ("{0} - {1}", artist, album));
+                    file_path = System.IO.Path.Combine (file_path, number_title);
+                } else if (depth == 2) {
+                    // Artist/Album/01 - Title
+                    file_path = System.IO.Path.Combine (file_path, artist);
+                    file_path = System.IO.Path.Combine (file_path, album);
+                    file_path = System.IO.Path.Combine (file_path, number_title);
+                } else {
+                    // If the *required* depth is more than 2..go nuts!
+                    for (int i = 0; i < depth - 2; i++) {
+                        file_path = System.IO.Path.Combine (file_path, artist.Substring (0, Math.Min (i, artist.Length)).Trim ());
+                    }
+
+                    // Finally add on the Artist/Album/01 - Track
+                    file_path = System.IO.Path.Combine (file_path, artist);
+                    file_path = System.IO.Path.Combine (file_path, album);
+                    file_path = System.IO.Path.Combine (file_path, number_title);
+                }
+            } else {
+                file_path = System.IO.Path.Combine (file_path, FileNamePattern.CreateFromTrackInfo (track));
+            }
+            */
+
+            file_path = System.IO.Path.Combine (file_path, FileNamePattern.CreateFromTrackInfo (track));
+            file_path += System.IO.Path.GetExtension (track.Uri.LocalPath);
+
+            return file_path;
+        }
     }
 }

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	Wed Apr  9 08:11:10 2008
@@ -1,5 +1,5 @@
 //
-// MassStorageSource.cs
+// MtpSource.cs
 //
 // Author:
 //   Gabriel Burt <gburt novell com>
@@ -33,6 +33,7 @@
 
 using Hyena;
 using Hyena.Collections;
+using Mtp;
 
 using Banshee.Base;
 using Banshee.ServiceStack;
@@ -46,32 +47,94 @@
 {
     public class MtpSource : DapSource
     {
-        protected IDevice device;
+        // libmtp only lets us have one device connected at a time
+        private static MtpSource mtp_source;
+
+		private MtpDevice mtp_device;
+        //private bool supports_jpegs = false;
 
         public MtpSource () : base ()
         {
         }
 
-        public override bool Initialize (IDevice device)
+        protected override bool Initialize (IDevice device)
         {
-            this.device = device;
-
-            type_unique_id = device.Uuid;
-
-            Name = volume.Name;
-            GenericName = Catalog.GetString ("Audio Player");
+            Log.DebugFormat ("MTP testing device {0}", device.Uuid);
+            if (MediaCapabilities == null || !MediaCapabilities.IsType ("mtp")) {
+                Log.DebugFormat ("FAILED");
+                return false;
+            }
+
+            // libmtp only allows us to have one MTP device active
+            if (mtp_source != null) {
+                Log.Information (
+                    Catalog.GetString ("MTP Support Ignoring Device"),
+                    Catalog.GetString ("Banshee's MTP audio player support can only handle one device at a time."),
+                    true
+                );
+				return false;
+            }
+
+            string serial = "";//hal_device ["usb.serial"];
+
+			List<MtpDevice> devices = null;
+			try {
+				devices = MtpDevice.Detect ();
+			} catch (TypeInitializationException e) {
+                Log.Exception (e);
+				Log.Error (
+                    Catalog.GetString ("Error Initializing MTP Device Support"),
+                    Catalog.GetString ("There was an error intializing MTP device support.  See http://www.banshee-project.org/Guide/DAPs/MTP for more information.")
+                );
+				return false;
+			} catch (Exception e) {
+                Log.Exception (e);
+				//ShowGeneralExceptionDialog (e);
+				return false;
+			}
+
+            if (devices == null || devices.Count == 0) {
+				Log.Error (
+                    Catalog.GetString ("Error Finding MTP Device Support"),
+                    Catalog.GetString ("An MTP device was detected, but Banshee was unable to load support for it.")
+                );
+            } else {
+                string mtp_serial = devices[0].SerialNumber;
+                if (!String.IsNullOrEmpty (mtp_serial) && !String.IsNullOrEmpty (serial)) {
+                    if (mtp_serial.Contains (serial)) {
+                        mtp_device = devices[0];
+                        mtp_source = this;
+                    }
+                }
+
+                if (mtp_device == null) {
+                    Log.Information(
+                        Catalog.GetString ("MTP Support Ignoring Device"),
+                        Catalog.GetString ("Banshee's MTP audio player support can only handle one device at a time."),
+                        true
+                    );
+                }
+            }
+
+            if (mtp_device == null) {
+                return false;
+            }
+
+			/*Log.Debug ("Loading MTP Device",
+                String.Format ("Name: {0}, ProductID: {1}, VendorID: {2}, Serial: {3}",
+                    hal_name, product_id, vendor_id, serial
+                )
+            );*/
 
             Initialize ();
 
-            Properties.SetStringList ("Icon.Name", "");
-
             // TODO differentiate between Audio Players and normal Disks, and include the size, eg "2GB Audio Player"?
             //GenericName = Catalog.GetString ("Audio Player");
 
             // TODO construct device-specific icon name as preferred icon
             //Properties.SetStringList ("Icon.Name", "media-player");
 
-            SetStatus (String.Format (Catalog.GetString ("Loading {0}"), Name), false);
+            //SetStatus (String.Format (Catalog.GetString ("Loading {0}"), Name), false);
             /*DatabaseImportManager importer = new DatabaseImportManager (this);
             importer.KeepUserJobHidden = true;
             importer.ImportFinished += delegate  { HideStatus (); };
@@ -86,15 +149,18 @@
         }
 
         public override long BytesUsed {
-            get { return BytesCapacity - volume.Available; }
+            //get { return BytesCapacity - volume.Available; }
+            get { return 0; }
         }
         
         public override long BytesCapacity {
-            get { return (long) volume.Capacity; }
+            //get { return (long) volume.Capacity; }
+            get { return 0; }
         }
 
         protected override bool IsReadOnly {
-            get { return volume.IsReadOnly; }
+            //get { return volume.IsReadOnly; }
+            get { return false; }
         }
 
         protected override void DeleteTrack (DatabaseTrackInfo track)

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	Wed Apr  9 08:11:10 2008
@@ -149,7 +149,7 @@
             foreach (TypeExtensionNode node in supported_dap_types) {
                 try {
                     DapSource src = (DapSource) node.CreateInstance ();
-                    if (src.Initialize (device)) {
+                    if (src.Resolve (device)) {
                         return src;
                     }
                 } catch (Exception e) {

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	Wed Apr  9 08:11:10 2008
@@ -43,6 +43,8 @@
 {
     public abstract class DapSource : RemovableSource
     {
+        protected IDevice device;
+
         protected DapSource () : base ()
         {
         }
@@ -50,9 +52,36 @@
         protected override void Initialize ()
         {
             base.Initialize ();
-            Properties.SetStringList ("Icon.Name", "multimedia-player");
+
+            if (!String.IsNullOrEmpty (device.Vendor) && !String.IsNullOrEmpty (device.Product)) {
+                string device_icon_name = (device.Vendor.Trim () + "-" + device.Product.Trim ()).Replace (' ', '-').ToLower ();
+                Properties.SetStringList ("Icon.Name", device_icon_name, FallbackIcon);
+            } else {
+                Properties.SetStringList ("Icon.Name", FallbackIcon);
+            }
+
+            GenericName = IsMediaDevice ? Catalog.GetString ("Audio Player") : Catalog.GetString ("Media Device");
+        }
+
+        public bool Resolve (IDevice device)
+        {
+            this.device = device;
+            type_unique_id = device.Uuid;
+            return Initialize (device);
         }
 
-        public abstract bool Initialize (IDevice device);
+        protected abstract bool Initialize (IDevice device);
+
+        protected virtual bool IsMediaDevice {
+            get { return device.MediaCapabilities != null; }
+        }
+
+        protected virtual string FallbackIcon {
+            get { return IsMediaDevice ? "multimedia-player" : "harddrive"; }
+        }
+
+        protected IDeviceMediaCapabilities MediaCapabilities {
+            get { return device.MediaCapabilities; }
+        }
     }
 }

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	Wed Apr  9 08:11:10 2008
@@ -41,7 +41,7 @@
 
 namespace Banshee.Dap
 {
-    public abstract class RemovableSource : PrimarySource, IUnmapableSource, IDisposable, Banshee.Library.IImportSource
+    public abstract class RemovableSource : PrimarySource, IUnmapableSource, Banshee.Library.IImportSource
     {
         protected RemovableSource () : base ()
         {
@@ -66,12 +66,6 @@
             }
         }
 
-        public void Dispose ()
-        {
-            ClearChildSources ();
-            ServiceManager.SourceManager.RemoveSource (this);
-        }
-        
         public override bool CanRemoveTracks {
             get { return false; }
         }
@@ -80,6 +74,10 @@
             get { return !IsReadOnly; }
         }
 
+        public override bool CanAddTracks {
+            get { return !IsReadOnly; }
+        }
+
         public virtual bool CanImport {
             get { return true; }
         }
@@ -88,40 +86,6 @@
             get { return (double) BytesUsed / (double) BytesCapacity; }
         }
 
-#region Source Overrides
-
-        public override bool AcceptsInputFromSource (Source source)
-        {
-            // TODO: Probably should be more restrictive than this
-            return source is DatabaseSource;
-        }
-        
-        public override void MergeSourceInput (Source from, SourceMergeType mergeType)
-        {
-            DatabaseSource source = from as DatabaseSource;
-            if (source == null || !(source.TrackModel is TrackListDatabaseModel)) {
-                return;
-            }
-            
-            //TrackListDatabaseModel model = (TrackListDatabaseModel)source.TrackModel;
-            
-            switch (mergeType) {
-                case SourceMergeType.ModelSelection:
-                    //AddSelectedTracks (model);
-                    break;
-                case SourceMergeType.Source:
-                    //AddTrackRange (model, new RangeCollection.Range (0, model.Count));
-                    Reload ();
-                    break;
-            }
-        }
-        
-        public override SourceMergeType SupportedMergeTypes {
-            get { return IsReadOnly ? SourceMergeType.None : SourceMergeType.All; }
-        }
-
-#endregion
-
 #region IUnmapableSource Implementation
 
         public bool Unmap ()

Modified: trunk/banshee/src/Extensions/Banshee.AudioCd/Banshee.AudioCd/AudioCdSource.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.AudioCd/Banshee.AudioCd/AudioCdSource.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.AudioCd/Banshee.AudioCd/AudioCdSource.cs	Wed Apr  9 08:11:10 2008
@@ -231,6 +231,10 @@
         {
         }
 
+        public bool CanAddTracks {
+            get { return false; }
+        }
+
         public bool CanRemoveTracks {
             get { return false; }
         }

Modified: trunk/banshee/src/Extensions/Banshee.Daap/Banshee.Daap/DaapPlaylistSource.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Daap/Banshee.Daap/DaapPlaylistSource.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Daap/Banshee.Daap/DaapPlaylistSource.cs	Wed Apr  9 08:11:10 2008
@@ -72,6 +72,10 @@
         public TrackListModel TrackModel {
             get { return track_model; }
         }
+
+        public bool CanAddTracks {
+            get { return false; }
+        }
         
         public bool CanRemoveTracks {
             get { return false; }

Modified: trunk/banshee/src/Extensions/Banshee.Daap/Banshee.Daap/DaapSource.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Daap/Banshee.Daap/DaapSource.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Daap/Banshee.Daap/DaapSource.cs	Wed Apr  9 08:11:10 2008
@@ -40,7 +40,7 @@
 
 namespace Banshee.Daap
 {
-    public class DaapSource : PrimarySource, IDurationAggregator, IDisposable, IUnmapableSource, IImportSource
+    public class DaapSource : PrimarySource, IDurationAggregator, IUnmapableSource, IImportSource
     {
         private Service service;
         private DAAP.Client client;
@@ -166,9 +166,10 @@
             return true;
         }
         
-        public void Dispose ()
+        public override void Dispose ()
         {
             Disconnect (true);
+            base.Dispose ();
         }
         
         private void PromptLogin (object o, EventArgs args)

Modified: trunk/banshee/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.Lastfm/Banshee.Lastfm.Radio/StationSource.cs	Wed Apr  9 08:11:10 2008
@@ -429,6 +429,10 @@
             throw new Exception ("Should not call DeleteSelectedTracks on StationSource");
         }
 
+        public bool CanAddTracks {
+            get { return false; }
+        }
+
         public bool CanRemoveTracks {
             get { return false; }
         }

Modified: trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs	Wed Apr  9 08:11:10 2008
@@ -162,7 +162,7 @@
         
         private void OnAddToPlayQueue (object o, EventArgs args)
         {
-            AddSelectedTracks (ServiceManager.Get<InterfaceActionService> ().TrackActions.TrackSelector.TrackModel);
+            AddSelectedTracks (ServiceManager.SourceManager.ActiveSource);
         }
         
         private void OnClearPlayQueue (object o, EventArgs args)

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/DatabaseColumn.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/DatabaseColumn.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/DatabaseColumn.cs	Wed Apr  9 08:11:10 2008
@@ -72,6 +72,11 @@
             this.name = attribute.ColumnName ?? member_info.Name;
             this.type = type;
         }
+
+        public object GetRawValue (object target)
+        {
+            return field_info != null ? field_info.GetValue (target) : property_info.GetValue (target, null);
+        }
         
         public object GetValue (object target)
         {

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelProvider.cs	Wed Apr  9 08:11:10 2008
@@ -380,6 +380,15 @@
             }
             return false;
         }
+
+        public void Copy (T original, T copy)
+        {
+            foreach (DatabaseColumn column in select_columns) {
+                if (column != key) {
+                    column.SetValue (copy, column.GetRawValue (original));
+                }
+            }
+        }
         
         protected virtual HyenaSqliteCommand CreateCommand {
             get {



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