[model/wip/api-redesign] Split up model.c in per classes sources
- From: Alberto Ruiz <aruiz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [model/wip/api-redesign] Split up model.c in per classes sources
- Date: Fri, 26 Oct 2012 21:22:09 +0000 (UTC)
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]