Release Clutter 1.11.4 (snapshot)
[profile/ivi/clutter.git] / clutter / clutter-model.c
1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Authored By Matthew Allum  <mallum@openedhand.com>
7  *             Neil Jagdish Patel <njp@o-hand.com>
8  *             Emmanuele Bassi <ebassi@openedhand.com>
9  *
10  * Copyright (C) 2006 OpenedHand
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
24  *
25  *
26  *
27  * NB: Inspiration for column storage taken from GtkListStore
28  */
29
30 /**
31  * SECTION:clutter-model
32  * @short_description: A generic model implementation
33  *
34  * #ClutterModel is a generic list model API which can be used to implement
35  * the model-view-controller architectural pattern in Clutter.
36  *
37  * The #ClutterModel class is a list model which can accept most GObject 
38  * types as a column type.
39  * 
40  * Creating a simple clutter model:
41  * <informalexample><programlisting>
42  * enum
43  * {
44  *   COLUMN_INT,
45  *   COLUMN_STRING,
46  *
47  *   N_COLUMNS
48  * };
49  * 
50  * {
51  *   ClutterModel *model;
52  *   gint i;
53  *
54  *   model = clutter_model_default_new (N_COLUMNS,
55  *                                      /<!-- -->* column type, column title *<!-- -->/
56  *                                      G_TYPE_INT,     "my integers",
57  *                                      G_TYPE_STRING,  "my strings");
58  *   for (i = 0; i < 10; i++)
59  *     {
60  *       gchar *string = g_strdup_printf ("String %d", i);
61  *       clutter_model_append (model,
62  *                             COLUMN_INT, i,
63  *                             COLUMN_STRING, string,
64  *                             -1);
65  *       g_free (string);
66  *     }
67  *
68  *   
69  * }
70  * </programlisting></informalexample>
71  *
72  * Iterating through the model consists of retrieving a new #ClutterModelIter
73  * pointing to the starting row, and calling clutter_model_iter_next() or
74  * clutter_model_iter_prev() to move forward or backwards, repectively.
75  *
76  * A valid #ClutterModelIter represents the position between two rows in the
77  * model. For example, the "first" iterator represents the gap immediately 
78  * before the first row, and the "last" iterator represents the gap immediately
79  * after the last row. In an empty sequence, the first and last iterators are
80  * the same.
81  *
82  * Iterating a #ClutterModel:
83  * <informalexample><programlisting>
84  * enum
85  * {
86  *   COLUMN_INT,
87  *   COLUMN_STRING.
88  *
89  *   N_COLUMNS
90  * };
91  * 
92  * {
93  *   ClutterModel *model;
94  *   ClutterModelIter *iter = NULL;
95  *
96  *   /<!-- -->*  Fill the model *<!-- -->/
97  *   model = populate_model ();
98  *
99  *   /<!-- -->* Get the first iter *<!-- -->/
100  *   iter = clutter_model_get_first_iter (model);
101  *   while (!clutter_model_iter_is_last (iter))
102  *     {
103  *       print_row (iter);
104  *       
105  *       iter = clutter_model_iter_next (iter);
106  *     }
107  *
108  *   /<!-- -->* Make sure to unref the iter *<!-- -->/
109  *   g_object_unref (iter);
110  * }
111  * </programlisting></informalexample>
112  *
113  * #ClutterModel is an abstract class. Clutter provides a list model
114  * implementation called #ClutterListModel which has been optimised
115  * for insertion and look up in sorted lists.
116  *
117  * <refsect2 id="ClutterModel-script">
118  *   <title>ClutterModel custom properties for #ClutterScript</title>
119  *   <para>#ClutterModel defines a custom property "columns" for #ClutterScript
120  *   which allows defining the column names and types. It also defines a custom
121  *   "rows" property which allows filling the #ClutterModel with some
122  *   data.</para>
123  *   <example id="ClutterModel-script-example">
124  *     <title>Example of the "columns" and "rows" custom properties</title>
125  *     <para>The definition below will create a #ClutterListModel with three
126  *     columns: the first one with name "Name" and containing strings; the
127  *     second one with name "Score" and containing integers; the third one with
128  *     name "Icon" and containing #ClutterTexture<!-- -->s. The model is filled
129  *     with three rows. A row can be defined either with an array that holds
130  *     all columns of a row, or an object that holds "column-name" :
131  *     "column-value" pairs.
132  *     </para>
133  *     <programlisting>
134  *  {
135  *    "type" : "ClutterListModel",
136  *    "id" : "teams-model",
137  *    "columns" : [
138  *      [ "Name", "gchararray" ],
139  *      [ "Score", "gint" ],
140  *      [ "Icon", "ClutterTexture" ]
141  *    ],
142  *    "rows" : [
143  *      [ "Team 1", 42, { "type" : "ClutterTexture", "filename" : "team1.png" } ],
144  *      [ "Team 2", 23, "team2-icon-script-id" ],
145  *      { "Name" : "Team 3", "Icon" : "team3-icon-script-id" }
146  *    ]
147  *  }
148  *     </programlisting>
149  *   </example>
150  * </refsect2>
151  *
152  * #ClutterModel is available since Clutter 0.6
153  */
154
155
156 #ifdef HAVE_CONFIG_H
157 #include "config.h"
158 #endif
159
160 #include <string.h>
161 #include <glib-object.h>
162 #include <gobject/gvaluecollector.h>
163
164 #include "clutter-model.h"
165 #include "clutter-model-private.h"
166
167 #include "clutter-marshal.h"
168 #include "clutter-private.h"
169 #include "clutter-debug.h"
170 #include "clutter-scriptable.h"
171 #include "clutter-script-private.h"
172
173 static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
174
175 G_DEFINE_ABSTRACT_TYPE_WITH_CODE
176         (ClutterModel, clutter_model, G_TYPE_OBJECT,
177          G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
178                                 clutter_scriptable_iface_init));
179
180 enum
181 {
182   PROP_0,
183
184   PROP_FILTER_SET
185 };
186
187 enum
188 {
189   ROW_ADDED,
190   ROW_REMOVED,
191   ROW_CHANGED,
192
193   SORT_CHANGED,
194   FILTER_CHANGED,
195   
196   LAST_SIGNAL
197 };
198
199 static guint model_signals[LAST_SIGNAL] = { 0, };
200
201 #define CLUTTER_MODEL_GET_PRIVATE(obj) \
202   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_MODEL, ClutterModelPrivate))
203
204 struct _ClutterModelPrivate
205 {
206   GType                  *column_types;
207   gchar                 **column_names;
208
209   /* we use an integer here because we want to be able to use -1 as a
210    * guard value, to allow calling set_names() and set_types() from
211    * sub-classes of ClutterModel. see bug:
212    *
213    *   http://bugzilla.openedhand.com/show_bug.cgi?id=2032
214    *
215    * for a reference.
216    */
217   gint                    n_columns; 
218
219   ClutterModelFilterFunc  filter_func;
220   gpointer                filter_data;
221   GDestroyNotify          filter_notify;
222
223   gint                    sort_column;
224   ClutterModelSortFunc    sort_func;
225   gpointer                sort_data;
226   GDestroyNotify          sort_notify;
227 };
228
229 static GType
230 clutter_model_real_get_column_type (ClutterModel *model,
231                                     guint         column)
232 {
233   ClutterModelPrivate *priv = model->priv;
234
235   if (column >= clutter_model_get_n_columns (model))
236     return G_TYPE_INVALID;
237
238   return priv->column_types[column];
239 }
240
241 static const gchar *
242 clutter_model_real_get_column_name (ClutterModel *model,
243                                     guint         column)
244 {
245   ClutterModelPrivate *priv = model->priv;
246
247   if (column >= clutter_model_get_n_columns (model))
248     return NULL;
249
250   if (priv->column_names && priv->column_names[column])
251     return priv->column_names[column];
252
253   return g_type_name (priv->column_types[column]);
254 }
255
256 static guint
257 clutter_model_real_get_n_columns (ClutterModel *model)
258 {
259   ClutterModelPrivate *priv = model->priv;
260
261   if (priv->n_columns < 0)
262     return 0;
263
264   return priv->n_columns;
265 }
266
267 static guint
268 clutter_model_real_get_n_rows (ClutterModel *model)
269 {
270   ClutterModelIter *iter;
271   guint row_count;
272
273   g_return_val_if_fail (CLUTTER_IS_MODEL (model), 0);
274
275   iter = clutter_model_get_first_iter (model);
276   if (iter == NULL)
277     return 0;
278
279   row_count = 0;
280   while (!clutter_model_iter_is_last (iter))
281     {
282       if (clutter_model_filter_iter (model, iter))
283         row_count += 1;
284
285       iter = clutter_model_iter_next (iter);
286     }
287
288   g_object_unref (iter);
289
290   return row_count;
291 }
292
293 static void 
294 clutter_model_finalize (GObject *object)
295 {
296   ClutterModelPrivate *priv = CLUTTER_MODEL (object)->priv;
297   gint i;
298
299   if (priv->sort_notify)
300     priv->sort_notify (priv->sort_data);
301   
302   if (priv->filter_notify)
303     priv->filter_notify (priv->filter_data);
304
305   g_free (priv->column_types);
306
307   if (priv->column_names != NULL)
308     {
309       /* the column_names vector might have holes in it, so we need
310        * to use the columns number to clear up everything
311        */
312       for (i = 0; i < priv->n_columns; i++)
313         g_free (priv->column_names[i]);
314
315       g_free (priv->column_names);
316     }
317
318   G_OBJECT_CLASS (clutter_model_parent_class)->finalize (object);
319 }
320
321 static void
322 clutter_model_get_property (GObject    *gobject,
323                             guint       prop_id,
324                             GValue     *value,
325                             GParamSpec *pspec)
326 {
327   ClutterModelPrivate *priv = CLUTTER_MODEL (gobject)->priv;
328
329   switch (prop_id)
330     {
331     case PROP_FILTER_SET:
332       g_value_set_boolean (value, priv->filter_func != NULL);
333       break;
334
335     default:
336       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
337       break;
338     }
339 }
340
341 static void
342 clutter_model_class_init (ClutterModelClass *klass)
343 {
344   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
345   GParamSpec *pspec;
346
347   gobject_class->get_property = clutter_model_get_property;
348   gobject_class->finalize = clutter_model_finalize;
349
350   g_type_class_add_private (gobject_class, sizeof (ClutterModelPrivate));
351
352   klass->get_column_name  = clutter_model_real_get_column_name;
353   klass->get_column_type  = clutter_model_real_get_column_type;
354   klass->get_n_columns    = clutter_model_real_get_n_columns;
355   klass->get_n_rows       = clutter_model_real_get_n_rows;
356
357   /**
358    * ClutterModel:filter-set:
359    *
360    * Whether the #ClutterModel has a filter set
361    *
362    * This property is set to %TRUE if a filter function has been
363    * set using clutter_model_set_filter()
364    *
365    * Since: 1.0
366    */
367   pspec = g_param_spec_boolean ("filter-set",
368                                 "Filter Set",
369                                 "Whether the model has a filter",
370                                 FALSE,
371                                 CLUTTER_PARAM_READABLE);
372   g_object_class_install_property (gobject_class, PROP_FILTER_SET, pspec);
373
374    /**
375    * ClutterModel::row-added:
376    * @model: the #ClutterModel on which the signal is emitted
377    * @iter: a #ClutterModelIter pointing to the new row
378    *
379    * The ::row-added signal is emitted when a new row has been added.
380    * The data on the row has already been set when the ::row-added signal
381    * has been emitted.
382    *
383    * Since: 0.6
384    */
385   model_signals[ROW_ADDED] =
386     g_signal_new ("row-added",
387                   G_TYPE_FROM_CLASS (gobject_class),
388                   G_SIGNAL_RUN_LAST,
389                   G_STRUCT_OFFSET (ClutterModelClass, row_added),
390                   NULL, NULL,
391                   _clutter_marshal_VOID__OBJECT,
392                   G_TYPE_NONE, 1,
393                   CLUTTER_TYPE_MODEL_ITER);
394    /**
395    * ClutterModel::row-removed:
396    * @model: the #ClutterModel on which the signal is emitted
397    * @iter: a #ClutterModelIter pointing to the removed row
398    *
399    * The ::row-removed signal is emitted when a row has been removed.
400    * The data on the row pointed by the passed iterator is still valid
401    * when the ::row-removed signal has been emitted.
402    *
403    * Since: 0.6
404    */
405   model_signals[ROW_REMOVED] =
406     g_signal_new ("row-removed",
407                   G_TYPE_FROM_CLASS (gobject_class),
408                   G_SIGNAL_RUN_LAST,
409                   G_STRUCT_OFFSET (ClutterModelClass, row_removed),
410                   NULL, NULL,
411                   _clutter_marshal_VOID__OBJECT,
412                   G_TYPE_NONE, 1,
413                   CLUTTER_TYPE_MODEL_ITER);
414    /**
415    * ClutterModel::row-changed:
416    * @model: the #ClutterModel on which the signal is emitted
417    * @iter: a #ClutterModelIter pointing to the changed row
418    *
419    * The ::row-removed signal is emitted when a row has been changed.
420    * The data on the row has already been updated when the ::row-changed
421    * signal has been emitted.
422    *
423    * Since: 0.6
424    */
425   model_signals[ROW_CHANGED] =
426     g_signal_new ("row-changed",
427                   G_TYPE_FROM_CLASS (gobject_class),
428                   G_SIGNAL_RUN_LAST,
429                   G_STRUCT_OFFSET (ClutterModelClass, row_changed),
430                   NULL, NULL,
431                   _clutter_marshal_VOID__OBJECT,
432                   G_TYPE_NONE, 1,
433                   CLUTTER_TYPE_MODEL_ITER);
434   /**
435    * ClutterModel::sort-changed:
436    * @model: the #ClutterModel on which the signal is emitted
437    * 
438    * The ::sort-changed signal is emitted after the model has been sorted
439    *
440    * Since: 0.6
441    */
442   model_signals[SORT_CHANGED] =
443     g_signal_new ("sort-changed",
444                   G_TYPE_FROM_CLASS (gobject_class),
445                   G_SIGNAL_RUN_LAST,
446                   G_STRUCT_OFFSET (ClutterModelClass, sort_changed),
447                   NULL, NULL,
448                   _clutter_marshal_VOID__VOID,
449                   G_TYPE_NONE, 0);
450    /**
451    * ClutterModel::filter-changed:
452    * @model: the #ClutterModel on which the signal is emitted   
453    *
454    * The ::filter-changed signal is emitted when a new filter has been applied
455    *
456    * Since: 0.6
457    */
458   model_signals[FILTER_CHANGED] =
459     g_signal_new ("filter-changed",
460                   G_TYPE_FROM_CLASS (gobject_class),
461                   G_SIGNAL_RUN_LAST,
462                   G_STRUCT_OFFSET (ClutterModelClass, filter_changed),
463                   NULL, NULL,
464                   _clutter_marshal_VOID__VOID,
465                   G_TYPE_NONE, 0);
466 }
467
468 static void
469 clutter_model_init (ClutterModel *self)
470 {
471   ClutterModelPrivate *priv;
472   
473   self->priv = priv = CLUTTER_MODEL_GET_PRIVATE (self);
474
475   priv->n_columns = -1;
476   priv->column_types = NULL;
477   priv->column_names = NULL;
478
479   priv->filter_func = NULL;
480   priv->filter_data = NULL;
481   priv->filter_notify = NULL;
482
483   priv->sort_column = -1;
484   priv->sort_func = NULL;
485   priv->sort_data = NULL;
486   priv->sort_notify = NULL;
487 }
488
489 /* XXX - is this whitelist really necessary? we accept every fundamental
490  * type.
491  */
492 gboolean
493 _clutter_model_check_type (GType gtype)
494 {
495   gint i = 0;
496   static const GType type_list[] =
497     {
498       G_TYPE_BOOLEAN,
499       G_TYPE_CHAR,
500       G_TYPE_UCHAR,
501       G_TYPE_INT,
502       G_TYPE_UINT,
503       G_TYPE_LONG,
504       G_TYPE_ULONG,
505       G_TYPE_INT64,
506       G_TYPE_UINT64,
507       G_TYPE_ENUM,
508       G_TYPE_FLAGS,
509       G_TYPE_FLOAT,
510       G_TYPE_DOUBLE,
511       G_TYPE_STRING,
512       G_TYPE_POINTER,
513       G_TYPE_BOXED,
514       G_TYPE_OBJECT,
515       G_TYPE_INVALID
516     };
517
518   if (! G_TYPE_IS_VALUE_TYPE (gtype))
519     return FALSE;
520
521   while (type_list[i] != G_TYPE_INVALID)
522     {
523       if (g_type_is_a (gtype, type_list[i]))
524         return TRUE;
525       i++;
526     }
527   return FALSE;
528 }
529
530
531 typedef struct {
532     gchar *name;
533     GType  type;
534 } ColumnInfo;
535
536 static gboolean
537 clutter_model_parse_custom_node (ClutterScriptable *scriptable,
538                                  ClutterScript     *script,
539                                  GValue            *value,
540                                  const gchar       *name,
541                                  JsonNode          *node)
542 {
543   if (strcmp (name, "columns") == 0)
544     {
545       GSList *columns = NULL;
546       GList *elements, *l;
547
548       if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
549         return FALSE;
550
551       elements = json_array_get_elements (json_node_get_array (node));
552
553       for (l = elements; l != NULL; l = l->next)
554         {
555           JsonNode *child_node = l->data;
556           JsonArray *array = json_node_get_array (child_node);
557           ColumnInfo *cinfo;
558           const gchar *column_name;
559           const gchar *type_name;
560
561           if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY ||
562               json_array_get_length (array) != 2)
563             {
564               g_warning ("A column must be an array of "
565                          "[\"column-name\", \"GType-name\"] pairs");
566               return FALSE;
567             }
568
569           column_name = json_array_get_string_element (array, 0);
570           type_name = json_array_get_string_element (array, 1);
571
572           cinfo = g_slice_new0 (ColumnInfo);
573           cinfo->name = g_strdup (column_name);
574           cinfo->type = clutter_script_get_type_from_name (script, type_name);
575
576           columns = g_slist_prepend (columns, cinfo);
577         }
578
579       g_list_free (elements);
580
581       g_value_init (value, G_TYPE_POINTER);
582       g_value_set_pointer (value, g_slist_reverse (columns));
583
584       return TRUE;
585     }
586   else if (strcmp (name, "rows") == 0)
587     {
588       GSList *rows = NULL;
589       GList *elements, *l;
590
591       if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
592         return FALSE;
593
594       /*
595        * at this point we have no information about the column types, so
596        * we just copy the json elements and resolve them in the
597        * set_custom_property method
598        */
599       elements = json_array_get_elements (json_node_get_array (node));
600       for (l = elements; l != NULL; l = l->next)
601         rows = g_slist_prepend (rows, json_node_copy (l->data));
602       g_list_free (elements);
603
604       g_value_init (value, G_TYPE_POINTER);
605       g_value_set_pointer (value, g_slist_reverse (rows));
606
607       return TRUE;
608     }
609   return FALSE;
610 }
611
612 static void
613 clutter_model_set_custom_property (ClutterScriptable *scriptable,
614                                    ClutterScript     *script,
615                                    const gchar       *name,
616                                    const GValue      *value)
617 {
618   if (strcmp (name, "columns") == 0)
619     {
620       ClutterModel *model = CLUTTER_MODEL (scriptable);
621       GSList *columns, *l;
622       guint n_columns;
623       gint i;
624
625       columns = g_value_get_pointer (value);
626       n_columns = g_slist_length (columns);
627
628       _clutter_model_set_n_columns (model, n_columns, TRUE, TRUE);
629
630       for (i = 0, l = columns; l != NULL; l = l->next, i++)
631         {
632           ColumnInfo *cinfo = l->data;
633
634           _clutter_model_set_column_name (model, i, cinfo->name);
635           _clutter_model_set_column_type (model, i, cinfo->type);
636
637           g_free (cinfo->name);
638           g_slice_free (ColumnInfo, cinfo);
639         }
640
641       g_slist_free (columns);
642     }
643   else if (strcmp (name, "rows") == 0)
644     {
645       ClutterModel *model = CLUTTER_MODEL (scriptable);
646       GSList *rows, *l;
647       guint n_columns, row = 0;
648
649       rows = g_value_get_pointer (value);
650       n_columns = clutter_model_get_n_columns (model);
651
652       for (l = rows; l; l = l->next)
653         {
654           JsonNode *node = l->data;
655           guint *columns = NULL, i, n_values = 0;
656           GValue *values = NULL;
657
658           if (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY)
659             {
660               JsonArray *array = json_node_get_array (node);
661
662               if (json_array_get_length (array) != n_columns)
663                 {
664                   g_warning ("Row %d contains the wrong count of columns",
665                              g_slist_position (rows, l) + 1);
666                   row += 1;
667                   continue;
668                 }
669
670               /* array more requires all columns */
671               n_values = n_columns;
672
673               columns = g_new (guint, n_values);
674               values = g_new0 (GValue, n_values);
675
676               for (i = 0; i < n_values; i++)
677                 {
678                   GType column_type;
679                   const gchar *column_name;
680
681                   column_type = clutter_model_get_column_type (model, i);
682                   column_name = clutter_model_get_column_name (model, i);
683
684                   columns[i] = i;
685                   g_value_init (&values[i], column_type);
686
687                   _clutter_script_parse_node (script, &values[i], column_name,
688                                               json_array_get_element (array, i),
689                                               NULL);
690                 }
691             }
692           else if (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT)
693             {
694               JsonObject *object = json_node_get_object (node);
695               GList *members, *m;
696               guint column = 0;
697
698               /* object mode does not require all columns */
699               n_values = json_object_get_size (object);
700
701               columns = g_new (guint, n_values);
702               values = g_new0 (GValue, n_values);
703
704               members = json_object_get_members (object);
705               for (m = members; m; m = m->next)
706                 {
707                   const gchar *mname = m->data;
708
709                   for (i = 0; i < clutter_model_get_n_columns (model); i++)
710                     {
711                       const gchar *cname;
712
713                       cname = clutter_model_get_column_name (model, i);
714                       if (strcmp (mname, cname) == 0)
715                         {
716                           JsonNode *member;
717                           GType col_type;
718                           const gchar *col_name;
719
720                           member = json_object_get_member (object, mname);
721
722                           col_type = clutter_model_get_column_type (model, i);
723                           col_name = clutter_model_get_column_name (model, i);
724
725                           columns[column] = i;
726                           g_value_init (&values[column], col_type);
727
728                           _clutter_script_parse_node (script, &values[column],
729                                                       col_name, member,
730                                                       NULL);
731                           break;
732                         }
733                     }
734
735                   column += 1;
736                 }
737             }
738           else
739             {
740               row += 1;
741               continue;
742             }
743
744           clutter_model_insertv (model, row, n_values, columns, values);
745
746           g_free (values);
747           g_free (columns);
748           json_node_free (node);
749
750           row += 1;
751         }
752       g_slist_free (rows);
753     }
754 }
755
756
757 static void
758 clutter_scriptable_iface_init (ClutterScriptableIface *iface)
759 {
760   iface->parse_custom_node = clutter_model_parse_custom_node;
761   iface->set_custom_property = clutter_model_set_custom_property;
762 }
763
764 /**
765  * clutter_model_resort:
766  * @model: a #ClutterModel
767  *
768  * Force a resort on the @model. This function should only be
769  * used by subclasses of #ClutterModel.
770  *
771  * Since: 0.6
772  */
773 void
774 clutter_model_resort (ClutterModel *model)
775 {
776   ClutterModelPrivate *priv;
777   ClutterModelClass *klass;
778
779   g_return_if_fail (CLUTTER_IS_MODEL (model));
780   priv = model->priv;
781
782   klass = CLUTTER_MODEL_GET_CLASS (model);
783
784   if (klass->resort)
785     klass->resort (model, priv->sort_func, priv->sort_data);
786 }
787
788 /**
789  * clutter_model_filter_row:
790  * @model: a #ClutterModel
791  * @row: the row to filter
792  *
793  * Checks whether @row should be filtered or not using the
794  * filtering function set on @model.
795  *
796  * This function should be used only by subclasses of #ClutterModel.
797  *
798  * Return value: %TRUE if the row should be displayed,
799  *   %FALSE otherwise
800  *
801  * Since: 0.6
802  */
803 gboolean
804 clutter_model_filter_row (ClutterModel *model,
805                           guint         row)
806 {
807   ClutterModelPrivate *priv;
808   ClutterModelIter *iter;
809   gboolean res = TRUE;
810
811   g_return_val_if_fail (CLUTTER_IS_MODEL (model), TRUE);
812
813   priv = model->priv;
814
815   if (!priv->filter_func)
816     return TRUE;
817
818   iter = clutter_model_get_iter_at_row (model, row);
819   if (iter == NULL)
820     return FALSE;
821
822   res = priv->filter_func (model, iter, priv->filter_data);
823
824   g_object_unref (iter);
825
826   return res;
827 }
828
829 /**
830  * clutter_model_filter_iter:
831  * @model: a #ClutterModel
832  * @iter: the row to filter
833  *
834  * Checks whether the row pointer by @iter should be filtered or not using
835  * the filtering function set on @model.
836  *
837  * This function should be used only by subclasses of #ClutterModel.
838  *
839  * Return value: %TRUE if the row should be displayed,
840  *   %FALSE otherwise
841  *
842  * Since: 0.6
843  */
844 gboolean
845 clutter_model_filter_iter (ClutterModel     *model,
846                            ClutterModelIter *iter)
847 {
848   ClutterModelPrivate *priv;
849
850   g_return_val_if_fail (CLUTTER_IS_MODEL (model), TRUE);
851   g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), TRUE);
852
853   priv = model->priv;
854
855   if (!priv->filter_func)
856     return TRUE;
857
858   return priv->filter_func (model, iter, priv->filter_data);
859 }
860
861 /*< private >
862  * clutter_model_set_n_columns:
863  * @model: a #ClutterModel
864  * @n_columns: number of columns
865  * @set_types: set the columns type
866  * @set_names: set the columns name
867  *
868  * Sets the number of columns in @model to @n_columns. If @set_types
869  * or @set_names are %TRUE, initialises the columns type and name
870  * arrays as well.
871  *
872  * This function can only be called once.
873  */
874 void
875 _clutter_model_set_n_columns (ClutterModel *model,
876                               gint          n_columns,
877                               gboolean      set_types,
878                               gboolean      set_names)
879 {
880   ClutterModelPrivate *priv = model->priv;
881
882   if (priv->n_columns > 0 && priv->n_columns != n_columns)
883     return;
884
885   priv->n_columns = n_columns;
886   
887   if (set_types && !priv->column_types)
888     priv->column_types = g_new0 (GType,  n_columns);
889
890   if (set_names && !priv->column_names)
891     priv->column_names = g_new0 (gchar*, n_columns);
892 }
893
894 /*< private >
895  * _clutter_model_set_column_type:
896  * @model: a #ClutterModel
897  * @column: column index
898  * @gtype: type of the column
899  *
900  * Sets the type of @column inside @model
901  */
902 void
903 _clutter_model_set_column_type (ClutterModel *model,
904                                 gint          column,
905                                 GType         gtype)
906 {
907   ClutterModelPrivate *priv = model->priv;
908
909   priv->column_types[column] = gtype;
910 }
911
912 /*< private >
913  * _clutter_model_set_column_name:
914  * @model: a #ClutterModel
915  * @column: column index
916  * @name: name of the column, or %NULL
917  *
918  * Sets the name of @column inside @model
919  */
920 void
921 _clutter_model_set_column_name (ClutterModel *model,
922                                 gint          column,
923                                 const gchar  *name)
924 {
925   ClutterModelPrivate *priv = model->priv;
926
927   priv->column_names[column] = g_strdup (name);
928 }
929
930 /**
931  * clutter_model_set_types:
932  * @model: a #ClutterModel
933  * @n_columns: number of columns for the model
934  * @types: (array length=n_columns): an array of #GType types
935  *
936  * Sets the types of the columns inside a #ClutterModel.
937  *
938  * This function is meant primarily for #GObjects that inherit from
939  * #ClutterModel, and should only be used when contructing a #ClutterModel.
940  * It will not work after the initial creation of the #ClutterModel.
941  *
942  * Since: 0.6
943  */
944 void
945 clutter_model_set_types (ClutterModel *model,
946                          guint         n_columns,
947                          GType        *types)
948 {
949   ClutterModelPrivate *priv;
950   gint i;
951
952   g_return_if_fail (CLUTTER_IS_MODEL (model));
953   g_return_if_fail (n_columns > 0);
954
955   priv = model->priv;
956
957   g_return_if_fail (priv->n_columns < 0 || priv->n_columns == n_columns);
958   g_return_if_fail (priv->column_types == NULL);
959
960   _clutter_model_set_n_columns (model, n_columns, TRUE, FALSE);
961
962   for (i = 0; i < n_columns; i++)
963     {
964       if (!_clutter_model_check_type (types[i]))
965         {
966           g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
967           return;
968         }
969
970       _clutter_model_set_column_type (model, i, types[i]);
971     }
972 }
973
974 /**
975  * clutter_model_set_names:
976  * @model: a #ClutterModel
977  * @n_columns: the number of column names
978  * @names: (array length=n_columns): an array of strings
979  *
980  * Assigns a name to the columns of a #ClutterModel.
981  *
982  * This function is meant primarily for #GObjects that inherit from
983  * #ClutterModel, and should only be used when contructing a #ClutterModel.
984  * It will not work after the initial creation of the #ClutterModel.
985  *
986  * Since: 0.6
987  */
988 void
989 clutter_model_set_names (ClutterModel        *model,
990                          guint                n_columns,
991                          const gchar * const  names[])
992 {
993   ClutterModelPrivate *priv;
994   gint i;
995
996   g_return_if_fail (CLUTTER_IS_MODEL (model));
997   g_return_if_fail (n_columns > 0);
998
999   priv = model->priv;
1000
1001   g_return_if_fail (priv->n_columns < 0 || priv->n_columns == n_columns);
1002   g_return_if_fail (priv->column_names == NULL);
1003
1004   _clutter_model_set_n_columns (model, n_columns, FALSE, TRUE);
1005
1006   for (i = 0; i < n_columns; i++)
1007     _clutter_model_set_column_name (model, i, names[i]);
1008 }
1009
1010 /**
1011  * clutter_model_get_n_columns:
1012  * @model: a #ClutterModel
1013  *
1014  * Retrieves the number of columns inside @model.
1015  *
1016  * Return value: the number of columns
1017  *
1018  * Since: 0.6
1019  */
1020 guint
1021 clutter_model_get_n_columns (ClutterModel *model)
1022 {
1023   g_return_val_if_fail (CLUTTER_IS_MODEL (model), 0);
1024
1025   return CLUTTER_MODEL_GET_CLASS (model)->get_n_columns (model);
1026 }
1027
1028 /**
1029  * clutter_model_appendv:
1030  * @model: a #ClutterModel
1031  * @n_columns: the number of columns and values
1032  * @columns: (array length=n_columns): a vector with the columns to set
1033  * @values: (array length=n_columns): a vector with the values
1034  *
1035  * Creates and appends a new row to the #ClutterModel, setting the row
1036  * values for the given @columns upon creation.
1037  *
1038  * Since: 0.6
1039  */
1040 void
1041 clutter_model_appendv (ClutterModel *model,
1042                        guint         n_columns,
1043                        guint        *columns,
1044                        GValue       *values)
1045 {
1046   ClutterModelPrivate *priv;
1047   ClutterModelIter *iter;
1048   gint i;
1049   gboolean resort = FALSE;
1050
1051   g_return_if_fail (CLUTTER_IS_MODEL (model));
1052   g_return_if_fail (n_columns <= clutter_model_get_n_columns (model));
1053   g_return_if_fail (columns != NULL);
1054   g_return_if_fail (values != NULL);
1055
1056   priv = model->priv;
1057
1058   iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, -1);
1059   g_assert (CLUTTER_IS_MODEL_ITER (iter));
1060
1061   for (i = 0; i < n_columns; i++)
1062     {
1063       if (priv->sort_column == columns[i])
1064         resort = TRUE;
1065
1066       clutter_model_iter_set_value (iter, columns[i], &values[i]);
1067     }
1068
1069   g_signal_emit (model, model_signals[ROW_ADDED], 0, iter);
1070
1071   if (resort)
1072     clutter_model_resort (model);
1073
1074   g_object_unref (iter);
1075 }
1076
1077 /* forward declaration */
1078 static void clutter_model_iter_set_internal_valist (ClutterModelIter *iter,
1079                                                     va_list           args);
1080
1081 /**
1082  * clutter_model_append:
1083  * @model: a #ClutterModel
1084  * @...: pairs of column number and value, terminated with -1
1085  *
1086  * Creates and appends a new row to the #ClutterModel, setting the
1087  * row values upon creation. For example, to append a new row where
1088  * column 0 is type %G_TYPE_INT and column 1 is of type %G_TYPE_STRING:
1089  *
1090  * <informalexample><programlisting>
1091  *   ClutterModel *model;
1092  *   model = clutter_model_default_new (2,
1093  *                                      G_TYPE_INT,    "Score",
1094  *                                      G_TYPE_STRING, "Team");
1095  *   clutter_model_append (model, 0, 42, 1, "Team #1", -1);
1096  * </programlisting></informalexample>
1097  *
1098  * Since: 0.6
1099  */
1100 void
1101 clutter_model_append (ClutterModel *model,
1102                       ...)
1103 {
1104   ClutterModelIter *iter;
1105   va_list args;
1106
1107   g_return_if_fail (CLUTTER_IS_MODEL (model));
1108
1109   iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, -1);
1110   g_assert (CLUTTER_IS_MODEL_ITER (iter));
1111
1112   /* do not emit the ::row-changed signal */
1113   va_start (args, model);
1114   clutter_model_iter_set_internal_valist (iter, args);
1115   va_end (args);
1116
1117   g_signal_emit (model, model_signals[ROW_ADDED], 0, iter);
1118
1119   g_object_unref (iter);
1120 }
1121
1122 /**
1123  * clutter_model_prependv:
1124  * @model: a #ClutterModel
1125  * @n_columns: the number of columns and values to set
1126  * @columns: (array length=n_columns): a vector containing the columns to set
1127  * @values: (array length=n_columns): a vector containing the values for the cells
1128  *
1129  * Creates and prepends a new row to the #ClutterModel, setting the row
1130  * values for the given @columns upon creation.
1131  *
1132  * Since: 0.6
1133  */
1134 void
1135 clutter_model_prependv (ClutterModel *model,
1136                         guint         n_columns,
1137                         guint        *columns,
1138                         GValue       *values)
1139 {
1140   ClutterModelPrivate *priv;
1141   ClutterModelIter *iter;
1142   gint i;
1143   gboolean resort = FALSE;
1144
1145   g_return_if_fail (CLUTTER_IS_MODEL (model));
1146   g_return_if_fail (n_columns <= clutter_model_get_n_columns (model));
1147   g_return_if_fail (columns != NULL);
1148   g_return_if_fail (values != NULL);
1149
1150   priv = model->priv;
1151
1152   iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, 0);
1153   g_assert (CLUTTER_IS_MODEL_ITER (iter));
1154
1155   for (i = 0; i < n_columns; i++)
1156     {
1157       if (priv->sort_column == columns[i])
1158         resort = TRUE;
1159
1160       clutter_model_iter_set_value (iter, columns[i], &values[i]);
1161     }
1162
1163   g_signal_emit (model, model_signals[ROW_ADDED], 0, iter);
1164
1165   if (resort)
1166     clutter_model_resort (model);
1167
1168   g_object_unref (iter);
1169 }
1170
1171 /**
1172  * clutter_model_prepend:
1173  * @model: a #ClutterModel
1174  * @...: pairs of column number and value, terminated with -1
1175  *
1176  * Creates and prepends a new row to the #ClutterModel, setting the row
1177  * values upon creation. For example, to prepend a new row where column 0
1178  * is type %G_TYPE_INT and column 1 is of type %G_TYPE_STRING:
1179  *
1180  * <informalexample><programlisting>
1181  *   ClutterModel *model;
1182  *   model = clutter_model_default_new (2,
1183  *                                      G_TYPE_INT,    "Score",
1184  *                                      G_TYPE_STRING, "Team");
1185  *   clutter_model_prepend (model, 0, 42, 1, "Team #1", -1);
1186  * </programlisting></informalexample>
1187  *
1188  * Since: 0.6
1189  */
1190 void
1191 clutter_model_prepend (ClutterModel *model,
1192                        ...)
1193 {
1194   ClutterModelIter *iter;
1195   va_list args;
1196
1197   g_return_if_fail (CLUTTER_IS_MODEL (model));
1198
1199   iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, 0);
1200   g_assert (CLUTTER_IS_MODEL_ITER (iter));
1201
1202   va_start (args, model);
1203   clutter_model_iter_set_internal_valist (iter, args);
1204   va_end (args);
1205
1206   g_signal_emit (model, model_signals[ROW_ADDED], 0, iter);
1207
1208   g_object_unref (iter);
1209 }
1210
1211
1212 /**
1213  * clutter_model_insert:
1214  * @model: a #ClutterModel
1215  * @row: the position to insert the new row
1216  * @...: pairs of column number and value, terminated with -1
1217  *
1218  * Inserts a new row to the #ClutterModel at @row, setting the row
1219  * values upon creation. For example, to insert a new row at index 100,
1220  * where column 0 is type %G_TYPE_INT and column 1 is of type
1221  * %G_TYPE_STRING:
1222  *
1223  * <informalexample><programlisting>
1224  *   ClutterModel *model;
1225  *   model = clutter_model_default_new (2,
1226  *                                      G_TYPE_INT,    "Score",
1227  *                                      G_TYPE_STRING, "Team");
1228  *   clutter_model_insert (model, 3, 0, 42, 1, "Team #1", -1);
1229  * </programlisting></informalexample>
1230  *
1231  * Since: 0.6
1232  */
1233 void
1234 clutter_model_insert (ClutterModel *model,
1235                       guint         row,
1236                       ...)
1237 {
1238   ClutterModelIter *iter;
1239   va_list args;
1240
1241   g_return_if_fail (CLUTTER_IS_MODEL (model));
1242
1243   iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, row);
1244   g_assert (CLUTTER_IS_MODEL_ITER (iter));
1245
1246   /* set_valist() will call clutter_model_resort() if one of the
1247    * passed columns matches the model sorting column index
1248    */
1249   va_start (args, row);
1250   clutter_model_iter_set_internal_valist (iter, args);
1251   va_end (args);
1252
1253   g_signal_emit (model, model_signals[ROW_ADDED], 0, iter);
1254
1255   g_object_unref (iter);
1256 }
1257
1258 /**
1259  * clutter_model_insertv:
1260  * @model: a #ClutterModel
1261  * @row: row index
1262  * @n_columns: the number of columns and values to set
1263  * @columns: (array length=n_columns): a vector containing the columns to set
1264  * @values: (array length=n_columns): a vector containing the values for the cells
1265  *
1266  * Inserts data at @row into the #ClutterModel, setting the row
1267  * values for the given @columns upon creation.
1268  *
1269  * Since: 0.6
1270  */
1271 void
1272 clutter_model_insertv (ClutterModel *model,
1273                        guint         row,
1274                        guint         n_columns,
1275                        guint        *columns,
1276                        GValue       *values)
1277 {
1278   ClutterModelPrivate *priv;
1279   ClutterModelIter *iter;
1280   gint i;
1281   gboolean resort = FALSE;
1282
1283   g_return_if_fail (CLUTTER_IS_MODEL (model));
1284   g_return_if_fail (n_columns <= clutter_model_get_n_columns (model));
1285   g_return_if_fail (columns != NULL);
1286   g_return_if_fail (values != NULL);
1287
1288   priv = model->priv;
1289
1290   iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, row);
1291   g_assert (CLUTTER_IS_MODEL_ITER (iter));
1292
1293   for (i = 0; i < n_columns; i++)
1294     {
1295       if (priv->sort_column == columns[i])
1296         resort = TRUE;
1297
1298       clutter_model_iter_set_value (iter, columns[i], &values[i]);
1299     }
1300
1301   g_signal_emit (model, model_signals[ROW_ADDED], 0, iter);
1302
1303   if (resort)
1304     clutter_model_resort (model);
1305
1306   g_object_unref (iter);
1307 }
1308
1309 /**
1310  * clutter_model_insert_value:
1311  * @model: a #ClutterModel
1312  * @row: position of the row to modify
1313  * @column: column to modify
1314  * @value: new value for the cell
1315  *
1316  * Sets the data in the cell specified by @iter and @column. The type of 
1317  * @value must be convertable to the type of the column. If the row does
1318  * not exist then it is created.
1319  *
1320  * Since: 0.6
1321  */
1322 void
1323 clutter_model_insert_value (ClutterModel *model,
1324                             guint         row,
1325                             guint         column,
1326                             const GValue *value)
1327 {
1328   ClutterModelPrivate *priv;
1329   ClutterModelClass *klass;
1330   ClutterModelIter *iter;
1331   gboolean added = FALSE;
1332   
1333   g_return_if_fail (CLUTTER_IS_MODEL (model));
1334
1335   priv = model->priv;
1336   klass = CLUTTER_MODEL_GET_CLASS (model);
1337
1338   iter = klass->get_iter_at_row (model, row);
1339   if (!iter)
1340     {
1341       iter = klass->insert_row (model, row);
1342       added = TRUE;
1343     }
1344
1345   g_assert (CLUTTER_IS_MODEL_ITER (iter));
1346
1347   clutter_model_iter_set_value (iter, column, value);
1348
1349   if (added)
1350     g_signal_emit (model, model_signals[ROW_ADDED], 0, iter);
1351
1352   if (priv->sort_column == column)
1353     clutter_model_resort (model);
1354
1355   g_object_unref (iter);
1356 }
1357
1358 /**
1359  * clutter_model_remove:
1360  * @model: a #ClutterModel
1361  * @row: position of row to remove
1362  *
1363  * Removes the row at the given position from the model.
1364  *
1365  * Since: 0.6
1366  */
1367 void
1368 clutter_model_remove (ClutterModel *model,
1369                       guint         row)
1370 {
1371   ClutterModelClass *klass;
1372
1373   g_return_if_fail (CLUTTER_IS_MODEL (model));
1374
1375   klass = CLUTTER_MODEL_GET_CLASS (model);
1376   if (klass->remove_row)
1377     klass->remove_row (model, row);
1378 }
1379
1380 /**
1381  * clutter_model_get_column_name:
1382  * @model: #ClutterModel
1383  * @column: the column number
1384  *
1385  * Retrieves the name of the @column
1386  *
1387  * Return value: the name of the column. The model holds the returned
1388  *   string, and it should not be modified or freed
1389  *
1390  * Since: 0.6
1391  */
1392 const gchar *
1393 clutter_model_get_column_name (ClutterModel *model,
1394                                guint         column)
1395 {
1396   ClutterModelClass *klass;
1397
1398   g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL);
1399
1400   if (column >= clutter_model_get_n_columns (model))
1401     {
1402       g_warning ("%s: Invalid column id value %d\n", G_STRLOC, column);
1403       return NULL;
1404     }
1405
1406   klass = CLUTTER_MODEL_GET_CLASS (model);
1407   if (klass->get_column_name)
1408     return klass->get_column_name (model, column);
1409
1410   return NULL;
1411 }
1412
1413 /**
1414  * clutter_model_get_column_type:
1415  * @model: #ClutterModel
1416  * @column: the column number
1417  *
1418  * Retrieves the type of the @column.
1419  *
1420  * Return value: the type of the column.
1421  *
1422  * Since: 0.6
1423  */
1424 GType
1425 clutter_model_get_column_type (ClutterModel *model,
1426                                guint         column)
1427 {
1428   ClutterModelClass *klass;
1429
1430   g_return_val_if_fail (CLUTTER_IS_MODEL (model), G_TYPE_INVALID);
1431
1432   if (column >= clutter_model_get_n_columns (model))
1433     {
1434       g_warning ("%s: Invalid column id value %d\n", G_STRLOC, column);
1435       return G_TYPE_INVALID;
1436     }
1437
1438   klass = CLUTTER_MODEL_GET_CLASS (model);
1439   if (klass->get_column_type)
1440     return klass->get_column_type (model, column);
1441
1442   return G_TYPE_INVALID;
1443 }
1444
1445 /**
1446  * clutter_model_get_iter_at_row:
1447  * @model: a #ClutterModel
1448  * @row: position of the row to retrieve
1449  *
1450  * Retrieves a #ClutterModelIter representing the row at the given index.
1451  *
1452  * If a filter function has been set using clutter_model_set_filter()
1453  * then the @model implementation will return the first non filtered
1454  * row.
1455  *
1456  * Return value: (transfer full): A new #ClutterModelIter, or %NULL if @row was
1457  *   out of bounds. When done using the iterator object, call g_object_unref()
1458  *   to deallocate its resources
1459  *
1460  * Since: 0.6
1461  */
1462 ClutterModelIter * 
1463 clutter_model_get_iter_at_row (ClutterModel *model,
1464                                guint         row)
1465 {
1466   ClutterModelClass *klass;
1467
1468   g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL);
1469
1470   klass = CLUTTER_MODEL_GET_CLASS (model);
1471   if (klass->get_iter_at_row)
1472     return klass->get_iter_at_row (model, row);
1473
1474   return NULL;
1475 }
1476
1477
1478 /**
1479  * clutter_model_get_first_iter:
1480  * @model: a #ClutterModel
1481  *
1482  * Retrieves a #ClutterModelIter representing the first non-filtered
1483  * row in @model.
1484  *
1485  * Return value: (transfer full): A new #ClutterModelIter.
1486  *   Call g_object_unref() when done using it
1487  *
1488  * Since: 0.6
1489  */
1490 ClutterModelIter *
1491 clutter_model_get_first_iter (ClutterModel *model)
1492 {
1493   ClutterModelIter *retval;
1494
1495   g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL);
1496
1497   retval = clutter_model_get_iter_at_row (model, 0);
1498   if (retval != NULL)
1499     {
1500       g_assert (clutter_model_filter_iter (model, retval) != FALSE);
1501       g_assert (clutter_model_iter_get_row (retval) == 0);
1502     }
1503
1504   return retval;
1505 }
1506
1507 /**
1508  * clutter_model_get_last_iter:
1509  * @model: a #ClutterModel
1510  *
1511  * Retrieves a #ClutterModelIter representing the last non-filtered
1512  * row in @model.
1513  *
1514  * Return value: (transfer full): A new #ClutterModelIter.
1515  *   Call g_object_unref() when done using it
1516  *
1517  * Since: 0.6
1518  */
1519 ClutterModelIter *
1520 clutter_model_get_last_iter (ClutterModel *model)
1521 {
1522   ClutterModelIter *retval;
1523   guint length;
1524
1525   g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL);
1526
1527   length = clutter_model_get_n_rows (model);
1528   retval = clutter_model_get_iter_at_row (model, length - 1);
1529   if (retval != NULL)
1530     g_assert (clutter_model_filter_iter (model, retval) != FALSE);
1531
1532   return retval;
1533 }
1534
1535 /**
1536  * clutter_model_get_n_rows:
1537  * @model: a #ClutterModel
1538  *
1539  * Retrieves the number of rows inside @model, eventually taking
1540  * into account any filtering function set using clutter_model_set_filter().
1541  *
1542  * Return value: The length of the @model. If there is a filter set, then
1543  *   the length of the filtered @model is returned.
1544  *
1545  * Since: 0.6
1546  */
1547 guint
1548 clutter_model_get_n_rows (ClutterModel *model)
1549 {
1550   g_return_val_if_fail (CLUTTER_IS_MODEL (model), 0);
1551
1552   return CLUTTER_MODEL_GET_CLASS (model)->get_n_rows (model);
1553 }
1554
1555 /**
1556  * clutter_model_set_sorting_column:
1557  * @model: a #ClutterModel
1558  * @column: the column of the @model to sort, or -1
1559  *
1560  * Sets the model to sort by @column. If @column is a negative value
1561  * the sorting column will be unset.
1562  *
1563  * Since: 0.6
1564  */
1565 void               
1566 clutter_model_set_sorting_column (ClutterModel *model,
1567                                   gint          column)
1568 {
1569   ClutterModelPrivate *priv;
1570
1571   g_return_if_fail (CLUTTER_IS_MODEL (model));
1572   priv = model->priv;
1573
1574   /* The extra comparison for >= 0 is because column gets promoted to
1575      unsigned in the second comparison */
1576   if (column >= 0 && column >= clutter_model_get_n_columns (model))
1577     {
1578       g_warning ("%s: Invalid column id value %d\n", G_STRLOC, column);
1579       return;
1580     }
1581
1582   priv->sort_column = column;
1583
1584   if (priv->sort_column >= 0)
1585     clutter_model_resort (model);
1586
1587   g_signal_emit (model, model_signals[SORT_CHANGED], 0);
1588 }
1589
1590 /**
1591  * clutter_model_get_sorting_column:
1592  * @model: a #ClutterModel
1593  *
1594  * Retrieves the number of column used for sorting the @model.
1595  *
1596  * Return value: a column number, or -1 if the model is not sorted
1597  *
1598  * Since: 0.6
1599  */
1600 gint
1601 clutter_model_get_sorting_column (ClutterModel *model)
1602 {
1603   g_return_val_if_fail (CLUTTER_IS_MODEL (model), -1);
1604
1605   return model->priv->sort_column;
1606 }
1607
1608 /**
1609  * clutter_model_foreach:
1610  * @model: a #ClutterModel
1611  * @func: (scope call): a #ClutterModelForeachFunc
1612  * @user_data: user data to pass to @func
1613  *
1614  * Calls @func for each row in the model. 
1615  *
1616  * Since: 0.6
1617  */
1618 void
1619 clutter_model_foreach (ClutterModel            *model,
1620                        ClutterModelForeachFunc  func,
1621                        gpointer                 user_data)
1622 {
1623   ClutterModelIter *iter;
1624   
1625   g_return_if_fail (CLUTTER_IS_MODEL (model));
1626
1627   iter = clutter_model_get_first_iter (model);
1628   if (!iter)
1629     return;
1630
1631   while (!clutter_model_iter_is_last (iter))
1632     {
1633       if (clutter_model_filter_iter (model, iter))
1634         {
1635           if (!func (model, iter, user_data))
1636             break;
1637         }
1638
1639       iter = clutter_model_iter_next (iter);
1640     }
1641
1642   g_object_unref (iter);
1643 }
1644
1645 /**
1646  * clutter_model_set_sort:
1647  * @model: a #ClutterModel
1648  * @column: the column to sort on
1649  * @func: (allow-none): a #ClutterModelSortFunc, or #NULL
1650  * @user_data: user data to pass to @func, or #NULL
1651  * @notify: destroy notifier of @user_data, or #NULL
1652  *
1653  * Sorts @model using the given sorting function.
1654  *
1655  * Since: 0.6
1656  */
1657 void
1658 clutter_model_set_sort (ClutterModel         *model,
1659                         gint                  column,
1660                         ClutterModelSortFunc  func,
1661                         gpointer              user_data,
1662                         GDestroyNotify        notify)
1663 {
1664   ClutterModelPrivate *priv;
1665     
1666   g_return_if_fail (CLUTTER_IS_MODEL (model));
1667   g_return_if_fail ((func != NULL && column >= 0) ||
1668                     (func == NULL && column == -1));
1669
1670   priv = model->priv;
1671
1672   if (priv->sort_notify)
1673     priv->sort_notify (priv->sort_data);
1674
1675   priv->sort_func = func;
1676   priv->sort_data = user_data;
1677   priv->sort_notify = notify;
1678   
1679   /* This takes care of calling _model_sort & emitting the signal*/
1680   clutter_model_set_sorting_column (model, column);
1681 }
1682
1683 /**
1684  * clutter_model_set_filter:
1685  * @model: a #ClutterModel
1686  * @func: (allow-none): a #ClutterModelFilterFunc, or #NULL
1687  * @user_data: user data to pass to @func, or #NULL
1688  * @notify: destroy notifier of @user_data, or #NULL
1689  *
1690  * Filters the @model using the given filtering function.
1691  *
1692  * Since: 0.6
1693  */
1694 void
1695 clutter_model_set_filter (ClutterModel           *model,
1696                           ClutterModelFilterFunc  func,
1697                           gpointer                user_data,
1698                           GDestroyNotify          notify)
1699 {
1700   ClutterModelPrivate *priv;
1701     
1702   g_return_if_fail (CLUTTER_IS_MODEL (model));
1703   priv = model->priv;
1704
1705   if (priv->filter_notify)
1706     priv->filter_notify (priv->filter_data);
1707
1708   priv->filter_func = func;
1709   priv->filter_data = user_data;
1710   priv->filter_notify = notify;
1711
1712   g_signal_emit (model, model_signals[FILTER_CHANGED], 0);
1713   g_object_notify (G_OBJECT (model), "filter-set");
1714 }
1715
1716 /**
1717  * clutter_model_get_filter_set:
1718  * @model: a #ClutterModel
1719  *
1720  * Returns whether the @model has a filter in place, set
1721  * using clutter_model_set_filter()
1722  *
1723  * Return value: %TRUE if a filter is set
1724  *
1725  * Since: 1.0
1726  */
1727 gboolean
1728 clutter_model_get_filter_set (ClutterModel *model)
1729 {
1730   g_return_val_if_fail (CLUTTER_IS_MODEL (model), FALSE);
1731
1732   return model->priv->filter_func != NULL;
1733 }
1734
1735 /*
1736  * ClutterModelIter Object 
1737  */
1738
1739 /**
1740  * SECTION:clutter-model-iter
1741  * @short_description: Iterates through a model
1742  *
1743  * #ClutterModelIter is an object used for iterating through all the rows
1744  * of a #ClutterModel. It allows setting and getting values on the row
1745  * which is currently pointing at.
1746  *
1747  * A #ClutterModelIter represents a position between two elements
1748  * of the sequence. For example, the iterator returned by
1749  * clutter_model_get_first_iter() represents the gap immediately before
1750  * the first row of the #ClutterModel, and the iterator returned by
1751  * clutter_model_get_last_iter() represents the gap immediately after the
1752  * last row.
1753  *
1754  * A #ClutterModelIter can only be created by a #ClutterModel implementation
1755  * and it is valid as long as the model does not change.
1756  *
1757  * #ClutterModelIter is available since Clutter 0.6
1758  */
1759
1760 G_DEFINE_ABSTRACT_TYPE (ClutterModelIter, clutter_model_iter, G_TYPE_OBJECT);
1761
1762 #define CLUTTER_MODEL_ITER_GET_PRIVATE(obj) \
1763   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
1764   CLUTTER_TYPE_MODEL_ITER, ClutterModelIterPrivate))
1765
1766 struct _ClutterModelIterPrivate
1767 {
1768   ClutterModel  *model;
1769
1770   gint row;
1771 };
1772
1773 enum
1774 {
1775   ITER_PROP_0,
1776
1777   ITER_PROP_MODEL,
1778   ITER_PROP_ROW
1779 };
1780
1781 static ClutterModel *
1782 clutter_model_iter_real_get_model (ClutterModelIter *iter)
1783 {
1784   return iter->priv->model;
1785 }
1786
1787 static guint
1788 clutter_model_iter_real_get_row (ClutterModelIter *iter)
1789 {
1790   return iter->priv->row;
1791 }
1792
1793 /* private function */
1794 void
1795 _clutter_model_iter_set_row (ClutterModelIter *iter,
1796                              guint             row)
1797 {
1798   iter->priv->row = row;
1799 }
1800
1801 static void
1802 clutter_model_iter_get_value_unimplemented (ClutterModelIter *iter,
1803                                             guint             column,
1804                                             GValue           *value)
1805 {
1806   g_warning ("%s: Iterator of type '%s' does not implement the "
1807              "ClutterModelIter::get_value() virtual function",
1808              G_STRLOC,
1809              g_type_name (G_OBJECT_TYPE (iter)));
1810 }
1811
1812 static void
1813 clutter_model_iter_set_value_unimplemented (ClutterModelIter *iter,
1814                                             guint             column,
1815                                             const GValue     *value)
1816 {
1817   g_warning ("%s: Iterator of type '%s' does not implement the "
1818              "ClutterModelIter::set_value() virtual function",
1819              G_STRLOC,
1820              g_type_name (G_OBJECT_TYPE (iter)));
1821 }
1822
1823 static gboolean
1824 clutter_model_iter_is_first_unimplemented (ClutterModelIter *iter)
1825 {
1826   g_warning ("%s: Iterator of type '%s' does not implement the "
1827              "ClutterModelIter::is_first() virtual function",
1828              G_STRLOC,
1829              g_type_name (G_OBJECT_TYPE (iter)));
1830   return FALSE;
1831 }
1832
1833 static gboolean
1834 clutter_model_iter_is_last_unimplemented (ClutterModelIter *iter)
1835 {
1836   g_warning ("%s: Iterator of type '%s' does not implement the "
1837              "ClutterModelIter::is_last() virtual function",
1838              G_STRLOC,
1839              g_type_name (G_OBJECT_TYPE (iter)));
1840   return FALSE;
1841 }
1842
1843 static ClutterModelIter *
1844 clutter_model_iter_next_unimplemented (ClutterModelIter *iter)
1845 {
1846   g_warning ("%s: Iterator of type '%s' does not implement the "
1847              "ClutterModelIter::next() virtual function",
1848              G_STRLOC,
1849              g_type_name (G_OBJECT_TYPE (iter)));
1850   return NULL;
1851 }
1852
1853 static ClutterModelIter *
1854 clutter_model_iter_prev_unimplemented (ClutterModelIter *iter)
1855 {
1856   g_warning ("%s: Iterator of type '%s' does not implement the "
1857              "ClutterModelIter::prev() virtual function",
1858              G_STRLOC,
1859              g_type_name (G_OBJECT_TYPE (iter)));
1860   return NULL;
1861 }
1862
1863 static ClutterModelIter *
1864 clutter_model_iter_copy_unimplemented (ClutterModelIter *iter)
1865 {
1866   g_warning ("%s: Iterator of type '%s' does not implement the "
1867              "ClutterModelIter::copy() virtual function",
1868              G_STRLOC,
1869              g_type_name (G_OBJECT_TYPE (iter)));
1870   return NULL;
1871 }
1872
1873 static void
1874 clutter_model_iter_get_property (GObject    *object,
1875                                  guint       prop_id,
1876                                  GValue     *value,
1877                                  GParamSpec *pspec)
1878 {
1879   ClutterModelIter *iter = CLUTTER_MODEL_ITER (object);
1880   ClutterModelIterPrivate *priv = iter->priv;
1881
1882   switch (prop_id)
1883     {
1884     case ITER_PROP_MODEL:
1885       g_value_set_object (value, priv->model);
1886       break;
1887     case ITER_PROP_ROW:
1888       g_value_set_uint (value, priv->row);
1889       break;
1890     default:
1891       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1892       break;
1893     }
1894 }
1895
1896 static void
1897 clutter_model_iter_set_property (GObject      *object,
1898                                  guint         prop_id,
1899                                  const GValue *value,
1900                                  GParamSpec   *pspec)
1901 {
1902   ClutterModelIter *iter = CLUTTER_MODEL_ITER (object);
1903   ClutterModelIterPrivate *priv = iter->priv;
1904
1905   switch (prop_id)
1906     {
1907     case ITER_PROP_MODEL:
1908       priv->model = g_value_get_object (value);
1909       break;
1910     case ITER_PROP_ROW:
1911       priv->row = g_value_get_uint (value);
1912       break;
1913     default:
1914       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1915       break;
1916     }
1917 }
1918
1919 static void
1920 clutter_model_iter_class_init (ClutterModelIterClass *klass)
1921 {
1922   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1923   GParamSpec *pspec;
1924
1925   gobject_class->get_property = clutter_model_iter_get_property;
1926   gobject_class->set_property = clutter_model_iter_set_property;
1927
1928   klass->get_model = clutter_model_iter_real_get_model;
1929   klass->get_row   = clutter_model_iter_real_get_row;
1930   klass->is_first  = clutter_model_iter_is_first_unimplemented;
1931   klass->is_last   = clutter_model_iter_is_last_unimplemented;
1932   klass->next      = clutter_model_iter_next_unimplemented;
1933   klass->prev      = clutter_model_iter_prev_unimplemented;
1934   klass->get_value = clutter_model_iter_get_value_unimplemented;
1935   klass->set_value = clutter_model_iter_set_value_unimplemented;
1936   klass->copy      = clutter_model_iter_copy_unimplemented;
1937
1938   /* Properties */
1939
1940   /**
1941    * ClutterModelIter:model:
1942    *
1943    * A reference to the #ClutterModel that this iter belongs to.
1944    *
1945    * Since: 0.6
1946    */
1947   pspec = g_param_spec_object ("model",
1948                                "Model",
1949                                "The model to which the iterator belongs to",
1950                                CLUTTER_TYPE_MODEL,
1951                                CLUTTER_PARAM_READWRITE);
1952   g_object_class_install_property (gobject_class, ITER_PROP_MODEL, pspec);
1953
1954   /**
1955    * ClutterModelIter:row:
1956    *
1957    * The row number to which this iter points to.
1958    *
1959    * Since: 0.6
1960    */
1961   pspec = g_param_spec_uint ("row",
1962                              "Row",
1963                              "The row to which the iterator points to",
1964                              0, G_MAXUINT, 0,
1965                              CLUTTER_PARAM_READWRITE);
1966   g_object_class_install_property (gobject_class, ITER_PROP_ROW, pspec);
1967   
1968   g_type_class_add_private (gobject_class, sizeof (ClutterModelIterPrivate));
1969 }
1970
1971 static void
1972 clutter_model_iter_init (ClutterModelIter *self)
1973 {
1974   ClutterModelIterPrivate *priv;
1975   
1976   self->priv = priv = CLUTTER_MODEL_ITER_GET_PRIVATE (self);
1977
1978   priv->model = NULL;
1979   priv->row = 0;
1980 }
1981
1982 /*
1983  *  Public functions
1984  */
1985
1986 static inline void
1987 clutter_model_iter_set_value_internal (ClutterModelIter *iter,
1988                                        guint             column,
1989                                        const GValue     *value)
1990 {
1991   CLUTTER_MODEL_ITER_GET_CLASS (iter)->set_value (iter, column, value);
1992 }
1993
1994 static void
1995 clutter_model_iter_set_internal_valist (ClutterModelIter *iter,
1996                                         va_list           args)
1997 {
1998   ClutterModelIterPrivate *priv = iter->priv;
1999   ClutterModel *model = priv->model;
2000   guint column = 0;
2001   gboolean sort = FALSE;
2002   
2003   g_assert (CLUTTER_IS_MODEL (model));
2004
2005   column = va_arg (args, gint);
2006   
2007   while (column != -1)
2008     {
2009       GValue value = G_VALUE_INIT;
2010       gchar *error = NULL;
2011       GType col_type;
2012
2013       if (column >= clutter_model_get_n_columns (model))
2014         { 
2015           g_warning ("%s: Invalid column number %d added to iter "
2016                      "(remember to end you list of columns with a -1)",
2017                      G_STRLOC, column);
2018           break;
2019         }
2020
2021       col_type = clutter_model_get_column_type (model, column);
2022
2023       G_VALUE_COLLECT_INIT (&value, col_type, args, 0, &error);
2024       if (error)
2025         {
2026           g_warning ("%s: %s", G_STRLOC, error);
2027           g_free (error);
2028
2029           /* Leak value as it might not be in a sane state */
2030           break;
2031         }
2032
2033       clutter_model_iter_set_value_internal (iter, column, &value);
2034       
2035       g_value_unset (&value);
2036       
2037       if (column == clutter_model_get_sorting_column (model))
2038         sort = TRUE;
2039       
2040       column = va_arg (args, gint);
2041     }
2042
2043   if (sort)
2044     clutter_model_resort (model);
2045 }
2046
2047 static void inline
2048 clutter_model_iter_emit_row_changed (ClutterModelIter *iter)
2049 {
2050   ClutterModelIterPrivate *priv = iter->priv;
2051   ClutterModel *model = priv->model;
2052
2053   g_assert (CLUTTER_IS_MODEL (model));
2054
2055   g_signal_emit (model, model_signals[ROW_CHANGED], 0, iter);
2056 }
2057
2058 /**
2059  * clutter_model_iter_set_valist:
2060  * @iter: a #ClutterModelIter
2061  * @args: va_list of column/value pairs, terminiated by -1
2062  *
2063  * See clutter_model_iter_set(); this version takes a va_list for language
2064  * bindings.
2065  *
2066  * Since: 0.6
2067  */
2068 void 
2069 clutter_model_iter_set_valist (ClutterModelIter *iter,
2070                                va_list           args)
2071 {
2072   g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter));
2073
2074   clutter_model_iter_set_internal_valist (iter, args);
2075   clutter_model_iter_emit_row_changed (iter);
2076 }
2077
2078 /**
2079  * clutter_model_iter_get:
2080  * @iter: a #ClutterModelIter
2081  * @...: a list of column/return location pairs, terminated by -1
2082  *
2083  * Gets the value of one or more cells in the row referenced by @iter. The
2084  * variable argument list should contain integer column numbers, each column
2085  * column number followed by a place to store the value being retrieved. The
2086  * list is terminated by a -1.
2087  *
2088  * For example, to get a value from column 0 with type %G_TYPE_STRING use:
2089  * <informalexample><programlisting>
2090  *   clutter_model_iter_get (iter, 0, &place_string_here, -1);
2091  * </programlisting></informalexample>
2092  * 
2093  * where place_string_here is a gchar* to be filled with the string. If
2094  * appropriate, the returned values have to be freed or unreferenced.
2095  *
2096  * Since: 0.6
2097  */
2098 void
2099 clutter_model_iter_get (ClutterModelIter *iter,
2100                         ...)
2101 {
2102   va_list args;
2103
2104   g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter));
2105
2106   va_start (args, iter);
2107   clutter_model_iter_get_valist (iter, args);
2108   va_end (args);
2109 }
2110
2111 static inline void
2112 clutter_model_iter_get_value_internal (ClutterModelIter *iter,
2113                                        guint             column,
2114                                        GValue           *value)
2115 {
2116   CLUTTER_MODEL_ITER_GET_CLASS (iter)->get_value (iter, column, value);
2117 }
2118
2119 /**
2120  * clutter_model_iter_get_value:
2121  * @iter: a #ClutterModelIter
2122  * @column: column number to retrieve the value from
2123  * @value: (out): an empty #GValue to set
2124  *
2125  * Sets an initializes @value to that at @column. When done with @value, 
2126  * g_value_unset() needs to be called to free any allocated memory.
2127  *
2128  * Since: 0.6
2129  */
2130 void
2131 clutter_model_iter_get_value (ClutterModelIter *iter,
2132                               guint             column,
2133                               GValue           *value)
2134 {
2135   ClutterModel *model;
2136
2137   g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter));
2138   
2139   model = iter->priv->model;
2140
2141   if (G_VALUE_TYPE (value) == G_TYPE_INVALID)
2142     g_value_init (value, clutter_model_get_column_type (model, column));
2143
2144   CLUTTER_MODEL_ITER_GET_CLASS (iter)->get_value (iter, column, value);
2145 }
2146
2147 /**
2148  * clutter_model_iter_get_valist:
2149  * @iter: a #ClutterModelIter
2150  * @args: a list of column/return location pairs, terminated by -1
2151  *
2152  * See clutter_model_iter_get(). This version takes a va_list for language
2153  * bindings.
2154  *
2155  * Since: 0.6
2156  */
2157 void 
2158 clutter_model_iter_get_valist (ClutterModelIter *iter,
2159                                va_list           args)
2160 {
2161   ClutterModelIterPrivate *priv;
2162   ClutterModel *model;
2163   guint column = 0;
2164   
2165   g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter));
2166
2167   priv = iter->priv;
2168   model = priv->model;
2169   g_assert (CLUTTER_IS_MODEL (model));
2170
2171   column = va_arg (args, gint);
2172
2173   while (column != -1)
2174     {
2175       GValue value = G_VALUE_INIT;
2176       gchar *error = NULL;
2177       GType col_type;
2178
2179       if (column >= clutter_model_get_n_columns (model))
2180         { 
2181           g_warning ("%s: Invalid column number %d added to iter "
2182                      "(remember to end you list of columns with a -1)",
2183                      G_STRLOC, column);
2184           break;
2185         }
2186
2187       col_type = clutter_model_get_column_type (model, column);
2188       g_value_init (&value, col_type);
2189
2190       clutter_model_iter_get_value_internal (iter, column, &value);
2191
2192       G_VALUE_LCOPY (&value, args, 0, &error);
2193       if (error)
2194         {
2195           g_warning ("%s: %s", G_STRLOC, error);
2196           g_free (error);
2197
2198           /* Leak value as it might not be in a sane state */
2199           break;
2200         }
2201      
2202       g_value_unset (&value);
2203       
2204       column = va_arg (args, gint);
2205     }
2206 }
2207
2208 /**
2209  * clutter_model_iter_set:
2210  * @iter: a #ClutterModelIter
2211  * @...: a list of column/return location pairs, terminated by -1
2212  *
2213  * Sets the value of one or more cells in the row referenced by @iter. The
2214  * variable argument list should contain integer column numbers, each column
2215  * column number followed by the value to be set. The  list is terminated by a
2216  * -1.
2217  *
2218  * For example, to set column 0 with type %G_TYPE_STRING, use:
2219  * <informalexample><programlisting>
2220  *   clutter_model_iter_set (iter, 0, "foo", -1);
2221  * </programlisting></informalexample>
2222  *
2223  * Since: 0.6
2224  */
2225 void
2226 clutter_model_iter_set (ClutterModelIter *iter,
2227                         ...)
2228 {
2229   va_list args;
2230
2231   g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter));
2232
2233   va_start (args, iter);
2234   clutter_model_iter_set_internal_valist (iter, args);
2235   clutter_model_iter_emit_row_changed (iter);
2236   va_end (args);
2237 }
2238
2239 /**
2240  * clutter_model_iter_set_value:
2241  * @iter: a #ClutterModelIter
2242  * @column: column number to retrieve the value from
2243  * @value: new value for the cell
2244  *
2245  * Sets the data in the cell specified by @iter and @column. The type of
2246  * @value must be convertable to the type of the column.
2247  *
2248  * Since: 0.6
2249  */
2250 void
2251 clutter_model_iter_set_value (ClutterModelIter *iter,
2252                               guint             column,
2253                               const GValue     *value)
2254 {
2255   g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter));
2256
2257   clutter_model_iter_set_value_internal (iter, column, value);
2258   clutter_model_iter_emit_row_changed (iter);
2259 }
2260
2261 /**
2262  * clutter_model_iter_is_first:
2263  * @iter: a #ClutterModelIter
2264  *
2265  * Gets whether the current iterator is at the beginning of the model
2266  * to which it belongs.
2267  *
2268  * Return value: #TRUE if @iter is the first iter in the filtered model
2269  *
2270  * Since: 0.6
2271  */
2272 gboolean
2273 clutter_model_iter_is_first (ClutterModelIter *iter)
2274 {
2275   g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), FALSE);
2276   
2277   return CLUTTER_MODEL_ITER_GET_CLASS (iter)->is_first (iter);
2278 }
2279
2280 /**
2281  * clutter_model_iter_is_last:
2282  * @iter: a #ClutterModelIter
2283  * 
2284  * Gets whether the iterator is at the end of the model to which it
2285  * belongs.
2286  *
2287  * Return value: #TRUE if @iter is the last iter in the filtered model.
2288  *
2289  * Since: 0.6
2290  */
2291 gboolean
2292 clutter_model_iter_is_last (ClutterModelIter *iter)
2293 {
2294   g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), FALSE);
2295   
2296   return CLUTTER_MODEL_ITER_GET_CLASS (iter)->is_last (iter);
2297 }
2298
2299 /**
2300  * clutter_model_iter_next:
2301  * @iter: a #ClutterModelIter
2302  * 
2303  * Updates the @iter to point at the next position in the model.
2304  * The model implementation should take into account the presence of
2305  * a filter function.
2306  *
2307  * Return value: (transfer none): The passed iterator, updated to point at the next
2308  *   row in the model.
2309  *
2310  * Since: 0.6
2311  */
2312 ClutterModelIter *
2313 clutter_model_iter_next (ClutterModelIter *iter)
2314 {
2315   g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL);
2316   
2317   return CLUTTER_MODEL_ITER_GET_CLASS (iter)->next (iter);
2318 }
2319
2320 /**
2321  * clutter_model_iter_prev:
2322  * @iter: a #ClutterModelIter
2323  * 
2324  * Sets the @iter to point at the previous position in the model.
2325  * The model implementation should take into account the presence of
2326  * a filter function.
2327  *
2328  * Return value: (transfer none): The passed iterator, updated to point at the previous
2329  *   row in the model.
2330  *
2331  * Since: 0.6
2332  */
2333 ClutterModelIter *
2334 clutter_model_iter_prev (ClutterModelIter *iter)
2335 {
2336   g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL);
2337   
2338   return CLUTTER_MODEL_ITER_GET_CLASS (iter)->prev (iter);
2339 }
2340
2341 /**
2342  * clutter_model_iter_get_model:
2343  * @iter: a #ClutterModelIter
2344  * 
2345  * Retrieves a pointer to the #ClutterModel that this iter is part of.
2346  *
2347  * Return value: (transfer none): a pointer to a #ClutterModel.
2348  *
2349  * Since: 0.6
2350  */
2351 ClutterModel *
2352 clutter_model_iter_get_model (ClutterModelIter *iter)
2353 {
2354   g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL);
2355   
2356   return CLUTTER_MODEL_ITER_GET_CLASS (iter)->get_model (iter);
2357 }
2358
2359 /**
2360  * clutter_model_iter_get_row:
2361  * @iter: a #ClutterModelIter
2362  * 
2363  * Retrieves the position of the row that the @iter points to.
2364  *
2365  * Return value: the position of the @iter in the model
2366  *
2367  * Since: 0.6
2368  */
2369 guint
2370 clutter_model_iter_get_row (ClutterModelIter *iter)
2371 {
2372   g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), 0);
2373   
2374   return CLUTTER_MODEL_ITER_GET_CLASS (iter)->get_row (iter);
2375 }
2376
2377 /**
2378  * clutter_model_iter_copy:
2379  * @iter: a #ClutterModelIter
2380  *
2381  * Copies the passed iterator.
2382  *
2383  * Return value: (transfer full): a copy of the iterator, or %NULL
2384  *
2385  * Since: 0.8
2386  */
2387 ClutterModelIter *
2388 clutter_model_iter_copy (ClutterModelIter *iter)
2389 {
2390   g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL);
2391
2392   return CLUTTER_MODEL_ITER_GET_CLASS (iter)->copy (iter);
2393 }