Here's a preliminary patch. There are still some things I'd like to tweak, but this should give you an idea of how it works. Index: src/Core/Banshee.Services/Banshee.Sources/Source.cs =================================================================== --- src/Core/Banshee.Services/Banshee.Sources/Source.cs (revision 3358) +++ src/Core/Banshee.Services/Banshee.Sources/Source.cs (working copy) @@ -31,6 +31,7 @@ using System.Text; using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; using Mono.Unix; @@ -47,6 +48,7 @@ private Source parent; private PropertyStore properties = new PropertyStore (); private List<Source> child_sources = new List<Source> (); + private ReadOnlyCollection<Source> read_only_children; public event EventHandler Updated; public event EventHandler UserNotifyUpdated; @@ -132,21 +134,23 @@ public virtual void AddChildSource (Source child) { - lock (Children) { + lock (child_sources) { child.SetParentSource (this); child_sources.Add (child); + read_only_children = null; OnChildSourceAdded (child); } } public virtual void RemoveChildSource (Source child) { - lock (Children) { - if (child.Children.Count > 0) { + lock (child_sources) { + if (child.child_sources.Count > 0) { child.ClearChildSources (); } child_sources.Remove (child); + read_only_children = null; if (ServiceManager.SourceManager.ActiveSource == child) { ServiceManager.SourceManager.SetActiveSource (ServiceManager.SourceManager.DefaultSource); @@ -158,7 +162,7 @@ public virtual void ClearChildSources () { - lock (Children) { + lock (child_sources) { while (child_sources.Count > 0) { RemoveChildSource (child_sources[child_sources.Count - 1]); } @@ -183,7 +187,7 @@ public virtual void SortChildSources (IComparer<Source> comparer, bool asc) { - lock (Children) { + lock (child_sources) { child_sources.Sort (comparer); if (!asc) { child_sources.Reverse (); @@ -249,8 +253,13 @@ #region Public Properties - public ICollection<Source> Children { - get { return child_sources; } + public ReadOnlyCollection<Source> Children { + get { + if (read_only_children == null) { + read_only_children = new ReadOnlyCollection<Source> (child_sources); + } + return read_only_children; + } } string [] ISource.Children { Index: src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs =================================================================== --- src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs (revision 3358) +++ src/Core/Banshee.Services/Banshee.Sources/DatabaseSource.cs (working copy) @@ -67,6 +67,7 @@ track_model.CacheId )); reload_limiter = new RateLimiter (50.0, RateLimitedReload); + reload_node = new LinkedListNode<ITrackModelSource> (this); } #region Public Properties @@ -162,15 +163,51 @@ OnUpdated (); } + private LinkedList<ITrackModelSource> reload_list = new LinkedList<ITrackModelSource> (); + protected virtual void AddToReloadList (LinkedList<ITrackModelSource> reload_list) + { + reload_list.AddFirst (reload_node); + } + protected virtual void ReloadChildren () { - foreach (Source child in Children) { - if (child is ITrackModelSource) { - (child as ITrackModelSource).Reload (); + if (reload_list.Count < Children.Count) { + foreach (Source child in Children) { + DatabaseSource c = child as DatabaseSource; + if (c != null) { + c.AddToReloadList (reload_list); + } else { + ITrackModelSource tms = child as ITrackModelSource; + if (tms != null) { + reload_list.AddFirst (tms); + } + } } } + + foreach (ITrackModelSource c in reload_list) { + c.Reload (); + } } + + public override void AddChildSource (Source child) + { + reload_list.Clear (); + base.AddChildSource (child); + } + public override void RemoveChildSource (Source child) + { + reload_list.Clear (); + base.RemoveChildSource (child); + } + + + private LinkedListNode<ITrackModelSource> reload_node; + protected LinkedListNode<ITrackModelSource> ReloadNode { + get { return reload_node; } + } + public virtual void RemoveTrack (int index) { RemoveTrack (track_model [index] as DatabaseTrackInfo); Index: src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistCore.cs =================================================================== --- src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistCore.cs (revision 3358) +++ src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistCore.cs (working copy) @@ -1,6 +1,5 @@ using System; using System.Data; -using System.Collections; using System.Collections.Generic; using Mono.Unix; @@ -29,7 +28,7 @@ private readonly double RATE_LIMIT_CPU_MAX = 0.10; private static int RATE_LIMIT_REFRESH = 5; - private ArrayList playlists = new ArrayList(); + private List<SmartPlaylistSource> playlists = new List<SmartPlaylistSource> (); private DateTime last_check = DateTime.MinValue; private uint event_counter = 0; @@ -278,6 +277,17 @@ public void SortPlaylists () { playlists.Sort(new DependencyComparer()); } + + public SmartPlaylistSource GetSmartPlaylistFromDbId (int dbId) + { + // TODO use a dictionary + foreach (SmartPlaylistSource sp in playlists) { + if (sp.DbId == dbId) { + return sp; + } + } + return null; + } } // Class used for timing different operations. Commented out for normal operation. @@ -330,15 +340,12 @@ } } - public class DependencyComparer : IComparer { - public int Compare(object ao, object bo) + public class DependencyComparer : IComparer<SmartPlaylistSource> { + public int Compare(SmartPlaylistSource a, SmartPlaylistSource b) { - SmartPlaylistSource a = ao as SmartPlaylistSource; - SmartPlaylistSource b = bo as SmartPlaylistSource; - - if (b.DependsOn(a)) { + if (b.DependsOn (a)) { return -1; - } else if (a.DependsOn(b)) { + } else if (a.DependsOn (b)) { return 1; } else { return 0; Index: src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs =================================================================== --- src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs (revision 3358) +++ src/Core/Banshee.Services/Banshee.SmartPlaylist/SmartPlaylistSource.cs (working copy) @@ -221,21 +221,36 @@ return false; } + foreach (int i in GetDependancies()) { + if (i == source.DbId) { + return true; + } + } + + return false; + } + + private IEnumerable<int> GetDependancies () + { + foreach(int i in GetDependancies (ConditionTree)) { + yield return i; + } + } + + private IEnumerable<int> GetDependancies (QueryNode node) + { if (node is QueryListNode) { foreach (QueryNode child in (node as QueryListNode).Children) { - if (DependsOn (source, child)) { - return true; + foreach (int i in GetDependancies (child)) { + yield return i; } } } else { QueryTermNode term = node as QueryTermNode; - if (term.Field == BansheeQuery.SmartPlaylistField) { - if ((term.Value as IntegerQueryValue).IntValue == source.DbId) - return true; + if (term != null && term.Field == BansheeQuery.SmartPlaylistField) { + yield return (int)(term.Value as IntegerQueryValue).IntValue; } } - - return false; } #endregion @@ -276,7 +291,38 @@ #endregion #region DatabaseSource overrides + + private bool adding_to_reload_list; + protected override void AddToReloadList (LinkedList<ITrackModelSource> reload_list) + { + if (ReloadNode.List != null) { + return; + } + + bool has_dependancies = adding_to_reload_list; + SmartPlaylistCore core = Banshee.ServiceStack.ServiceManager.Get<SmartPlaylistCore>("SmartPlaylistCore"); + + // Avoid infinite loops on circular dependancies + if (!adding_to_reload_list) { + adding_to_reload_list = true; + foreach (int i in GetDependancies()) { + SmartPlaylistSource sp = core.GetSmartPlaylistFromDbId (i); + if (sp != null) { + sp.AddToReloadList (reload_list); + has_dependancies = true; + } + } + adding_to_reload_list = false; + } + + if (has_dependancies) { + reload_list.AddLast (ReloadNode); + } else { + reload_list.AddFirst (ReloadNode); + } + } + public override void RateLimitedReload () { // Wipe the member list clean
Attachment:
patch
Description: Binary data