[model] make GtkTreeModel more robust



commit 4e215bfbc866834be56bc2102a3484b2e6aca8e4
Author: Ryan Lortie <desrt desrt ca>
Date:   Thu Mar 11 21:35:59 2010 -0500

    make GtkTreeModel more robust

 gtk/mg.vala        |    8 +--
 gtk/model-gtk.vala |  156 ++++++++++++++++++++++++++++++++++++++--------------
 2 files changed, 117 insertions(+), 47 deletions(-)
---
diff --git a/gtk/mg.vala b/gtk/mg.vala
index 3262cdc..025acd8 100644
--- a/gtk/mg.vala
+++ b/gtk/mg.vala
@@ -1,20 +1,16 @@
 Gtk.TreeView v;
 Model.List list;
 
-bool setup () {
-  v.set_model (new Model.GtkModel (list, {typeof(string),typeof(string)}, {"name", "type"}, "contents"));
-  return false;
-}
-
 void main (string[]args) {
   Gtk.init (ref args);
 
   var w = new Gtk.Window (Gtk.WindowType.TOPLEVEL);
+  w.set_default_size (800, 600);
   list = new FS.Directory (File.new_for_path ("/home/desrt/Desktop/small"));
   v = new Gtk.TreeView ();
   v.insert_column_with_attributes (0, "name", new Gtk.CellRendererText (), "text", 0);
   v.insert_column_with_attributes (0, "type", new Gtk.CellRendererText (), "text", 1);
-  Timeout.add (1000, setup);
+  v.set_model (new Model.GtkModel (list, {typeof(string),typeof(string)}, {"name", "type"}, "contents"));
   var sc = new Gtk.ScrolledWindow (null, null);
   sc.add (v);
   w.add (sc);
diff --git a/gtk/model-gtk.vala b/gtk/model-gtk.vala
index 3377418..e5ec1b7 100644
--- a/gtk/model-gtk.vala
+++ b/gtk/model-gtk.vala
@@ -1,7 +1,7 @@
 namespace Model {
 	class ListTracker {
 		internal DictionaryTracker? first;
-		//DictionaryTracker[]? array;
+		DictionaryTracker[]? array;
 		internal int length;
 		ulong changed_id;
 
@@ -12,17 +12,19 @@ namespace Model {
 		DictionaryTracker **cached_child;
 		ulong cached_child_index;
 
+		internal Gtk.TreePath get_tree_path () {
+			if (parent != null) {
+				return ((!) parent).get_tree_path ();
+			} else {
+				return new Gtk.TreePath ();
+			}
+		}
+
 		void source_changed (Model.List source, ulong position, ulong deleted, ulong inserted, bool more) {
-			Gtk.TreePath path;
 			bool was_empty;
 
 			was_empty = length == 0;
-
-			if (parent != null) {
-				path = parent.get_tree_path ();
-			} else {
-				path = new Gtk.TreePath ();
-			}
+			array = null;
 
 			/* seek to position */
 			if (cached_child_index > position) {
@@ -37,6 +39,7 @@ namespace Model {
 				}
 			}
 
+			var path = get_tree_path ();
 			path.append_index ((int) position);
 
 			while (deleted --> 0) {
@@ -75,9 +78,23 @@ namespace Model {
 
 			if (more == false) {
 				cached_child = null;
+				build_array ();
 			}
 		}
 
+		void build_array () {
+			var link = first;
+
+			array = new DictionaryTracker[length];
+			for (var i = 0; i < length; i++) {
+				array[i] = link;
+				link.index = i;
+				link = link.next;
+			}
+
+			assert (link == null);
+		}
+
 		internal ListTracker (GtkModel model, Model.List source, DictionaryTracker? parent = null) {
 			this.parent = parent;
 			this.source = source;
@@ -90,16 +107,21 @@ namespace Model {
 			}
 
 			changed_id = source.changed.connect (source_changed);
+			build_array ();
 		}
 
 		internal DictionaryTracker? get_nth (int n) {
-			var dt = first;
+			if (array != null) {
+				return array[n];
+			} else {
+				var dt = first;
 
-			while (dt != null && n --> 0) {
-				dt = dt.next;
-			}
+				while (dt != null && n --> 0) {
+					dt = dt.next;
+				}
 
-			return dt;
+				return dt;
+			}
 		}
 
 		internal DictionaryTracker? get_for_path (Gtk.TreePath path, int depth = 0) {
@@ -116,6 +138,45 @@ namespace Model {
 			return item;
 		}
 
+		internal int find (DictionaryTracker child) {
+			if (array != null) {
+				assert (array[child.index] == child);
+				return child.index;
+			} else {
+				var link = first;
+				var i = 0;
+
+				while (link != child) {
+					link = link.next;
+					i++;
+				}
+
+				return i;
+			}
+		}
+
+		internal void delete_all () {
+			if (length > 0) {
+				var path = get_tree_path ();
+				path.append_index (0);
+
+				array = null;
+				while (first != null) {
+					model.row_deleted (path);
+					first = first.next;
+					length--;
+				}
+
+				assert (length == 0);
+				path.up ();
+
+				Gtk.TreeIter iter;
+				if (model.write_iter (out iter, parent)) {
+					model.row_has_child_toggled (path, iter);
+				}
+			}
+		}
+
 		~ListTracker () {
 			source.disconnect (changed_id);
 		}
@@ -124,66 +185,79 @@ namespace Model {
 	class DictionaryTracker {
 		Model.Reference? children_reference;
 		internal ListTracker? children;
+		ulong children_handler;
+
+		Model.Reference[] references;
+		ulong[] reference_handlers;
 
 		internal weak ListTracker siblings;
-		internal Model.Dictionary source;
-		weak GtkModel model;
+		internal int index;
 
 		internal DictionaryTracker? next;
 
 		void children_reference_changed (Model.Reference reference) {
 			var list = reference.get_value () as Model.List;
 
+			if (children != null) {
+				children.delete_all ();
+			}
+
 			if (list != null) {
-				children = new ListTracker (model, list, this);
+				children = new ListTracker (siblings.model, list, this);
 			} else {
 				children = null;
 			}
 		}
 
+		void reference_changed (Model.Reference reference) {
+			var path = get_tree_path ();
+			Gtk.TreeIter iter;
+
+			siblings.model.write_iter (out iter, this);
+			siblings.model.row_changed (path, iter);
+		}
+
 		public DictionaryTracker (ListTracker siblings, Model.Dictionary source, DictionaryTracker? next) {
-			this.model = siblings.model;
+			var model = siblings.model;
+
 			this.siblings = siblings;
-			this.source = source;
 			this.next = next;
 
 			if (model.children_key != null) {
 				children_reference = source.get_reference ((!) model.children_key);
-				children_reference.changed += children_reference_changed;
+				children_handler = children_reference.changed.connect (children_reference_changed);
 				children_reference_changed ((!) children_reference);
 			}
-		}
 
-		internal int get_index () {
-			var chain = siblings.first;
-			var i = 0;
-
-			while (chain != this) {
-				chain = chain.next;
-				i++;
+			references = new Model.Reference[model.keys.length];
+			reference_handlers = new ulong[model.keys.length];
+			for (var i = 0; i < model.keys.length; i++) {
+				references[i] = source.get_reference (model.keys[i]);
+				reference_handlers[i] = references[i].changed.connect (reference_changed);
 			}
-
-			return i;
 		}
 
 		internal Gtk.TreePath get_tree_path () {
-			Gtk.TreePath path;
-
-			if (siblings.parent != null) {
-				path = siblings.parent.get_tree_path ();
-			} else {
-				path = new Gtk.TreePath ();
-			}
+			var path = siblings.get_tree_path ();
+			path.append_index (siblings.find (this));
+			return path;
+		}
 
-			path.append_index (get_index ());
+		internal Model.Object get_value (int index) {
+			return references[index].get_value ();
+		}
 
-			return path;
+		~DictionaryTracker () {
+			children_reference.disconnect (children_handler);
+			for (var i = 0; i < references.length; i++) {
+				references[i].disconnect (reference_handlers[i]);
+			}
 		}
 	}
 
 	public class GtkModel : GLib.Object, Gtk.TreeModel {
 		internal string? children_key;
-		string[] keys;
+		internal string[] keys;
 		Type[] types;
 
 		ListTracker root;
@@ -219,7 +293,7 @@ namespace Model {
 
 		void get_value (Gtk.TreeIter iter, int column, out GLib.Value value) {
 			var dt = iter_to_dt (iter);
-			var object = dt.source.get_value (keys[column]);
+			var object = dt.get_value (column);
 
 			value.init (types[column]);
 
@@ -316,4 +390,4 @@ namespace Model {
 	}
 }
 
-// vim:ts=8 sw=8 noet:
+// vim:ts=4 sw=4 noet:



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