[tasque/transition: 68/213] Change Categories type from Gtk.TreeModel to ObservableCollection<T>.



commit 236ee81e81f013fd89972d4e6e5ad58bdc45ab08
Author: Antonius Riha <antoniusriha gmail com>
Date:   Mon Jul 9 16:10:16 2012 +0200

    Change Categories type from Gtk.TreeModel to ObservableCollection<T>.
    
    * ICategory.cs: must be INotifyPropertyChanged in order to work with CollectionView.
    
    +++
    NOTE: This should not be necessary and must be fixed in CollectionView, preferably by adopting the .NET implementation of CollectionView/ListCollectionView/...
    Issue has been filed on Github.
    +++

 src/libtasque/IBackend.cs                  |    6 +-
 src/libtasque/ICategory.cs                 |   34 ++++++++++++---
 src/tasque/AllCategory.cs                  |   11 +++++
 src/tasque/Backends/Dummy/DummyBackend.cs  |   65 ++++++++--------------------
 src/tasque/Backends/Dummy/DummyCategory.cs |   14 ++++++
 src/tasque/CompletedTaskGroup.cs           |   17 +------
 src/tasque/PreferencesDialog.cs            |   33 +++-----------
 src/tasque/RemoteControl.cs                |   63 ++++++---------------------
 src/tasque/TaskGroup.cs                    |   22 ++-------
 src/tasque/TaskWindow.cs                   |   52 +++++++++-------------
 10 files changed, 124 insertions(+), 193 deletions(-)
---
diff --git a/src/libtasque/IBackend.cs b/src/libtasque/IBackend.cs
index 8bfaf4a..2917256 100644
--- a/src/libtasque/IBackend.cs
+++ b/src/libtasque/IBackend.cs
@@ -46,9 +46,9 @@ namespace Tasque.Backends
 		/// <value>
 		/// This returns all the ICategory items from the backend.
 		/// </value>
-		Gtk.TreeModel Categories {
-			get;
-		}
+		ObservableCollection<ICategory> Categories { get; }
+		
+		IEnumerable SortedCategories { get;	}
 		
 		/// <value>
 		/// Indication that the backend has enough information
diff --git a/src/libtasque/ICategory.cs b/src/libtasque/ICategory.cs
index 3ba1794..08427d6 100644
--- a/src/libtasque/ICategory.cs
+++ b/src/libtasque/ICategory.cs
@@ -3,17 +3,39 @@
 //
 // To change standard headers go to Edit->Preferences->Coding->Standard Headers
 //
-
+// 
+// ICategory.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.ComponentModel;
 
 namespace Tasque
 {
-	public interface ICategory
+	public interface ICategory : IComparable<ICategory>, INotifyPropertyChanged
 	{
-		string Name
-		{
-			get;
-		}
+		string Name	{ get; }
 		
 		bool ContainsTask(ITask task);
 	}
diff --git a/src/tasque/AllCategory.cs b/src/tasque/AllCategory.cs
index 0e5505b..dc45b56 100644
--- a/src/tasque/AllCategory.cs
+++ b/src/tasque/AllCategory.cs
@@ -50,5 +50,16 @@ namespace Tasque
 			categoriesToHide =
 				preferences.GetStringList (Preferences.HideInAllCategory);
 		}
+
+		#region IComparable implementation
+		public int CompareTo (ICategory other)
+		{
+			return -1;
+		}
+		#endregion
+
+		#region INotifyPropertyChanged implementation
+		public event PropertyChangedEventHandler PropertyChanged;
+		#endregion
 	}
 }
diff --git a/src/tasque/Backends/Dummy/DummyBackend.cs b/src/tasque/Backends/Dummy/DummyBackend.cs
index be9eb9d..fa04125 100644
--- a/src/tasque/Backends/Dummy/DummyBackend.cs
+++ b/src/tasque/Backends/Dummy/DummyBackend.cs
@@ -19,12 +19,9 @@ namespace Tasque.Backends.Dummy
 		/// Key   = Task ID
 		/// Value = Gtk.TreeIter in taskStore
 		/// </summary>
-		private int newTaskId;
-		private bool initialized;
-		private bool configured = true;
-		
-		private Gtk.ListStore categoryListStore;
-		private Gtk.TreeModelSort sortedCategoriesModel;
+		int newTaskId;
+		bool initialized;
+		bool configured = true;
 
 		public event BackendInitializedHandler BackendInitialized;
 		public event BackendSyncStartedHandler BackendSyncStarted;
@@ -39,19 +36,18 @@ namespace Tasque.Backends.Dummy
 			initialized = false;
 			newTaskId = 0;
 			Tasks = new ObservableCollection<ITask> ();
-			var cv =  new CollectionView<ITask> (Tasks);
+			var cvTasks =  new CollectionView<ITask> (Tasks);
 			/*
 			 * this invokes the default comparer, which in turn
 			 * will use the IComparable implmentation of Task
 			 */
-			cv.SortDescriptions.Add (new SortDescription ());
-			SortedTasks = cv;
-			
-			categoryListStore = new Gtk.ListStore (typeof(ICategory));
+			cvTasks.SortDescriptions.Add (new SortDescription ());
+			SortedTasks = cvTasks;
 			
-			sortedCategoriesModel = new Gtk.TreeModelSort (categoryListStore);
-			sortedCategoriesModel.SetSortFunc (0, new Gtk.TreeIterCompareFunc (CompareCategorySortFunc));
-			sortedCategoriesModel.SetSortColumnId (0, Gtk.SortType.Ascending);
+			Categories = new ObservableCollection<ICategory> ();
+			var cvCategories = new CollectionView<ICategory> (Categories);
+			cvCategories.SortDescriptions.Add (new SortDescription ());
+			SortedCategories = cvCategories;
 		}
 		
 		#region Public Properties
@@ -69,9 +65,9 @@ namespace Tasque.Backends.Dummy
 		/// <value>
 		/// This returns all the task lists (categories) that exist.
 		/// </value>
-		public Gtk.TreeModel Categories {
-			get { return sortedCategoriesModel; }
-		}
+		public IEnumerable SortedCategories { get; private set; }
+		
+		public ObservableCollection<ICategory> Categories { get; private set; }
 		
 		/// <value>
 		/// Indication that the dummy backend is configured
@@ -116,29 +112,23 @@ namespace Tasque.Backends.Dummy
 		
 		public void Initialize ()
 		{
-			Gtk.TreeIter iter;
-			
 			//
 			// Add in the "All" Category
 			//
-			AllCategory allCategory = new Tasque.AllCategory ();
-			iter = categoryListStore.Append ();
-			categoryListStore.SetValue (iter, 0, allCategory);
+			AllCategory allCategory = new AllCategory ();
+			Categories.Add (allCategory);
 			
 			//
 			// Add in some fake categories
 			//
 			homeCategory = new DummyCategory ("Home");
-			iter = categoryListStore.Append ();
-			categoryListStore.SetValue (iter, 0, homeCategory);
+			Categories.Add (homeCategory);
 			
 			workCategory = new DummyCategory ("Work");
-			iter = categoryListStore.Append ();
-			categoryListStore.SetValue (iter, 0, workCategory);
+			Categories.Add (workCategory);
 			
 			projectsCategory = new DummyCategory ("Projects");
-			iter = categoryListStore.Append ();
-			categoryListStore.SetValue (iter, 0, projectsCategory);
+			Categories.Add (projectsCategory);
 			
 			//
 			// Add in some fake tasks
@@ -240,25 +230,6 @@ namespace Tasque.Backends.Dummy
 		#endregion // Public Methods
 		
 		#region Private Methods
-
-		static int CompareCategorySortFunc (Gtk.TreeModel model,
-											Gtk.TreeIter a,
-											Gtk.TreeIter b)
-		{
-			ICategory categoryA = model.GetValue (a, 0) as ICategory;
-			ICategory categoryB = model.GetValue (b, 0) as ICategory;
-			
-			if (categoryA == null || categoryB == null)
-				return 0;
-			
-			if (categoryA is Tasque.AllCategory)
-				return -1;
-			else if (categoryB is Tasque.AllCategory)
-				return 1;
-			
-			return (categoryA.Name.CompareTo (categoryB.Name));
-		}
-
 		public void UpdateTask (DummyTask task)
 		{
 			if (!Tasks.Contains (task))
diff --git a/src/tasque/Backends/Dummy/DummyCategory.cs b/src/tasque/Backends/Dummy/DummyCategory.cs
index 5ef4e6c..2d68ee1 100644
--- a/src/tasque/Backends/Dummy/DummyCategory.cs
+++ b/src/tasque/Backends/Dummy/DummyCategory.cs
@@ -33,5 +33,19 @@ namespace Tasque.Backends.Dummy
 				return false;
 		}
 		
+		public int CompareTo (ICategory other)
+		{
+			if (other == null)
+				return -1;
+			
+			if (other is AllCategory)
+				return 1;
+			
+			return name.CompareTo (other.Name);
+		}
+
+		#region INotifyPropertyChanged implementation
+		public event PropertyChangedEventHandler PropertyChanged;
+		#endregion
 	}
 }
diff --git a/src/tasque/CompletedTaskGroup.cs b/src/tasque/CompletedTaskGroup.cs
index 43e5c0b..d41fbf4 100644
--- a/src/tasque/CompletedTaskGroup.cs
+++ b/src/tasque/CompletedTaskGroup.cs
@@ -114,21 +114,10 @@ namespace Tasque
 		{
 			ICategory foundCategory = null;
 			
-			string cat = Application.Preferences.Get (
-							Preferences.SelectedCategoryKey);
+			string cat = Application.Preferences.Get (Preferences.SelectedCategoryKey);
 			if (cat != null) {
-				TreeIter iter;
-				TreeModel model = Application.Backend.Categories;
-				
-				if (model.GetIterFirst (out iter)) {
-					do {
-						ICategory category = model.GetValue (iter, 0) as ICategory;
-						if (category.Name.CompareTo (cat) == 0) {
-							foundCategory = category;
-							break;
-						}
-					} while (model.IterNext (ref iter));
-				}
+				var categories = Application.Backend.Categories;
+				foundCategory = categories.SingleOrDefault (c => c.Name == cat);
 			}
 			
 			return foundCategory;
diff --git a/src/tasque/PreferencesDialog.cs b/src/tasque/PreferencesDialog.cs
index 6c288cb..5e586f5 100644
--- a/src/tasque/PreferencesDialog.cs
+++ b/src/tasque/PreferencesDialog.cs
@@ -31,6 +31,7 @@ using System.Collections.Generic;
 using Gtk;
 using Mono.Unix;
 using Tasque.Backends;
+using CollectionTransforms;
 
 namespace Tasque
 {
@@ -50,7 +51,7 @@ namespace Tasque
 		Dictionary<int, IBackend> backendComboMap; // track backends
 		int 					selectedBackend;
 		Gtk.CheckButton			showCompletedTasksCheckButton;
-		Gtk.TreeModelFilter		filteredCategories;
+		CollectionView<ICategory> filteredCategories;
 		List<string>			categoriesToHide;
 		Gtk.TreeView			categoriesTree;
 
@@ -593,36 +594,16 @@ namespace Tasque
 			}
 			
 			IBackend backend = backendComboMap [selectedBackend];
-			filteredCategories = new TreeModelFilter (backend.Categories, null);
-			filteredCategories.VisibleFunc = FilterFunc;
-			categoriesTree.Model = filteredCategories;
+			filteredCategories = new CollectionView<ICategory> (backend.SortedCategories);
+			// Filter out the AllCategory
+			filteredCategories.Filter = c => c != null && !(c is AllCategory);
+			var adapter = new TreeModelListAdapter<ICategory> (filteredCategories);
+			categoriesTree.Model = adapter;
 		}
 		
 		void OnShown (object sender, EventArgs args)
 		{
 			RebuildCategoryTree ();
 		}
-		
-		/// <summary>
-		/// Filter out the AllCategory
-		/// </summary>
-		/// <param name="model">
-		/// A <see cref="Gtk.TreeModel"/>
-		/// </param>
-		/// <param name="iter">
-		/// A <see cref="Gtk.TreeIter"/>
-		/// </param>
-		/// <returns>
-		/// A <see cref="System.Boolean"/>
-		/// </returns>
-		protected bool FilterFunc (Gtk.TreeModel model,
-										   Gtk.TreeIter iter)
-		{
-			ICategory category = model.GetValue (iter, 0) as ICategory;
-			if (category == null || category is AllCategory)
-				return false;
-			
-			return true;
-		}
 	}
 }
diff --git a/src/tasque/RemoteControl.cs b/src/tasque/RemoteControl.cs
index df51eab..d2aea30 100644
--- a/src/tasque/RemoteControl.cs
+++ b/src/tasque/RemoteControl.cs
@@ -85,37 +85,23 @@ namespace Tasque
 		public string CreateTask (string categoryName, string taskName,
 						bool enterEditMode, bool parseDate)
 		{
-			Gtk.TreeIter iter;
-			Gtk.TreeModel model = Application.Backend.Categories;
+			var categories = Application.Backend.Categories;
 			
 			//
 			// Validate the input parameters.  Don't allow null or empty strings
 			// be passed-in.
 			//
-			if (categoryName == null || categoryName.Trim () == string.Empty
-					|| taskName == null || taskName.Trim () == string.Empty) {
+			if (string.IsNullOrWhiteSpace (categoryName) || string.IsNullOrWhiteSpace (taskName))
 				return string.Empty;
-			}
 			
 			//
 			// Look for the specified category
 			//
-			if (!model.GetIterFirst (out iter)) {
-				return string.Empty;
-			}
-			
 			ICategory category = null;
-			do {
-				ICategory tempCategory = model.GetValue (iter, 0) as ICategory;
-				if (tempCategory.Name.ToLower ().CompareTo (categoryName.ToLower ()) == 0) {
-					// Found a match
-					category = tempCategory;
-				}
-			} while (model.IterNext (ref iter));
+			categories.SingleOrDefault (c => c.Name.ToLower () == categoryName.ToLower ());
 			
-			if (category == null) {
+			if (category == null)
 				return string.Empty;
-			}
 			
 			// If enabled, attempt to parse due date information
 			// out of the taskName.
@@ -167,20 +153,14 @@ namespace Tasque
 		public string[] GetCategoryNames ()
 		{
 			List<string> categories = new List<string> ();
-			string[] emptyArray = categories.ToArray ();
-			
-			Gtk.TreeIter iter;
-			Gtk.TreeModel model = Application.Backend.Categories;
-			
-			if (!model.GetIterFirst (out iter))
-				return emptyArray;
+			var model = Application.Backend.SortedCategories;
 			
-			do {
-				ICategory category = model.GetValue (iter, 0) as ICategory;
-				if (category is AllCategory)
-					continue; // Prevent the AllCategory from being returned
-				categories.Add (category.Name);
-			} while (model.IterNext (ref iter));
+			foreach (var item in model) {
+				if (item is AllCategory)
+					continue;
+				
+				categories.Add (((ICategory)item).Name);
+			}
 			
 			return categories.ToArray ();
 		}
@@ -280,29 +260,14 @@ namespace Tasque
 		/// A <see cref="System.Boolean"/>, true for success, false
 		/// for failure.
 		/// </returns>
-		public bool SetCategoryForTaskById (string id,
-							string categoryName)
+		public bool SetCategoryForTaskById (string id, string categoryName)
 		{
 			ITask task = GetTaskById (id);
 			if (task == null)
-			{
-				return false;
-			}
-			Gtk.TreeIter iter;
-			Gtk.TreeModel model = Application.Backend.Categories;
-			
-			if (!model.GetIterFirst (out iter))
 				return false;
 			
-			do {
-				ICategory category = model.GetValue (iter, 0) as ICategory;
-				if (string.Compare(category.Name,categoryName)==0)
-				{
-					task.Category = category;
-					return true;
-				}
-			} while (model.IterNext (ref iter));
-			return false;
+			var categories = Application.Backend.Categories;
+			return categories.Contains (task.Category);
 		}
 		
 		/// <summary>
diff --git a/src/tasque/TaskGroup.cs b/src/tasque/TaskGroup.cs
index 0e4d29f..0fb2154 100644
--- a/src/tasque/TaskGroup.cs
+++ b/src/tasque/TaskGroup.cs
@@ -26,8 +26,9 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 using System;
-using Gtk;
 using System.Collections;
+using System.Linq;
+using Gtk;
 
 namespace Tasque
 {
@@ -375,7 +376,7 @@ namespace Tasque
 		/// <returns>
 		/// A <see cref="ICategory"/>
 		/// </returns>
-		private ICategory GetSelectedCategory ()
+		ICategory GetSelectedCategory ()
 		{
 			// TODO: Move this code into some function in the backend/somewhere
 			// with the signature of GetCategoryForName (string catName):ICategory
@@ -383,21 +384,8 @@ namespace Tasque
 				Application.Preferences.Get (Preferences.SelectedCategoryKey);
 			
 			if (selectedCategoryName != null) {
-				Gtk.TreeIter iter;
-				Gtk.TreeModel model = Application.Backend.Categories;
-
-				// Iterate through (yeah, I know this is gross!) and find the
-				// matching category
-				if (model.GetIterFirst (out iter)) {
-					do {
-						ICategory cat = model.GetValue (iter, 0) as ICategory;
-						if (cat == null)
-							continue; // Needed for some reason to prevent crashes from some backends
-						if (cat.Name.CompareTo (selectedCategoryName) == 0) {
-							return cat;
-						}
-					} while (model.IterNext (ref iter));
-				}
+				var categories = Application.Backend.Categories;
+				return categories.SingleOrDefault (c => c.Name == selectedCategoryName);
 			}
 			
 			return null;
diff --git a/src/tasque/TaskWindow.cs b/src/tasque/TaskWindow.cs
index 1b80947..a71368a 100644
--- a/src/tasque/TaskWindow.cs
+++ b/src/tasque/TaskWindow.cs
@@ -35,6 +35,8 @@ using Gtk;
 using Mono.Unix;
 
 using Tasque.Backends;
+using CollectionTransforms;
+using System.Collections;
 
 namespace Tasque
 {
@@ -356,7 +358,8 @@ namespace Tasque
 			
 			// Set up the combo box (after the above to set the current filter)
 
-			categoryComboBox.Model = Application.Backend.Categories;		
+			var adapter = new TreeModelListAdapter<ICategory> (Application.Backend.SortedCategories);
+			categoryComboBox.Model = adapter;	
 
 			// Read preferences for the last-selected category and select it
 			string selectedCategoryName =
@@ -689,24 +692,18 @@ namespace Tasque
 			}
 		}
 		
-		private void RebuildAddTaskMenu (Gtk.TreeModel categoriesModel)
+		void RebuildAddTaskMenu (CollectionView<ICategory> categories)
 		{
-			Gtk.Menu menu = new Menu ();
+			Menu menu = new Menu ();
 			
-			Gtk.TreeIter iter;
-			if (categoriesModel.GetIterFirst (out iter)) {
-				do {
-					ICategory category =
-						categoriesModel.GetValue (iter, 0) as ICategory;
-					
-					if (category is AllCategory)
-						continue; // Skip this one
-					
-					CategoryMenuItem item = new CategoryMenuItem (category);
-					item.Activated += OnNewTaskByCategory;
-					item.ShowAll ();
-					menu.Add (item);
-				} while (categoriesModel.IterNext (ref iter));
+			foreach (var cat in categories) {
+				if (cat is AllCategory)
+					continue;
+				
+				CategoryMenuItem item = new CategoryMenuItem ((ICategory)cat);
+				item.Activated += OnNewTaskByCategory;
+				item.ShowAll ();
+				menu.Add (item);
 			}
 			
 			addTaskButton.Menu = menu;
@@ -1081,26 +1078,19 @@ namespace Tasque
 					 * here in order to enable changing categories. The list of available categories
 					 * is pre-filtered as to not contain the current category and the AllCategory.
 					 */
-					TreeModelFilter filteredCategories = new TreeModelFilter(Application.Backend.Categories, null);
-					filteredCategories.VisibleFunc = delegate(TreeModel t, TreeIter i) {
-						ICategory category = t.GetValue (i, 0) as ICategory;
-						if (category == null || category is AllCategory || category.Equals(clickedTask.Category))
-							return false;
-						return true;
-					};
+					var cvCategories = new CollectionView<ICategory> (Application.Backend.SortedCategories);
+					cvCategories.Filter = c => c != null && !(c is AllCategory) && !c.Equals(clickedTask.Category);
 
 					// The categories submenu is only created in case we actually provide at least one category.
-					if (filteredCategories.GetIterFirst(out iter))
-					{
+					if (cvCategories.Count > 0) {
 						Menu categoryMenu = new Menu();
 						CategoryMenuItem categoryItem;
 
-						filteredCategories.Foreach(delegate(TreeModel t, TreePath p, TreeIter i) {
-							categoryItem = new CategoryMenuItem((ICategory)t.GetValue(i, 0));
+						foreach (var cat in cvCategories) {
+							categoryItem = new CategoryMenuItem((ICategory)cat);
 							categoryItem.Activated += OnChangeCategory;
 							categoryMenu.Add(categoryItem);
-							return false;
-						});
+						}
 					
 						// TODO Needs translation.
 						item = new ImageMenuItem(Catalog.GetString("_Change category"));
@@ -1186,7 +1176,7 @@ namespace Tasque
 				status = string.Format (Catalog.GetString ("Tasks loaded: {0}"), now);
 				TaskWindow.lastLoadedTime = now;
 				TaskWindow.ShowStatus (status);
-				RebuildAddTaskMenu (Application.Backend.Categories);
+				RebuildAddTaskMenu ((CollectionView<ICategory>)Application.Backend.SortedCategories);
 				addTaskEntry.Sensitive = true;
 				categoryComboBox.Sensitive = true;
 				// Keep insensitive text color



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]