Index: src/Banshee.Base/ChildSource.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Base/ChildSource.cs,v
retrieving revision 1.2
diff -u -8 -p -r1.2 ChildSource.cs
--- src/Banshee.Base/ChildSource.cs    3 Jul 2006 00:27:39 -0000    1.2
+++ src/Banshee.Base/ChildSource.cs    21 Oct 2006 16:56:54 -0000
@@ -33,26 +33,16 @@ namespace Banshee.Sources
     public class ChildSource : Source
     {
         private Source parent;        
 
         protected ChildSource(string name, int position) : base(name, position)
         {
         }
 
-        public override void AddChildSource(ChildSource source)
-        {
-            throw new Exception("Cannot add a child source to a child source!");
-        }
-
-        public override void RemoveChildSource(ChildSource source)
-        {
-            throw new Exception("Cannot remove a child source from a child source!");
-        }
-
         public void SetParentSource(Source source)
         {
             parent = source;
         }
 
         public Source Parent {
             get { return parent; }
         }
Index: src/Banshee.Base/Source.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Base/Source.cs,v
retrieving revision 1.19
diff -u -8 -p -r1.19 Source.cs
--- src/Banshee.Base/Source.cs    4 Sep 2006 22:38:00 -0000    1.19
+++ src/Banshee.Base/Source.cs    21 Oct 2006 16:56:54 -0000
@@ -218,55 +218,63 @@ namespace Banshee.Sources
             } else if (criteria == SortCriteria.Size) {
                 copy.Sort (new SizeComparer());
             }
 
             if(order == SortOrder.Descending) {
                 copy.Reverse ();
             }
 
-            foreach(ChildSource child in copy) {
-                AddChildSource (child);
+            lock(Children) {
+                foreach(ChildSource child in copy) {
+                    AddChildSource (child);
+                }
             }
         }
         
         public virtual void AddChildSource(ChildSource source)
         {
-            source.SetParentSource(this);
-            child_sources.Add(source);
-        
-            SourceEventHandler handler = ChildSourceAdded;
-            if(handler != null) {
-                SourceEventArgs evargs = new SourceEventArgs();
-                evargs.Source = source;
-                handler(evargs);
+            lock(Children) {
+                source.SetParentSource(this);
+                child_sources.Add(source);
+            
+                SourceEventHandler handler = ChildSourceAdded;
+                if(handler != null) {
+                    SourceEventArgs evargs = new SourceEventArgs();
+                    evargs.Source = source;
+                    handler(evargs);
+                }
             }
         }
 
         public virtual void RemoveChildSource(ChildSource source)
         {
-            child_sources.Remove(source);
-            
-            if(SourceManager.ActiveSource == source) {
-                SourceManager.SetActiveSource(SourceManager.DefaultSource);
-            }
-
-            SourceEventHandler handler = ChildSourceRemoved;
-            if(handler != null) {
-                SourceEventArgs evargs = new SourceEventArgs();
-                evargs.Source = source;
-                handler(evargs);
-            }
+            lock(Children) {
+                child_sources.Remove(source);
+                
+                if(SourceManager.ActiveSource == source) {
+                    SourceManager.SetActiveSource(SourceManager.DefaultSource);
+                }
+
+                SourceEventHandler handler = ChildSourceRemoved;
+                if(handler != null) {
+                    SourceEventArgs evargs = new SourceEventArgs();
+                    evargs.Source = source;
+                    handler(evargs);
+                }
+            }
         }
         
         public virtual void ClearChildSources()
         {
-            while(child_sources.Count > 0) {
-                RemoveChildSource(child_sources[0] as ChildSource);
-            }
+            lock(Children) {
+                while(child_sources.Count > 0) {
+                    RemoveChildSource(child_sources[0] as ChildSource);
+                }
+            }
         }
         
         public virtual void SourceDrop(Source source)
         {
         }
         
         public virtual TrackInfo GetTrackAt(int index)
         {
@@ -366,16 +374,20 @@ namespace Banshee.Sources
         }
         
         public int Order {
             get { return order; }
         }
  
         public virtual bool HasEmphasis {
             get { return false; }
+        }
+        
+        public virtual bool AutoExpand {
+            get { return true; }
         }
 
         private bool can_rename = true;
         public bool CanRename {
             get { return ReflectionUtil.IsVirtualMethodImplemented(GetType(), "UpdateName") && can_rename; }
             protected set { can_rename = value; }
         }
         
Index: src/Banshee.Base/Gui/SourceView.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Base/Gui/SourceView.cs,v
retrieving revision 1.57
diff -u -8 -p -r1.57 SourceView.cs
--- src/Banshee.Base/Gui/SourceView.cs    27 Sep 2006 16:02:15 -0000    1.57
+++ src/Banshee.Base/Gui/SourceView.cs    21 Oct 2006 16:56:55 -0000
@@ -128,74 +128,78 @@ namespace Banshee.Gui
                 ResetHighlight();
             };
             
             SourceManager.SourceUpdated += delegate(SourceEventArgs args) {
                 QueueDraw();
             };
         }
 
-        // FIXME: This is lame and could use some recusrion instead (Lukas)
         private TreeIter FindSource(Source source)
         {
-            for(int i = 0, m = store.IterNChildren(); i < m; i++) {
-                TreeIter iter = TreeIter.Zero;
-                if(!store.IterNthChild(out iter, i)) {
-                    continue;
-                }
-                
-                if((store.GetValue(iter, 0) as Source) == source) {
-                    return iter;
-                }
+            TreeIter iter = TreeIter.Zero;
+            store.GetIterFirst(out iter);
+            return FindSource(source, iter);
+        }
         
-                for(int j = 0, n = store.IterNChildren(iter); j < n; j++) {
+        private TreeIter FindSource(Source source, TreeIter iter)
+        {
+            if (!store.IterIsValid(iter))
+                return TreeIter.Zero;
+            do {
+                if((store.GetValue(iter, 0) as Source) == source)
+                    return iter;
+                if(store.IterHasChild(iter)) {
                     TreeIter citer = TreeIter.Zero;
-                    if(!store.IterNthChild(out citer, iter, j)) {
-                        continue;
-                    }
-    
-                    if((store.GetValue(citer, 0) as Source) == source) {
-                        return citer;
-                    }
+                    store.IterChildren(out citer, iter);
+                    TreeIter result = FindSource(source, citer);
+                    if (!result.Equals(TreeIter.Zero))
+                        return result;
                 }
             }
-
+            while (store.IterNext(ref iter));
             return TreeIter.Zero;
         }
         
         private void AddSource(Source source)
         {
             AddSource(source, -1);
         }
 
         private void AddSource(Source source, int position)
         {
-            if(FindSource(source).Equals(TreeIter.Zero)) {
-                TreeIter iter = store.InsertNode(position);
-                store.SetValue(iter, 0, source);
+            AddSource(source, position, TreeIter.Zero);
+        }
+        
+        private void AddSource(Source source, int position, TreeIter parent)
+        {
+            if(!FindSource(source).Equals(TreeIter.Zero))
+                return;
+
+            TreeIter iter = (parent.Equals(TreeIter.Zero))
+                ? store.InsertNode(position) : iter = store.AppendNode(parent);
+            store.SetValue(iter, 0, source);
 
+            lock(source.Children) {
                 foreach (ChildSource s in source.Children) {
-                    TreeIter i = store.AppendNode(iter);
-                    store.SetValue(i, 0, s);
+                    AddSource(s, position, iter);
                 }
-        
-                source.ChildSourceAdded += delegate(SourceEventArgs e) {
-                    TreeIter i = store.AppendNode(iter);
-                    store.SetValue(i, 0, e.Source);
-                    Expand(iter);
-                    UpdateView ();
-                };
-
-                source.ChildSourceRemoved += delegate(SourceEventArgs e) {
-                    RemoveSource(e.Source);
-                };
+            }
 
+            source.ChildSourceAdded += delegate(SourceEventArgs e) {
+                AddSource(e.Source, position, iter);
+            };
+
+            source.ChildSourceRemoved += delegate(SourceEventArgs e) {
+                RemoveSource(e.Source);
+            };
+            
+            if (source.AutoExpand) {
                 Expand(iter);
             }
-
             UpdateView();
         }
 
         private void RemoveSource(Source source)
         {
             TreeIter iter = FindSource(source);
             if(!iter.Equals(TreeIter.Zero)) {
                 store.Remove(ref iter);
@@ -211,17 +215,17 @@ namespace Banshee.Gui
         }
     
         private void RefreshList()
         {
             store.Clear();
             foreach(Source source in SourceManager.Sources) {
                 AddSource (source);
             }
-        } 
+        }
 
         private bool UpdateView()
         {
             for(int i = 0, m = store.IterNChildren(); i < m; i++) {
                 TreeIter iter = TreeIter.Zero;
                 if(!store.IterNthChild(out iter, i)) {
                     continue;
                 }
Index: src/Banshee.Plugins/Daap/DaapContainerSource.cs
===================================================================
RCS file: src/Banshee.Plugins/Daap/DaapContainerSource.cs
diff -N src/Banshee.Plugins/Daap/DaapContainerSource.cs
--- /dev/null    1 Jan 1970 00:00:00 -0000
+++ src/Banshee.Plugins/Daap/DaapContainerSource.cs    21 Oct 2006 16:56:55 -0000
@@ -0,0 +1,62 @@
+/***************************************************************************
+ *  DaapContainer.cs
+ *
+ *  Copyright (C) 2005-2006 Novell, Inc.
+ *  Written by Scott Peterson <lunchtimemama@gmail.com>
+ ****************************************************************************/
+
+/*  THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: 
+ *
+ *  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.IO;
+using System.Collections.Generic;
+using System.Collections;
+using Mono.Unix;
+using DAAP;
+
+using Banshee.Base;
+using Banshee.Sources;
+
+namespace Banshee.Plugins.Daap
+{
+    public class DaapContainerSource : Source
+    {
+
+        public DaapContainerSource() : base("Shared Music", 300)
+        {
+        }
+
+        public override int Count {
+            get { return DaapCore.ServerCount; }
+        }
+
+        private static Gdk.Pixbuf icon = IconThemeUtils.LoadIcon(22, "network-server", Gtk.Stock.Network); 
+
+        public override Gdk.Pixbuf Icon {
+            get { return icon; }
+        }
+        
+        public override bool AutoExpand {
+            get { return false; }
+        }
+    }
+}
Index: src/Banshee.Plugins/Daap/DaapCore.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Plugins/Daap/DaapCore.cs,v
retrieving revision 1.13
diff -u -8 -p -r1.13 DaapCore.cs
--- src/Banshee.Plugins/Daap/DaapCore.cs    25 Sep 2006 17:04:39 -0000    1.13
+++ src/Banshee.Plugins/Daap/DaapCore.cs    21 Oct 2006 16:56:56 -0000
@@ -41,39 +41,42 @@ namespace Banshee.Plugins.Daap
     {
         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 DaapContainerSource container_source;
         
         private static bool initial_db_committed = false;
         
         internal static void Initialize(DaapPlugin plugin)
         {
             DaapCore.plugin = plugin;
             
+            container_source = new DaapContainerSource();
+            SourceManager.AddSource(container_source);
+            
             source_map = new Hashtable();
             locator = new ServiceLocator();
             locator.Found += OnServiceFound;
             locator.Removed += OnServiceRemoved;
             locator.ShowLocalServices = true;
             locator.Start();
             
             proxy_server = new DaapProxyWebServer();
             proxy_server.Start();
             
             string share_name = null;
             
             try {
                 share_name = Globals.Configuration.Get(plugin.ConfigurationKeys["ShareName"]) as string;
-            } catch {
-            }
+            } catch {}
             
             if(share_name == null || share_name == String.Empty) {
                 share_name = Catalog.GetString("Banshee Music Share");
             }
             collision_count = 0;
             
             database = new DAAP.Database(share_name);
             server = new Server(share_name);
@@ -119,42 +122,43 @@ namespace Banshee.Plugins.Daap
         }
         
         private static void OnServiceFound(object o, ServiceArgs args)
         {
             if (args.Service.Name == ServerName)
                 return;
             
             try {
-                Source source = new DaapSource(args.Service);
+                DaapSource source = new DaapSource(args.Service);
                 int collision = 0;
                 string service_name = args.Service.Name;
                 
                 if(service_name.ToLower().Contains("jono")) {
                     return;
                 }
                 
                 while (source_map.Contains(service_name))
                     service_name = args.Service.Name + " [" + ++collision + "]";
                 source_map.Add(service_name, source);
-                SourceManager.AddSource(source);
+                container_source.AddChildSource(source);
+                
             } catch(InvalidSourceException) {
             }
         }
         
         private static void OnServiceRemoved(object o, ServiceArgs args)
         {
             DaapSource source = source_map[args.Service.Name] as DaapSource;
             if(source == null) {
                 return;
             }
-
+            
             source.Disconnect (false);
             source.Dispose();
-            SourceManager.RemoveSource(source);
+            container_source.RemoveChildSource(source);
             source_map.Remove(args.Service.Name);
         }
         
         internal static void StartServer()
         {
             Console.WriteLine("Starting DAAP Server");
             try {
                 server.Start();
@@ -247,14 +251,16 @@ namespace Banshee.Plugins.Daap
                     server.Name = value;
                     database.Name = value;
                     Globals.Configuration.Set(plugin.ConfigurationKeys["ShareName"], value);
                 }
             }
         }
         
         internal static bool IsServerRunning {
-            get {
-                return server.IsRunning;
-            }
+            get { return server.IsRunning; }
+        }
+        
+        internal static int ServerCount {
+            get { return source_map.Count; }
         }
     }
 }
Index: src/Banshee.Plugins/Daap/DaapSource.cs
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Plugins/Daap/DaapSource.cs,v
retrieving revision 1.10
diff -u -8 -p -r1.10 DaapSource.cs
--- src/Banshee.Plugins/Daap/DaapSource.cs    25 Sep 2006 16:42:13 -0000    1.10
+++ src/Banshee.Plugins/Daap/DaapSource.cs    21 Oct 2006 16:56:56 -0000
@@ -33,53 +33,55 @@ using System.Collections;
 using Mono.Unix;
 using DAAP;
 
 using Banshee.Base;
 using Banshee.Sources;
 
 namespace Banshee.Plugins.Daap
 {
-    public class DaapSource : Source, IImportable, IImportSource
-    {
+    
+    public class DaapSource : ChildSource, IImportable, IImportSource
+    {        
         private Service service;
         private Client client;
         private DAAP.Database database;
         private DatabaseProxy database_proxy;
         private bool is_activating;
         
         public DaapSource(Service service) : base(service.Name, 300)
         {
             this.service = service;
             is_activating = false;
             database_proxy = new DatabaseProxy();
         }
         
         public override void Activate()
         {
-            if(client == null && !is_activating) {
-                is_activating = true;
-                Console.WriteLine("Connecting to DAAP share: " + service);
-                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) {
-                        LogCore.Instance.PushError(Catalog.GetString("Cannot login to DAAP share"),
-                            e.Message);
-                    }
-                    
-                    is_activating = false;
-                });
+            if(client != null || is_activating) {
+                return;
             }
+            is_activating = true;
+            Console.WriteLine("Connecting to DAAP share: " + service);
+            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) {
+                    LogCore.Instance.PushError(Catalog.GetString("Cannot login to DAAP share"),
+                        e.Message);
+                }
+               
+                is_activating = false;
+            });
         }
 
         private void AddPlaylistSources ()
         {
             foreach (Playlist pl in database.Playlists) {
                 AddPlaylistSource (pl);
             }
         }
@@ -121,17 +123,17 @@ namespace Banshee.Plugins.Daap
             Unmap();
         }
 
         internal bool Disconnect (bool logout)
         {
             if(client != null) {
                 if (logout)
                     client.Logout();
-                
+
                 client.Dispose();
                 client = null;
                 database = null;
             }
             
             if(database != null) {
                 database.TrackAdded -= OnDatabaseTrackAdded;
                 database.TrackRemoved -= OnDatabaseTrackRemoved;
@@ -195,16 +197,20 @@ namespace Banshee.Plugins.Daap
         
         public override int Count {
             get { return database == null ? -1 : database.TrackCount; }
         }
         
         private static Gdk.Pixbuf icon = IconThemeUtils.LoadIcon(22, "network-server", Gtk.Stock.Network); 
         public override Gdk.Pixbuf Icon {
             get { return icon; }
+        }
+        
+        public override bool AutoExpand {
+            get { return false; }
         }
 
         public void Import()
         {
             Activate ();
 
             // omg this is so crappy
             while (is_activating)
Index: src/Banshee.Plugins/Daap/Makefile.am
===================================================================
RCS file: /cvs/gnome/banshee/src/Banshee.Plugins/Daap/Makefile.am,v
retrieving revision 1.12
diff -u -8 -p -r1.12 Makefile.am
--- src/Banshee.Plugins/Daap/Makefile.am    19 Oct 2006 21:35:37 -0000    1.12
+++ src/Banshee.Plugins/Daap/Makefile.am    21 Oct 2006 16:56:56 -0000
@@ -6,16 +6,17 @@ ASSEMBLY = $(ASSEMBLY_NAME).dll
 
 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)/DaapTrackInfo.cs \
     $(srcdir)/DaapLoginDialog.cs \
     $(srcdir)/DatabaseProxy.cs \
     $(srcdir)/DaapPlaylistSource.cs \
     $(srcdir)/DaapProxyWebServer.cs \
     $(srcdir)/DaapConfigPage.cs \
     $(srcdir)/daap-sharp/*.cs \
