[ease] [general] Document is based on a list store



commit e3108014812893a62180a25f5c40a5f9e364abac
Author: Nate Stedman <natesm gmail com>
Date:   Sun Jul 25 22:33:18 2010 -0400

    [general] Document is based on a list store
    
    - Added iterable ListStore and TreeModel.
    - Slides can be reordered by the user.
    - SlideButtonPanel uses the document's mode,
      no more need for syncing two separate data
      structures

 Makefile.am                      |    1 +
 src/ease-document.vala           |  130 +++++++++++++++++++++++++++++---------
 src/ease-editor-window.vala      |    2 +-
 src/ease-iterables.vala          |   74 +++++++++++++++++++++
 src/ease-player.vala             |    4 +-
 src/ease-slide-button-panel.vala |   91 ++++++++++----------------
 src/ease-slide.vala              |   10 ++-
 7 files changed, 218 insertions(+), 94 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 811df46..266b630 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -32,6 +32,7 @@ ease_SOURCES = \
 	src/ease-inspector-pane.vala \
 	src/ease-inspector.vala \
 	src/ease-inspector-window.vala \
+	src/ease-iterables.vala \
 	src/ease-media-element.vala \
 	src/ease-open-dialog.vala \
 	src/ease-player.vala \
diff --git a/src/ease-document.vala b/src/ease-document.vala
index 209fa30..641be11 100644
--- a/src/ease-document.vala
+++ b/src/ease-document.vala
@@ -44,6 +44,21 @@ public class Ease.Document : GLib.Object
 	 * Path of the Document's { link Theme} data files.
 	 */
 	public const string THEME_PATH = "Theme";
+	
+	/**
+	 * Model column count.
+	 */
+	private const int MODEL_COLS = 2;
+	
+	/**
+	 * Model Slide column.
+	 */
+	public const int COL_SLIDE = 0;
+	
+	/**
+	 * Model pixbuf column.
+	 */
+	public const int COL_PIXBUF = 1;
 
 	/**
 	 * The { link Theme} linked to this Document.
@@ -79,7 +94,9 @@ public class Ease.Document : GLib.Object
 	/**
 	 * All { link Slide}s in this Document.
 	 */
-	public Gee.LinkedList<Slide> slides = new Gee.LinkedList<Slide>();
+	public Iterable.ListStore slides = new Iterable.ListStore(
+		{ typeof(Slide),
+		  typeof(Gdk.Pixbuf) });
 	
 	/**
 	 * The number of { link Slide}s in the Document.
@@ -123,12 +140,12 @@ public class Ease.Document : GLib.Object
 		height = (int)root.get_string_member("height").to_int();
 		
 		// add all slides
-		var slides = root.get_array_member("slides");
+		var json_slides = root.get_array_member("slides");
 		
-		for (var i = 0; i < slides.get_length(); i++)
+		for (var i = 0; i < json_slides.get_length(); i++)
 		{
-			var node = slides.get_object_element(i);
-			add_slide(length, new Slide.from_json(node));
+			var node = json_slides.get_object_element(i);
+			append_slide(new Slide.from_json(node));
 		}
 		
 		// get the document's theme
@@ -184,8 +201,10 @@ public class Ease.Document : GLib.Object
 		
 		// add the document's slides
 		var slides_json = new Json.Array();
-		foreach (var s in slides)
+		Slide s;
+		foreach (var itr in slides)
 		{
+			slides.get(itr, COL_SLIDE, out s);
 			slides_json.add_element(s.to_json());
 		}
 		obj.set_array_member("slides", slides_json);
@@ -212,7 +231,9 @@ public class Ease.Document : GLib.Object
 	public void add_slide(int index, Slide s)
 	{
 		s.parent = this;
-		slides.insert(index, s);
+		Gtk.TreeIter itr;
+		slides.insert(out itr, index);
+		slides.set(itr, COL_SLIDE, s);
 		slide_added(s, index);
 	}
 	
@@ -221,26 +242,41 @@ public class Ease.Document : GLib.Object
 	 */
 	public void append_slide(Slide s)
 	{
-		s.parent = this;
-		slides.offer_head(s);
-		slide_added(s, slides.size - 1);
+		add_slide(length, s);
 	}
 	
 	/**
 	 * Removes the specified { link Slide}, returning an Slide that the editor
 	 * can safely jump to.
 	 *
-	 * @param s The slide to remove.
+	 * @param slide The slide to remove.
 	 */
-	public Slide remove_slide(Slide s)
+	public Slide remove_slide(Slide slide)
 	{
-		int ind = index_of(s);
+		Slide s;
+		var index = 0;
+		foreach (var itr in slides)
+		{
+			slides.get(itr, COL_SLIDE, out s);
+			if (slide == s)
+			{
+				slides.remove(itr);
+				slide_deleted(s, index);
+				break;
+			}
+			index++;
+		}
 		
-		slides.remove(s);
-		slide_deleted(s, ind);
+		Slide ret;
+		Gtk.TreeIter itr;
+		slides.get_iter_first(out itr);
 		
-		if (ind == 0) return slides.get(0);
-		return slides.get(ind - 1);
+		// iterate to the slide. the first two are slide zero.
+		for (int i = 1; i < index; i++) slides.iter_next(ref itr);
+		
+		// retrieve and return the slide
+		slides.get(itr, COL_SLIDE, out ret);
+		return ret;
 	}
 	
 	/**
@@ -249,42 +285,68 @@ public class Ease.Document : GLib.Object
 	 */
 	public bool has_next_slide(Slide slide)
 	{
-		for (int i = 0; i < slides.size - 1; i++)
+		Slide s;
+		Gtk.TreeIter itr;
+		if (!slides.get_iter_first(out itr)) return false;
+		
+		do
 		{
-			if (slides.get(i) == slide)
-			{
-				return true;
-			}
-		}
+			slides.get(itr, COL_SLIDE, out s);
+			if (s == slide) return slides.iter_next(ref itr);
+		} while (slides.iter_next(ref itr));
+		
 		return false;
 	}
 	
 	/**
 	 * Finds the index of the given slide, or returns -1 if it is not found.
 	 *
-	 * @param s The { link Slide} to find the index of.
+	 * @param slide The { link Slide} to find the index of.
 	 */
-	public int index_of(Slide s)
+	public int index_of(Slide slide)
 	{
-		for (int i = 0; i < slides.size; i++)
+		Slide s;
+		var i = 0;
+		foreach (var itr in slides)
 		{
-			if (slides.get(i) == s)
+			slides.get(itr, COL_SLIDE, out s);
+			if (s == slide)
 			{
 				return i;
 			}
+			i++;
 		}
 		return -1;
 	}
 	
 	/**
+	 * Returns the Slide at the specified index.
+	 */
+	public Slide get_slide(int index)
+	{
+		Slide ret;
+		Gtk.TreeIter itr;
+		slides.get_iter_first(out itr);
+		
+		// iterate to the slide
+		for (int i = 0; i < index; i++) slides.iter_next(ref itr);
+		
+		// retrieve and return the slide
+		slides.get(itr, COL_SLIDE, out ret);
+		return ret;
+	}
+	
+	/**
 	 * Finds a { link Slide} by its "title" property.
 	 *
 	 * @param id The title to search for.
 	 */
 	public Slide? slide_by_title(string title)
 	{
-		foreach (Slide s in slides)
+		Slide s;
+		foreach (var itr in slides)
 		{
+			slides.get(itr, COL_SLIDE, out s);
 			if (s.title == title)
 			{
 				return s;
@@ -329,8 +391,10 @@ public class Ease.Document : GLib.Object
 			var surface = new Cairo.PdfSurface(path, width, height);
 			var context = new Cairo.Context(surface);
 		
-			foreach (var s in slides)
+			Slide s;
+			foreach (var itr in slides)
 			{
+				slides.get(itr, COL_SLIDE, out s);
 				s.cairo_render(context);
 				context.show_page();
 			}
@@ -365,9 +429,13 @@ public class Ease.Document : GLib.Object
 		// substitute in the values
 		
 		// add each slide
-		for (var i = 0; i < slides.size; i++)
+		Slide slide;
+		int index = 0;
+		foreach (var itr in slides)
 		{
-			slides.get(i).to_html(ref html, exporter, 1.0 / slides.size, i);
+			slides.get(itr, COL_SLIDE, out slide);
+			slide.to_html(ref html, exporter, 1.0 / slides.size, index);
+			index++;
 		}
 		
 		// finish the document
diff --git a/src/ease-editor-window.vala b/src/ease-editor-window.vala
index 2a0ef50..d16ba6f 100644
--- a/src/ease-editor-window.vala
+++ b/src/ease-editor-window.vala
@@ -217,7 +217,7 @@ public class Ease.EditorWindow : Gtk.Window
 	 */
 	public void set_slide(int index)
 	{
-		slide = document.slides.get(index);
+		slide = document.get_slide(index);
 		
 		// update ui elements for this new slide
 		inspector.slide = slide;
diff --git a/src/ease-iterables.vala b/src/ease-iterables.vala
new file mode 100644
index 0000000..d4a065f
--- /dev/null
+++ b/src/ease-iterables.vala
@@ -0,0 +1,74 @@
+/*  Ease, a GTK presentation application
+    Copyright (C) 2010 Nate Stedman
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * A Gtk.TreeModel iterable through "foreach".
+ *
+ * The foreach loop returns a Gtk.TreeIter. The Gtk.TreePath provided by the 
+ * built in TreeModel foreach function is not (immediately) available.
+ */
+public interface Ease.Iterable.TreeModel : Gtk.TreeModel
+{
+	public Iterator iterator()
+	{
+		return new Iterator(this);
+	}
+
+	public class Iterator
+	{
+		private Gtk.TreeIter itr;
+		private TreeModel model;
+		private bool more;
+		
+		public Iterator(TreeModel self)
+		{
+			more = self.get_iter_first(out itr);
+			model = self;
+		}
+		
+		public bool next()
+		{
+			return more;
+		}
+		
+		public Gtk.TreeIter get()
+		{
+			var ret = itr;
+			more = model.iter_next(ref itr);
+			return ret;
+		}
+	}
+}
+
+/**
+ * ListStore with the { link Iterable.TreeModel} mixin.
+ */
+public class Ease.Iterable.ListStore : Gtk.ListStore, TreeModel
+{
+	/**
+	 * Creates an iterable ListStore with the specified types.
+	 */
+	public ListStore(Type[] types)
+	{
+		set_column_types(types);
+	}
+	
+	/**
+	 * The number of items in this ListStore.
+	 */
+	public int size { get { return iter_n_children(null); } }
+}
diff --git a/src/ease-player.vala b/src/ease-player.vala
index b1ac1cf..5e6f7dd 100644
--- a/src/ease-player.vala
+++ b/src/ease-player.vala
@@ -237,7 +237,7 @@ public class Ease.Player : GLib.Object
 			return;
 		}
 		
-		var slide = document.slides.get(slide_index);
+		var slide = document.get_slide(slide_index);
 		
 		// the first slide simply fades in
 		if (slide_index == 0)
@@ -289,7 +289,7 @@ public class Ease.Player : GLib.Object
 		can_animate = true;
 		
 		container.remove_all();
-		create_current_slide(document.slides.get(slide_index));
+		create_current_slide(document.get_slide(slide_index));
 		current_slide.stack(container);
 		container.add_actor(current_slide);
 	}
diff --git a/src/ease-slide-button-panel.vala b/src/ease-slide-button-panel.vala
index 8a922fc..3bb2349 100644
--- a/src/ease-slide-button-panel.vala
+++ b/src/ease-slide-button-panel.vala
@@ -28,7 +28,6 @@ public class Ease.SlideButtonPanel : Gtk.ScrolledWindow
 	
 	// tree view
 	private Gtk.TreeView slides;
-	private Gtk.ListStore list_store;
 	private Gtk.CellRendererPixbuf renderer;
 	
 	// thumbnails on disk
@@ -72,25 +71,16 @@ public class Ease.SlideButtonPanel : Gtk.ScrolledWindow
 		hscrollbar_policy = Gtk.PolicyType.NEVER;
 		shadow_type = Gtk.ShadowType.IN;
 		
-		// create the list store and add all current slides
-		list_store = new Gtk.ListStore(2, typeof(Gdk.Pixbuf), typeof(Slide));
-		Gtk.TreeIter iter;
-		foreach (var slide in document.slides)
-		{
-			list_store.append(out iter);
-			var pb = pixbuf(slide, PREV_WIDTH);
-			list_store.set(iter, 0, pb, 1, slide);
-			slide.changed.connect(slide_redraw);
-		}
-		
 		// create the tree view
 		slides = new Gtk.TreeView();
+		slides.reorderable = true;
 		slides.headers_visible = false;
 		renderer = new Gtk.CellRendererPixbuf();
 		renderer.set_padding(PADDING, PADDING);
 		slides.insert_column_with_attributes(-1, "Slides", renderer,
-		                                     "pixbuf", 0);
-		slides.set_model(list_store);
+		                                     "pixbuf", Document.COL_PIXBUF);
+		slides.set_model(document.slides);
+		
 		
 		// add the tree view with a viewport
 		var viewport = new Gtk.Viewport(null, null);
@@ -98,39 +88,33 @@ public class Ease.SlideButtonPanel : Gtk.ScrolledWindow
 		viewport.add(slides);
 		add(viewport);
 		
+		// render pixbufs for all current slides
+		foreach (var itr in document.slides)
+		{
+			slide_redraw(itr);
+		}
+		
 		// switch slides when the selection changes
 		slides.get_selection().changed.connect((sender) => {
 			slides.get_selection().selected_foreach((m, p, itr) => {
 				Slide s = new Slide();
-				m.get(itr, 1, ref s);
-				owner.set_slide(document.slides.index_of(s));
+				m.get(itr, Document.COL_SLIDE, ref s);
+				owner.set_slide(document.index_of(s));
 			});
 		});
 		
-		// handle the document's slide_added signal
 		document.slide_added.connect((slide, index) => {
-			Gtk.TreeIter itr;
-			list_store.insert(out itr, index);
-			var pb = pixbuf(slide, PREV_WIDTH);
-			list_store.set(itr, 0, pb, 1, slide);
-			slide.changed.connect(slide_redraw);
-		});
-		
-		// handle the removal of slides
-		document.slide_deleted.connect((slide, index) => {
-			Gtk.TreeIter itr;
-			Slide s = new Slide();
-			slide.changed.connect(slide_redraw);
-			if (!list_store.get_iter_first(out itr)) return;
-			do
+			Slide s;
+			foreach (var itr in document.slides)
 			{
-				list_store.get(itr, 1, ref s);
+				document.slides.get(itr, Document.COL_SLIDE, out s);
 				if (s == slide)
 				{
-					list_store.remove(itr);
-					break;
+					slide_redraw(itr);
+					return;
 				}
-			} while (list_store.iter_next(ref itr));
+			}
+			debug("new slide");
 		});
 		
 		// redraw all slides when the size allocation changes
@@ -138,12 +122,12 @@ public class Ease.SlideButtonPanel : Gtk.ScrolledWindow
 			var width = alloc.width - 2 * PADDING;
 			
 			Gtk.TreeIter itr;
-			if (!list_store.get_iter_first(out itr)) return;
-			for (; list_store.iter_next(ref itr);)
+			if (!document.slides.get_iter_first(out itr)) return;
+			for (; document.slides.iter_next(ref itr);)
 			{
 				Slide s = new Slide();
-				list_store.get(itr, 1, ref s);
-				list_store.set(itr, 0, pixbuf(s, width));
+				document.slides.get(itr, 1, ref s);
+				document.slides.set(itr, 0, pixbuf(s, width));
 			}
 		});*/
 	}
@@ -157,37 +141,32 @@ public class Ease.SlideButtonPanel : Gtk.ScrolledWindow
 	{
 		Gtk.TreeIter itr;
 		Slide s = new Slide();
-		if (!list_store.get_iter_first(out itr)) return;
+		if (!document.slides.get_iter_first(out itr)) return;
 		do
 		{
-			list_store.get(itr, 1, ref s);
+			document.slides.get(itr, Document.COL_SLIDE, ref s);
 			if (s == slide)
 			{
 				slides.get_selection().select_iter(itr);
 				break;
 			}
-		} while (list_store.iter_next(ref itr));
+		} while (document.slides.iter_next(ref itr));
 	}
 	
 	/**
 	 * Redraws a { link Slide} when it is changed.
 	 *
-	 * @param slide The slide to redraw.
+	 * @param itr An iterator pointing to the slide's row.
 	 */
-	private void slide_redraw(Slide slide)
+	private void slide_redraw(Gtk.TreeIter itr)
 	{
-		Gtk.TreeIter itr;
-		Slide s = new Slide();
-		if (!list_store.get_iter_first(out itr)) return;
-		do
-		{
-			list_store.get(itr, 1, ref s);
-			if (s == slide)
-			{
-				var pb = pixbuf(slide, PREV_WIDTH);
-				list_store.set(itr, 0, pb);
-			}
-		} while (list_store.iter_next(ref itr));
+		// grab the Slide
+		Slide slide;
+		document.slides.get(itr, Document.COL_SLIDE, out slide);
+		
+		// render the pixbuf
+		var pb = pixbuf(slide, PREV_WIDTH);
+		document.slides.set(itr, Document.COL_PIXBUF, pb);
 	}
 	
 	/**
diff --git a/src/ease-slide.vala b/src/ease-slide.vala
index f288128..9c74e0d 100644
--- a/src/ease-slide.vala
+++ b/src/ease-slide.vala
@@ -170,9 +170,9 @@ public class Ease.Slide : GLib.Object
 		{
 			for (int i = 0; i < parent.slides.size - 1; i++)
 			{
-				if (parent.slides.get(i) == this)
+				if (parent.get_slide(i) == this)
 				{
-					return parent.slides.get(i + 1);
+					return parent.get_slide(i + 1);
 				}
 			}
 			return null;
@@ -188,9 +188,9 @@ public class Ease.Slide : GLib.Object
 		{
 			for (int i = 1; i < parent.slides.size; i++)
 			{
-				if (parent.slides.get(i) == this)
+				if (parent.get_slide(i) == this)
 				{
-					return parent.slides.get(i - 1);
+					return parent.get_slide(i - 1);
 				}
 			}
 			return null;
@@ -244,6 +244,8 @@ public class Ease.Slide : GLib.Object
 	 */
 	internal Slide.from_json(Json.Object obj)
 	{
+		this();
+		
 		var slide = new Slide();
 		
 		// read the slide's transition properties



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