[tasque/transition: 202/213] [libtasque] Implement BackendTaskCollection to save memory
- From: Antonius Riha <antoniusri src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tasque/transition: 202/213] [libtasque] Implement BackendTaskCollection to save memory
- Date: Wed, 29 Aug 2012 18:51:00 +0000 (UTC)
commit ae1b41f530842f6654f517f6b88ea6f23d7d613b
Author: Antonius Riha <antoniusriha gmail com>
Date: Sun Aug 19 21:43:56 2012 +0200
[libtasque] Implement BackendTaskCollection to save memory
BackendTaskCollection exposes the tasks that are entailed in the backend's
categories as a ReadOnlySortedNotifyCollection<Task>.
src/libtasque/Backend.cs | 94 ++---------------
src/libtasque/BackendTaskCollection.cs | 124 +++++++++++++++++++++++
src/libtasque/ReadOnlySortedNotifyCollection.cs | 103 ++++++++++++++-----
src/libtasque/libtasque.csproj | 1 +
4 files changed, 214 insertions(+), 108 deletions(-)
---
diff --git a/src/libtasque/Backend.cs b/src/libtasque/Backend.cs
index 172c7c3..6e7d26f 100644
--- a/src/libtasque/Backend.cs
+++ b/src/libtasque/Backend.cs
@@ -26,8 +26,6 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
-using System.Collections.Generic;
-using System.Collections.Specialized;
namespace Tasque
{
@@ -43,14 +41,9 @@ namespace Tasque
throw new ArgumentNullException ("name");
Name = name;
-
- tasks = new SortedNotifyCollection<Task> ();
- Tasks = new ReadOnlySortedNotifyCollection<Task> (tasks);
-
- categoriesChangedSources = new List<INotifyCollectionChanged> ();
- Categories = new SortedNotifyCollection<Category> ();
- Categories.CollectionChanged += HandleCategoriesChanged;
+ Categories = new SortedNotifyCollection<Category> ();
+ Tasks = new BackendTaskCollection (Categories);
}
#region Properties
@@ -110,12 +103,20 @@ namespace Tasque
GC.SuppressFinalize (this);
}
- protected virtual void Dispose (bool disposing) {}
+ protected virtual void Dispose (bool disposing)
+ {
+ if (!disposed && disposing) {
+ Tasks.Dispose ();
+ disposed = true;
+ }
+ }
~Backend ()
{
Dispose (false);
}
+
+ bool disposed;
#endregion
#region Methods
@@ -167,79 +168,6 @@ namespace Tasque
public event EventHandler BackendSyncFinished;
public event EventHandler BackendSyncStarted;
- void HandleCategoriesChanged (object sender, NotifyCollectionChangedEventArgs e)
- {
- switch (e.Action) {
- case NotifyCollectionChangedAction.Add: {
- var cat = (Category)e.NewItems [0];
- RegisterCategoriesChanged (cat);
- foreach (var item in cat)
- tasks.Add (item);
- break;
- }
- case NotifyCollectionChangedAction.Remove: {
- var cat = (Category)e.OldItems [0];
- UnRegisterCategoriesChanged (cat);
- RemoveCategoryContent (cat);
- break;
- }
- case NotifyCollectionChangedAction.Reset:
- for (int i = 0; i < categoriesChangedSources.Count; i++) {
- UnRegisterCategoriesChanged (categoriesChangedSources [0]);
- }
- tasks.Clear ();
- break;
- }
- }
-
- void HandleTaskCollectionChanged (object sender, NotifyCollectionChangedEventArgs e)
- {
- switch (e.Action) {
- case NotifyCollectionChangedAction.Add:
- tasks.Add ((Task)e.NewItems [0]);
- break;
- case NotifyCollectionChangedAction.Remove:
- var task = (Task)e.OldItems [0];
- if (IsSoleOccurenceInCategory ((Category)sender, task))
- tasks.Remove (task);
- break;
- case NotifyCollectionChangedAction.Reset:
- RemoveCategoryContent ((Category)sender);
- break;
- }
- }
-
- bool IsSoleOccurenceInCategory (Category cat, Task task)
- {
- foreach (var item in Categories) {
- if (cat != item && cat.Contains (task))
- return false;
- }
- return true;
- }
-
- void RemoveCategoryContent (Category cat)
- {
- foreach (var item in cat) {
- if (IsSoleOccurenceInCategory (cat, item))
- tasks.Remove (item);
- }
- }
-
- void RegisterCategoriesChanged (INotifyCollectionChanged source)
- {
- categoriesChangedSources.Add (source);
- source.CollectionChanged += HandleTaskCollectionChanged;
- }
-
- void UnRegisterCategoriesChanged (INotifyCollectionChanged source)
- {
- source.CollectionChanged -= HandleTaskCollectionChanged;
- categoriesChangedSources.Remove (source);
- }
-
- List<INotifyCollectionChanged> categoriesChangedSources;
- SortedNotifyCollection<Task> tasks;
bool initialized;
}
}
diff --git a/src/libtasque/BackendTaskCollection.cs b/src/libtasque/BackendTaskCollection.cs
new file mode 100644
index 0000000..d9935fd
--- /dev/null
+++ b/src/libtasque/BackendTaskCollection.cs
@@ -0,0 +1,124 @@
+//
+// BackendTaskCollection.cs
+//
+// Author:
+// Antonius Riha <antoniusriha gmail com>
+//
+// Copyright (c) 2012 Antonius Riha
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Linq;
+
+namespace Tasque
+{
+ class BackendTaskCollection : ReadOnlySortedNotifyCollection<Task>
+ {
+ internal BackendTaskCollection (SortedNotifyCollection<Category> categories)
+ {
+ if (categories == null)
+ throw new ArgumentNullException ("source");
+ categories.CollectionChanged += HandleSourceCollectionChanged;
+ this.categories = categories;
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (!disposed && disposing) {
+ foreach (var item in categories)
+ item.CollectionChanged -= HandleCollectionChanged;
+ disposed = true;
+ }
+ }
+
+ internal protected override int CountProtected {
+ get { return categories.SelectMany (c => c).Distinct ().Count (); }
+ }
+
+ internal protected override bool ContainsProtected (Task item)
+ {
+ return categories.Any (c => c.Contains (item));
+ }
+
+ internal protected override void CopyToProtected (Task[] array, int arrayIndex)
+ {
+ if (array == null)
+ throw new ArgumentNullException ("array");
+ if (arrayIndex < 0)
+ throw new ArgumentOutOfRangeException ("arrayIndex is less than 0.");
+ if (CountProtected > array.Length - arrayIndex)
+ throw new ArgumentException ("There is not enough space for the elements of the" +
+ "source collection in the provided array starting from arrayIndex."
+ );
+
+ foreach (var item in this)
+ array [arrayIndex++] = item;
+ }
+
+ internal protected override IEnumerator<Task> GetEnumeratorProtected ()
+ {
+ Task [] tasks = new Task [CountProtected];
+ int i = 0;
+ foreach (var collection in categories) {
+ foreach (var item in collection) {
+ if (tasks.Contains (item))
+ continue;
+ tasks [i++] = item;
+ yield return item;
+ }
+ }
+ }
+
+ void AddCollection (Category category)
+ {
+ categories.Add (category);
+ if (categories.Contains (category))
+ category.CollectionChanged += HandleCollectionChanged;
+ }
+
+ bool RemoveCollection (Category category)
+ {
+ if (categories.Contains (category))
+ category.CollectionChanged -= HandleCollectionChanged;
+ return categories.Remove (category);
+ }
+
+ void HandleCollectionChanged (object sender, NotifyCollectionChangedEventArgs e)
+ {
+ OnCollectionChanged (e);
+ }
+
+ void HandleSourceCollectionChanged (object sender, NotifyCollectionChangedEventArgs e)
+ {
+ switch (e.Action) {
+ case NotifyCollectionChangedAction.Add:
+ AddCollection (e.NewItems [0] as Category);
+ break;
+ case NotifyCollectionChangedAction.Remove:
+ RemoveCollection (e.OldItems [0] as Category);
+ break;
+ }
+ }
+
+ SortedNotifyCollection<Category> categories;
+ bool disposed;
+ }
+}
diff --git a/src/libtasque/ReadOnlySortedNotifyCollection.cs b/src/libtasque/ReadOnlySortedNotifyCollection.cs
index cf977d8..d06ca82 100644
--- a/src/libtasque/ReadOnlySortedNotifyCollection.cs
+++ b/src/libtasque/ReadOnlySortedNotifyCollection.cs
@@ -31,30 +31,23 @@ using System.ComponentModel;
namespace Tasque
{
- public class ReadOnlySortedNotifyCollection<T> : ICollection<T>, INotifyCollectionChanged
+ public class ReadOnlySortedNotifyCollection<T> : ICollection<T>, INotifyCollectionChanged, IDisposable
where T : INotifyPropertyChanged, IComparable<T>
{
public ReadOnlySortedNotifyCollection (SortedNotifyCollection<T> source)
{
if (source == null)
throw new ArgumentNullException ("source");
-
+
+ source.CollectionChanged += HandleCollectionChanged;
items = source;
}
-
- #region IEnumerable implementation
- IEnumerator IEnumerable.GetEnumerator ()
- {
- return GetEnumerator ();
- }
-
- public IEnumerator<T> GetEnumerator ()
- {
- return items.GetEnumerator ();
- }
- #endregion
-
+
#region ICollection implementation
+ public int Count { get { return CountProtected; } }
+
+ public bool IsReadOnly { get { return true; } }
+
void ICollection<T>.Add (T item)
{
throw new NotSupportedException ("This collection is read-only.");
@@ -67,28 +60,88 @@ namespace Tasque
public bool Contains (T item)
{
- return items.Contains (item);
+ return ContainsProtected (item);
}
public void CopyTo (T[] array, int arrayIndex)
{
- items.CopyTo (array, arrayIndex);
+ CopyToProtected (array, arrayIndex);
}
bool ICollection<T>.Remove (T item)
{
throw new NotSupportedException ("This collection is read-only.");
}
-
- public int Count { get { return items.Count; } }
-
- public bool IsReadOnly { get { return true; } }
#endregion
-
+
+ #region IEnumerable implementation
+ public IEnumerator<T> GetEnumerator ()
+ {
+ return GetEnumeratorProtected ();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator ()
+ {
+ return GetEnumerator ();
+ }
+ #endregion
+
#region INotifyCollectionChanged implementation
- public event NotifyCollectionChangedEventHandler CollectionChanged {
- add { items.CollectionChanged += value; }
- remove { items.CollectionChanged -= value; }
+ public event NotifyCollectionChangedEventHandler CollectionChanged;
+
+ void HandleCollectionChanged (object sender, NotifyCollectionChangedEventArgs e)
+ {
+ OnCollectionChanged (e);
+ }
+ #endregion
+
+ #region IDisposable implementation
+ public void Dispose ()
+ {
+ Dispose (true);
+ GC.SuppressFinalize (this);
+ }
+
+ protected virtual void Dispose (bool disposing)
+ {
+ if (!disposed && disposing) {
+ items.CollectionChanged -= HandleCollectionChanged;
+ disposed = true;
+ }
+ }
+
+ ~ReadOnlySortedNotifyCollection ()
+ {
+ Dispose (false);
+ }
+
+ bool disposed;
+ #endregion
+
+ #region Internal
+ internal protected ReadOnlySortedNotifyCollection () {}
+
+ internal protected virtual int CountProtected { get { return items.Count; } }
+
+ internal protected virtual bool ContainsProtected (T item)
+ {
+ return items.Contains (item);
+ }
+
+ internal protected virtual void CopyToProtected (T[] array, int arrayIndex)
+ {
+ items.CopyTo (array, arrayIndex);
+ }
+
+ internal protected virtual IEnumerator<T> GetEnumeratorProtected ()
+ {
+ return items.GetEnumerator ();
+ }
+
+ internal protected void OnCollectionChanged (NotifyCollectionChangedEventArgs e)
+ {
+ if (CollectionChanged != null)
+ CollectionChanged (this, e);
}
#endregion
diff --git a/src/libtasque/libtasque.csproj b/src/libtasque/libtasque.csproj
index 3cdb2c3..643f283 100644
--- a/src/libtasque/libtasque.csproj
+++ b/src/libtasque/libtasque.csproj
@@ -72,6 +72,7 @@
<Compile Include="CompletedTaskGroupModel.cs" />
<Compile Include="Application.cs" />
<Compile Include="Dispatcher.cs" />
+ <Compile Include="BackendTaskCollection.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]