? .git
? Updated_iPod_playlist_banshee.diff
? src/Banshee.Dap/Ipod/Ipod.mds
? src/Banshee.Dap/Ipod/Ipod.userprefs
Index: src/Banshee.Base/Banshee.Base.mdp
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Base/Banshee.Base.mdp,v
retrieving revision 1.22
diff -u -r1.22 Banshee.Base.mdp
--- src/Banshee.Base/Banshee.Base.mdp	5 Dec 2006 06:00:23 -0000	1.22
+++ src/Banshee.Base/Banshee.Base.mdp	13 Dec 2006 05:40:35 -0000
@@ -208,6 +208,7 @@
     <File name="./IO/GnomeVfs.cs" subtype="Code" buildaction="Compile" />
     <File name="./SampleTrackInfo.cs" subtype="Code" buildaction="Compile" />
     <File name="./IO/Utilities.cs" subtype="Code" buildaction="Compile" />
+    <File name="./Sources/DapPlaylistSource.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Gac" localcopy="True" refto="gtk-sharp, Version=2.8.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
Index: src/Banshee.Base/Makefile.am
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Base/Makefile.am,v
retrieving revision 1.80
diff -u -r1.80 Makefile.am
--- src/Banshee.Base/Makefile.am	5 Dec 2006 06:00:23 -0000	1.80
+++ src/Banshee.Base/Makefile.am	13 Dec 2006 05:40:35 -0000
@@ -161,7 +161,8 @@
 	$(srcdir)/Sources/DapSource.cs \
 	$(srcdir)/Sources/LocalQueueSource.cs \
 	$(srcdir)/Sources/ImportErrorsSource.cs \
-	$(srcdir)/Sources/TestSource.cs
+	$(srcdir)/Sources/TestSource.cs	\
+	$(srcdir)/Sources/DapPlaylistSource.cs
 
 NETWORKMANAGER_SOURCES = \
 	$(srcdir)/NetworkManager/Manager.cs 
Index: src/Banshee.Base/Dap/Dap.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Base/Dap/Dap.cs,v
retrieving revision 1.24
diff -u -r1.24 Dap.cs
--- src/Banshee.Base/Dap/Dap.cs	12 Dec 2006 09:11:27 -0000	1.24
+++ src/Banshee.Base/Dap/Dap.cs	13 Dec 2006 05:40:35 -0000
@@ -121,15 +121,21 @@
         private DapProperties type_properties;
 
         protected List<TrackInfo> tracks = new List<TrackInfo>(); 
+        //protected List<TrackInfo> playlists = new List<TrackInfo>(); 
+        private ArrayList playlists = new ArrayList();
         
         public event DapTrackListUpdatedHandler TrackAdded;
         public event DapTrackListUpdatedHandler TrackRemoved;
         public event EventHandler TracksCleared;
+	public event EventHandler PlaylistAdded;
+	public event EventHandler PlaylistRemoved;
+	public event EventHandler PlaylistsCleared;
         public event EventHandler PropertiesChanged;
         public event EventHandler Ejected;
         public event EventHandler SaveStarted;
         public event EventHandler SaveFinished;
         public event EventHandler Reactivate;
+	public event EventHandler Loaded;
         
         public Hal.Device HalDevice;
         private Source source;
@@ -183,6 +189,14 @@
                 handler(this, new EventArgs());
             }
         }
+
+	protected void OnLoaded()
+	{
+	    EventHandler handler = Loaded;
+	    if(handler != null) {
+		handler(this, new EventArgs());
+	    }
+	}
         
         protected void InstallProperty(string name, string value)
         {
@@ -211,12 +225,12 @@
             }
         }
         
-        public virtual void Dispose()
-        {
-            if(source != null) {
-                SourceManager.RemoveSource(source);
-            }
-        }
+//        public virtual void Dispose()
+//        {
+//            if(source != null) {
+//                SourceManager.RemoveSource(source);
+//            }
+//        }
         
         public void ClearTracks()
         {
@@ -234,6 +248,57 @@
                 }
             }
         }
+
+	public void AddPlaylist(DapPlaylistSource dps)
+	{
+	    if(dps == null)
+		return;
+
+	    playlists.Add(dps);
+	    OnPlaylistAdded (dps);
+	}
+
+	public void AddPlaylist(PlaylistSource ps)
+	{
+	    if(ps == null)
+		return;
+
+	    DapPlaylistSource dps = new DapPlaylistSource(ps.Name);
+
+	    // FIXME: Also add tracks we need if there is enough disk space
+	    foreach(TrackInfo ti in ps.Tracks) {
+		if (TrackExistsInList(ti, tracks))
+		    dps.AddTrack(ti);
+	    }
+
+	    AddPlaylist(dps);
+	}
+        
+	public void RemovePlaylist(DapPlaylistSource dps)
+	{
+	    dps.Delete();
+	    playlists.Remove(dps);
+	    OnPlaylistRemoved(dps);
+	}
+
+	public void ClearPlaylists()
+	{
+	    foreach(DapPlaylistSource dps in playlists)
+		dps.Delete();
+
+	    playlists.Clear();
+	    OnPlaylistsCleared();
+
+    	    EventHandler handler = PlaylistsCleared;
+	    if(handler != null) {
+		handler(null, new EventArgs());
+	    }
+	}
+
+        public virtual void Dispose()
+        {
+            SourceManager.RemoveSource(source);
+        }
         
         protected virtual void OnTrackAdded (TrackInfo track)
         {
@@ -250,6 +315,26 @@
         protected virtual void OnTracksCleared()
         {
         }
+
+        protected virtual void OnPlaylistAdded(DapPlaylistSource dps)
+        {
+            EventHandler handler = PlaylistAdded;
+	    if(handler != null) {
+		handler(dps, new EventArgs());
+	    }
+        }
+        
+        protected virtual void OnPlaylistRemoved(DapPlaylistSource dps)
+        {
+            EventHandler handler = PlaylistRemoved;
+	    if(handler != null) {
+		handler(dps, new EventArgs());
+	    }
+        }
+
+	protected virtual void OnPlaylistsCleared()
+	{
+	}
         
         public virtual void Activate()
         {
@@ -277,7 +362,7 @@
                 a.TrackNumber == b.TrackNumber;
         }
         
-        protected bool TrackExistsInList(TrackInfo track, ICollection<TrackInfo> list)
+        protected bool TrackExistsInList(TrackInfo track, IEnumerable<TrackInfo> list)
         {
             try {
                 foreach(TrackInfo track_b in list) {
@@ -291,12 +376,12 @@
             return false;
         }
 
-        public void Save(ICollection<TrackInfo> library)
+        public void Save(LibrarySource library)
         {
             Queue remove_queue = new Queue();
             
-            foreach(TrackInfo ti in Tracks) {
-                if(TrackExistsInList(ti, library)) {
+            foreach(TrackInfo ti in library.Tracks) {
+                if(TrackExistsInList(ti, library.Tracks)) {
                     continue;
                 }
                 
@@ -307,13 +392,21 @@
                 RemoveTrack(remove_queue.Dequeue() as TrackInfo);
             }
             
-            foreach(TrackInfo ti in library) {
-                if(TrackExistsInList(ti, Tracks) || ti.Uri == null) {
+            foreach(TrackInfo ti in library.Tracks) {
+                if(TrackExistsInList(ti, library.Tracks) || ti.Uri == null) {
                     continue;
                 }
                 
                 AddTrack(ti);
             }
+
+	    foreach(ChildSource cs in source.Children) {
+		if(!(cs is PlaylistSource))
+		    continue;
+
+		PlaylistSource ps = cs as PlaylistSource;
+		AddPlaylist(ps);
+	    }
             
             Save();
         }
@@ -620,6 +713,12 @@
         public IList<TrackInfo> Tracks {
             get { return tracks; }
         }
+        
+        public IList Playlists {
+	    get {
+		return playlists;
+	    }
+	}
         
         public bool IsSyncing {
             get { return is_syncing; }
Index: src/Banshee.Base/Sources/DapPlaylistSource.cs
===================================================================
RCS file: src/Banshee.Base/Sources/DapPlaylistSource.cs
diff -N src/Banshee.Base/Sources/DapPlaylistSource.cs
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/Banshee.Base/Sources/DapPlaylistSource.cs	13 Dec 2006 05:40:35 -0000
@@ -0,0 +1,174 @@
+ using System;
+ using System.Data;
+ using System.Collections;
+ using System.Collections.Generic;
+ using Mono.Unix;
+ 
+ using Banshee.Base;
+ 
+ namespace Banshee.Sources
+ {
+     public class DapPlaylistSource : ChildSource
+    {
+         //private ArrayList tracks = new ArrayList();
+         private List<TrackInfo> tracks = new List<TrackInfo>();
+         private Queue remove_queue = new Queue();
+         private Queue append_queue = new Queue();
+ 
+         public DapPlaylistSource() : base(Catalog.GetString("New Playlist"), 500)
+         {
+         }
+ 
+         public DapPlaylistSource(string name) : base(name, 500)
+         {
+         }
+       
+         protected override bool UpdateName(string oldName, string newName)
+         {
+            if(oldName.Equals(newName)) {
+                 return false;
+             }
+             
+ 	    // FIXME: Check for same name
+             /*if(PlaylistUtil.PlaylistExists(newName)) {
+                 LogCore.Instance.PushWarning(
+                     Catalog.GetString("Cannot Rename Playlist"),
+                     Catalog.GetString("A playlist with this name already exists. Please choose another name."));
+                 return false;
+ 		}*/
+             
+             Name = newName;
+             return true;
+         }
+  	
+         public override void AddTrack(TrackInfo track)
+         {
+             if(track is LibraryTrackInfo) {
+                 lock(TracksMutex) {
+                     tracks.Add(track);
+                     append_queue.Enqueue(track);
+                 }
+                 OnUpdated();
+             }
+         }
+ 
+         public override void RemoveTrack(TrackInfo track)
+         {
+             lock(TracksMutex) {
+                 tracks.Remove(track);
+                 remove_queue.Enqueue(track);
+             }
+         }
+ 
+         public override void Commit()
+         {
+         }
+ 
+         public void Delete()
+         {
+             tracks.Clear();
+             append_queue.Clear();
+             remove_queue.Clear();
+             SourceManager.RemoveSource(this);
+         }
+         
+         /*public override void Reorder(TrackInfo track, int position)
+         {
+             lock(TracksMutex) {
+                 int sql_position = 1;
+             
+                 if(position > 0) {
+                     TrackInfo sibling = tracks[position] as TrackInfo;
+                     if(sibling == track || sibling == null) {
+                         return;
+                     }
+                     
+                     sql_position = Convert.ToInt32(Globals.Library.Db.QuerySingle(String.Format(
+                         @"SELECT ViewOrder
+                             FROM PlaylistEntries
+                             WHERE PlaylistID = '{0}'
+                                 AND TrackID = '{1}'
+                             LIMIT 1", id, sibling.TrackId)
+                     ));
+                 } else if(tracks[position] == track) {
+                     return;
+                 } 
+                 
+                 Globals.Library.Db.Execute(String.Format(
+                     @"UPDATE PlaylistEntries
+                         SET ViewOrder = ViewOrder + 1
+                         WHERE PlaylistID = '{0}'
+                             AND ViewOrder >= '{1}'",
+                     id, sql_position
+                 ));
+                 
+                 Globals.Library.Db.Execute(String.Format(
+                     @"UPDATE PlaylistEntries
+                         SET ViewOrder = '{1}'
+                         WHERE PlaylistID = '{0}'
+                             AND TrackID = '{2}'",
+                     id, sql_position, track.TrackId
+                 ));
+                 
+                 tracks.Remove(track);
+                 tracks.Insert(position, track);
+             }
+         }*/
+         
+         private void OnLibraryTrackRemoved(object o, LibraryTrackRemovedArgs args)
+         {
+             if(args.Track != null) {
+                 if(tracks.Contains(args.Track)) {
+                     RemoveTrack(args.Track);
+                     
+                     if(Count == 0) {
+                         Delete();
+                     } else {
+                         Commit();
+                     }
+                 }          
+             } else if (args.Tracks == null) {
+ 		return;
+ 	    }
+             
+             int removed_count = 0;
+             
+             lock(TracksMutex) {
+                 foreach(TrackInfo track in args.Tracks) {
+                     if(tracks.Contains(track)) {
+                         tracks.Remove(track);
+                         remove_queue.Enqueue(track);
+                         removed_count++;
+                     }
+                 }
+             }
+             
+             if(removed_count > 0) {
+                 if(Count == 0) {
+                     Delete();
+                 } else {
+                     Commit();
+                 }
+             }
+         }
+         
+        public override IEnumerable<TrackInfo> Tracks {
+             get { return tracks; }
+         }
+         
+         public override object TracksMutex {
+             get { return ((IList)tracks).SyncRoot; }
+         }
+         
+         public override int Count {
+             get { return tracks.Count; }
+         }  
+         
+         private static Gdk.Pixbuf commited_icon = IconThemeUtils.LoadIcon(22, "source-playlist");
+         private static Gdk.Pixbuf uncommited_icon = IconThemeUtils.LoadIcon(22, "source-playlist-uncommited");
+ 
+         public override Gdk.Pixbuf Icon {
+             get { return commited_icon; }
+         }
+     }
+ }
Index: src/Banshee.Base/Sources/DapSource.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Base/Sources/DapSource.cs,v
retrieving revision 1.12
diff -u -r1.12 DapSource.cs
--- src/Banshee.Base/Sources/DapSource.cs	28 Jul 2006 22:05:48 -0000	1.12
+++ src/Banshee.Base/Sources/DapSource.cs	13 Dec 2006 05:40:35 -0000
@@ -50,9 +50,12 @@
         public DapSource(Banshee.Dap.DapDevice device) : base(device.Name, 400)
         {
             this.device = device;
+
             device.SaveStarted += OnDapSaveStarted;
             device.SaveFinished += OnDapSaveFinished;
             device.Reactivate += OnDapReactivate;
+	    device.Loaded += OnDapLoaded;
+
             CanRename = device.CanSetName;
         }
         
@@ -130,6 +133,13 @@
             OnViewChanged();
             OnUpdated();
         }
+
+	private void OnDapLoaded(object o, EventArgs args)
+	{
+	    foreach(DapPlaylistSource dps in device.Playlists) {
+		AddChildSource(dps);
+	    }
+	}
         
         public override void Activate()
         {
Index: src/Banshee.Dap/Ipod/IpodDap.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Dap/Ipod/IpodDap.cs,v
retrieving revision 1.25
diff -u -r1.25 IpodDap.cs
--- src/Banshee.Dap/Ipod/IpodDap.cs	31 Oct 2006 18:29:07 -0000	1.25
+++ src/Banshee.Dap/Ipod/IpodDap.cs	13 Dec 2006 05:40:35 -0000
@@ -39,6 +39,7 @@
 using Banshee.Base;
 using Banshee.Dap;
 using Banshee.Widgets;
+using Banshee.Sources;
 
 public static class PluginModuleEntry
 {
@@ -204,6 +205,17 @@
                     IpodDapTrackInfo ti = new IpodDapTrackInfo(track);
                     AddTrack(ti);            
                 }
+
+//		foreach(Playlist playlist in device.TrackDatabase.Playlists) {
+//		    DapPlaylistSource dps = new DapPlaylistSource (playlist.Name);
+//
+//		    foreach(Track song in playlist.Tracks) {
+//			IpodDapTrackInfo track = new IpodDapTrackInfo(song);
+//			dps.AddTrack(track);
+//		    }
+//
+//		    AddPlaylist(dps);
+//		}
             } else {
                 BuildDatabaseUnsupportedWidget();
             }
@@ -211,9 +223,36 @@
             if(previous_database_supported != database_supported) {
                 OnPropertiesChanged();
             }
+
+	    OnLoaded();
         }
-        
-        public override void Eject()
+
+	// FIXME: Lame comparsion
+        private string ToLower(string str)
+	{
+            return str == null ? null : str.ToLower();
+	}
+
+        private bool TrackSongCompare(TrackInfo a, Track b)
+        {
+            Console.WriteLine ("Comparing " + a + " to " + b);
+            return ToLower(a.Title) == ToLower(b.Title) &&
+                ToLower(a.Album) == ToLower(b.Album) &&
+                ToLower(a.Artist) == ToLower(b.Artist) &&
+                a.Year == b.Year &&
+                a.TrackNumber == b.TrackNumber;
+        }
+
+	private void DeleteAllPlaylists (TrackDatabase db)
+	{
+		IEnumerator ie = db.Playlists.GetEnumerator();
+		while (ie.MoveNext() ){
+			Console.WriteLine (ie.ToString());
+			db.RemovePlaylist ((Playlist) ie.Current);
+	   }
+	}
+	
+	public override void Eject()
         {
             try {
                 device.Eject();
@@ -238,7 +277,13 @@
                     track.Track.Uri = new Uri(track.Uri.AbsoluteUri);
                 }
             }
-            
+           // DeleteAllPlaylists (device.TrackDatabase);
+		    Console.WriteLine (device.TrackDatabase.Playlists);
+		    //Console.WriteLine (PlaylistUtil.LoadSources());
+		    foreach(PlaylistSource ps in PlaylistUtil.LoadSources()) {
+				CommitPlaylistToDevice (ps);
+		    }
+	    
             device.TrackDatabase.SaveProgressChanged += delegate(object o, TrackSaveProgressArgs args)
             {
                 double progress = args.CurrentTrack == null ? 0.0 : args.TotalProgress;
@@ -340,6 +385,32 @@
                 }
             }
         }
+	
+	private void CommitPlaylistToDevice (PlaylistSource source)
+	{
+	    Playlist playlist = device.TrackDatabase.LookupPlaylist (source.Name);
+	    
+	    // FIXME: Incrementally update. Maybe later :-)
+	    
+	    if (playlist == null)
+	    	playlist = device.TrackDatabase.CreatePlaylist (source.Name);
+	    	//device.TrackDatabase.RemovePlaylist (playlist);
+	    Console.WriteLine (source.Name);
+	    
+	    //Console.WriteLine (playlist);
+	    foreach (TrackInfo track in source.Tracks) {
+			
+			foreach(Track track2 in device.TrackDatabase.Tracks) {
+			    
+			    Console.WriteLine ("Comparing: " + track + " to " + track2);
+			    if (!TrackSongCompare (track, track2))
+					continue;
+			    Console.WriteLine ("Adding: " + track2);
+			    playlist.AddTrack (track2);
+			}
+	    }
+       }
+
         
         public override Gdk.Pixbuf GetIcon(int size)
         {
