[model/wip/api-redesign] Split up model.c in per classes sources



commit f0c1583df16b4c14cc7c9620f99fdf7cf2faf16b
Author: Alberto Ruiz <aruiz gnome org>
Date:   Fri Oct 26 23:21:13 2012 +0200

    Split up model.c in per classes sources

 model/Makefile.am                  |   15 +-
 model/model-abstract-sorted-list.c |  340 +++++
 model/model-basictypes.c           |  320 +++++
 model/model-dictionary.c           |  140 ++
 model/model-implementation.h       |    3 +-
 model/model-list.c                 |  248 ++++
 model/model-object.c               |   45 +
 model/model-reference-helper.c     |  441 +++++++
 model/model-reference.c            |  115 ++
 model/model-simple-dictionary.c    |  434 +++++++
 model/model-simple-list.c          |  198 +++
 model/model-simple-reference.c     |  316 +++++
 model/model.c                      | 2444 ------------------------------------
 13 files changed, 2612 insertions(+), 2447 deletions(-)
---
diff --git a/model/Makefile.am b/model/Makefile.am
index 9ef82ba..d704407 100644
--- a/model/Makefile.am
+++ b/model/Makefile.am
@@ -1,12 +1,23 @@
 lib_LTLIBRARIES = libmodel.la
 AM_CFLAGS = $(gobject_CFLAGS) -Wall -Wmissing-prototypes -Wwrite-strings
 libmodel_la_LIBADD = $(gobject_LIBS)
-libmodel_la_SOURCES = model.c
+libmodel_la_SOURCES = \
+	model-abstract-sorted-list.c  \
+	model-dictionary.c \
+	model-object.c \
+	model-reference-helper.c \
+	model-simple-list.c \
+	model-basictypes.c \
+	model-list.c \
+	model-reference.c \
+	model-simple-reference.c
+
+#model-simple-dictionary.c
 
 Model-0.2.typelib: Model-0.2.gir libmodel.la
 	g-ir-compiler -o $@ --shared-library=libmodel $<
 
-Model-0.2.gir: model.h model-implementation.h model.c libmodel.la
+Model-0.2.gir: model.h model-implementation.h $(libmodel_la_SOURCES) libmodel.la
 	g-ir-scanner --namespace Model --nsversion=0.2 --output $@ \
 	  --c-include=model-implementation.h --libtool="$(LIBTOOL)" \
 	  --library=model --pkg-export=model --include=GObject-2.0 \
diff --git a/model/model-abstract-sorted-list.c b/model/model-abstract-sorted-list.c
new file mode 100644
index 0000000..06abc67
--- /dev/null
+++ b/model/model-abstract-sorted-list.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright  2009 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the licence, or (at your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "model-implementation.h"
+#include "model.h"
+
+#include <string.h>
+
+/**
+ * SECTION:abstractsortedlist
+ * @Short_Description: a basis for creating name-based #ModelList
+ *                     implementations
+ *
+ * #ModelAbstractSortedList provides a basis for creating #ModelList
+ * implementations where it is easier to view the data set as a
+ * dictionary than a list.  It is an abstract class -- it must be
+ * subclassed to be used.
+ *
+ * The list is kept in sorted form for efficiency.
+ *
+ * The canonical example here is a list of files in a directory.  The
+ * interface to the kernel is defined in terms of names -- not positions
+ * in a list.  Operations to update the model are easier performed on
+ * the basis of those names.  This class keeps track of all of the
+ * details for you.
+ *
+ * There is only one method on this class:
+ * model_abstract_sorted_list_merge(), but it is essential for
+ * subclasses to implement a number of virtual functions as described in
+ * #ModelAbstractSortedListClass.
+ *
+ * The #ModelList virtual functions for model_list_n_children() and
+ * model_list_get_child() are implemented by this class.
+ **/
+
+/**
+ * ModelAbstractSortedList:
+ *
+ * This is an opaque structure; it may not be accessed directly.
+ **/
+
+/**
+ * ModelAbstractSortedListClass:
+ * @compare: Compares two keys.  This function defines the sort order of
+ *           the list.
+ * @warning: This function is called when there is unexpected state
+ *           during a call to model_abstract_sorted_list_merge().
+ *           @index is the index of the item in the list that was passed
+ *           in to the function.  @key is the key at that index.  @mode
+ *           is the mode specified for that key.  For mode 'I',
+ *           @current_index specifies the current index of the
+ *           already-existing item in the list and @value is the value
+ *           of that item.  For the other two modes, @current_index and
+ *           @value will be 0 and %NULL, respectively.
+ * @create_item: This function is called to create an item for a given
+ *               key before inserting it into the list during a call to
+ *               model_abstract_sorted_list_merge().  The function is
+ *               also responsible for allocating the permanent copy of
+ *               the key that will be used by the list.  @index is the
+ *               index of the item in the list that was passed in to the
+ *               function.  @key is the key at that index.  This
+ *               function is responsible for setting the value of
+ *               @new_key and @new_object to the values that will be
+ *               inserted.
+ * @free_key: This function frees a key that was allocated by the
+ *            @create_item function.
+ *
+ * The class structure for #ModelAbstractSortedList.  All virtual functions
+ * must be implemented by each subclass.
+ **/
+G_DEFINE_ABSTRACT_TYPE (ModelAbstractSortedList,
+                        model_abstract_sorted_list,
+                        MODEL_TYPE_LIST)
+struct _ModelAbstractSortedListPrivate
+{
+  ModelObject **objects;
+  gpointer *keys;
+  gulong n_items;
+};
+
+/**
+ * model_abstract_sorted_list_merge:
+ * @sorted: a #ModelAbstractSortedList
+ * @mode: the mode string
+ * @keys: an array of keys to add or remove
+ * @n_keys: the length of @keys
+ *
+ * Modifies the list by performing insertions, replacements and
+ * deletions.
+ *
+ * @keys (of length @n_keys) is an array of pointers to the keys to
+ * insert, replace or delete.  It must be sorted.  @keys is not modified
+ * in any way, and the values in @keys are not used in any way except
+ * for being passed in to the 'compare' and 'create_item' functions
+ * specified in the #ModelAbstractSortedListClass.
+ *
+ * @mode is a string.  It must either be a single character in length or
+ * the same length as @keys.  If it is the length of @keys then each
+ * character in @mode corresponds, respectively, with each item in
+ * @keys.  If @mode is a single character, then that character is used
+ * for all of the keys.
+ *
+ * Each character of @mode may be only 'i', 'I', 'r', 'R', 'd', or 'D'.
+ * The lowercase letters correspond to the operations "insert",
+ * "replace" and "delete".  The uppercase letters correspond to the same
+ * operations, but with warnings issued in case of an unexpected state.
+ * A warning is issued in the case of inserting an item when that item
+ * already exists or replacing or deleting an item when that item does
+ * not exist.  The warnings are issued by calling the warning virtual
+ * function defined in the #ModelAbstractSortedListClass.
+ **/
+void
+model_abstract_sorted_list_merge (ModelAbstractSortedList *sorted,
+                                  const gchar             *mode,
+                                  const gconstpointer     *keys,
+                                  gulong                   n_keys)
+{
+  gulong change_position = 0, change_removed = 0, change_inserted = 0;
+  ModelAbstractSortedListClass *class;
+  gboolean in_change_set = FALSE;
+  ModelObject **old_objects;
+  gpointer *old_keys;
+  gulong old_n_items;
+  gulong i, j, k;
+
+  g_return_if_fail (MODEL_IS_ABSTRACT_SORTED_LIST (sorted));
+  g_return_if_fail (keys != NULL || n_keys == 0);
+  g_return_if_fail (mode != NULL || n_keys == 0);
+
+  class = MODEL_ABSTRACT_SORTED_LIST_GET_CLASS (sorted);
+  old_objects = sorted->priv->objects;
+  old_keys = sorted->priv->keys;
+  old_n_items = sorted->priv->n_items;
+
+  {
+    gulong max_len = sorted->priv->n_items + n_keys;
+    sorted->priv->objects = g_new (ModelObject *, max_len);
+    sorted->priv->keys = g_new (gpointer, max_len);
+  }
+
+  sorted->priv->n_items = 0;
+  i = j = k = 0;
+
+  while (i < old_n_items || j < n_keys)
+    {
+      gboolean removed = FALSE, inserted = FALSE;
+      gchar this_mode;
+      gint cmp;
+
+      this_mode = 0; /* fix compiler warning */
+
+      if (j == n_keys)
+        cmp = -1;
+      else
+        {
+          this_mode = (j == 0 || mode[1] == '\0') ? mode[0] : mode[j];
+
+          if (i == old_n_items)
+            cmp = 1;
+          else
+            cmp = class->compare (sorted, old_keys[i], keys[j]);
+        }
+
+      if (cmp == 0)
+        {
+          if (this_mode == 'r' || this_mode == 'R')
+            {
+              class->create_item (sorted, j, keys[j],
+                                  &sorted->priv->keys[k],
+                                  &sorted->priv->objects[k]);
+
+              g_object_unref (old_objects[i]);
+              class->free_key (sorted, old_keys[i]);
+              removed = inserted = TRUE;
+              k++;
+            }
+          else if (this_mode == 'i' || this_mode == 'I')
+            {
+              if G_UNLIKELY (this_mode == 'I')
+                class->warning (sorted, j, keys[j], 'I', k, old_objects[i]);
+
+              sorted->priv->objects[k] = old_objects[i];
+              sorted->priv->keys[k] = old_keys[i];
+              k++;
+            }
+          else if (this_mode == 'd' || this_mode == 'D')
+            {
+              g_object_unref (old_objects[i]);
+              class->free_key (sorted, old_keys[i]);
+              removed = TRUE;
+            }
+          else
+            g_error ("unrecognised mode: `%c'\n", this_mode);
+
+          i++, j++;
+        }
+      else if (cmp < 0)
+        {
+          sorted->priv->objects[k] = old_objects[i];
+          sorted->priv->keys[k] = old_keys[i];
+          i++, k++;
+        }
+      else if (cmp > 0)
+        {
+          if (this_mode == 'i' || this_mode == 'r' ||
+              this_mode == 'I' || this_mode == 'R')
+            {
+              if G_UNLIKELY (this_mode == 'R')
+                class->warning (sorted, j, keys[j], 'R', 0, NULL);
+
+              class->create_item (sorted, j, keys[j],
+                                  &sorted->priv->keys[k],
+                                  &sorted->priv->objects[k]);
+              inserted = TRUE;
+              k++;
+            }
+          else if (this_mode == 'd' || this_mode == 'D')
+            {
+              if G_UNLIKELY (this_mode == 'D')
+                class->warning (sorted, j, keys[j], 'D', 0, NULL);
+            }
+          else
+            g_error ("unrecognised mode: `%c'", this_mode);
+
+          j++;
+        }
+
+      if (in_change_set)
+        {
+          if (inserted)
+            change_inserted++;
+
+          if (removed)
+            change_removed++;
+
+          if (!inserted && !removed)
+            in_change_set = FALSE;
+        }
+      else
+        {
+          if (inserted || removed)
+            {
+              if (change_inserted || change_removed)
+                {
+                  sorted->priv->n_items = k;
+                  model_list_changed (MODEL_LIST (sorted), change_position,
+                                      change_removed, change_inserted, TRUE);
+                }
+
+              change_position = k - inserted;
+              change_inserted = inserted;
+              change_removed = removed;
+              in_change_set = TRUE;
+            }
+        }
+    }
+
+  sorted->priv->objects = g_renew (ModelObject *, sorted->priv->objects, k);
+  sorted->priv->keys = g_renew (gpointer, sorted->priv->keys, k);
+  sorted->priv->n_items = k;
+
+  g_free (old_objects);
+  g_free (old_keys);
+
+  if (change_inserted || change_removed)
+    model_list_changed (MODEL_LIST (sorted), change_position,
+                        change_removed, change_inserted, FALSE);
+}
+
+static gulong
+model_abstract_sorted_list_n_children (ModelList *list)
+{
+  ModelAbstractSortedList *sorted = MODEL_ABSTRACT_SORTED_LIST (list);
+
+  return sorted->priv->n_items;
+}
+
+static ModelObject *
+model_abstract_sorted_list_get_child (ModelList *list,
+                                      gulong     index)
+{
+  ModelAbstractSortedList *sorted = MODEL_ABSTRACT_SORTED_LIST (list);
+
+  g_return_val_if_fail (index < sorted->priv->n_items, NULL);
+
+  return g_object_ref (sorted->priv->objects[index]);
+}
+
+static void
+model_abstract_sorted_list_finalize (GObject *object)
+{
+  ModelAbstractSortedListClass *class;
+  ModelAbstractSortedList *sorted = MODEL_ABSTRACT_SORTED_LIST (object);
+  gint i;
+
+  class = MODEL_ABSTRACT_SORTED_LIST_GET_CLASS (object);
+
+  for (i = 0; i < sorted->priv->n_items; i++)
+    {
+      class->free_key (sorted, sorted->priv->keys[i]);
+      g_object_unref (sorted->priv->objects[i]);
+    }
+
+  g_free (sorted->priv->keys);
+  g_free (sorted->priv->objects);
+
+  G_OBJECT_CLASS (model_abstract_sorted_list_parent_class)
+    ->finalize (object);
+}
+
+static void
+model_abstract_sorted_list_init (ModelAbstractSortedList *sorted)
+{
+  sorted->priv =
+    G_TYPE_INSTANCE_GET_PRIVATE (sorted, MODEL_TYPE_ABSTRACT_SORTED_LIST,
+                                 ModelAbstractSortedListPrivate);
+}
+
+static void
+model_abstract_sorted_list_class_init (ModelAbstractSortedListClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  ModelListClass *list_class = MODEL_LIST_CLASS (class);
+
+  object_class->finalize = model_abstract_sorted_list_finalize;
+  list_class->n_children = model_abstract_sorted_list_n_children;
+  list_class->get_child = model_abstract_sorted_list_get_child;
+
+  g_type_class_add_private (class, sizeof (ModelAbstractSortedListPrivate));
+}
diff --git a/model/model-basictypes.c b/model/model-basictypes.c
new file mode 100644
index 0000000..e3b5156
--- /dev/null
+++ b/model/model-basictypes.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright  2009 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the licence, or (at your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "model-implementation.h"
+#include "model.h"
+
+#include <string.h>
+
+/**
+ * SECTION:string
+ * @Short_Description: a #ModelObject containing a string
+ * @Image: string.png
+ *
+ * #ModelString is a simple #ModelObject subclass containing an
+ * immutable non-%NULL string.
+ **/
+
+/**
+ * ModelString:
+ *
+ * This is an opaque structure; it may not be accessed directly.
+ **/
+typedef ModelObjectClass ModelStringClass;
+struct _ModelString
+{
+  ModelObject parent_instance;
+  gchar *value;
+};
+G_DEFINE_TYPE (ModelString, model_string, MODEL_TYPE_OBJECT);
+
+/**
+ * model_string_get:
+ * @object: a #ModelString
+ * @Returns: the string value of @object, owned by the caller
+ *
+ * Gets the string value of @object.
+ *
+ * It is appropriate for the caller to call g_free() on the return
+ * value.
+ **/
+gchar *
+model_string_get (ModelString *object)
+{
+  g_return_val_if_fail (MODEL_IS_STRING (object), NULL);
+
+  return g_strdup (object->value);
+}
+
+/**
+ * model_string_peek:
+ * @object: a #ModelString
+ * @Returns: the string value of @object, owned by @object
+ *
+ * Peeks the string value of @object.  The result is owned by @object
+ * and must not be modified or freed.
+ **/
+const gchar *
+model_string_peek (ModelString *object)
+{
+  g_return_val_if_fail (MODEL_IS_STRING (object), NULL);
+
+  return object->value;
+}
+
+/**
+ * model_string_new:
+ * @value: a string, non-%NULL
+ * @Returns: a new #ModelObject
+ *
+ * Creates a #ModelString, containing @value.
+ *
+ * This function should only be called by model implementations.
+ **/
+ModelObject *
+model_string_new (const gchar *value)
+{
+  ModelString *object;
+
+  g_return_val_if_fail (value != NULL, NULL);
+
+  object = g_object_new (MODEL_TYPE_STRING, NULL);
+  object->value = g_strdup (value);
+
+  return (ModelObject *) object;
+}
+
+static void
+model_string_finalize (GObject *object)
+{
+  ModelString *string = MODEL_STRING (object);
+
+  g_free (string->value);
+
+  G_OBJECT_CLASS (model_string_parent_class)
+    ->finalize (object);
+}
+
+static void
+model_string_class_init (ModelStringClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->finalize = model_string_finalize;
+}
+
+static void
+model_string_init (ModelString *object)
+{
+}
+
+/**
+ * SECTION:integer
+ * @Short_Description: a #ModelObject containing a #gint
+ * @Image: integer.png
+ *
+ * #ModelInteger is a simple #ModelObject subclass containing an
+ * immutable #gint value.
+ **/
+
+/**
+ * ModelInteger:
+ *
+ * This is an opaque structure; it may not be accessed directly.
+ **/
+typedef ModelObjectClass ModelIntegerClass;
+struct _ModelInteger
+{
+  ModelObject parent_instance;
+  gint value;
+};
+G_DEFINE_TYPE (ModelInteger, model_integer, MODEL_TYPE_OBJECT);
+
+/**
+ * model_integer_get:
+ * @object: a #ModelInteger
+ * @Returns: the integer value of @object
+ *
+ * Gets the integer value of @object.
+ **/
+gint
+model_integer_get (ModelInteger *object)
+{
+  g_return_val_if_fail (MODEL_IS_INTEGER (object), 0);
+
+  return object->value;
+}
+
+/**
+ * model_integer_new:
+ * @value: an integer
+ * @Returns: a new #ModelObject
+ *
+ * Creates a #ModelInteger, containing @value.
+ *
+ * This function should only be called by model implementations.
+ **/
+ModelObject *
+model_integer_new (gint value)
+{
+  ModelInteger *object;
+
+  object = g_object_new (MODEL_TYPE_INTEGER, NULL);
+  object->value = value;
+
+  return (ModelObject *) object;
+}
+
+static void
+model_integer_class_init (ModelIntegerClass *class)
+{
+}
+
+static void
+model_integer_init (ModelInteger *object)
+{
+}
+
+/**
+ * SECTION:float
+ * @Short_Description: a #ModelObject containing a #gdouble
+ * @Image: float.png
+ *
+ * #ModelFloat is a simple #ModelObject subclass containing an immutable
+ * #gdouble value.
+ **/
+
+/**
+ * ModelFloat:
+ *
+ * This is an opaque structure; it may not be accessed directly.
+ **/
+typedef ModelObjectClass ModelFloatClass;
+struct _ModelFloat
+{
+  ModelObject parent_instance;
+  gdouble value;
+};
+G_DEFINE_TYPE (ModelFloat, model_float, MODEL_TYPE_OBJECT);
+
+/**
+ * model_float_get:
+ * @object: a #ModelFloat
+ * @Returns: the double precision floating point value of @object
+ *
+ * Gets the floating point value of @object.
+ **/
+gdouble
+model_float_get (ModelFloat *object)
+{
+  g_return_val_if_fail (MODEL_IS_FLOAT (object), 0.);
+
+  return object->value;
+}
+
+/**
+ * model_float_new:
+ * @value: a double precision floating point value
+ * @Returns: a new #ModelObject
+ *
+ * Creates a #ModelFloat, containing @value.
+ *
+ * This function should only be called by model implementations.
+ **/
+ModelObject *
+model_float_new (gdouble value)
+{
+  ModelFloat *object;
+
+  object = g_object_new (MODEL_TYPE_FLOAT, NULL);
+  object->value = value;
+
+  return (ModelObject *) object;
+}
+
+static void
+model_float_class_init (ModelFloatClass *class)
+{
+}
+
+static void
+model_float_init (ModelFloat *object)
+{
+}
+
+/**
+ * SECTION:boolean
+ * @Short_Description: a #ModelObject containing a #gboolean
+ * @Image: boolean.png
+ *
+ * #ModelBoolean is a simple #ModelObject subclass containing an
+ * immutable #gboolean value.
+ **/
+
+/**
+ * ModelBoolean:
+ *
+ * This is an opaque structure; it may not be accessed directly.
+ **/
+typedef ModelObjectClass ModelBooleanClass;
+struct _ModelBoolean
+{
+  ModelObject parent_instance;
+  gboolean value;
+};
+G_DEFINE_TYPE (ModelBoolean, model_boolean, MODEL_TYPE_OBJECT);
+
+/**
+ * model_boolean_get:
+ * @object: a #ModelBoolean
+ * @Returns: the boolean value of @object
+ *
+ * Gets the boolean value of @object.
+ **/
+gboolean
+model_boolean_get (ModelBoolean *object)
+{
+  g_return_val_if_fail (MODEL_IS_BOOLEAN (object), FALSE);
+
+  return object->value;
+}
+
+/**
+ * model_boolean_new:
+ * @value: a boolean value
+ * @Returns: a new #ModelObject
+ *
+ * Creates a #ModelBoolean, containing @value.
+ *
+ * This function should only be called by model implementations.
+ **/
+ModelObject *
+model_boolean_new (gboolean value)
+{
+  ModelBoolean *object;
+
+  object = g_object_new (MODEL_TYPE_BOOLEAN, NULL);
+  object->value = value;
+
+  return (ModelObject *) object;
+}
+
+static void
+model_boolean_class_init (ModelBooleanClass *class)
+{
+}
+
+static void
+model_boolean_init (ModelBoolean *object)
+{
+}
diff --git a/model/model-dictionary.c b/model/model-dictionary.c
new file mode 100644
index 0000000..1643b7e
--- /dev/null
+++ b/model/model-dictionary.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright  2009 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the licence, or (at your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "model-implementation.h"
+#include "model.h"
+
+#include <string.h>
+
+/**
+ * SECTION:dictionary
+ * @Short_Description: an immutable mapping from string to
+ *                     #ModelReference
+ * @Image: dictionary.png
+ *
+ * #ModelDictionary is a lookup table of strings, mapping to
+ * #ModelReference instances.  It is immutable in the sense that keys
+ * may not be be added or removed and that the #ModelReference pointed
+ * to by each key remains the same.  The #ModelReference itself is of
+ * course mutable.
+ **/
+
+/**
+ * ModelDictionary:
+ *
+ * This is an opaque structure; it may not be accessed directly.
+ **/
+
+/**
+ * ModelDictionaryClass:
+ * @get_reference: virtual function pointer for
+ *                 model_dictionary_get_reference()
+ * @get_value: virtual function pointer for model_dictionary_get_value()
+ * @list_keys: virtual function pointer for model_dictionary_list_keys()
+ *
+ * The class structure for #ModelDictionary.  All virtual functions must
+ * be implemented by each subclass.
+ **/
+G_DEFINE_ABSTRACT_TYPE (ModelDictionary, model_dictionary, MODEL_TYPE_OBJECT);
+
+/**
+ * model_dictionary_get_reference:
+ * @dictionary: a #ModelDictionary
+ * @key: the key to fetch the reference for
+ * @returns: a #ModelReference for the key, owned by the caller
+ *
+ * Gets a #ModelReference object corresponding to @key on @dictionary.
+ * @key must be a valid key on the dictionary.
+ *
+ * Using this function (instead of model_dictionary_get_value()) allows
+ * you to watch for changes in the value of the key.  Any changes to the
+ * value of a key will be result in the "changed" signal being emitted
+ * on the reference object returned by this function.
+ *
+ * It is appropriate for the caller to call g_object_unref() on the
+ * return value.
+ **/
+ModelReference *
+model_dictionary_get_reference (ModelDictionary *dictionary,
+                                const gchar     *key)
+{
+  g_return_val_if_fail (MODEL_IS_DICTIONARY (dictionary), NULL);
+  g_return_val_if_fail (key != NULL, NULL);
+
+  return MODEL_DICTIONARY_GET_CLASS (dictionary)
+    ->get_reference (dictionary, key);
+}
+
+/**
+ * model_dictionary_get_value:
+ * @dictionary: a #ModelDictionary
+ * @key: the key to fetch the reference for
+ * @returns: a #ModelObject for the key, owned by the caller
+ *
+ * Gets a #ModelObject corresponding to the current value of @key on
+ * @dictionary.  @key must be a valid key on the dictionary.  
+ *
+ * This function is equivalent to calling
+ * model_dictionary_get_reference() and model_reference_get_value() but
+ * is often substantially more efficient (since the model implementation
+ * need not setup watches for change notification).
+ *
+ * It is appropriate for the caller to call g_object_unref() on the
+ * return value.
+ **/
+ModelObject *
+model_dictionary_get_value (ModelDictionary *dictionary,
+                            const gchar     *key)
+{
+  g_return_val_if_fail (MODEL_IS_DICTIONARY (dictionary), NULL);
+  g_return_val_if_fail (key != NULL, NULL);
+
+  return MODEL_DICTIONARY_GET_CLASS (dictionary)
+    ->get_value (dictionary, key);
+}
+
+/**
+ * model_dictionary_list_keys:
+ * @dictionary: a #ModelDictionary
+ * @length: a pointer to the number of keys returned, or %NULL
+ * @returns: a list of the keys on the dictionary, owned by the caller
+ *
+ * Gets a list of the keys on @dictionary.
+ *
+ * If length is non-%NULL then it will be set to the number of items in
+ * the array that is returned.  It is appropriate for the caller to call
+ * g_strfreev() on the return value.
+ *
+ * This function allows dictionaries to be introspected for purposes of
+ * debugging and testing, but if your model is well-constructed then you
+ * should know which keys are on your dictionary objects.
+ **/
+gchar **
+model_dictionary_list_keys (ModelDictionary *dictionary,
+                            gint            *length)
+{
+  g_return_val_if_fail (MODEL_IS_DICTIONARY (dictionary), NULL);
+
+  return MODEL_DICTIONARY_GET_CLASS (dictionary)
+    ->list_keys (dictionary, length);
+}
+
+static void
+model_dictionary_class_init (ModelDictionaryClass *class)
+{
+}
+
+static void
+model_dictionary_init (ModelDictionary *dictionary)
+{
+}
diff --git a/model/model-implementation.h b/model/model-implementation.h
index 9d1ba43..d232f4b 100644
--- a/model/model-implementation.h
+++ b/model/model-implementation.h
@@ -87,7 +87,7 @@ void                    model_reference_helper_set_float                (ModelRe
                                                                          gdouble                  value);
 void                    model_reference_helper_set_boolean              (ModelReferenceHelper    *helper,
                                                                          gboolean                 value);
-
+#if 0
 #define MODEL_TYPE_SIMPLE_DICTIONARY                        model_simple_dictionary_get_type ()
 #define MODEL_SIMPLE_DICTIONARY(inst)                       (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
                                                              MODEL_TYPE_SIMPLE_DICTIONARY,                           \
@@ -142,6 +142,7 @@ void                    model_simple_dictionary_set_string              (ModelSi
                                                                          const gchar             *key,
                                                                          const gchar             *value,
                                                                          gboolean                 monitored);
+#endif
 
 #define MODEL_TYPE_SIMPLE_LIST                               model_simple_list_get_type ()
 #define MODEL_SIMPLE_LIST(inst)                             (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
diff --git a/model/model-list.c b/model/model-list.c
new file mode 100644
index 0000000..0fb6e9b
--- /dev/null
+++ b/model/model-list.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright  2009 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the licence, or (at your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "model-implementation.h"
+#include "model.h"
+
+#include <string.h>
+
+/**
+ * SECTION:list
+ * @Short_Description: a mutable list of #ModelObject instances
+ * @Image: list.png
+ *
+ * #ModelList is a mutable list of #ModelObject instances (items).
+ * Items can be inserted and removed, changing the length and
+ * composition of the list.
+ *
+ * #ModelReference is not used here.  The only way to change the value
+ * of an item at a particular array index is to remove that item and
+ * insert a new one at the same position.
+ *
+ * When the list changes, the "changed" signal is emitted.  The signal
+ * is always emitted from the mainloop; never during the execution of
+ * method calls on the model.
+ **/
+
+/**
+ * ModelList:
+ *
+ * This is an opaque structure; it may not be accessed directly.
+ **/
+
+/**
+ * ModelListClass:
+ * @n_children: virtual function pointer for model_list_n_children()
+ * @get_child: virtual function pointer for model_list_get_child()
+ *
+ * The class structure for #ModelList.  All virtual functions must be
+ * implemented by each subclass.
+ **/
+G_DEFINE_ABSTRACT_TYPE (ModelList, model_list, MODEL_TYPE_OBJECT);
+
+struct _ModelListPrivate
+{
+  gulong position;
+  gulong inserted;
+};
+
+static guint model_list_changed_signal;
+
+/**
+ * model_list_n_children:
+ * @list: a #ModelList
+ * @returns: the number of items in @list
+ *
+ * Gets the number of items in @list.
+ **/
+gulong
+model_list_n_children (ModelList *list)
+{
+  g_return_val_if_fail (MODEL_IS_LIST (list), 0);
+
+  if (list->priv)
+    {
+      g_critical ("can not call model_list_n_children() "
+                  "from the 'changed' signal handler");
+      return 0;
+    }
+
+  return MODEL_LIST_GET_CLASS (list)
+    ->n_children (list);
+}
+
+/**
+ * model_list_get_child:
+ * @list: a #modelList
+ * @index: the index of the child value to get
+ * @returns: the #ModelObject for the child value, owned by the caller
+ *
+ * Gets the child value at position @index of @list.  @index must be a
+ * valid index in the array (ie: strictly less than the result of
+ * model_list_n_children()).
+ *
+ * It is appropriate for the caller to call g_object_unref() on the
+ * return value.
+ **/
+ModelObject *
+model_list_get_child (ModelList *list,
+                      gulong     index)
+{
+  g_return_val_if_fail (MODEL_IS_LIST (list), NULL);
+
+  if (list->priv &&
+      (index < list->priv->position ||
+       index >= list->priv->position + list->priv->inserted))
+    {
+      g_critical ("can only call model_list_get_child() "
+                  "from the 'changed' signal handler for "
+                  "inserted children");
+      return 0;
+    }
+
+  return MODEL_LIST_GET_CLASS (list)
+    ->get_child (list, index);
+}
+
+/**
+ * model_list_changed:
+ * @list: a #ModelList
+ * @position: the position at which the change occurred
+ * @removed: the number of items removed in the change
+ * @inserted: the number of items inserted in the change
+ * @more: %TRUE if more changes are coming
+ *
+ * Emits the "changed" signal on @list.
+ **/
+void
+model_list_changed (ModelList *list,
+                    gulong     position,
+                    gulong     removed,
+                    gulong     inserted,
+                    gboolean   more)
+{
+  ModelListPrivate private = { position, inserted };
+
+  g_return_if_fail (MODEL_IS_LIST (list));
+
+  /* enforce restrictions on calls during signal emission */
+  if (more)
+    list->priv = &private;
+
+  g_signal_emit (list, model_list_changed_signal, 0,
+                 position, removed, inserted, more);
+
+  /* lift restrictions */
+  list->priv = NULL;
+}
+
+static void
+model_list_init (ModelList *list)
+{
+}
+
+static void
+model_list_marshal_changed_signal (GClosure     *closure,
+                                   GValue       *return_value,
+                                   guint         n_param_values,
+                                   const GValue *param_values,
+                                   gpointer      invocation_hint,
+                                   gpointer      marshal_data)
+{
+  void (*callback) (gpointer, guint, guint, guint, gboolean, gpointer);
+  GCClosure *c_closure;
+  ModelList *instance;
+
+  g_assert (return_value == NULL);
+  g_assert (n_param_values == 5);
+
+  c_closure = (GCClosure *) closure;
+  callback = marshal_data ? marshal_data : c_closure->callback;
+  instance = param_values[0].data[0].v_pointer;
+
+#define ARG(i) param_values[(i) + 1].data[0].v_uint
+  if (G_CCLOSURE_SWAP_DATA (closure))
+    callback (closure->data, ARG(0), ARG(1), ARG(2), ARG(3), instance);
+  else
+    callback (instance, ARG(0), ARG(1), ARG(2), ARG(3), closure->data);
+#undef ARG
+}
+
+static void
+model_list_class_init (ModelListClass *class)
+{
+  /**
+   * ModelList::changed:
+   * @list: a #ModelList
+   * @position: the position at which the change occurred
+   * @removed: the number of items removed in the change
+   * @inserted: the number of items inserted in the change
+   * @more: %TRUE if more changes are coming
+   *
+   * This signal is emitted whenever the list has been changed (ie: has
+   * had items removed or inserted).
+   *
+   * One change signal can be emitted for several removes and inserts
+   * occuring at the same position in the list.
+   *
+   * The change occured at the index specified by @position.  Starting at
+   * that point, @removed items were removed.  In their place, @inserted
+   * new items were added.  As a simple example, if @list has 4 items in
+   * it and the last item were removed, then a signal would be emitted
+   * with @position equal to 3, @removed equal to 1 and @inserted equal
+   * to 0.
+   *
+   * If a single change to the list is too complex to be described by a
+   * single block of removes and inserts then the signal handler will be
+   * called multiple times.  Each time except for the last, @more will
+   * be set to %TRUE.  On the last call, @more will be set to %FALSE.
+   * No other visible action may occur meanwhile (such as emitting
+   * signals elsewhere or returning to the mainloop).  A set of changes
+   * may not contain overlapping items.
+   *
+   * At the end of a set of change signals (ie: when @more is %FALSE),
+   * @list will be consistent with its previous value, subject to all of
+   * the changes.
+   *
+   * In the midst of a set of changes, the exact state of @list may be
+   * one of two things: it may either be in its final state (ie: equal
+   * to the state that it will have at the end of the set of signals) or
+   * it may be in an intermediate state where only the changes signaled
+   * so far are visible.  In any case, it is valid (and only valid) for
+   * the signal handler to call model_list_get_child() on the children
+   * signaled as having been inserted by the current signal invocation
+   * (model_list_n_children() may not be called at all).  As a model
+   * implementor, this implies that if you decide to make all of the
+   * changes immediately (ie: before the first signal) then you must
+   * emit your set of changes in ascending order of @position.
+   *
+   * As an example, assume @list contains [1, 2, 3, 4, 5] and it is
+   * modified to contain [6, 3, 4, 7, 8].  There are many possible
+   * combinations of signals that could describe this change.  We
+   * give a simple one here:
+   *
+   * Two signals are emitted.  First, (@position = 0, @removed = 2,
+   * @inserted = 1, @more = %TRUE).  At this point, @list could either
+   * equal its final value, or an intermediate value of [6, 3, 4, 5].
+   * Note that in either case, calling model_list_get_child() on the one
+   * item inserted at poisition 0 will return the same value -- 6.
+   * Next, (@position = 3, @removed = 1, @inserted = 2, @more = %FALSE).
+   * Note that @position is always given in terms of the partially
+   * updated list -- not the original.  @list is now in its final state.
+   **/
+  model_list_changed_signal =
+    g_signal_new ("changed", MODEL_TYPE_LIST, G_SIGNAL_RUN_LAST, 0, NULL,
+                  NULL, model_list_marshal_changed_signal, G_TYPE_NONE, 4,
+                  G_TYPE_ULONG, G_TYPE_ULONG, G_TYPE_ULONG, G_TYPE_BOOLEAN);
+}
+
diff --git a/model/model-object.c b/model/model-object.c
new file mode 100644
index 0000000..56f416b
--- /dev/null
+++ b/model/model-object.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright  2009 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the licence, or (at your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "model-implementation.h"
+#include "model.h"
+
+#include <string.h>
+
+/**
+ * SECTION:object
+ * @Short_Description: the base value type
+ * @image: object.png
+ *
+ * A ModelObject represents a node within the data model.  There are two
+ * types of ModelObjects: immutable value objects (like String, Boolean,
+ * Integer, Float) and mutable container objects (like Lists and
+ * Dictionaries).
+ **/
+
+/**
+ * ModelObject:
+ *
+ * This is an opaque structure; it may not be accessed directly.
+ **/
+G_DEFINE_ABSTRACT_TYPE (ModelObject, model_object, G_TYPE_OBJECT);
+
+static void
+model_object_class_init (ModelObjectClass *class)
+{
+}
+
+static void
+model_object_init (ModelObject *object)
+{
+}
diff --git a/model/model-reference-helper.c b/model/model-reference-helper.c
new file mode 100644
index 0000000..19960b8
--- /dev/null
+++ b/model/model-reference-helper.c
@@ -0,0 +1,441 @@
+/*
+ * Copyright  2009 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the licence, or (at your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "model-implementation.h"
+#include "model.h"
+
+#include <string.h>
+
+/**
+ * SECTION:referencehelper
+ * @Short_Description: a way to control object life-cycle when using
+ *                     #ModelReference objects
+ * @Image: referencehelper.png
+ *
+ * When using #ModelSimpleReference to create #ModelReference objects, a
+ * problem often arises.  The part of the model ("the source object")
+ * that is responsible for monitoring the data source and updating the
+ * #ModelReference holds a strong reference on the
+ * #ModelSimpleReference.  This means that the #ModelReference can not
+ * hold a strong reference on the source object and that, once remaining
+ * outside references to the source object are dropped, it will be
+ * finalized.  This finalization occurs even if there are users of the
+ * model still monitoring the #ModelReference for changes -- changes
+ * that will now no longer be delivered.
+ *
+ * #ModelReferenceHelper introduces a 3rd object to resolve this
+ * situation.  The reference helper (blue in the diagram) is held (by
+ * strong reference) by the source object (orange).  The reference
+ * helper has only a weak reference to the source object.  Just like a
+ * #ModelSimpleReference, the reference helper keeps a strong reference
+ * to the value of the reference (green).  When
+ * model_reference_helper_get_reference() is called, a #ModelReference
+ * (ping) is created that holds a strong reference to the source object.
+ * The source object is kept alive to update the reference for as long
+ * as the reference exists.
+ *
+ * The core API of #ModelReferenceHelper consists of
+ * model_reference_helper_new(), model_reference_helper_set() and
+ * model_reference_helper_get_reference().  Additionally, there are
+ * helper functions to set and construct from one of the basic value
+ * types without requiring the manual construction of a corresponding
+ * #ModelObject instance.
+ **/
+
+/**
+ * ModelReferenceHelper:
+ *
+ * This is an opaque structure; it may not be accessed directly.
+ **/
+static GType model_rhr_get_type (void);
+#define MODEL_TYPE_RHR model_rhr_get_type ()
+#define MODEL_RHR(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+                         MODEL_TYPE_RHR, ModelReferenceHelperReference))
+typedef ModelReferenceClass ModelReferenceHelperReferenceClass;
+typedef struct
+{
+  ModelReference parent_instance;
+
+  ModelObject **value_location;
+  ModelObject *direct_value;
+  GObject *owner;
+} ModelReferenceHelperReference;
+
+G_DEFINE_TYPE (ModelReferenceHelperReference,
+               model_rhr, MODEL_TYPE_REFERENCE)
+
+typedef GObjectClass ModelReferenceHelperClass;
+struct _ModelReferenceHelper
+{
+  GObject parent_instance;
+
+  ModelObject *value;
+  GObject *owner;
+  gpointer rhr;
+};
+G_DEFINE_TYPE (ModelReferenceHelper,
+               model_reference_helper,
+               G_TYPE_OBJECT)
+
+static ModelObject *
+model_rhr_get_value (ModelReference *reference)
+{
+  ModelReferenceHelperReference *rhr = MODEL_RHR (reference);
+
+  if (*rhr->value_location != NULL)
+    return g_object_ref (*rhr->value_location);
+
+  else
+    return NULL;
+}
+
+static void
+model_rhr_finalize (GObject *object)
+{
+  ModelReferenceHelperReference *rhr = MODEL_RHR (object);
+
+  if (rhr->owner != NULL)
+    g_object_unref (rhr->owner);
+
+  if (rhr->direct_value != NULL)
+    g_object_unref (rhr->direct_value);
+
+  G_OBJECT_CLASS (model_rhr_parent_class)
+    ->finalize (object);
+}
+
+static void
+model_rhr_init (ModelReferenceHelperReference *rhr)
+{
+}
+
+static void
+model_rhr_class_init (ModelReferenceHelperReferenceClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->finalize = model_rhr_finalize;
+  class->get_value = model_rhr_get_value;
+}
+
+/**
+ * model_reference_helper_get_reference:
+ * @helper: a #ModelReferenceHelper
+ * Returns: a #ModelReference
+ *
+ * Creates and returns a #ModelReference object for the value stored in
+ * @helper.  Any #ModelReference created with this function will have
+ * its "changed" signal emitted when model_reference_helper_set() is
+ * called on @helper.
+ *
+ * This function is not thread-safe with respect to g_object_unref()
+ * being called in other threads.  See bug #548954 for why.
+ **/
+ModelReference *
+model_reference_helper_get_reference (ModelReferenceHelper *helper)
+{
+  g_return_val_if_fail (MODEL_IS_REFERENCE_HELPER (helper), NULL);
+
+  if (helper->rhr == NULL)
+    { 
+      ModelReferenceHelperReference *rhr;
+
+      rhr = g_object_new (MODEL_TYPE_RHR, NULL);
+      rhr->owner = g_object_ref (helper->owner);
+      rhr->value_location = &helper->value;
+      helper->rhr = rhr;
+
+      g_object_add_weak_pointer (helper->rhr, &helper->rhr);
+    }
+  else
+    g_object_ref (helper->rhr);
+
+  return MODEL_REFERENCE (helper->rhr);
+}
+
+/**
+ * model_reference_helper_set:
+ * @helper: a #ModelReferenceHelper
+ * @value: the #ModelObject to use as the new value, or %NULL
+ *
+ * Changes the value held by @helper to @value.
+ *
+ * If the helper has outstanding references (as returned by
+ * model_reference_helper_get_reference()) then the "changed" signal
+ * will be emitted on them.
+ **/
+void
+model_reference_helper_set (ModelReferenceHelper *helper,
+                            ModelObject          *value)
+{
+  g_return_if_fail (MODEL_IS_REFERENCE_HELPER (helper));
+
+  if (value != helper->value)
+    {
+      if (helper->value != NULL)
+        g_object_unref (helper->value);
+
+      helper->value = NULL;
+
+      if (value != NULL)
+        helper->value = g_object_ref (value);
+
+      if (helper->rhr != NULL)
+        model_reference_changed (helper->rhr);
+    }
+}
+
+/**
+ * model_reference_helper_set_string:
+ * @helper: a #ModelReferenceHelper
+ * @value: a string
+ *
+ * Updates the value of @helper to the given string.
+ *
+ * This is a convenience wrapper around model_reference_helper_set() and
+ * model_string_new().
+ **/
+void
+model_reference_helper_set_string (ModelReferenceHelper *helper,
+                                   const gchar          *value)
+{
+  ModelObject *object;
+
+  object = model_string_new (value);
+  model_reference_helper_set (helper, object);
+  g_object_unref (object);
+}
+
+/**
+ * model_reference_helper_set_integer:
+ * @helper: a #ModelReferenceHelper
+ * @value: an integer
+ *
+ * Updates the value of @helper to the given integer.
+ *
+ * This is a convenience wrapper around model_reference_helper_set() and
+ * model_integer_new().
+ **/
+void
+model_reference_helper_set_integer (ModelReferenceHelper *helper,
+                                    gint                  value)
+{
+  ModelObject *object;
+
+  object = model_integer_new (value);
+  model_reference_helper_set (helper, object);
+  g_object_unref (object);
+}
+
+/**
+ * model_reference_helper_set_float:
+ * @helper: a #ModelReferenceHelper
+ * @value: a double precision floating point value
+ *
+ * Updates the value of @helper to the given floating point value.
+ *
+ * This is a convenience wrapper around model_reference_helper_set() and
+ * model_float_new().
+ **/
+void
+model_reference_helper_set_float (ModelReferenceHelper *helper,
+                                  gdouble               value)
+{
+  ModelObject *object;
+
+  object = model_float_new (value);
+  model_reference_helper_set (helper, object);
+  g_object_unref (object);
+}
+
+/**
+ * model_reference_helper_set_boolean:
+ * @helper: a #ModelReferenceHelper
+ * @value: a boolean value
+ *
+ * Updates the value of @helper to the given boolean value.
+ *
+ * This is a convenience wrapper around model_reference_helper_set() and
+ * model_boolean_new().
+ **/
+void
+model_reference_helper_set_boolean (ModelReferenceHelper *helper,
+                                    gboolean              value)
+{
+  ModelObject *object;
+
+  object = model_boolean_new (value);
+  model_reference_helper_set (helper, object);
+  g_object_unref (object);
+}
+
+/**
+ * model_reference_helper_new:
+ * @owner: the "owner" #GObject
+ * @value: the #ModelObject with the initial value
+ * @returns: a new #ModelReferenceHelper
+ *
+ * Creates a new model reference helper for use with @owner.  The
+ * initial value of the helper is @value.
+ **/
+ModelReferenceHelper *
+model_reference_helper_new (GObject     *owner,
+                            ModelObject *value)
+{
+  ModelReferenceHelper *helper;
+
+  g_return_val_if_fail (G_IS_OBJECT (owner), NULL);
+  g_return_val_if_fail (value == NULL || MODEL_IS_OBJECT (value), NULL);
+
+  helper = g_object_new (MODEL_TYPE_REFERENCE_HELPER, NULL);
+  helper->owner = owner;
+
+  if (value != NULL)
+    helper->value = g_object_ref (value);
+
+  return helper;
+}
+
+/**
+ * model_reference_helper_new_string:
+ * @owner: the "owner" #GObject
+ * @value: a string
+ * @returns: a new #ModelReferenceHelper
+ *
+ * Creates a new #ModelReferenceHelper holding a string.
+ *
+ * This is a convenience wrapper around model_reference_helper_new() and
+ * model_string_new().
+ **/
+ModelReferenceHelper *
+model_reference_helper_new_string (GObject     *owner,
+                                   const gchar *value)
+{
+  ModelReferenceHelper *helper;
+  ModelObject *object;
+
+  g_return_val_if_fail (value != NULL, NULL);
+
+  object = model_string_new (value);
+  helper = model_reference_helper_new (owner, object);
+  g_object_unref (object);
+
+  return helper;
+}
+
+/**
+ * model_reference_helper_new_integer:
+ * @owner: the "owner" #GObject
+ * @value: an integer
+ * @returns: a new #ModelReferenceHelper
+ *
+ * Creates a new #ModelReferenceHelper holding an integer.
+ *
+ * This is a convenience wrapper around model_reference_helper_new() and
+ * model_integer_new().
+ **/
+ModelReferenceHelper *
+model_reference_helper_new_integer (GObject *owner,
+                                    gint     value)
+{
+  ModelReferenceHelper *helper;
+  ModelObject *object;
+
+  object = model_integer_new (value);
+  helper = model_reference_helper_new (owner, object);
+  g_object_unref (object);
+
+  return helper;
+}
+
+/**
+ * model_reference_helper_new_float:
+ * @owner: the "owner" #GObject
+ * @value: a double precision floating point value
+ * @returns: a new #ModelReferenceHelper
+ *
+ * Creates a new #ModelReferenceHelper holding a floating point value.
+ *
+ * This is a convenience wrapper around model_reference_helper_new() and
+ * model_float_new().
+ **/
+ModelReferenceHelper *
+model_reference_helper_new_float (GObject *owner,
+                                  gdouble  value)
+{
+  ModelReferenceHelper *helper;
+  ModelObject *object;
+
+  object = model_float_new (value);
+  helper = model_reference_helper_new (owner, object);
+  g_object_unref (object);
+
+  return helper;
+}
+
+/**
+ * model_reference_helper_new_boolean:
+ * @owner: the "owner" #GObject
+ * @value: a boolean value
+ * @returns: a new #ModelReferenceHelper
+ *
+ * Creates a new #ModelReferenceHelper holding a boolean value.
+ *
+ * This is a convenience wrapper around model_reference_helper_new() and
+ * model_boolean_new().
+ **/
+ModelReferenceHelper *
+model_reference_helper_new_boolean (GObject  *owner,
+                                    gboolean  value)
+{
+  ModelReferenceHelper *helper;
+  ModelObject *object;
+
+  object = model_boolean_new (value);
+  helper = model_reference_helper_new (owner, object);
+  g_object_unref (object);
+
+  return helper;
+}
+
+static void
+model_reference_helper_finalize (GObject *object)
+{
+  ModelReferenceHelper *helper = MODEL_REFERENCE_HELPER (object);
+
+  if G_UNLIKELY (helper->rhr != NULL)
+    {
+      g_critical ("a ModelReferenceHelper (%p) is being destroyed but there "
+                  "is still an outstanding ModelReference (%p) -- leaking "
+                  "memory in order to avoid future heap corruption.",
+                  helper, helper->rhr);
+      return;
+    }
+
+  if (helper->value != NULL)
+    g_object_unref (helper->value);
+
+  G_OBJECT_CLASS (model_reference_helper_parent_class)
+    ->finalize (object);
+}
+
+static void
+model_reference_helper_init (ModelReferenceHelper *helper)
+{
+}
+
+static void
+model_reference_helper_class_init (ModelReferenceHelperClass *class)
+{
+  class->finalize = model_reference_helper_finalize;
+}
diff --git a/model/model-reference.c b/model/model-reference.c
new file mode 100644
index 0000000..119237e
--- /dev/null
+++ b/model/model-reference.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright  2009 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the licence, or (at your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "model-implementation.h"
+#include "model.h"
+
+#include <string.h>
+
+/**
+ * SECTION:reference
+ * @Short_Description: a mutable reference to a #ModelObject
+ * @Image: reference.png
+ *
+ * A ModelReference is essentially a variable containing a reference to
+ * a #ModelObject, or %NULL.
+ *
+ * The #ModelObject that a #ModelReference refers to (ie: the value of
+ * the reference) can change with time.
+ *
+ * The most useful attribute of a #ModelReference is that change
+ * notification is supported.  Whenever the value of the #ModelReference
+ * changes, the "changed" signal is emitted.  The signal is always
+ * emitted from the mainloop; never during the execution of method calls
+ * on the model.
+ **/
+
+/**
+ * ModelReference:
+ *
+ * This is an opaque structure; it may not be accessed directly.
+ **/
+
+/**
+ * ModelReferenceClass:
+ * @get_value: virtual function pointer for model_reference_get_value()
+ *
+ * The class structure for #ModelReference.  All virtual functions must
+ * be implemented by each subclass.
+ **/
+G_DEFINE_ABSTRACT_TYPE (ModelReference, model_reference, G_TYPE_OBJECT);
+
+static guint model_reference_changed_signal;
+
+/**
+ * model_reference_get_value:
+ * @reference: a #ModelReference
+ * @returns: the current value of the reference, owned by the caller
+ *
+ * Reads the current value of the reference.  This is essentially the
+ * dereference operation.
+ *
+ * It is appropriate for the caller to call g_object_unref() on the
+ * return value.
+ **/
+ModelObject *
+model_reference_get_value (ModelReference *reference)
+{
+  g_return_val_if_fail (MODEL_IS_REFERENCE (reference), NULL);
+
+  return MODEL_REFERENCE_GET_CLASS (reference)
+    ->get_value (reference);
+}
+
+/**
+ * model_reference_changed:
+ * @reference: a #ModelReference
+ *
+ * Emits the "changed" signal on @reference.  This should be done
+ * whenever the reference takes on a new value (ie:
+ * model_reference_get_value() will return something different than last
+ * time).
+ *
+ * This function should only be called by model implementations.
+ **/
+void
+model_reference_changed (ModelReference *reference)
+{
+  g_return_if_fail (MODEL_IS_REFERENCE (reference));
+
+  g_signal_emit (reference, model_reference_changed_signal, 0);
+}
+
+static void
+model_reference_class_init (ModelReferenceClass *class)
+{
+  /**
+   * ModelReference::changed:
+   * @reference: a #ModelReference
+   *
+   * This signal is emitted whenever the value of the reference has
+   * changed (ie: calling model_reference_get_value() will have a
+   * different result).
+   *
+   * The new value of the reference is available to the signal handler.
+   **/
+  model_reference_changed_signal =
+    g_signal_new ("changed", MODEL_TYPE_REFERENCE,
+                  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+}
+
+static void
+model_reference_init (ModelReference *reference)
+{
+}
diff --git a/model/model-simple-dictionary.c b/model/model-simple-dictionary.c
new file mode 100644
index 0000000..f87c773
--- /dev/null
+++ b/model/model-simple-dictionary.c
@@ -0,0 +1,434 @@
+/*
+ * Copyright  2009 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the licence, or (at your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "model-implementation.h"
+#include "model.h"
+
+#include <string.h>
+
+/**
+ * SECTION:simpledictionary
+ * @Short_Description: a very simple implementation of #ModelDictionary
+ *
+ * #ModelSimpleDictionary is a simple #ModelDictionary implementation.
+ *
+ * After creating an instance, it needs to be filled with values using
+ * model_simple_dictionary_set() or its convenience wrappers.
+ *
+ * No new keys may be added after the first use of any of the
+ * #ModelDictionary APIs, but values of existing keys may be changed.
+ * If you don't know the value of a particular key at creation time then
+ * use %NULL.
+ **/
+
+/**
+ * ModelSimpleDictionary:
+ *
+ * This is an opaque structure; it may not be accessed directly.
+ **/
+G_DEFINE_TYPE (ModelSimpleDictionary,
+               model_simple_dictionary,
+               MODEL_TYPE_DICTIONARY);
+
+typedef struct
+{
+  guint hash : 31;
+  guint monitored : 1;
+  gchar *key;
+
+  ModelObject *value;
+  gpointer rhr;
+} MSDE;
+
+struct _ModelSimpleDictionaryPrivate
+{
+  MSDE *columns[37];
+  gboolean used;
+};
+
+/**
+ * model_simple_dictionary_new:
+ * @returns: a new #ModelSimpleDictionary
+ *
+ * Creates a new #ModelSimpleDictionary with no keys.
+ *
+ * You must add the entire set of keys to it with
+ * model_simple_dictionary_set() before using any of the
+ * #ModelDictionary APIs.
+ **/
+ModelSimpleDictionary *
+model_simple_dictionary_new (void)
+{
+  return g_object_new (MODEL_TYPE_SIMPLE_DICTIONARY, NULL);
+}
+
+/**
+ * model_simple_dictionary_set:
+ * @simple: a #ModelSimpleDictionary
+ * @key: a string, the key to set
+ * @value: the new value, a #ModelObject or %NULL
+ * @monitored: %TRUE if the key is being monitored
+ *
+ * Create a new key, @key, or set the value of an existing key.
+ *
+ * The value is set to @value, which may be %NULL.
+ *
+ * If @monitored is %TRUE, then @simple is kept alive for as long as
+ * there is a #ModelReference for @key.  This allows subclasses of
+ * #ModelSimpleDictionary to continue monitoring for changes in the
+ * value.  If @monitored is %FALSE, then no extra effort is made to keep
+ * @simple alive when #ModelReferences are being held for @key.
+ **/
+void
+model_simple_dictionary_set (ModelSimpleDictionary *simple,
+                             const gchar           *key,
+                             ModelObject           *value,
+                             gboolean               monitored)
+{
+  guint hash;
+  MSDE **col;
+  gint i;
+
+  g_return_if_fail (MODEL_IS_SIMPLE_DICTIONARY (simple));
+  g_return_if_fail (key != NULL);
+
+  hash = g_str_hash (key) & ~(1u<<31);
+  col = &simple->priv->columns[hash % G_N_ELEMENTS (simple->priv->columns)];
+
+  for (i = 0; *col && (*col)[i].key; i++)
+    if ((*col)[i].hash == hash && strcmp ((*col)[i].key, key) == 0)
+      break;
+
+  g_object_ref (simple);
+
+  if (*col == NULL || (*col)[i].key == NULL)
+    {
+      if G_UNLIKELY (simple->priv->used)
+        {
+          g_critical ("key `%s' does not exist in the dictionary "
+                      "and new keys may not be added after the "
+                      "dictionary has been used", key);
+
+          g_object_unref (simple);
+          return;
+        }
+
+      *col = g_renew (MSDE, *col, i + 2);
+      (*col)[i+1].key = NULL;
+
+      (*col)[i].key = g_strdup (key);
+      (*col)[i].hash = hash;
+      (*col)[i].rhr = NULL;
+    }
+  else
+    {
+      if ((*col)[i].value != NULL)
+        g_object_unref ((*col)[i].value);
+
+      if ((*col)[i].monitored != monitored && (*col)[i].rhr)
+        {
+          ModelReferenceHelperReference *rhr = (*col)[i].rhr;
+          if (monitored)
+            {
+              g_assert (rhr->owner == NULL);
+              rhr->owner = g_object_ref (simple);
+            }
+          else
+            {
+              g_assert (rhr->owner == G_OBJECT (simple));
+              g_object_unref (rhr->owner);
+              rhr->owner = NULL;
+            }
+        }
+    }
+
+  (*col)[i].monitored = monitored;
+
+  if (value)
+    (*col)[i].value = g_object_ref (value);
+  else
+    (*col)[i].value = NULL;
+
+  if ((*col)[i].rhr != NULL)
+    model_reference_changed ((*col)[i].rhr);
+
+  g_object_unref (simple);
+}
+
+/**
+ * model_simple_dictionary_set_string:
+ * @simple: a #ModelSimpleDictionary
+ * @key: a string, the key to set
+ * @value: a string
+ * @monitored: %TRUE if the key is being monitored
+ *
+ * Updates the value of @key to the given string.
+ *
+ * This is a convenience wrapper around model_simple_dictionary_set()
+ * and model_string_new().
+ **/
+void
+model_simple_dictionary_set_string (ModelSimpleDictionary *simple,
+                                    const gchar           *key,
+                                    const gchar           *value,
+                                    gboolean               monitored)
+{
+  ModelObject *object;
+
+  object = model_string_new (value);
+  model_simple_dictionary_set (simple, key, object, monitored);
+  g_object_unref (object);
+}
+
+/**
+ * model_simple_dictionary_set_integer:
+ * @simple: a #ModelSimpleDictionary
+ * @key: a string, the key to set
+ * @value: an integer
+ * @monitored: %TRUE if the key is being monitored
+ *
+ * Updates the value of @key to the given integer.
+ *
+ * This is a convenience wrapper around model_simple_dictionary_set()
+ * and model_integer_new().
+ **/
+void
+model_simple_dictionary_set_integer (ModelSimpleDictionary *simple,
+                                     const gchar           *key,
+                                     gint                   value,
+                                     gboolean               monitored)
+{
+  ModelObject *object;
+
+  object = model_integer_new (value);
+  model_simple_dictionary_set (simple, key, object, monitored);
+  g_object_unref (object);
+}
+
+/**
+ * model_simple_dictionary_set_boolean:
+ * @simple: a #ModelSimpleDictionary
+ * @key: a string, the key to set
+ * @value: a boolean value
+ * @monitored: %TRUE if the key is being monitored
+ *
+ * Updates the value of @key to the given boolean value.
+ *
+ * This is a convenience wrapper around model_simple_dictionary_set()
+ * and model_boolean_new().
+ **/
+void
+model_simple_dictionary_set_boolean (ModelSimpleDictionary *simple,
+                                     const gchar           *key,
+                                     gboolean               value,
+                                     gboolean               monitored)
+{
+  ModelObject *object;
+
+  object = model_boolean_new (value);
+  model_simple_dictionary_set (simple, key, object, monitored);
+  g_object_unref (object);
+}
+
+/**
+ * model_simple_dictionary_set_float:
+ * @simple: a #ModelSimpleDictionary
+ * @key: a string, the key to set
+ * @value: a double precision floating point value
+ * @monitored: %TRUE if the key is being monitored
+ *
+ * Updates the value of @key to the given floating point value.
+ *
+ * This is a convenience wrapper around model_simple_dictionary_set()
+ * and model_float_new().
+ **/
+void
+model_simple_dictionary_set_float (ModelSimpleDictionary *simple,
+                                   const gchar           *key,
+                                   gdouble                value,
+                                   gboolean               monitored)
+{
+  ModelObject *object;
+
+  object = model_float_new (value);
+  model_simple_dictionary_set (simple, key, object, monitored);
+  g_object_unref (object);
+}
+
+static MSDE *
+model_simple_dictionary_get_mdse (ModelSimpleDictionary *simple,
+                                  const gchar           *key)
+{
+  guint hash;
+  MSDE *col;
+  gint i;
+
+  simple->priv->used = TRUE;
+
+  hash = g_str_hash (key) & ~(1u<<31);
+  col = simple->priv->columns[hash % G_N_ELEMENTS (simple->priv->columns)];
+
+  for (i = 0; col && col[i].key; i++)
+    if (col[i].hash == hash && strcmp (col[i].key, key) == 0)
+      return &col[i];
+
+  return NULL;
+}
+
+static ModelObject *
+model_simple_dictionary_get_value (ModelDictionary *dict,
+                                   const gchar     *key)
+{
+  ModelSimpleDictionary *simple = MODEL_SIMPLE_DICTIONARY (dict);
+  MSDE *entry;
+
+  entry = model_simple_dictionary_get_mdse (simple, key);
+
+  if G_UNLIKELY (entry == NULL)
+    {
+      g_critical ("key `%s' is not in the dictionary", key);
+      return NULL;
+    }
+
+  if (entry->value != NULL)
+    return g_object_ref (entry->value);
+
+  else
+    return NULL;
+}
+
+static ModelReference *
+model_simple_dictionary_get_reference (ModelDictionary *dict,
+                                       const gchar     *key)
+{
+  ModelSimpleDictionary *simple = MODEL_SIMPLE_DICTIONARY (dict);
+  MSDE *entry;
+
+  entry = model_simple_dictionary_get_mdse (simple, key);
+
+  if G_UNLIKELY (entry == NULL)
+    {
+      g_critical ("key `%s' is not in the dictionary", key);
+      return NULL;
+    }
+
+  if (entry->rhr == NULL)
+    { 
+      ModelReferenceHelperReference *rhr;
+
+      rhr = g_object_new (MODEL_TYPE_RHR, NULL);
+
+      if (entry->monitored)
+        rhr->owner = g_object_ref (simple);
+
+      rhr->value_location = &entry->value;
+      entry->rhr = rhr;
+
+      g_object_add_weak_pointer (entry->rhr, &entry->rhr);
+    }
+  else
+    g_object_ref (entry->rhr);
+
+  return entry->rhr;
+}
+
+static gchar **
+model_simple_dictionary_list_keys (ModelDictionary *dict,
+                                   gint            *length)
+{
+  ModelSimpleDictionary *simple = MODEL_SIMPLE_DICTIONARY (dict);
+  gchar **result;
+  gint items = 0;
+  gint i, j, k;
+
+  for (i = 0; i < G_N_ELEMENTS (simple->priv->columns); i++)
+    for (j = 0; simple->priv->columns[i][j].key; j++)
+      items++;
+
+  result = g_new (gchar *, items + 1);
+  k = 0;
+
+  for (i = 0; i < G_N_ELEMENTS (simple->priv->columns); i++)
+    for (j = 0; simple->priv->columns[i][j].key; j++)
+      result[k++] = g_strdup (simple->priv->columns[i][j].key);
+
+  g_assert (items == k);
+  result[k++] = NULL;
+
+  if (length)
+    *length = items;
+
+  return result;
+}
+
+static void
+model_simple_dictionary_finalize (GObject *object)
+{
+  ModelSimpleDictionary *simple = MODEL_SIMPLE_DICTIONARY (object);
+  gint i, j;
+
+  for (i = 0; i < G_N_ELEMENTS (simple->priv->columns); i++)
+    if (simple->priv->columns[i] != NULL)
+      {
+        for (j = 0; simple->priv->columns[i][j].key; j++)
+          {
+            MSDE *entry = &simple->priv->columns[i][j];
+
+            g_free (entry->key);
+
+            if (entry->rhr != NULL)
+              {
+                ModelReferenceHelperReference *rhr = entry->rhr;
+
+                /* we're going away now, so stash the value */
+                g_assert (rhr->value_location == &entry->value);
+                rhr->value_location = &rhr->direct_value;
+                rhr->direct_value = entry->value;
+              }
+            else
+              {
+                if (entry->value != NULL)
+                  g_object_unref (entry->value);
+              }
+
+            g_assert (entry->rhr == NULL);
+          }
+
+        g_free (simple->priv->columns[i]);
+      }
+
+  G_OBJECT_CLASS (model_simple_dictionary_parent_class)
+    ->finalize (object);
+}
+
+static void
+model_simple_dictionary_init (ModelSimpleDictionary *simple)
+{
+  simple->priv = G_TYPE_INSTANCE_GET_PRIVATE (simple,
+                                              MODEL_TYPE_SIMPLE_DICTIONARY,
+                                              ModelSimpleDictionaryPrivate);
+}
+
+static void
+model_simple_dictionary_class_init (ModelSimpleDictionaryClass *class)
+{
+  ModelDictionaryClass *dict_class = MODEL_DICTIONARY_CLASS (class);
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->finalize = model_simple_dictionary_finalize;
+  dict_class->get_value = model_simple_dictionary_get_value;
+  dict_class->get_reference = model_simple_dictionary_get_reference;
+  dict_class->list_keys = model_simple_dictionary_list_keys;
+
+  g_type_class_add_private (class, sizeof (ModelSimpleDictionaryPrivate));
+}
diff --git a/model/model-simple-list.c b/model/model-simple-list.c
new file mode 100644
index 0000000..52f0962
--- /dev/null
+++ b/model/model-simple-list.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright  2009 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the licence, or (at your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "model-implementation.h"
+#include "model.h"
+
+#include <string.h>
+
+/**
+ * SECTION:simplelist
+ * @Short_Description: a very simple implementation of #ModelList
+ *
+ * #ModelSimpleList is a simple #ModelList implementation.  It is empty
+ * when constructed.  There are simple APIs for inserting and removing
+ * items by their index.  There is also a more complicated "splice" API
+ * to allow performing adjacent removes and inserts simultaneously.
+ *
+ * If your list contains items that can be identified by some sort of
+ * key (such as files in a directory) then #ModelAbstractSortedList
+ * might be more useful.
+ **/
+
+/**
+ * ModelSimpleList:
+ *
+ * This is an opaque structure; it may not be accessed directly.
+ **/
+typedef ModelListClass ModelSimpleListClass;
+struct _ModelSimpleList
+{
+  ModelList parent_instance;
+
+  ModelObject **items;
+  gulong n_items;
+};
+G_DEFINE_TYPE (ModelSimpleList, model_simple_list, MODEL_TYPE_LIST)
+
+/**
+ * model_simple_list_splice:
+ * @simple: a #ModelSimpleList
+ * @position: the position at which to perform the splice
+ * @n_removes: the number of items to remove from @position
+ * @inserts: the list of items to insert at @position
+ * @n_inserts: the number of items to insert (the length of @inserts)
+ * @more: %TRUE if more events are coming
+ *
+ * Performs a splice operation on the list.  This is similar to the
+ * JavaScript list operation of the same name.
+ *
+ * Starting at @position, @n_removes items are removed from the list.
+ * In their place, the items given in @inserts are added.
+ *
+ * This function takes its own references to each of the items in
+ * @inserts, but does not modify the array.
+ **/ 
+void
+model_simple_list_splice (ModelSimpleList     *simple,
+                          gulong               position,
+                          gulong               n_removes,
+                          ModelObject * const *inserts,
+                          gulong               n_inserts,
+                          gboolean             more)
+{
+  gulong new_count, old_count;
+  ModelObject **old_items;
+
+  old_count = simple->n_items;
+  old_items = simple->items;
+
+  new_count = old_count + n_inserts + n_removes;
+
+  if (new_count != old_count)
+    {
+      ModelObject **new_items;
+      gulong i;
+
+      new_items = g_new (ModelObject *, new_count);
+
+      for (i = 0; i < position; i++)
+        new_items[i] = old_items[i];
+
+      for (i = 0; i < n_inserts; i++)
+        new_items[position + i] = g_object_ref (inserts[i]);
+
+      for (i = position + n_removes; i < old_count; i++)
+        new_items[i + n_inserts - n_removes] = old_items[i];
+
+      g_free (simple->items);
+
+      simple->n_items = new_count;
+      simple->items = new_items;
+    }
+}
+
+/**
+ * model_simple_list_remove:
+ * @simple: a #ModelSimpleList
+ * @position: the index of the item to remove
+ *
+ * Removes a single item from the list.
+ **/
+void
+model_simple_list_remove (ModelSimpleList *simple,
+                          gulong           position)
+{
+  model_simple_list_splice (simple, position, 1, NULL, 0, FALSE);
+}
+
+/**
+ * model_simple_list_insert:
+ * @simple: a #ModelSimpleList
+ * @position: the position to insert at
+ * @value: the item to insert into the list
+ *
+ * Inserts a single item to the list.  @position is the index of the
+ * item to insert before.
+ **/
+void
+model_simple_list_insert (ModelSimpleList *simple,
+                          gulong           position,
+                          ModelObject     *value)
+{
+  model_simple_list_splice (simple, position, 0, &value, 1, FALSE);
+}
+
+/**
+ * model_simple_list_append:
+ * @simple: a #ModelSimpleList
+ * @value: the item to insert into the list
+ *
+ * Appends an item to the end of the list.
+ **/
+void
+model_simple_list_append (ModelSimpleList *simple,
+                          ModelObject     *value)
+{
+  model_simple_list_splice (simple, simple->n_items, 0, &value, 1, FALSE);
+}
+
+static gulong
+model_simple_list_n_children (ModelList *list)
+{
+  ModelSimpleList *simple = MODEL_SIMPLE_LIST (list);
+
+  return simple->n_items;
+}
+
+static ModelObject *
+model_simple_list_get_child (ModelList *list,
+                             gulong     index)
+{
+  ModelSimpleList *simple = MODEL_SIMPLE_LIST (list);
+
+  g_return_val_if_fail (index < simple->n_items, NULL);
+
+  return g_object_ref (simple->items[index]);
+}
+
+static void
+model_simple_list_finalize (GObject *object)
+{
+  ModelSimpleList *simple = MODEL_SIMPLE_LIST (object);
+  gint i;
+
+  for (i = 0; i < simple->n_items; i++)
+    g_object_unref (simple->items[i]);
+
+  g_free (simple->items);
+
+  G_OBJECT_CLASS (model_simple_list_parent_class)
+    ->finalize (object);
+}
+
+static void
+model_simple_list_init (ModelSimpleList *simple)
+{
+}
+
+static void
+model_simple_list_class_init (ModelSimpleListClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  ModelListClass *list_class = MODEL_LIST_CLASS (class);
+
+  object_class->finalize = model_simple_list_finalize;
+  list_class->n_children = model_simple_list_n_children;
+  list_class->get_child = model_simple_list_get_child;
+}
diff --git a/model/model-simple-reference.c b/model/model-simple-reference.c
new file mode 100644
index 0000000..1534829
--- /dev/null
+++ b/model/model-simple-reference.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright  2009 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the licence, or (at your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Authors: Ryan Lortie <desrt desrt ca>
+ */
+
+#include "model-implementation.h"
+#include "model.h"
+
+#include <string.h>
+
+/**
+ * SECTION:simplereference
+ * @Short_Description: a very simple implementation of #ModelReference
+ * @Image: simplereference.png
+ *
+ * #ModelSimpleReference is a #ModelReference implementation.  It stores
+ * a #ModelObject as the value of the reference.
+ * model_simple_reference_set() can be used to change the value of the
+ * reference, and when the value is changed, the "changed" signal is
+ * emitted.
+ *
+ * The core API of #ModelSimpleReference consists of
+ * model_simple_reference_new() and model_simple_reference_set().
+ * Additionally, there are helper functions to set and construct from
+ * one of the basic value types without requiring the manual
+ * construction of a corresponding #ModelObject instance.
+ **/
+
+/**
+ * ModelSimpleReference:
+ *
+ * This is an opaque structure; it may not be accessed directly.
+ **/
+typedef ModelReferenceClass ModelSimpleReferenceClass;
+struct _ModelSimpleReference
+{
+  ModelReference parent_instance;
+  ModelObject *value;
+};
+G_DEFINE_TYPE (ModelSimpleReference,
+               model_simple_reference,
+               MODEL_TYPE_REFERENCE);
+
+static ModelObject *
+model_simple_reference_get_value (ModelReference *reference)
+{
+  ModelSimpleReference *simple = MODEL_SIMPLE_REFERENCE (reference);
+
+  if (simple->value != NULL)
+    return g_object_ref (simple->value);
+  else
+    return NULL;
+}
+
+static void
+model_simple_reference_finalize (GObject *object)
+{
+  ModelSimpleReference *simple = MODEL_SIMPLE_REFERENCE (object);
+
+  if (simple->value != NULL)
+    g_object_unref (simple->value);
+
+  G_OBJECT_CLASS (model_simple_reference_parent_class)
+    ->finalize (object);
+}
+
+static void
+model_simple_reference_init (ModelSimpleReference *simple)
+{
+}
+
+static void
+model_simple_reference_class_init (ModelSimpleReferenceClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+  object_class->finalize = model_simple_reference_finalize;
+  class->get_value = model_simple_reference_get_value;
+}
+
+/**
+ * model_simple_reference_set:
+ * @simple: a #ModelSimpleReference
+ * @value: the #ModelObject to use as the new value, or %NULL
+ *
+ * Changes the value held by @simple to @value and emits the "changed"
+ * signal.
+ **/
+void
+model_simple_reference_set (ModelSimpleReference *simple,
+                            ModelObject          *value)
+{
+  g_return_if_fail (MODEL_IS_SIMPLE_REFERENCE (simple));
+  g_return_if_fail (value == NULL || MODEL_IS_OBJECT (value));
+
+  if (simple->value != value)
+    {
+      if (simple->value != NULL)
+        g_object_unref (simple->value);
+
+      simple->value = NULL;
+
+      if (value != NULL)
+        simple->value = g_object_ref (value);
+
+      model_reference_changed (MODEL_REFERENCE (simple));
+    }
+}
+
+/**
+ * model_simple_reference_set_string:
+ * @simple: a #ModelSimpleReference
+ * @value: a string
+ *
+ * Updates the value of @simple to the given string.
+ *
+ * This is a convenience wrapper around model_simple_reference_set() and
+ * model_string_new().
+ **/
+void
+model_simple_reference_set_string (ModelSimpleReference *simple,
+                                   const gchar          *value)
+{
+  ModelObject *object;
+
+  object = model_string_new (value);
+  model_simple_reference_set (simple, object);
+  g_object_unref (object);
+}
+
+/**
+ * model_simple_reference_set_integer:
+ * @simple: a #ModelSimpleReference
+ * @value: an integer
+ *
+ * Updates the value of @simple to the given integer.
+ *
+ * This is a convenience wrapper around model_simple_reference_set() and
+ * model_integer_new().
+ **/
+void
+model_simple_reference_set_integer (ModelSimpleReference *simple,
+                                    gint                  value)
+{
+  ModelObject *object;
+
+  object = model_integer_new (value);
+  model_simple_reference_set (simple, object);
+  g_object_unref (object);
+}
+
+/**
+ * model_simple_reference_set_float:
+ * @simple: a #ModelSimpleReference
+ * @value: a double precision floating point value
+ *
+ * Updates the value of @simple to the given floating point value.
+ *
+ * This is a convenience wrapper around model_simple_reference_set() and
+ * model_float_new().
+ **/
+void
+model_simple_reference_set_float (ModelSimpleReference *simple,
+                                  gdouble               value)
+{
+  ModelObject *object;
+
+  object = model_float_new (value);
+  model_simple_reference_set (simple, object);
+  g_object_unref (object);
+}
+
+/**
+ * model_simple_reference_set_boolean:
+ * @simple: a #ModelSimpleReference
+ * @value: a boolean value
+ *
+ * Updates the value of @simple to the given boolean value.
+ *
+ * This is a convenience wrapper around model_simple_reference_set() and
+ * model_boolean_new().
+ **/
+void
+model_simple_reference_set_boolean (ModelSimpleReference *simple,
+                                    gboolean              value)
+{
+  ModelObject *object;
+
+  object = model_boolean_new (value);
+  model_simple_reference_set (simple, object);
+  g_object_unref (object);
+}
+
+/**
+ * model_simple_reference_new:
+ * @value: a #ModelObject to use as the initial value, or %NULL
+ * @returns: a new #ModelSimpleReference
+ *
+ * Creates a #ModelSimpleReference, using @value as the initial value.
+ **/
+ModelSimpleReference *
+model_simple_reference_new (ModelObject *value)
+{
+  ModelSimpleReference *simple;
+
+  g_return_val_if_fail (value == NULL || MODEL_IS_OBJECT (value), NULL);
+
+  simple = g_object_new (MODEL_TYPE_SIMPLE_REFERENCE, NULL);
+
+  if (value != NULL)
+    simple->value = g_object_ref (value);
+
+  return simple;
+}
+
+/**
+ * model_simple_reference_new_string:
+ * @value: a string
+ * @returns: a new #ModelSimpleReference
+ *
+ * Creates a new #ModelSimpleReference holding a string.
+ *
+ * This is a convenience wrapper around model_simple_reference_new() and
+ * model_string_new().
+ **/
+ModelSimpleReference *
+model_simple_reference_new_string (const gchar *value)
+{
+  ModelSimpleReference *simple;
+  ModelObject *object;
+
+  g_return_val_if_fail (value != NULL, NULL);
+
+  object = model_string_new (value);
+  simple = model_simple_reference_new (object);
+  g_object_unref (object);
+
+  return simple;
+}
+
+/**
+ * model_simple_reference_new_integer:
+ * @value: an integer
+ * @returns: a new #ModelSimpleReference
+ *
+ * Creates a new #ModelSimpleReference holding an integer.
+ *
+ * This is a convenience wrapper around model_simple_reference_new() and
+ * model_integer_new().
+ **/
+ModelSimpleReference *
+model_simple_reference_new_integer (gint value)
+{
+  ModelSimpleReference *simple;
+  ModelObject *object;
+
+  object = model_integer_new (value);
+  simple = model_simple_reference_new (object);
+  g_object_unref (object);
+
+  return simple;
+}
+
+/**
+ * model_simple_reference_new_float:
+ * @value: a double precision floating point value
+ * @returns: a new #ModelSimpleReference
+ *
+ * Creates a new #ModelSimpleReference holding a floating point value.
+ *
+ * This is a convenience wrapper around model_simple_reference_new() and
+ * model_float_new().
+ **/
+ModelSimpleReference *
+model_simple_reference_new_float (gdouble value)
+{
+  ModelSimpleReference *simple;
+  ModelObject *object;
+
+  object = model_float_new (value);
+  simple = model_simple_reference_new (object);
+  g_object_unref (object);
+
+  return simple;
+}
+
+/**
+ * model_simple_reference_new_boolean:
+ * @value: a boolean value
+ * @returns: a new #ModelSimpleReference
+ *
+ * Creates a new #ModelSimpleReference holding a boolean value.
+ *
+ * This is a convenience wrapper around model_simple_reference_new() and
+ * model_boolean_new().
+ **/
+ModelSimpleReference *
+model_simple_reference_new_boolean (gboolean value)
+{
+  ModelSimpleReference *simple;
+  ModelObject *object;
+
+  object = model_boolean_new (value);
+  simple = model_simple_reference_new (object);
+  g_object_unref (object);
+
+  return simple;
+}



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