Index: src/Banshee.Plugins/Daap/Daap.mdp
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Plugins/Daap/Daap.mdp,v
retrieving revision 1.2
diff -u -8 -p -r1.2 Daap.mdp
--- src/Banshee.Plugins/Daap/Daap.mdp	25 Oct 2006 22:28:01 -0000	1.2
+++ src/Banshee.Plugins/Daap/Daap.mdp	27 Oct 2006 15:08:48 -0000
@@ -21,14 +21,18 @@
     <File name="./DaapLoginDialog.cs" subtype="Code" buildaction="Compile" />
     <File name="./DaapPlaylistSource.cs" subtype="Code" buildaction="Compile" />
     <File name="./DaapPlugin.cs" subtype="Code" buildaction="Compile" />
     <File name="./DaapProxyWebServer.cs" subtype="Code" buildaction="Compile" />
     <File name="./DaapSource.cs" subtype="Code" buildaction="Compile" />
     <File name="./DaapTrackInfo.cs" subtype="Code" buildaction="Compile" />
     <File name="./DatabaseProxy.cs" subtype="Code" buildaction="Compile" />
     <File name="./DaapErrorView.cs" subtype="Code" buildaction="Compile" />
+    <File name="./DaapConnectingWidget.cs" subtype="Code" buildaction="Compile" />
+    <File name="./DaapStatusWidget.cs" subtype="Code" buildaction="Compile" />
+    <File name="./DaapSummaryWidget.cs" subtype="Code" buildaction="Compile" />
+    <File name="./DaapImporter.cs" subtype="Code" buildaction="Compile" />
   </Contents>
   <References>
     <ProjectReference type="Gac" localcopy="True" refto="gtk-sharp, Version=2.8.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
     <ProjectReference type="Gac" localcopy="True" refto="Banshee.Widgets, Version=0.11.2.25666, Culture=neutral" />
   </References>
 </Project>
Index: src/Banshee.Plugins/Daap/DaapConnectingWidget.cs
===================================================================
RCS file: src/Banshee.Plugins/Daap/DaapConnectingWidget.cs
diff -N src/Banshee.Plugins/Daap/DaapConnectingWidget.cs
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/Banshee.Plugins/Daap/DaapConnectingWidget.cs	27 Oct 2006 15:08:48 -0000
@@ -0,0 +1,24 @@
+
+using System;
+using Mono.Unix;
+using Gtk;
+
+using Banshee.Widgets;
+
+namespace Banshee.Plugins.Daap
+{
+	
+	public class DaapConnectingWidget : ShadowContainer
+	{		
+		public DaapConnectingWidget(Gdk.Pixbuf icon, string sourceName)
+		{
+		    MessagePane pane = new MessagePane();
+		    pane.HeaderIcon = icon;
+		    pane.HeaderMarkup = String.Format("<big><b>{0} {1}</b></big>", 
+                Catalog.GetString("Connecting to"), sourceName);
+            Add(pane);
+            ShowAll();
+		}
+	}
+	
+}
Index: src/Banshee.Plugins/Daap/DaapContainerSource.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Plugins/Daap/DaapContainerSource.cs,v
retrieving revision 1.2
diff -u -8 -p -r1.2 DaapContainerSource.cs
--- src/Banshee.Plugins/Daap/DaapContainerSource.cs	24 Oct 2006 23:14:30 -0000	1.2
+++ src/Banshee.Plugins/Daap/DaapContainerSource.cs	27 Oct 2006 15:08:48 -0000
@@ -28,25 +28,54 @@
  
 using System;
 using System.IO;
 using System.Collections.Generic;
 using System.Collections;
 using Mono.Unix;
 using DAAP;
 
+using Gtk;
+
 using Banshee.Base;
 using Banshee.Sources;
 
 namespace Banshee.Plugins.Daap
 {
-    public class DaapContainerSource : Source
+    public class DaapContainerSource : Source, IImportable
     {
+        private List<TrackInfo> tracks = new List<TrackInfo> ();
+        private DaapStatusWidget status;
+        private Alignment container;
+        private VBox box;
+        private VBox vbox;
+        private DaapSummaryWidget summary;
+        
         public DaapContainerSource() : base(Catalog.GetString("Shared Music"), 300)
         {
+            box = new VBox();
+            summary = new DaapSummaryWidget();
+            vbox = new VBox();
+            vbox.Spacing = 5;
+            
+            container = new Alignment(0.0f, 0.0f, 1.0f, 1.0f);
+            status = new DaapStatusWidget();
+            
+            vbox.PackStart(container, true, true, 0);
+            vbox.PackStart(status, false, false, 0);
+            vbox.ShowAll();
+            
+            box.PackStart(summary);
+            box.ShowAll();
+        }
+        
+        public override void Activate()
+        {
+            InterfaceElements.DetachPlaylistContainer();
+            container.Add(InterfaceElements.PlaylistContainer);
         }
 
         public override int Count {
             get { return DaapCore.ServerCount; }
         }
 
         private static Gdk.Pixbuf icon = IconThemeUtils.LoadIcon(22, 
             "applications-internet", "network-server", Gtk.Stock.Network);
@@ -54,13 +83,92 @@ namespace Banshee.Plugins.Daap
         public override Gdk.Pixbuf Icon {
             get { return icon; }
         }
         
         public override bool AutoExpand {
             get { return false; }
         }
         
-        public override bool CanActivate {
-            get { return false; }
+        internal void MergeSource (object o, EventArgs args)
+        {
+            ThreadAssist.ProxyToMain(delegate{
+                DaapSource source = o as DaapSource;
+                if(box.Children[0] is DaapSummaryWidget) {
+                    while(box.Children.Length > 0) {
+                        box.Remove(box.Children[0]);
+                    }
+                    box.PackStart(vbox);
+                    box.ShowAll();
+                }
+                foreach (TrackInfo track in source.Tracks) {
+                    tracks.Add(track);
+                }
+                OnUpdated();
+            });
+        }
+        
+        internal void UnmergeSource (object o, EventArgs args)
+        {
+            ThreadAssist.ProxyToMain(delegate{
+                DaapSource source = o as DaapSource;
+                if(DaapCore.ConnectedServerCount == 0) {
+                    while(box.Children.Length > 0) {
+                        box.Remove(box.Children[0]);
+                    }
+                    box.PackStart(summary);
+                    box.ShowAll();
+                }
+                foreach (TrackInfo track in source.Tracks) {
+                    tracks.Remove(track);
+      			}
+                OnUpdated();
+            });
+        }
+        
+        internal void UpdateSource (object o, EventArgs args)
+        {
+            DaapSource source = o as DaapSource;
+            UnmergeSource(source, null);
+            MergeSource(source, null);
+        }
+        
+        public override IEnumerable<TrackInfo> Tracks {
+            get { return tracks; }
+        }
+        
+        public override bool Unmap()
+        {
+            DaapCore.DisconnectAll();
+            return true;
+        }
+        
+        public override string UnmapIcon {
+            get { return Gtk.Stock.Disconnect; }
+        }
+        
+        public override string UnmapLabel {
+            get { return Catalog.GetString("Disconnect From All"); }
+        }
+        
+        public override Gtk.Widget ViewWidget {
+            get { return box; }
+        }
+        
+        private DaapImporter importer;
+        
+        public void Import(IEnumerable<TrackInfo> tracks, PlaylistSource playlist)
+        {
+            if(importer == null) {
+                importer = new DaapImporter(Name, Icon);
+                importer.Finished += delegate(object o, EventArgs args) {
+                    importer = null;
+                };
+            }
+            importer.Import(tracks, playlist);
+        }
+        
+        public void Import(IEnumerable<TrackInfo> tracks)
+        {
+            Import(tracks, null);
         }
     }
 }
Index: src/Banshee.Plugins/Daap/DaapCore.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Plugins/Daap/DaapCore.cs,v
retrieving revision 1.14
diff -u -8 -p -r1.14 DaapCore.cs
--- src/Banshee.Plugins/Daap/DaapCore.cs	23 Oct 2006 05:33:09 -0000	1.14
+++ src/Banshee.Plugins/Daap/DaapCore.cs	27 Oct 2006 15:08:48 -0000
@@ -34,23 +34,27 @@ using DAAP;
 
 using Banshee.Base;
 using Banshee.Sources;
 
 namespace Banshee.Plugins.Daap
 {
     internal static class DaapCore
     {
+        public static event EventHandler ServerCountChanged;
+        public static event EventHandler ConnectedServerCountChanged;
+        
         private static DaapPlugin plugin;
         private static Server server;
         private static DAAP.Database database;
         private static ServiceLocator locator;
         private static DaapProxyWebServer proxy_server;
         private static Hashtable source_map;
         private static int collision_count;
+        private static int connected_count;
         private static DaapContainerSource container_source;
         
         private static bool initial_db_committed = false;
         
         internal static void Initialize(DaapPlugin plugin)
         {
             DaapCore.plugin = plugin;
             
@@ -134,20 +138,32 @@ namespace Banshee.Plugins.Daap
                 
                 while (source_map.Contains(service_name))
                     service_name = args.Service.Name + " [" + ++collision + "]";
                 source_map.Add(service_name, source);
                 if(source_map.Count == 1) {
                     container_source = new DaapContainerSource();
                     SourceManager.AddSource(container_source);
                 }
+                source.ClientLoggedIn += delegate (object o, EventArgs args) {
+                    connected_count++;
+                    OnConnectedServerCountChanged();
+                };
+                source.ClientLoggedIn += container_source.MergeSource;
+                source.ClientChanged += container_source.UpdateSource;
+                source.ClientLoggedOut += delegate (object o, EventArgs args) {
+                    connected_count--;
+                    OnConnectedServerCountChanged();
+                };
+                source.ClientLoggedOut += container_source.UnmergeSource;
                 container_source.AddChildSource(source);
                 
             } catch(InvalidSourceException) {
             }
+            OnServerCountChanged();
         }
         
         private static void OnServiceRemoved(object o, ServiceArgs args)
         {
             DaapSource source = source_map[args.Service.Name] as DaapSource;
             if(source == null) {
                 return;
             }
@@ -156,16 +172,17 @@ namespace Banshee.Plugins.Daap
             source.Dispose();
             container_source.RemoveChildSource(source);
             source_map.Remove(args.Service.Name);
             if(source_map.Count == 0) {
                 container_source.Dispose();
                 SourceManager.RemoveSource(container_source);
                 container_source = null;
             }
+            OnServerCountChanged();
         }
         
         internal static void StartServer()
         {
             Console.WriteLine("Starting DAAP Server");
             try {
                 server.Start();
             } catch (System.Net.Sockets.SocketException) {
@@ -229,16 +246,37 @@ namespace Banshee.Plugins.Daap
             try {
                 if((bool)Globals.Configuration.Get(plugin.ConfigurationKeys["ServerEnabled"])) {
                     StartServer();
                 }
             } catch {
             }
         }
         
+        public static void ConnectAll()
+        {
+        	foreach (DictionaryEntry entry in source_map)
+	       	{
+	       		DaapSource source = entry.Value as DaapSource;
+	       		if (!source.IsLoggedIn) {
+		       			source.Activate();
+		       		}
+	       	}
+        }
+        public static void DisconnectAll()
+        {
+        	foreach (DictionaryEntry entry in source_map)
+	       	{
+	       		DaapSource source = entry.Value as DaapSource;
+	       		if (source.IsLoggedIn) {
+		       		source.Unmap();
+		       	}
+	       	}
+        }
+        
         private static void OnLibraryReloaded(object o, EventArgs args)
         {
             Globals.Library.Reloaded -= OnLibraryReloaded;
             LoadInitialServerDatabase();
         }
 
         public static DaapProxyWebServer ProxyServer {
             get {
@@ -262,11 +300,29 @@ namespace Banshee.Plugins.Daap
         }
         
         internal static bool IsServerRunning {
             get { return server.IsRunning; }
         }
         
         internal static int ServerCount {
             get { return source_map.Count; }
+        }
+        
+        internal static int ConnectedServerCount {
+            get { return connected_count; }
+        }
+        
+        private static void OnServerCountChanged()
+        {
+            if(ServerCountChanged != null) {
+                ServerCountChanged(null, null);
+            }
+        }
+        
+        private static void OnConnectedServerCountChanged()
+        {
+            if(ConnectedServerCountChanged != null) {
+                ConnectedServerCountChanged(null, null);
+            }
         }
     }
 }
Index: src/Banshee.Plugins/Daap/DaapImporter.cs
===================================================================
RCS file: src/Banshee.Plugins/Daap/DaapImporter.cs
diff -N src/Banshee.Plugins/Daap/DaapImporter.cs
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/Banshee.Plugins/Daap/DaapImporter.cs	27 Oct 2006 15:08:48 -0000
@@ -0,0 +1,168 @@
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Collections;
+using Mono.Unix;
+
+using DAAP;
+
+using Banshee.Base;
+using Banshee.Sources;
+
+namespace Banshee.Plugins.Daap
+{
+	internal class DaapImporter
+	{
+		private string Name;
+		private Gdk.Pixbuf Icon;
+		private QueuedOperationManager import_manager;
+		public event EventHandler Finished;
+		
+		private void OnFinished()
+		{
+		    if(Finished != null) {
+		        Finished(this, null);
+		    }
+		}
+		
+		public DaapImporter(string name, Gdk.Pixbuf icon)
+		{
+		    Name = name;
+		    Icon = icon;
+		}
+		
+		public void Import(IEnumerable<TrackInfo> tracks, PlaylistSource playlist)
+        {
+            if(playlist != null && playlist.Count == 0) {
+                playlist.Rename(PlaylistUtil.GoodUniqueName(tracks));
+                playlist.Commit();
+            }
+        
+            if(import_manager == null) {
+                import_manager = new QueuedOperationManager();
+                import_manager.HandleActveUserEvent = false;
+                import_manager.ActionMessage = Catalog.GetString("Importing");
+                import_manager.UserEvent.CancelMessage = String.Format(Catalog.GetString(
+                    "You are currently importing from {0}. Would you like to stop it?"), Name);
+                import_manager.UserEvent.Icon = Icon;
+                import_manager.UserEvent.Header = String.Format(Catalog.GetString("Copying from {0}"), Name);
+                import_manager.UserEvent.Message = Catalog.GetString("Scanning...");
+                import_manager.OperationRequested += OnImportOperationRequested;
+                import_manager.Finished += delegate {
+                    OnFinished();
+                    import_manager = null;
+                };
+            }
+
+            foreach(TrackInfo track in tracks) {
+                if(playlist == null) {
+                    import_manager.Enqueue(track);
+                } else {
+                    import_manager.Enqueue(new KeyValuePair<TrackInfo, PlaylistSource>(track, playlist));
+                }
+            }
+        }
+        
+        private void OnImportOperationRequested(object o, QueuedOperationArgs args)
+        {
+            DaapTrackInfo track = null;
+            PlaylistSource playlist = null;
+            
+            if(args.Object is DaapTrackInfo) {
+                track = args.Object as DaapTrackInfo;
+            } else if(args.Object is KeyValuePair<TrackInfo, PlaylistSource>) {
+                KeyValuePair<TrackInfo, PlaylistSource> container = 
+                    (KeyValuePair<TrackInfo, PlaylistSource>)args.Object;
+                track = container.Key as DaapTrackInfo;
+                playlist = container.Value;
+            } else {
+                throw new ApplicationException ("Unknown object type: " + o.GetType ());
+            }
+            
+            import_manager.UserEvent.Progress = import_manager.ProcessedCount / (double)import_manager.TotalCount;
+            import_manager.UserEvent.Message = String.Format("{0} - {1}", track.Artist, track.Title);
+            
+            string from = track.Uri.LocalPath;
+            string to = FileNamePattern.BuildFull(track, track.Track.Format);
+            
+            try {
+                if(File.Exists(to)) {
+                    FileInfo to_info = new FileInfo(to);
+                    
+                    // probably already the same file
+                    if(track.Track.Size == to_info.Length) {
+                        try {
+                            new LibraryTrackInfo(new SafeUri(to, false), track);
+                        } catch {
+                            // was already in the library
+                        }
+                        
+                        return;
+                    }
+                }
+
+                long total_bytes;
+                using(Stream from_stream = track.GetStream (out total_bytes)) {
+                    long bytes_read = 0;
+                    
+                    using(FileStream to_stream = new FileStream(to, FileMode.Create, FileAccess.ReadWrite)) {
+                        byte [] buffer = new byte[8192];
+                        int chunk_bytes_read = 0;
+                        
+                        DateTime last_message_pump = DateTime.MinValue;
+                        TimeSpan message_pump_delay = TimeSpan.FromMilliseconds(500);
+
+                        while(bytes_read < total_bytes) {
+                            chunk_bytes_read = from_stream.Read(buffer, 0, (int) Math.Min(total_bytes - bytes_read,
+                                                                                          buffer.Length));
+                            to_stream.Write(buffer, 0, chunk_bytes_read);
+                            bytes_read += chunk_bytes_read;
+                            
+                            if(DateTime.Now - last_message_pump < message_pump_delay) {
+                                continue;
+                            }
+                            
+                            double tracks_processed = (double)import_manager.ProcessedCount;
+                            double tracks_total = (double)import_manager.TotalCount;
+                            
+                            import_manager.UserEvent.Progress = (tracks_processed / tracks_total) +
+                                ((bytes_read / (double)total_bytes) / tracks_total);
+                                
+                            if(import_manager.UserEvent.IsCancelRequested) {
+                                throw new QueuedOperationManager.OperationCanceledException();
+                            }
+                            
+                            last_message_pump = DateTime.Now;
+                        }
+                    }
+                }
+                
+                try {
+                    LibraryTrackInfo library_track = new LibraryTrackInfo(new SafeUri(to, false), track);
+                    if(playlist != null) {
+                        playlist.AddTrack(library_track);
+                        playlist.Commit();
+                    }
+                } catch (Exception e) {
+                    // song already in library
+                }
+            } catch(Exception e) {
+                try {
+                    File.Delete(to);
+                } catch {
+                }
+                
+                if(e is QueuedOperationManager.OperationCanceledException) {
+                    return;
+                }
+                
+                args.Abort = true;
+                
+                LogCore.Instance.PushError(String.Format(Catalog.GetString("Cannot import track from {0}"), 
+                    Name), e.Message);
+                Console.Error.WriteLine(e);
+            } 
+        }
+	}
+}
Index: src/Banshee.Plugins/Daap/DaapPlaylistSource.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Plugins/Daap/DaapPlaylistSource.cs,v
retrieving revision 1.1
diff -u -8 -p -r1.1 DaapPlaylistSource.cs
--- src/Banshee.Plugins/Daap/DaapPlaylistSource.cs	21 Sep 2006 19:44:38 -0000	1.1
+++ src/Banshee.Plugins/Daap/DaapPlaylistSource.cs	27 Oct 2006 15:08:48 -0000
@@ -33,17 +33,17 @@ using System.Collections;
 using Mono.Unix;
 using DAAP;
 
 using Banshee.Base;
 using Banshee.Sources;
 
 namespace Banshee.Plugins.Daap
 {
-    public class DaapPlaylistSource : ChildSource
+    public class DaapPlaylistSource : ChildSource, IImportable, IImportSource
     {
         private DAAP.Database db;
         private DAAP.Playlist pl;
         private List<TrackInfo> tracks = new List<TrackInfo> ();
 
         public override IEnumerable<TrackInfo> Tracks {
             get { return tracks; }
         }
@@ -54,11 +54,34 @@ namespace Banshee.Plugins.Daap
         
         public DaapPlaylistSource(DAAP.Database db, DAAP.Playlist pl) : base(pl.Name, 300)
         {
             this.db = db;
             this.pl = pl;
             foreach (Track t in pl.Tracks) {
                 tracks.Add (new DaapTrackInfo (t, db));
             }
+        }
+        
+        public void Import()
+        {      
+            Import(Tracks);
+        }
+        
+        private DaapImporter importer;
+        
+        public void Import(IEnumerable<TrackInfo> tracks, PlaylistSource playlist)
+        {
+            if(importer == null) {
+                importer = new DaapImporter(Name, Icon);
+                importer.Finished += delegate(object o, EventArgs args) {
+                    importer = null;
+                };
+            }
+            importer.Import(tracks, playlist);
+        }
+        
+        public void Import(IEnumerable<TrackInfo> tracks)
+        {
+            Import(tracks, null);
         }
     }
 }
Index: src/Banshee.Plugins/Daap/DaapSource.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Plugins/Daap/DaapSource.cs,v
retrieving revision 1.13
diff -u -8 -p -r1.13 DaapSource.cs
--- src/Banshee.Plugins/Daap/DaapSource.cs	25 Oct 2006 22:28:01 -0000	1.13
+++ src/Banshee.Plugins/Daap/DaapSource.cs	27 Oct 2006 15:08:48 -0000
@@ -43,88 +43,80 @@ namespace Banshee.Plugins.Daap
 {
     public class DaapSource : ChildSource, IImportable, IImportSource
     {        
         private Service service;
         private Client client;
         private DAAP.Database database;
         private DatabaseProxy database_proxy;
         private bool is_activating;
+        private bool failed;
+        private bool is_logged_in;
         private VBox box;
         private Alignment container;
-        private HighlightMessageArea message_area;
+        private DaapConnectingWidget connecting;
+        
+        public event EventHandler ClientLoggedIn;
+        public event EventHandler ClientLoggedOut;
+        public event EventHandler ClientChanged;
         
         public DaapSource(Service service) : base(service.Name, 300)
         {
             this.service = service;
             is_activating = false;
             database_proxy = new DatabaseProxy();
             
             box = new VBox();
             box.Spacing = 5;
             
             container = new Alignment(0.0f, 0.0f, 1.0f, 1.0f);
+
+            connecting = new DaapConnectingWidget(BigIcon, Name);
             
-            message_area = new HighlightMessageArea();
-            message_area.BorderWidth = 5;
-            message_area.LeftPadding = 15;
-            message_area.Pixbuf = Icon;
-            
-            box.PackStart(container, true, true, 0);
-            box.PackStart(message_area, false, false, 0);
+            box.PackStart(connecting, true, true, 0);
             box.ShowAll();
         }
         
         public override void Activate()
         {
-            InterfaceElements.DetachPlaylistContainer();
-            container.Add(InterfaceElements.PlaylistContainer);
-            
+            if(SourceManager.ActiveSource == this as Source) {
+                InterfaceElements.DetachPlaylistContainer();
+                container.Add(InterfaceElements.PlaylistContainer);
+            }
+
             if(client != null || is_activating) {
             	return;
             }
             
             is_activating = true;
             
-            SetStatusMessage(String.Format(Catalog.GetString("Connecting to {0}"), Name));
-            
             ThreadAssist.Spawn(delegate {
                 client = new Client(service);
                 client.Updated += OnClientUpdated;
                 try {
                     if(client.AuthenticationMethod == AuthenticationMethod.None) {
                         client.Login();
                     } else {
                         ThreadAssist.ProxyToMain(PromptLogin);
                     }
                 } catch(Exception e) {
                     ThreadAssist.ProxyToMain(delegate {
+                        failed = true;
                         DaapErrorView error_view = new DaapErrorView(this, DaapErrorType.BrokenAuthentication);
                         while(box.Children.Length > 0) {
                             box.Remove(box.Children[0]);
                         }
                         box.PackStart(error_view, true, true, 0);
                         error_view.Show();
                     });
                 }
                
                 is_activating = false;
             });
         }
-        
-        private void SetStatusMessage(string message)
-        {
-            message_area.Message = String.Format("<big>{0}</big>", GLib.Markup.EscapeText(message));
-            message_area.Visible = true;
-        }
-        
-        private void ClearStatusMessage()
-        {
-            message_area.Visible = false;
-        }
 
         private void AddPlaylistSources ()
         {
             foreach (Playlist pl in database.Playlists) {
                 AddPlaylistSource (pl);
             }
         }
 
@@ -144,19 +136,17 @@ namespace Banshee.Plugins.Daap
                     client.Login(username, password);
                 } catch(AuthenticationException) {
                     ThreadAssist.ProxyToMain(PromptLogin);
                 }
             });
         }
 
         private void PromptLogin(object o, EventArgs args)
-        {
-            SetStatusMessage(String.Format(Catalog.GetString("Logging in to {0}"), Name));
-            
+        {            
             DaapLoginDialog dialog = new DaapLoginDialog(client.Name, 
             client.AuthenticationMethod == AuthenticationMethod.UserAndPassword);
             if(dialog.Run() == (int)Gtk.ResponseType.Ok) {
                 AuthenticatedLogin(dialog.Username, dialog.Password);
             } else {
                 Disconnect(false);
             }
 
@@ -185,17 +175,20 @@ namespace Banshee.Plugins.Daap
                 database.TrackRemoved -= OnDatabaseTrackRemoved;
                 DaapCore.ProxyServer.UnregisterDatabase(database);
                 database = null;
             }
 
             ClearChildSources();
             
             ThreadAssist.ProxyToMain(delegate {
-                DaapErrorView error_view = new DaapErrorView(this, logout 
+                if(is_logged_in) {
+                    OnClientLoggedOut();
+                }
+                DaapErrorView error_view = new DaapErrorView(this, logout
                     ? DaapErrorType.UserDisconnect 
                     : DaapErrorType.InvalidAuthentication);
                 while(box.Children.Length > 0) {
                     box.Remove(box.Children[0]);
                 }
                 box.PackStart(error_view, true, true, 0);
                 error_view.Show();
             });
@@ -221,31 +214,36 @@ namespace Banshee.Plugins.Daap
             if(database == null && client.Databases.Count > 0) {
                 database = client.Databases[0];
                 database.TrackAdded += OnDatabaseTrackAdded;
                 database.TrackRemoved += OnDatabaseTrackRemoved;
                 database_proxy.Database = database;
                 DaapCore.ProxyServer.RegisterDatabase(database);
                 AddPlaylistSources ();
                 
+                failed = false;
                 ThreadAssist.ProxyToMain(delegate {
-                    ClearStatusMessage();
                     while(box.Children.Length > 0) {
                         box.Remove(box.Children[0]);
                     }
                     
                     box.PackStart(container, true, true, 0);
-                    box.PackStart(message_area, false, false, 0);
+                    container.ShowAll();
                 });
             }
             
             Name = client.Name;
             
             ThreadAssist.ProxyToMain(delegate {
                 OnUpdated();
+                if(is_logged_in) {
+                    OnClientChanged();
+                } else {
+                    OnClientLoggedIn();
+                }
             });
         }
         
         private void OnDatabaseTrackAdded(object o, TrackArgs args)
         {
             ThreadAssist.ProxyToMain (delegate {
                 OnTrackAdded(new DaapTrackInfo(args.Track, database));
             });
@@ -267,177 +265,105 @@ namespace Banshee.Plugins.Daap
         }
         
         private static Gdk.Pixbuf icon = IconThemeUtils.LoadIcon(22, "computer", 
             "network-server", Gtk.Stock.Network);
             
         private static Gdk.Pixbuf locked_icon = IconThemeUtils.LoadIcon(22,
             "system-lock-screen", "computer", "network-server", Gtk.Stock.Network);
             
+        private static Gdk.Pixbuf big_icon = IconThemeUtils.LoadIcon(48, "computer", 
+            "network-server", Gtk.Stock.Network);
+            
+        private static Gdk.Pixbuf big_locked_icon = IconThemeUtils.LoadIcon(48,
+            "system-lock-screen", "computer", "network-server", Gtk.Stock.Network);
+            
         public override Gdk.Pixbuf Icon {
             get { 
                 if(service != null && service.IsProtected) {
                     return locked_icon;
+                } else if(failed) {
+                    return Gtk.IconTheme.Default.LoadIcon("gtk-dialog-warning", 22, 0);
                 } else {
                     return icon;
                 }
             }
         }
         
+        public Gdk.Pixbuf BigIcon {
+            get { 
+                if(service != null && service.IsProtected) {
+                    return big_locked_icon;
+                } else {
+                    return big_icon;
+                }
+            }
+        }
+        
         public override bool AutoExpand {
             get { return false; }
         }
 
         public override Gtk.Widget ViewWidget {
             get { return box; }
         }
+        
+        public bool IsLoggedIn {
+            get { return is_logged_in; }
+        }
+        
+        private void OnClientLoggedIn()
+        {
+            is_logged_in = true;
+            if(ClientLoggedIn != null) {
+                ClientLoggedIn(this, null);
+            }
+        }
+        
+        private void OnClientLoggedOut()
+        {
+            is_logged_in = false;
+            if(ClientLoggedOut != null) {
+                ClientLoggedOut(this, null);
+            }
+        }
+        
+        private void OnClientChanged()
+        {
+            if(ClientChanged != null) {
+                ClientChanged(this, null);
+            }
+        }
 
         public void Import()
         {
-            Activate ();
-
-            // omg this is so crappy
-            while (is_activating)
-                System.Threading.Thread.Sleep (1);
-            
+            if(!is_logged_in) {
+                ClientLoggedIn += ContinueImport;
+            } else {            
+                Import(Tracks);
+            }
+        }
+        
+        private void ContinueImport(object o, EventArgs args)
+        {
+            ClientLoggedIn -= ContinueImport;
             Import(Tracks);
         }
         
-        private QueuedOperationManager import_manager;
+        private DaapImporter importer;
         
         public void Import(IEnumerable<TrackInfo> tracks, PlaylistSource playlist)
         {
-            if(playlist != null && playlist.Count == 0) {
-                playlist.Rename(PlaylistUtil.GoodUniqueName(tracks));
-                playlist.Commit();
-            }
-        
-            if(import_manager == null) {
-                import_manager = new QueuedOperationManager();
-                import_manager.HandleActveUserEvent = false;
-                import_manager.ActionMessage = Catalog.GetString("Importing");
-                import_manager.UserEvent.CancelMessage = String.Format(Catalog.GetString(
-                    "You are currently importing from {0}. Would you like to stop it?"), Name);
-                import_manager.UserEvent.Icon = Icon;
-                import_manager.UserEvent.Header = String.Format(Catalog.GetString("Copying from {0}"), Name);
-                import_manager.UserEvent.Message = Catalog.GetString("Scanning...");
-                import_manager.OperationRequested += OnImportOperationRequested;
-                import_manager.Finished += delegate {
-                    import_manager = null;
+            if(importer == null) {
+                importer = new DaapImporter(Name, Icon);
+                importer.Finished += delegate(object o, EventArgs args) {
+                    importer = null;
                 };
             }
-
-            foreach(TrackInfo track in tracks) {
-                if(playlist == null) {
-                    import_manager.Enqueue(track);
-                } else {
-                    import_manager.Enqueue(new KeyValuePair<TrackInfo, PlaylistSource>(track, playlist));
-                }
-            }
+            importer.Import(tracks, playlist);
         }
         
         public void Import(IEnumerable<TrackInfo> tracks)
         {
             Import(tracks, null);
-        }
-        
-        private void OnImportOperationRequested(object o, QueuedOperationArgs args)
-        {
-            DaapTrackInfo track = null;
-            PlaylistSource playlist = null;
-            
-            if(args.Object is DaapTrackInfo) {
-                track = args.Object as DaapTrackInfo;
-            } else if(args.Object is KeyValuePair<TrackInfo, PlaylistSource>) {
-                KeyValuePair<TrackInfo, PlaylistSource> container = 
-                    (KeyValuePair<TrackInfo, PlaylistSource>)args.Object;
-                track = container.Key as DaapTrackInfo;
-                playlist = container.Value;
-            } else {
-                throw new ApplicationException ("Unknown object type: " + o.GetType ());
-            }
-            
-            import_manager.UserEvent.Progress = import_manager.ProcessedCount / (double)import_manager.TotalCount;
-            import_manager.UserEvent.Message = String.Format("{0} - {1}", track.Artist, track.Title);
-            
-            string from = track.Uri.LocalPath;
-            string to = FileNamePattern.BuildFull(track, track.Track.Format);
-            
-            try {
-                if(File.Exists(to)) {
-                    FileInfo to_info = new FileInfo(to);
-                    
-                    // probably already the same file
-                    if(track.Track.Size == to_info.Length) {
-                        try {
-                            new LibraryTrackInfo(new SafeUri(to, false), track);
-                        } catch {
-                            // was already in the library
-                        }
-                        
-                        return;
-                    }
-                }
-
-                long total_bytes;
-                using(Stream from_stream = track.GetStream (out total_bytes)) {
-                    long bytes_read = 0;
-                    
-                    using(FileStream to_stream = new FileStream(to, FileMode.Create, FileAccess.ReadWrite)) {
-                        byte [] buffer = new byte[8192];
-                        int chunk_bytes_read = 0;
-                        
-                        DateTime last_message_pump = DateTime.MinValue;
-                        TimeSpan message_pump_delay = TimeSpan.FromMilliseconds(500);
-
-                        while(bytes_read < total_bytes) {
-                            chunk_bytes_read = from_stream.Read(buffer, 0, (int) Math.Min(total_bytes - bytes_read,
-                                                                                          buffer.Length));
-                            to_stream.Write(buffer, 0, chunk_bytes_read);
-                            bytes_read += chunk_bytes_read;
-                            
-                            if(DateTime.Now - last_message_pump < message_pump_delay) {
-                                continue;
-                            }
-                            
-                            double tracks_processed = (double)import_manager.ProcessedCount;
-                            double tracks_total = (double)import_manager.TotalCount;
-                            
-                            import_manager.UserEvent.Progress = (tracks_processed / tracks_total) +
-                                ((bytes_read / (double)total_bytes) / tracks_total);
-                                
-                            if(import_manager.UserEvent.IsCancelRequested) {
-                                throw new QueuedOperationManager.OperationCanceledException();
-                            }
-                            
-                            last_message_pump = DateTime.Now;
-                        }
-                    }
-                }
-                
-                try {
-                    LibraryTrackInfo library_track = new LibraryTrackInfo(new SafeUri(to, false), track);
-                    if(playlist != null) {
-                        playlist.AddTrack(library_track);
-                        playlist.Commit();
-                    }
-                } catch (Exception e) {
-                    // song already in library
-                }
-            } catch(Exception e) {
-                try {
-                    File.Delete(to);
-                } catch {
-                }
-                
-                if(e is QueuedOperationManager.OperationCanceledException) {
-                    return;
-                }
-                
-                args.Abort = true;
-                
-                LogCore.Instance.PushError(String.Format(Catalog.GetString("Cannot import track from {0}"), 
-                    Name), e.Message);
-                Console.Error.WriteLine(e);
-            } 
         }
     }
 }
Index: src/Banshee.Plugins/Daap/DaapStatusWidget.cs
===================================================================
RCS file: src/Banshee.Plugins/Daap/DaapStatusWidget.cs
diff -N src/Banshee.Plugins/Daap/DaapStatusWidget.cs
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/Banshee.Plugins/Daap/DaapStatusWidget.cs	27 Oct 2006 15:08:48 -0000
@@ -0,0 +1,67 @@
+
+using System;
+using Mono.Unix;
+using Gtk;
+
+using Banshee.Base;
+using Banshee.Widgets;
+
+namespace Banshee.Plugins.Daap
+{
+	
+	public class DaapStatusWidget : HBox
+	{
+		public Label label;
+		public Button button;
+		
+		public DaapStatusWidget()
+		{
+		    this.Spacing = 10;
+		    Image image = new Image();
+		    image.Pixbuf = IconThemeUtils.LoadIcon(30, 
+                "applications-internet", "network-server", Gtk.Stock.Network);
+		    image.Xalign = 1F;
+		    PackStart(image);
+		    label = new Label();
+		    label.Xalign = 0F;
+		    PackStart(label, false, false, 0);
+		    button = new Button();
+		    Image buttonImage = new Image();
+		    buttonImage.Pixbuf = Gtk.IconTheme.Default.LoadIcon("gtk-connect", 20, 0);
+		    button.Label = "Try connecting to all sources";
+		    button.Image = buttonImage;
+		    button.Clicked += delegate(object o, EventArgs args) {
+                DaapCore.ConnectAll();
+            };
+		    PackStart(button, false, true, 0);
+		    PackStart(new Label());
+		    ShowAll();
+		    DaapCore.ConnectedServerCountChanged += Update;
+		    Update(null, null);
+		}
+		
+		private void Update(object o, EventArgs args)
+		{
+		    string message = "<b>";
+		    if(DaapCore.ServerCount == 1) {
+		        message += Catalog.GetString("Connected to 1 shared music source");
+		        button.Visible = false;
+		    } else {
+		        if(DaapCore.ConnectedServerCount == DaapCore.ServerCount) {
+		            message += String.Format(Catalog.GetString(
+		                "Connected to all {0} sources"), DaapCore.ConnectedServerCount);
+		            button.Visible = false;
+		        } else {
+		            message += String.Format(Catalog.GetString(
+		                "Connected to {0} of {1} sources"),
+		                DaapCore.ConnectedServerCount, DaapCore.ServerCount);
+		            button.Visible = true;
+		        }
+		    }
+		    message += "</b>";
+		    
+		    label.Markup = message;
+		}
+	}
+	
+}
Index: src/Banshee.Plugins/Daap/DaapSummaryWidget.cs
===================================================================
RCS file: src/Banshee.Plugins/Daap/DaapSummaryWidget.cs
diff -N src/Banshee.Plugins/Daap/DaapSummaryWidget.cs
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ src/Banshee.Plugins/Daap/DaapSummaryWidget.cs	27 Oct 2006 15:08:48 -0000
@@ -0,0 +1,42 @@
+
+using System;
+using Gtk;
+using Mono.Unix;
+
+using Banshee.Base;
+using Banshee.Widgets;
+
+namespace Banshee.Plugins.Daap
+{
+	public class DaapSummaryWidget : ShadowContainer
+    {
+        private MessagePane pane;
+        public DaapSummaryWidget ()
+        {
+            pane = new MessagePane();
+		    pane.HeaderIcon = IconThemeUtils.LoadIcon(48, 
+                "applications-internet", "network-server", Gtk.Stock.Network);
+            Button button = new Button();
+            button.Clicked += delegate(object o, EventArgs args) {
+                DaapCore.ConnectAll();
+            };
+            button.Label = Catalog.GetString("Try connecting to all sources");
+            HBox bbox = new HBox();
+            bbox.PackStart(button, false, false, 0);
+            pane.Append(bbox);
+            Add(pane);
+            ShowAll();
+            Update(null, null);
+            DaapCore.ServerCountChanged += Update;
+        }
+        
+        public void Update(object o, EventArgs args)
+        {
+            pane.HeaderMarkup = String.Format(Catalog.GetString(
+                (DaapCore.ServerCount > 1)
+                ? "<big><b>There are {0} shared music sources</b></big>"
+                : "<big><b>There is {0} shared music source</b></big>"),
+                DaapCore.ServerCount);
+        }
+    }
+}
Index: src/Banshee.Plugins/Daap/Makefile.am
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Plugins/Daap/Makefile.am,v
retrieving revision 1.14
diff -u -8 -p -r1.14 Makefile.am
--- src/Banshee.Plugins/Daap/Makefile.am	25 Oct 2006 21:38:26 -0000	1.14
+++ src/Banshee.Plugins/Daap/Makefile.am	27 Oct 2006 15:08:48 -0000
@@ -8,19 +8,23 @@ daapdir = $(pkglibdir)/Banshee.Plugins
 daap_SCRIPTS = $(ASSEMBLY) $(ASSEMBLY).mdb $(ASSEMBLY).config
 
 ASSEMBLY_SOURCES = \
 	$(top_srcdir)/src/AssemblyInfo.cs \
 	$(srcdir)/DaapPlugin.cs \
 	$(srcdir)/DaapCore.cs \
 	$(srcdir)/DaapContainerSource.cs \
 	$(srcdir)/DaapSource.cs \
+	$(srcdir)/DaapImporter.cs \
 	$(srcdir)/DaapTrackInfo.cs \
 	$(srcdir)/DaapLoginDialog.cs \
 	$(srcdir)/DatabaseProxy.cs \
+	$(srcdir)/DaapSummaryWidget.cs \
+	$(srcdir)/DaapStatusWidget.cs \
+	$(srcdir)/DaapConnectingWidget.cs \
 	$(srcdir)/DaapPlaylistSource.cs \
 	$(srcdir)/DaapProxyWebServer.cs \
 	$(srcdir)/DaapConfigPage.cs \
 	$(srcdir)/DaapErrorView.cs \
 	$(srcdir)/daap-sharp/*.cs \
 	$(srcdir)/daap-sharp/Mono.Zeroconf/*.cs
 
 schema_in_files = daap.schemas.in
