diff --git a/ChangeLog b/ChangeLog index 9d003f7b9..53083a06c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +2007-12-14 Emmanuele Bassi + + * clutter/clutter-behaviour.c: + (clutter_knot_get_type): Use the I_() macro. + + * clutter/clutter-model.[ch]: Make ClutterModel and ClutterModelIter + abstract classes; also, provide more virtual functions inside the + ClutterModel vtable, to allow subclasses and language bindings to + override the entire ClutterModel using other/native data types + to store the rows. + + * clutter/clutter-model-default.[ch]: ClutterModelDefault is a + default implementation of ClutterModel and ClutterModelIter using + GSequence. + + * clutter/Makefile.am: + * clutter/clutter.h: Build glue for ClutterModelDefault. + + * tests/test-model.c: Update for constructor changes. + + * tests/test-shader.c: Fix a typo. + 2007-12-14 Matthew Allum * clutter/cogl/gl/cogl-defines.h.in: diff --git a/clutter/Makefile.am b/clutter/Makefile.am index daaa5ce62..21ed6c9f5 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -65,6 +65,7 @@ source_h = \ $(srcdir)/clutter-main.h \ $(srcdir)/clutter-media.h \ $(srcdir)/clutter-model.h \ + $(srcdir)/clutter-model-default.h \ $(srcdir)/clutter-rectangle.h \ $(srcdir)/clutter-score.h \ $(srcdir)/clutter-script.h \ @@ -149,6 +150,7 @@ source_c = \ clutter-marshal.c \ clutter-media.c \ clutter-model.c \ + clutter-model-default.c \ clutter-rectangle.c \ clutter-score.c \ clutter-script.c \ @@ -163,8 +165,8 @@ source_c = \ $(NULL) source_h_priv = \ - clutter-keysyms-table.h \ clutter-debug.h \ + clutter-keysyms-table.h \ clutter-private.h \ clutter-script-private.h \ $(NULL) diff --git a/clutter/clutter-behaviour.c b/clutter/clutter-behaviour.c index 62b2d38a7..3703774bf 100644 --- a/clutter/clutter-behaviour.c +++ b/clutter/clutter-behaviour.c @@ -131,7 +131,7 @@ clutter_knot_get_type (void) if (G_UNLIKELY (!our_type)) { our_type = - g_boxed_type_register_static ("ClutterKnot", + g_boxed_type_register_static (I_("ClutterKnot"), (GBoxedCopyFunc) clutter_knot_copy, (GBoxedFreeFunc) clutter_knot_free); } diff --git a/clutter/clutter-model-default.c b/clutter/clutter-model-default.c new file mode 100644 index 000000000..c633d572c --- /dev/null +++ b/clutter/clutter-model-default.c @@ -0,0 +1,636 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Matthew Allum + * Neil Jagdish Patel + * Emmanuele Bassi + * + * Copyright (C) 2006 OpenedHand + * + * 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 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:clutter-model-default: + * @short_description: Default model implementation + * + * #ClutterModelDefault is a #ClutterModel implementation provided by + * Clutter. #ClutterModelDefault uses a #GSequence for storing the + * values for each row, so it's optimized for insertion and look up + * in sorted lists. + * + * #ClutterModelDefault is a terminal class: it cannot be subclassed, + * only instantiated. + * + * #ClutterModelDefault is available since Clutter 0.6 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +#include "clutter-model.h" +#include "clutter-model-default.h" +#include "clutter-private.h" +#include "clutter-debug.h" + +#define CLUTTER_MODEL_DEFAULT_ITER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + CLUTTER_TYPE_MODEL_DEFAULT_ITER, \ + ClutterModelDefaultIterClass)) +#define CLUTTER_IS_MODEL_DEFAULT_ITER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + CLUTTER_TYPE_MODEL_DEFAULT_ITER)) +#define CLUTTER_MODEL_DEFAULT_ITER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + CLUTTER_TYPE_MODEL_DEFAULT_ITER, \ + ClutterModelDefaultIterClass)) + +#define CLUTTER_MODEL_DEFAULT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + CLUTTER_TYPE_MODEL_DEFAULT, \ + ClutterModelDefaultClass)) +#define CLUTTER_IS_MODEL_DEFAULT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + CLUTTER_TYPE_MODEL_DEFAULT)) +#define CLUTTER_MODEL_DEFAULT_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + CLUTTER_TYPE_MODEL_DEFAULT, \ + ClutterModelDefaultClass)) + +typedef struct _ClutterModelIterClass ClutterModelDefaultIterClass; +typedef struct _ClutterModelClass ClutterModelDefaultClass; + +struct _ClutterModelDefault +{ + ClutterModel parent_instance; + + GSequence *sequence; +}; + +struct _ClutterModelDefaultIter +{ + ClutterModelIter parent_instance; + + GSequenceIter *seq_iter; +}; + + + +/* + * ClutterModelDefault + */ + +G_DEFINE_TYPE (ClutterModelDefaultIter, + clutter_model_default_iter, + CLUTTER_TYPE_MODEL_ITER); + +static void +clutter_model_default_iter_get_value (ClutterModelIter *iter, + guint column, + GValue *value) +{ + ClutterModelDefaultIter *iter_default; + GValueArray *value_array; + GValue *iter_value; + GValue real_value = { 0, }; + gboolean converted = FALSE; + + iter_default = CLUTTER_MODEL_DEFAULT_ITER (iter); + g_assert (iter_default->seq_iter != NULL); + + value_array = g_sequence_get (iter_default->seq_iter); + iter_value = g_value_array_get_nth (value_array, column); + g_assert (iter_value != NULL); + + if (!g_type_is_a (G_VALUE_TYPE (value), G_VALUE_TYPE (iter_value))) + { + if (!g_value_type_compatible (G_VALUE_TYPE (value), + G_VALUE_TYPE (iter_value)) && + !g_value_type_compatible (G_VALUE_TYPE (iter_value), + G_VALUE_TYPE (value))) + { + g_warning ("%s: Unable to convert from %s to %s", + G_STRLOC, + g_type_name (G_VALUE_TYPE (value)), + g_type_name (G_VALUE_TYPE (iter_value))); + return; + } + + if (!g_value_transform (value, &real_value)) + { + g_warning ("%s: Unable to make conversion from %s to %s", + G_STRLOC, + g_type_name (G_VALUE_TYPE (value)), + g_type_name (G_VALUE_TYPE (iter_value))); + g_value_unset (&real_value); + } + + converted = TRUE; + } + + if (converted) + { + g_value_copy (&real_value, value); + g_value_unset (&real_value); + } + else + g_value_copy (iter_value, value); +} + +static void +clutter_model_default_iter_set_value (ClutterModelIter *iter, + guint column, + const GValue *value) +{ + ClutterModelDefaultIter *iter_default; + GValueArray *value_array; + GValue *iter_value; + GValue real_value = { 0, }; + gboolean converted = FALSE; + + iter_default = CLUTTER_MODEL_DEFAULT_ITER (iter); + g_assert (iter_default->seq_iter != NULL); + + value_array = g_sequence_get (iter_default->seq_iter); + iter_value = g_value_array_get_nth (value_array, column); + g_assert (iter_value != NULL); + + if (!g_type_is_a (G_VALUE_TYPE (value), G_VALUE_TYPE (iter_value))) + { + if (!g_value_type_compatible (G_VALUE_TYPE (value), + G_VALUE_TYPE (iter_value)) && + !g_value_type_compatible (G_VALUE_TYPE (iter_value), + G_VALUE_TYPE (value))) + { + g_warning ("%s: Unable to convert from %s to %s\n", + G_STRLOC, + g_type_name (G_VALUE_TYPE (value)), + g_type_name (G_VALUE_TYPE (iter_value))); + return; + } + + if (!g_value_transform (value, &real_value)) + { + g_warning ("%s: Unable to make conversion from %s to %s\n", + G_STRLOC, + g_type_name (G_VALUE_TYPE (value)), + g_type_name (G_VALUE_TYPE (iter_value))); + g_value_unset (&real_value); + } + + converted = TRUE; + } + + if (converted) + { + g_value_copy (&real_value, iter_value); + g_value_unset (&real_value); + } + else + g_value_copy (value, iter_value); +} + +static gboolean +clutter_model_default_iter_is_first (ClutterModelIter *iter) +{ + ClutterModelDefaultIter *iter_default; + ClutterModel *model; + ClutterModelIter *temp_iter; + GSequenceIter *begin, *end; + guint row; + + iter_default = CLUTTER_MODEL_DEFAULT_ITER (iter); + g_assert (iter_default->seq_iter != NULL); + + model = clutter_model_iter_get_model (iter); + row = clutter_model_iter_get_row (iter); + + begin = g_sequence_get_begin_iter (CLUTTER_MODEL_DEFAULT (model)->sequence); + end = iter_default->seq_iter; + + temp_iter = g_object_new (CLUTTER_TYPE_MODEL_DEFAULT_ITER, + "model", model, + NULL); + + while (!g_sequence_iter_is_begin (begin)) + { + CLUTTER_MODEL_DEFAULT_ITER (temp_iter)->seq_iter = begin; + g_object_set (G_OBJECT (temp_iter), "row", row, NULL); + + if (clutter_model_filter_iter (model, temp_iter)) + { + end = begin; + break; + } + + begin = g_sequence_iter_next (begin); + row += 1; + } + + g_object_unref (temp_iter); + + /* This is because the 'begin_iter' is always *before* the last valid + * iter, otherwise we'd have endless loops + */ + end = g_sequence_iter_prev (end); + + return iter_default->seq_iter == end; +} + +static gboolean +clutter_model_default_iter_is_last (ClutterModelIter *iter) +{ + ClutterModelDefaultIter *iter_default; + ClutterModelIter *temp_iter; + ClutterModel *model; + GSequenceIter *begin, *end; + guint row; + + iter_default = CLUTTER_MODEL_DEFAULT_ITER (iter); + g_assert (iter_default->seq_iter != NULL); + + if (g_sequence_iter_is_end (iter_default->seq_iter)) + return TRUE; + + model = clutter_model_iter_get_model (iter); + row = clutter_model_iter_get_row (iter); + + begin = g_sequence_get_end_iter (CLUTTER_MODEL_DEFAULT (model)->sequence); + begin = g_sequence_iter_prev (begin); + end = iter_default->seq_iter; + + temp_iter = g_object_new (CLUTTER_TYPE_MODEL_DEFAULT_ITER, + "model", model, + NULL); + + while (!g_sequence_iter_is_begin (begin)) + { + CLUTTER_MODEL_DEFAULT_ITER (temp_iter)->seq_iter = begin; + g_object_set (G_OBJECT (temp_iter), "row", row, NULL); + + if (clutter_model_filter_iter (model, temp_iter)) + { + end = begin; + break; + } + + begin = g_sequence_iter_prev (begin); + row += 1; + } + + g_object_unref (temp_iter); + + /* This is because the 'end_iter' is always *after* the last valid iter. + * Otherwise we'd have endless loops + */ + end = g_sequence_iter_next (end); + + return iter_default->seq_iter == end; +} + +static ClutterModelIter * +clutter_model_default_iter_next (ClutterModelIter *iter) +{ + ClutterModelDefaultIter *iter_default; + ClutterModelDefaultIter *retval; + ClutterModelIter *temp_iter; + ClutterModel *model = NULL; + GSequenceIter *filter_next; + guint row; + + iter_default = CLUTTER_MODEL_DEFAULT_ITER (iter); + g_assert (iter_default->seq_iter != NULL); + + model = clutter_model_iter_get_model (iter); + row = clutter_model_iter_get_row (iter) + 1; + + filter_next = g_sequence_iter_next (iter_default->seq_iter); + g_assert (filter_next != NULL); + + temp_iter = g_object_new (CLUTTER_TYPE_MODEL_DEFAULT_ITER, + "model", model, + NULL); + + while (!g_sequence_iter_is_end (filter_next)) + { + CLUTTER_MODEL_DEFAULT_ITER (temp_iter)->seq_iter = filter_next; + g_object_set (G_OBJECT (temp_iter), "row", row, NULL); + + if (clutter_model_filter_iter (model, temp_iter)) + break; + + filter_next = g_sequence_iter_next (filter_next); + row += 1; + } + + g_object_unref (temp_iter); + + /* We do this because the 'end_iter' is always *after* the last valid iter. + * Otherwise loops will go on forever + */ + if (filter_next == iter_default->seq_iter) + filter_next = g_sequence_iter_next (filter_next); + + retval = g_object_new (CLUTTER_TYPE_MODEL_DEFAULT_ITER, + "model", model, + "row", row, + NULL); + retval->seq_iter = filter_next; + + return CLUTTER_MODEL_ITER (retval); +} + +static ClutterModelIter * +clutter_model_default_iter_prev (ClutterModelIter *iter) +{ + ClutterModelDefaultIter *iter_default; + ClutterModelDefaultIter *retval; + ClutterModelIter *temp_iter; + ClutterModel *model; + GSequenceIter *filter_prev; + guint row; + + iter_default = CLUTTER_MODEL_DEFAULT_ITER (iter); + g_assert (iter_default->seq_iter != NULL); + + model = clutter_model_iter_get_model (iter); + row = clutter_model_iter_get_row (iter) - 1; + + filter_prev = g_sequence_iter_prev (iter_default->seq_iter); + g_assert (filter_prev != NULL); + + temp_iter = g_object_new (CLUTTER_TYPE_MODEL_DEFAULT_ITER, + "model", model, + NULL); + + while (!g_sequence_iter_is_begin (filter_prev)) + { + CLUTTER_MODEL_DEFAULT_ITER (temp_iter)->seq_iter = filter_prev; + g_object_set (G_OBJECT (temp_iter), "row", row, NULL); + + if (clutter_model_filter_iter (model, temp_iter)) + break; + + filter_prev = g_sequence_iter_prev (filter_prev); + row -= 1; + } + + g_object_unref (temp_iter); + + /* We do this because the 'end_iter' is always *after* the last valid iter. + * Otherwise loops will go on forever + */ + if (filter_prev == iter_default->seq_iter) + filter_prev = g_sequence_iter_prev (filter_prev); + + retval = g_object_new (CLUTTER_TYPE_MODEL_DEFAULT_ITER, + "model", model, + "row", row, + NULL); + retval->seq_iter = filter_prev; + + return CLUTTER_MODEL_ITER (retval); +} +static void +clutter_model_default_iter_class_init (ClutterModelDefaultIterClass *klass) +{ + ClutterModelIterClass *iter_class = CLUTTER_MODEL_ITER_CLASS (klass); + + iter_class->get_value = clutter_model_default_iter_get_value; + iter_class->set_value = clutter_model_default_iter_set_value; + iter_class->is_first = clutter_model_default_iter_is_first; + iter_class->is_last = clutter_model_default_iter_is_last; + iter_class->next = clutter_model_default_iter_next; + iter_class->prev = clutter_model_default_iter_prev; +} + +static void +clutter_model_default_iter_init (ClutterModelDefaultIter *iter) +{ + iter->seq_iter = NULL; +} + +/* + * ClutterModelDefault + */ + +G_DEFINE_TYPE (ClutterModelDefault, clutter_model_default, CLUTTER_TYPE_MODEL); + +static ClutterModelIter * +clutter_model_default_get_iter_at_row (ClutterModel *model, + guint row) +{ + ClutterModelDefault *model_default = CLUTTER_MODEL_DEFAULT (model); + ClutterModelDefaultIter *retval; + + if (row > g_sequence_get_length (model_default->sequence)) + return NULL; + + retval = g_object_new (CLUTTER_TYPE_MODEL_DEFAULT_ITER, + "model", model, + "row", row, + NULL); + retval->seq_iter = g_sequence_get_iter_at_pos (model_default->sequence, row); + + return CLUTTER_MODEL_ITER (retval); +} + +static ClutterModelIter * +clutter_model_default_insert_row (ClutterModel *model, + gint index_) +{ + ClutterModelDefault *model_default = CLUTTER_MODEL_DEFAULT (model); + ClutterModelDefaultIter *retval; + guint n_columns, i, pos; + GValueArray *array; + GSequenceIter *seq_iter; + + n_columns = clutter_model_get_n_columns (model); + array = g_value_array_new (n_columns); + + for (i = 0; i < n_columns; i++) + { + GValue *value = NULL; + + g_value_array_append (array, NULL); + + value = g_value_array_get_nth (array, i); + g_value_init (value, clutter_model_get_column_type (model, i)); + } + + if (index_ < 0) + { + seq_iter = g_sequence_append (model_default->sequence, array); + pos = g_sequence_get_length (model_default->sequence) - 1; + } + else if (index_ == 0) + { + seq_iter = g_sequence_prepend (model_default->sequence, array); + pos = 0; + } + else + { + seq_iter = g_sequence_get_iter_at_pos (model_default->sequence, index_); + seq_iter = g_sequence_insert_before (seq_iter, array); + pos = index_; + } + + retval = g_object_new (CLUTTER_TYPE_MODEL_DEFAULT_ITER, + "model", model, + "row", pos, + NULL); + retval->seq_iter = seq_iter; + + return CLUTTER_MODEL_ITER (retval); +} + +static void +clutter_model_default_remove_row (ClutterModel *model, + guint row) +{ + ClutterModelDefault *model_default = CLUTTER_MODEL_DEFAULT (model); + GSequenceIter *seq_iter; + guint pos = 0; + + seq_iter = g_sequence_get_begin_iter (model_default->sequence); + while (!g_sequence_iter_is_end (seq_iter)) + { + if (clutter_model_filter_row (model, pos)) + { + if (pos == row) + { + ClutterModelIter *iter; + GValueArray *array; + + iter = g_object_new (CLUTTER_TYPE_MODEL_DEFAULT_ITER, + "model", model, + "row", pos, + NULL); + CLUTTER_MODEL_DEFAULT_ITER (iter)->seq_iter = seq_iter; + + g_signal_emit_by_name (model, "row-removed", iter); + + g_object_unref (iter); + + array = g_sequence_get (seq_iter); + g_value_array_free (array); + + g_sequence_remove (seq_iter); + + break; + } + } + + pos += 1; + seq_iter = g_sequence_iter_next (seq_iter); + } +} + +static guint +clutter_model_default_get_n_rows (ClutterModel *model) +{ + ClutterModelDefault *model_default = CLUTTER_MODEL_DEFAULT (model); + + return g_sequence_get_length (model_default->sequence); +} + +typedef struct +{ + ClutterModel *model; + guint column; + ClutterModelSortFunc func; + gpointer data; +} SortClosure; + +static gint +sort_model_default (gconstpointer a, + gconstpointer b, + gpointer data) +{ + GValueArray *row_a = (GValueArray *) a; + GValueArray *row_b = (GValueArray *) b; + SortClosure *clos = data; + + return clos->func (clos->model, + g_value_array_get_nth (row_a, clos->column), + g_value_array_get_nth (row_b, clos->column), + clos->data); +} + +static void +clutter_model_default_resort (ClutterModel *model, + ClutterModelSortFunc func, + gpointer data) +{ + SortClosure sort_closure = { NULL, 0, NULL, NULL }; + + sort_closure.model = model; + sort_closure.column = clutter_model_get_sorting_column (model); + sort_closure.func = func; + sort_closure.data = data; + + g_sequence_sort (CLUTTER_MODEL_DEFAULT (model)->sequence, + sort_model_default, + &sort_closure); +} + +static void +clutter_model_default_finalize (GObject *gobject) +{ + ClutterModelDefault *model = CLUTTER_MODEL_DEFAULT (gobject); + GSequenceIter *iter; + + iter = g_sequence_get_begin_iter (model->sequence); + while (!g_sequence_iter_is_end (iter)) + { + GValueArray *value_array = g_sequence_get (iter); + + g_value_array_free (value_array); + iter = g_sequence_iter_next (iter); + } + g_sequence_free (model->sequence); + + G_OBJECT_CLASS (clutter_model_default_parent_class)->finalize (gobject); +} + +static void +clutter_model_default_class_init (ClutterModelDefaultClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ClutterModelClass *model_class = CLUTTER_MODEL_CLASS (klass); + + gobject_class->finalize = clutter_model_default_finalize; + + model_class->get_n_rows = clutter_model_default_get_n_rows; + model_class->get_iter_at_row = clutter_model_default_get_iter_at_row; + model_class->insert_row = clutter_model_default_insert_row; + model_class->remove_row = clutter_model_default_remove_row; + model_class->resort = clutter_model_default_resort; +} + +static void +clutter_model_default_init (ClutterModelDefault *model) +{ + model->sequence = g_sequence_new (NULL); +} diff --git a/clutter/clutter-model-default.h b/clutter/clutter-model-default.h new file mode 100644 index 000000000..f469c6b69 --- /dev/null +++ b/clutter/clutter-model-default.h @@ -0,0 +1,59 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Matthew Allum + * Neil Jagdish Patel + * Emmanuele Bassi + * + * Copyright (C) 2006 OpenedHand + * + * 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 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * NB: Inspiration for column storage taken from GtkListStore + */ + +#ifndef __CLUTTER_MODEL_DEFAULT_H__ +#define __CLUTTER_MODEL_DEFAULT_H__ + +#include + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_MODEL_DEFAULT_ITER (clutter_model_default_iter_get_type ()) +#define CLUTTER_MODEL_DEFAULT_ITER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MODEL_DEFAULT_ITER, ClutterModelDefaultIter)) +#define CLUTTER_IS_MODEL_DEFAULT_ITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MODEL_DEFAULT_ITER)) + +#define CLUTTER_TYPE_MODEL_DEFAULT (clutter_model_default_get_type ()) +#define CLUTTER_MODEL_DEFAULT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MODEL_DEFAULT, ClutterModelDefault)) +#define CLUTTER_IS_MODEL_DEFAULT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MODEL_DEFAULT)) + +typedef struct _ClutterModelDefaultIter ClutterModelDefaultIter; +typedef struct _ClutterModelDefault ClutterModelDefault; + +GType clutter_model_default_iter_get_type (void) G_GNUC_CONST; +GType clutter_model_default_get_type (void) G_GNUC_CONST; + +ClutterModel *clutter_model_default_new (guint n_columns, + ...); +ClutterModel *clutter_model_default_newv (guint n_columns, + GType *types, + const gchar * const names[]); + +G_END_DECLS + +#endif /* __CLUTTER_MODEL_DEFAULT_H__ */ diff --git a/clutter/clutter-model.c b/clutter/clutter-model.c index 507795e0c..3ef3e1abd 100644 --- a/clutter/clutter-model.c +++ b/clutter/clutter-model.c @@ -5,6 +5,7 @@ * * Authored By Matthew Allum * Neil Jagdish Patel + * Emmanuele Bassi * * Copyright (C) 2006 OpenedHand * @@ -30,18 +31,19 @@ * SECTION:clutter-model * @short_description: A generic model implementation * - * #ClutterModel is a generic list model which can be used to implement the - * model-view-controller architectural pattern in Clutter. + * #ClutterModel is a generic list model API which can be used to implement + * the model-view-controller architectural pattern in Clutter. * - * The #ClutterModel object is a list model which can accept most GObject - * types as a column type. Internally, it will keep a local copy of the data - * passed in (such as a string or a boxed pointer). + * The #ClutterModel class is a list model which can accept most GObject + * types as a column type. * * Creating a simple clutter model: - * - * enum { + * + * enum + * { * COLUMN_INT, - * COLUMN_STRING. + * COLUMN_STRING, + * * N_COLUMNS * }; * @@ -49,9 +51,10 @@ * ClutterModel *model; * gint i; * - * model = clutter_model_new (N_COLUMNS, - * G_TYPE_INT, "int", - * G_TYPE_STRING, "string"); + * model = clutter_model_default_new (N_COLUMNS, + * /* column type, column title */ + * G_TYPE_INT, "my integers", + * G_TYPE_STRING, "my strings"); * for (i = 0; i < 10; i++) * { * gchar *string = g_strdup_printf ("String %d", i); @@ -64,21 +67,22 @@ * * * } - * + * * * Iterating through the model consists of retrieving a new #ClutterModelIter - * pointing to the starting row, and calling #clutter_model_iter_next or - * #clutter_model_iter_prev to move forward or backwards, repectively. + * pointing to the starting row, and calling clutter_model_iter_next() or + * clutter_model_iter_prev() to move forward or backwards, repectively. * * A valid #ClutterModelIter represents the position between two rows in the - * model. For example, the @begin iterator represents the gap immediately - * before the first row, and the @end iterator represents the gap immediately - * after the last row. In an empty sequence, the begin and end iterators are + * model. For example, the "first" iterator represents the gap immediately + * before the first row, and the "last" iterator represents the gap immediately + * after the last row. In an empty sequence, the first and last iterators are * the same. * * Iterating a #ClutterModel: - * - * enum { + * + * enum + * { * COLUMN_INT, * COLUMN_STRING. * @@ -104,24 +108,33 @@ * /* Make sure to unref the iter */ * g_object_unref (iter); * } - * + * + * + * #ClutterModel is an abstract class. Clutter provides a default model + * implementation called #ClutterModelDefault which has been optimised + * for insertion and look up in sorted lists. * * #ClutterModel is available since Clutter 0.6 */ +#ifdef HAVE_CONFIG_H #include "config.h" +#endif #include #include #include #include "clutter-model.h" +#include "clutter-model-default.h" +#include "clutter-marshal.h" +#include "clutter-private.h" #include "clutter-debug.h" -G_DEFINE_TYPE (ClutterModel, clutter_model, G_TYPE_OBJECT); +G_DEFINE_ABSTRACT_TYPE (ClutterModel, clutter_model, G_TYPE_OBJECT); enum { @@ -142,45 +155,58 @@ static guint model_signals[LAST_SIGNAL] = { 0, }; struct _ClutterModelPrivate { - GSequence *sequence; - GType *column_types; gchar **column_names; gint n_columns; - - ClutterModelFilterFunc filter; + + ClutterModelFilterFunc filter_func; gpointer filter_data; GDestroyNotify filter_notify; - ClutterModelSortFunc sort; gint sort_column; + ClutterModelSortFunc sort_func; gpointer sort_data; GDestroyNotify sort_notify; }; -/* Forwards */ -static const gchar * _model_get_column_name (ClutterModel *model, - guint column); -static GType _model_get_column_type (ClutterModel *model, - guint column); -static ClutterModelIter * _model_get_iter_at_row (ClutterModel *model, - guint row); -static void clutter_model_real_remove (ClutterModel *model, - GSequenceIter *iter); +static GType +clutter_model_real_get_column_type (ClutterModel *model, + guint column) +{ + ClutterModelPrivate *priv = model->priv; + + if (column < 0 || column >= clutter_model_get_n_columns (model)) + return G_TYPE_INVALID; + + return priv->column_types[column]; +} + +static const gchar * +clutter_model_real_get_column_name (ClutterModel *model, + guint column) +{ + ClutterModelPrivate *priv = model->priv; + + if (column < 0 || column >= clutter_model_get_n_columns (model)) + return NULL; + + if (priv->column_names && priv->column_names[column]) + return priv->column_names[column]; + + return g_type_name (priv->column_types[column]); +} + +static guint +clutter_model_real_get_n_columns (ClutterModel *model) +{ + return model->priv->n_columns; +} static void clutter_model_finalize (GObject *object) { ClutterModelPrivate *priv = CLUTTER_MODEL (object)->priv; - GSequenceIter *iter; - - iter = g_sequence_get_end_iter (priv->sequence); - while (!g_sequence_iter_is_end (iter)) - { - clutter_model_real_remove (CLUTTER_MODEL (object), iter); - iter = g_sequence_iter_next (iter); - } - g_sequence_free (priv->sequence); + gint i; if (priv->sort_notify) priv->sort_notify (priv->sort_data); @@ -189,7 +215,14 @@ clutter_model_finalize (GObject *object) priv->filter_notify (priv->filter_data); g_free (priv->column_types); - g_strfreev (priv->column_names); + + /* the column_names vector might have holes in it, so we need to + * use the columns number to clear up everything + */ + for (i = 0; i < priv->n_columns; i++) + g_free (priv->column_names[i]); + + g_free (priv->column_names); G_OBJECT_CLASS (clutter_model_parent_class)->finalize (object); } @@ -201,9 +234,11 @@ clutter_model_class_init (ClutterModelClass *klass) gobject_class->finalize = clutter_model_finalize; - klass->get_iter_at_row = _model_get_iter_at_row; - klass->get_column_name = _model_get_column_name; - klass->get_column_type = _model_get_column_type; + g_type_class_add_private (gobject_class, sizeof (ClutterModelPrivate)); + + klass->get_column_name = clutter_model_real_get_column_name; + klass->get_column_type = clutter_model_real_get_column_type; + klass->get_n_columns = clutter_model_real_get_n_columns; /** * ClutterModel::row-added: @@ -220,9 +255,9 @@ clutter_model_class_init (ClutterModelClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterModelClass, row_added), NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - + clutter_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CLUTTER_TYPE_MODEL_ITER); /** * ClutterModel::row-removed: * @model: the #ClutterModel on which the signal is emitted @@ -238,9 +273,9 @@ clutter_model_class_init (ClutterModelClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterModelClass, row_removed), NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - + clutter_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CLUTTER_TYPE_MODEL_ITER); /** * ClutterModel::row-changed: * @model: the #ClutterModel on which the signal is emitted @@ -256,9 +291,9 @@ clutter_model_class_init (ClutterModelClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterModelClass, row_changed), NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - + clutter_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CLUTTER_TYPE_MODEL_ITER); /** * ClutterModel::sort-changed: * @model: the #ClutterModel on which the signal is emitted @@ -273,9 +308,8 @@ clutter_model_class_init (ClutterModelClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterModelClass, sort_changed), NULL, NULL, - g_cclosure_marshal_VOID__VOID, + clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); - /** * ClutterModel::filter-changed: * @model: the #ClutterModel on which the signal is emitted @@ -290,10 +324,8 @@ clutter_model_class_init (ClutterModelClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (ClutterModelClass, filter_changed), NULL, NULL, - g_cclosure_marshal_VOID__VOID, + clutter_marshal_VOID__VOID, G_TYPE_NONE, 0); - - g_type_class_add_private (gobject_class, sizeof (ClutterModelPrivate)); } static void @@ -303,21 +335,23 @@ clutter_model_init (ClutterModel *self) self->priv = priv = CLUTTER_MODEL_GET_PRIVATE (self); - priv->sequence = g_sequence_new (NULL); - - priv->column_types = NULL; priv->n_columns = -1; + priv->column_types = NULL; + priv->column_names = NULL; - priv->filter = NULL; + priv->filter_func = NULL; priv->filter_data = NULL; priv->filter_notify = NULL; - priv->sort = NULL; - priv->sort_data = NULL; + priv->sort_column = -1; + priv->sort_func = NULL; + priv->sort_data = NULL; priv->sort_notify = NULL; } - +/* XXX - is this whitelist really necessary? we accept every fundamental + * type. + */ static gboolean clutter_model_check_type (type) { @@ -347,7 +381,6 @@ clutter_model_check_type (type) if (! G_TYPE_IS_VALUE_TYPE (type)) return FALSE; - while (type_list[i] != G_TYPE_INVALID) { if (g_type_is_a (type, type_list[i])) @@ -357,58 +390,105 @@ clutter_model_check_type (type) return FALSE; } -static gint -_model_sort_func (GValueArray *val_a, - GValueArray *val_b, - ClutterModel *model) -{ - ClutterModelPrivate *priv; - const GValue *a; - const GValue *b; - - g_return_val_if_fail (CLUTTER_IS_MODEL (model), 0); - g_return_val_if_fail (val_a, 0); - g_return_val_if_fail (val_b, 0); - priv = model->priv; - - a = g_value_array_get_nth (val_a, priv->sort_column); - b = g_value_array_get_nth (val_b, priv->sort_column); - - return priv->sort (model, a, b, priv->sort_data); -} - -static void -_model_sort (ClutterModel *model) +/** + * clutter_model_resort: + * @model: a #ClutterModel + * + * Force a resort on the @model. This function should only be + * used by subclasses of #ClutterModel. + * + * Since: 0.6 + */ +void +clutter_model_resort (ClutterModel *model) { ClutterModelPrivate *priv; + ClutterModelClass *klass; g_return_if_fail (CLUTTER_IS_MODEL (model)); priv = model->priv; - if (!priv->sort) + if (!priv->sort_func) return; - g_sequence_sort (priv->sequence, (GCompareDataFunc)_model_sort_func, model); + klass = CLUTTER_MODEL_GET_CLASS (model); + + if (klass->resort) + klass->resort (model, priv->sort_func, priv->sort_data); } - -static gboolean -_model_filter (ClutterModel *model, ClutterModelIter *iter) +/** + * clutter_model_filter_row: + * @model: a #ClutterModel + * @row: the row to filter + * + * Checks whether @row should be filtered or not using the + * filtering function set on @model. + * + * This function should be used only by subclasses of #ClutterModel. + * + * Return value: %TRUE if the row should be displayed, + * %FALSE otherwise + * + * Since: 0.6 + */ +gboolean +clutter_model_filter_row (ClutterModel *model, + guint row) { ClutterModelPrivate *priv; + ClutterModelIter *iter; gboolean res = TRUE; g_return_val_if_fail (CLUTTER_IS_MODEL (model), TRUE); + priv = model->priv; - if (!priv->filter) + if (!priv->filter_func) return TRUE; - res = priv->filter (model, iter, priv->filter_data); + iter = clutter_model_get_iter_at_row (model, row); + if (!iter) + return FALSE; + + res = priv->filter_func (model, iter, priv->filter_data); + + g_object_unref (iter); return res; } +/** + * clutter_model_filter_iter: + * @model: a #ClutterModel + * @iter: the row to filter + * + * Checks whether the row pointer by @iter should be filtered or not using + * the filtering function set on @model. + * + * This function should be used only by subclasses of #ClutterModel. + * + * Return value: %TRUE if the row should be displayed, + * %FALSE otherwise + * + * Since: 0.6 + */ +gboolean +clutter_model_filter_iter (ClutterModel *model, + ClutterModelIter *iter) +{ + ClutterModelPrivate *priv; + + g_return_val_if_fail (CLUTTER_IS_MODEL (model), TRUE); + g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), TRUE); + + priv = model->priv; + + if (!priv->filter_func) + return TRUE; + + return priv->filter_func (model, iter, priv->filter_data); +} static void clutter_model_set_n_columns (ClutterModel *model, @@ -434,7 +514,7 @@ clutter_model_set_n_columns (ClutterModel *model, priv->column_names = g_new0 (gchar*, n_columns + 1); } -static void +static inline void clutter_model_set_column_type (ClutterModel *model, gint column, GType type) @@ -444,7 +524,7 @@ clutter_model_set_column_type (ClutterModel *model, priv->column_types[column] = type; } -static void +static inline void clutter_model_set_column_name (ClutterModel *model, gint column, const gchar *name) @@ -454,21 +534,27 @@ clutter_model_set_column_name (ClutterModel *model, priv->column_names[column] = g_strdup (name); } +/* we implement the constructors of the default model here because + * we need the private accessors to the column names and types + * vectors inside ClutterModelPrivate; the ClutterModelDefault ctors + * are declared inside clutter-model-default.h + */ + /** - * clutter_model_new: + * clutter_model_default_new: * @n_columns: number of columns in the model * @Varargs: @n_columns number of #GType and string pairs * - * Creates a new model with @n_columns columns with the types + * Creates a new default model with @n_columns columns with the types * and names passed in. * * For example: * * - * model = clutter_model_new (3, - * G_TYPE_INT, "int column", - * G_TYPE_STRING, "string column", - * GDK_TYPE_PIXBUF, "pixbuf column"); + * model = clutter_model_default_new (3, + * G_TYPE_INT, "Score", + * G_TYPE_STRING, "Team", + * GDK_TYPE_PIXBUF, "Logo"); * * * will create a new #ClutterModel with three columns of type int, @@ -479,8 +565,8 @@ clutter_model_set_column_name (ClutterModel *model, * Since 0.6 */ ClutterModel * -clutter_model_new (guint n_columns, - ...) +clutter_model_default_new (guint n_columns, + ...) { ClutterModel *model; va_list args; @@ -488,7 +574,7 @@ clutter_model_new (guint n_columns, g_return_val_if_fail (n_columns > 0, NULL); - model = g_object_new (CLUTTER_TYPE_MODEL, NULL); + model = g_object_new (CLUTTER_TYPE_MODEL_DEFAULT, NULL); clutter_model_set_n_columns (model, n_columns, TRUE, TRUE); va_start (args, n_columns); @@ -497,7 +583,7 @@ clutter_model_new (guint n_columns, { GType type = va_arg (args, GType); const gchar *name = va_arg (args, gchar*); - + if (!clutter_model_check_type (type)) { g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (type)); @@ -515,28 +601,28 @@ clutter_model_new (guint n_columns, } /** - * clutter_model_newv: + * clutter_model_default_newv: * @n_columns: number of columns in the model * @types: an array of #GType types for the columns, from first to last * @names: an array of names for the columns, from first to last * - * Non-vararg creation function. Used primarily by language bindings. + * Non-vararg creation function. Useful primarily by language bindings. * * Return value: a new #ClutterModel * * Since 0.6 */ ClutterModel * -clutter_model_newv (guint n_columns, - GType *types, - const gchar * const names[]) +clutter_model_default_newv (guint n_columns, + GType *types, + const gchar * const names[]) { ClutterModel *model; gint i; g_return_val_if_fail (n_columns > 0, NULL); - model = g_object_new (CLUTTER_TYPE_MODEL, NULL); + model = g_object_new (CLUTTER_TYPE_MODEL_DEFAULT, NULL); clutter_model_set_n_columns (model, n_columns, TRUE, TRUE); for (i = 0; i < n_columns; i++) @@ -650,31 +736,7 @@ clutter_model_get_n_columns (ClutterModel *model) { g_return_val_if_fail (CLUTTER_IS_MODEL (model), 0); - return model->priv->n_columns; -} - -static GValueArray * -clutter_model_new_row (ClutterModel *model) -{ - ClutterModelPrivate *priv; - GValueArray *row; - gint i; - - g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL); - priv = model->priv; - - row = g_value_array_new (priv->n_columns); - - for (i = 0; i < priv->n_columns; i++) - { - GValue value = { 0, }; - - g_value_init (&value, priv->column_types[i]); - g_value_array_append (row, &value); - g_value_unset (&value); - } - - return row; + return CLUTTER_MODEL_GET_CLASS (model)->get_n_columns (model); } /** @@ -695,27 +757,21 @@ clutter_model_append_value (ClutterModel *model, { ClutterModelPrivate *priv; ClutterModelIter *iter; - GSequenceIter *seq_iter; - GValueArray *row; g_return_if_fail (CLUTTER_IS_MODEL (model)); priv = model->priv; - row = clutter_model_new_row (model); - seq_iter = g_sequence_append (priv->sequence, row); - - iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, - "model", model, - "iter", seq_iter, - NULL); + iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, -1); + g_assert (CLUTTER_IS_MODEL_ITER (iter)); clutter_model_iter_set_value (iter, column, value); - if (priv->sort_column == column) - _model_sort (model); - g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); + + if (priv->sort_column == column) + clutter_model_resort (model); + g_object_unref (iter); } @@ -730,9 +786,9 @@ clutter_model_append_value (ClutterModel *model, * * * ClutterModel *model; - * model = clutter_model_new (2, - * G_TYPE_INT, "My integers", - * G_TYPE_STRING, "My strings"); + * model = clutter_model_default_new (2, + * G_TYPE_INT, "My integers", + * G_TYPE_STRING, "My strings"); * clutter_model_append (model, 0, 42, 1, "string", -1); * * @@ -744,27 +800,20 @@ clutter_model_append (ClutterModel *model, { ClutterModelPrivate *priv; ClutterModelIter *iter; - GSequenceIter *seq_iter; - GValueArray *row; va_list args; g_return_if_fail (CLUTTER_IS_MODEL (model)); priv = model->priv; - row = clutter_model_new_row (model); - seq_iter = g_sequence_append (priv->sequence, row); - - iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, - "model", model, - "iter", seq_iter, - NULL); + iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, -1); + g_assert (CLUTTER_IS_MODEL_ITER (iter)); va_start (args, model); clutter_model_iter_set_valist (iter, args); va_end (args); - /*FIXME: Sort the model if necessary */ g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); + g_object_unref (iter); } @@ -786,27 +835,21 @@ clutter_model_prepend_value (ClutterModel *model, { ClutterModelPrivate *priv; ClutterModelIter *iter; - GSequenceIter *seq_iter; - GValueArray *row; g_return_if_fail (CLUTTER_IS_MODEL (model)); priv = model->priv; - row = clutter_model_new_row (model); - seq_iter = g_sequence_prepend (priv->sequence, row); - - iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, - "model", model, - "iter", seq_iter, - NULL); + iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, 0); + g_assert (CLUTTER_IS_MODEL_ITER (iter)); clutter_model_iter_set_value (iter, column, value); - if (priv->sort_column == column) - _model_sort (model); + g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); + + if (priv->sort_column == column) + clutter_model_resort (model); - g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); g_object_unref (iter); } @@ -821,9 +864,9 @@ clutter_model_prepend_value (ClutterModel *model, * * * ClutterModel *model; - * model = clutter_model_new (2, - * G_TYPE_INT, "My integers", - * G_TYPE_STRING, "My strings"); + * model = clutter_model_default_new (2, + * G_TYPE_INT, "My integers", + * G_TYPE_STRING, "My strings"); * clutter_model_prepend (model, 0, 42, 1, "string", -1); * * @@ -833,29 +876,20 @@ void clutter_model_prepend (ClutterModel *model, ...) { - ClutterModelPrivate *priv; ClutterModelIter *iter; - GSequenceIter *seq_iter; - GValueArray *row; va_list args; g_return_if_fail (CLUTTER_IS_MODEL (model)); - priv = model->priv; + iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, 0); + g_assert (CLUTTER_IS_MODEL_ITER (iter)); - row = clutter_model_new_row (model); - seq_iter = g_sequence_prepend (priv->sequence, row); - - iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, - "model", model, - "iter", seq_iter, - NULL); va_start (args, model); clutter_model_iter_set_valist (iter, args); va_end (args); - /*FIXME: Sort the model if necessary */ - g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); + g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); + g_object_unref (iter); } @@ -873,9 +907,9 @@ clutter_model_prepend (ClutterModel *model, * * * ClutterModel *model; - * model = clutter_model_new (2, - * G_TYPE_INT, "My integers", - * G_TYPE_STRING, "My strings"); + * model = clutter_model_default_new (2, + * G_TYPE_INT, "My integers", + * G_TYPE_STRING, "My strings"); * clutter_model_insert (model, 100, 0, 42, 1, "string", -1); * * @@ -886,33 +920,23 @@ clutter_model_insert (ClutterModel *model, guint row, ...) { - ClutterModelPrivate *priv; ClutterModelIter *iter; - GValueArray *row_array; - GSequenceIter *seq_iter; va_list args; g_return_if_fail (CLUTTER_IS_MODEL (model)); - priv = model->priv; - - row_array = clutter_model_new_row (model); - - seq_iter = g_sequence_get_iter_at_pos (priv->sequence, row); - seq_iter = g_sequence_insert_before (seq_iter, row_array); - - iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, - "model", model, - "iter", seq_iter, - NULL); + iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, row); + g_assert (CLUTTER_IS_MODEL_ITER (iter)); + /* set_valist() will call clutter_model_resort() if one of the + * passed columns matches the model sorting column index + */ va_start (args, row); clutter_model_iter_set_valist (iter, args); va_end (args); - /* FIXME: Sort? */ - g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); + g_object_unref (iter); } @@ -924,7 +948,8 @@ clutter_model_insert (ClutterModel *model, * @value: new value for the cell * * Sets the data in the cell specified by @iter and @column. The type of - * @value must be convertable to the type of the column. + * @value must be convertable to the type of the column. If the row does + * not exist then it is created. * * Since 0.6 */ @@ -935,43 +960,35 @@ clutter_model_insert_value (ClutterModel *model, const GValue *value) { ClutterModelPrivate *priv; + ClutterModelClass *klass; ClutterModelIter *iter; - GSequenceIter *seq_iter; + gboolean added = FALSE; g_return_if_fail (CLUTTER_IS_MODEL (model)); priv = model->priv; + klass = CLUTTER_MODEL_GET_CLASS (model); - seq_iter = g_sequence_get_iter_at_pos (priv->sequence, row); - - iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, - "model", model, - "iter", seq_iter, - NULL); + iter = klass->get_iter_at_row (model, row); + if (!iter) + { + iter = klass->insert_row (model, row); + added = TRUE; + } + + g_assert (CLUTTER_IS_MODEL_ITER (iter)); clutter_model_iter_set_value (iter, column, value); + if (added) + g_signal_emit (model, model_signals[ROW_ADDED], 0, iter); + if (priv->sort_column == column) - _model_sort (model); + clutter_model_resort (model); - g_signal_emit (model, model_signals[ROW_CHANGED], 0, iter); g_object_unref (iter); } -static void -clutter_model_real_remove (ClutterModel *model, - GSequenceIter *iter) -{ - ClutterModelPrivate *priv; - GValueArray *value_array; - - g_return_if_fail (CLUTTER_IS_MODEL (model)); - priv = model->priv; - - value_array = g_sequence_get (iter); - g_value_array_free (value_array); -} - /** * clutter_model_remove: * @model: a #ClutterModel @@ -985,49 +1002,13 @@ void clutter_model_remove (ClutterModel *model, guint row) { - ClutterModelPrivate *priv; - ClutterModelIter *iter; - GSequenceIter *seq_iter; - gint i = 0; + ClutterModelClass *klass; g_return_if_fail (CLUTTER_IS_MODEL (model)); - priv = model->priv; - seq_iter = g_sequence_get_begin_iter (priv->sequence); - iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, "model", model, NULL); - - while (!g_sequence_iter_is_end (seq_iter)) - { - g_object_set (iter, "iter", seq_iter, NULL); - if (_model_filter (model, iter)) - { - if (i == row) - { - g_signal_emit (model, model_signals[ROW_REMOVED], 0, iter); - clutter_model_real_remove (model, seq_iter); - g_sequence_remove (seq_iter); - break; - } - i++; - } - seq_iter = g_sequence_iter_next (seq_iter); - } - g_object_unref (iter); -} - -static const gchar * -_model_get_column_name (ClutterModel *model, - guint column) -{ - ClutterModelPrivate *priv = model->priv; - - if (column < 0 || column >= priv->n_columns) - return NULL; - - if (priv->column_names && priv->column_names[column]) - return priv->column_names[column]; - - return g_type_name (priv->column_types[column]); + klass = CLUTTER_MODEL_GET_CLASS (model); + if (klass->remove_row) + klass->remove_row (model, row); } /** @@ -1052,7 +1033,7 @@ clutter_model_get_column_name (ClutterModel *model, g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL); priv = model->priv; - if (column < 0 || column > priv->n_columns) + if (column < 0 || column > clutter_model_get_n_columns (model)) { g_warning ("%s: Invalid column id value %d\n", G_STRLOC, column); return NULL; @@ -1065,18 +1046,6 @@ clutter_model_get_column_name (ClutterModel *model, return NULL; } -static GType -_model_get_column_type (ClutterModel *model, - guint column) -{ - ClutterModelPrivate *priv = model->priv; - - if (column < 0 || column >= priv->n_columns) - return G_TYPE_INVALID; - - return priv->column_types[column]; -} - /** * clutter_model_get_column_type: * @model: #ClutterModel @@ -1098,7 +1067,7 @@ clutter_model_get_column_type (ClutterModel *model, g_return_val_if_fail (CLUTTER_IS_MODEL (model), G_TYPE_INVALID); priv = model->priv; - if (column < 0 || column > priv->n_columns) + if (column < 0 || column > clutter_model_get_n_columns (model)) { g_warning ("%s: Invalid column id value %d\n", G_STRLOC, column); return G_TYPE_INVALID; @@ -1111,16 +1080,6 @@ clutter_model_get_column_type (ClutterModel *model, return G_TYPE_INVALID; } -static ClutterModelIter * -_model_get_iter_at_row (ClutterModel *model, - guint row) -{ - return g_object_new (CLUTTER_TYPE_MODEL_ITER, - "model", model, - "row", row, - NULL); -} - /** * clutter_model_get_iter_at_row: * @model: a #ClutterModel @@ -1185,7 +1144,7 @@ clutter_model_get_last_iter (ClutterModel *model) length = clutter_model_get_n_rows (model); - return clutter_model_get_iter_at_row (model, length-1); + return clutter_model_get_iter_at_row (model, length - 1); } /** @@ -1195,7 +1154,7 @@ clutter_model_get_last_iter (ClutterModel *model) * Retrieves the number of rows inside @model. * * Return value: The length of the @model. If there is a filter set, then - * thelength of the filtered @model is returned. + * the length of the filtered @model is returned. * * Since 0.6 */ @@ -1204,28 +1163,32 @@ clutter_model_get_n_rows (ClutterModel *model) { ClutterModelPrivate *priv; ClutterModelIter *iter; - GSequenceIter *seq_iter; - guint i = 0; + guint n_rows; g_return_val_if_fail (CLUTTER_IS_MODEL (model), 0); + priv = model->priv; - seq_iter = g_sequence_get_begin_iter (priv->sequence); - iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, "model", model, NULL); + /* if there's no filter set, just get the full number of rows */ + if (!priv->filter_func) + return CLUTTER_MODEL_GET_CLASS (model)->get_n_rows (model); - while (!g_sequence_iter_is_end (seq_iter)) + iter = clutter_model_get_first_iter (model); + if (!iter) + return 0; + + n_rows = 0; + while (!clutter_model_iter_is_last (iter)) { - g_object_set (iter, "iter", seq_iter, NULL); - if (_model_filter (model, iter)) - { - i++; - } - seq_iter = g_sequence_iter_next (seq_iter); + if (clutter_model_filter_iter (model, iter)) + n_rows += 1; + + iter = clutter_model_iter_next (iter); } g_object_unref (iter); - - return i; + + return n_rows; } @@ -1248,7 +1211,7 @@ clutter_model_set_sorting_column (ClutterModel *model, g_return_if_fail (CLUTTER_IS_MODEL (model)); priv = model->priv; - if (column > priv->n_columns) + if (column > clutter_model_get_n_columns (model)) { g_warning ("%s: Invalid column id value %d\n", G_STRLOC, column); return; @@ -1257,7 +1220,7 @@ clutter_model_set_sorting_column (ClutterModel *model, priv->sort_column = column; if (priv->sort_column > 0) - _model_sort (model); + clutter_model_resort (model); g_signal_emit (model, model_signals[SORT_CHANGED], 0); } @@ -1295,25 +1258,23 @@ clutter_model_foreach (ClutterModel *model, ClutterModelForeachFunc func, gpointer user_data) { - ClutterModelPrivate *priv; ClutterModelIter *iter; - GSequenceIter *seq_iter; g_return_if_fail (CLUTTER_IS_MODEL (model)); - priv = model->priv; - seq_iter = g_sequence_get_begin_iter (priv->sequence); - iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, "model", model, NULL); + iter = clutter_model_get_first_iter (model); + if (!iter) + return; - while (!g_sequence_iter_is_end (seq_iter)) + while (!clutter_model_iter_is_last (iter)) { - g_object_set (iter, "iter", seq_iter, NULL); - if (_model_filter (model, iter)) + if (clutter_model_filter_iter (model, iter)) { if (!func (model, iter, user_data)) break; } - seq_iter = g_sequence_iter_next (seq_iter); + + iter = clutter_model_iter_next (iter); } g_object_unref (iter); @@ -1343,10 +1304,10 @@ clutter_model_set_sort (ClutterModel *model, g_return_if_fail (CLUTTER_IS_MODEL (model)); priv = model->priv; - if (priv->sort_data && priv->sort_notify) + if (priv->sort_notify) priv->sort_notify (priv->sort_data); - priv->sort = func; + priv->sort_func = func; priv->sort_data = user_data; priv->sort_notify = notify; @@ -1376,10 +1337,10 @@ clutter_model_set_filter (ClutterModel *model, g_return_if_fail (CLUTTER_IS_MODEL (model)); priv = model->priv; - if (priv->filter_data && priv->filter_notify) + if (priv->filter_notify) priv->filter_notify (priv->filter_data); - priv->filter = func; + priv->filter_func = func; priv->filter_data = user_data; priv->filter_notify = notify; @@ -1405,13 +1366,13 @@ clutter_model_set_filter (ClutterModel *model, * clutter_model_get_last_iter() represents the gap immediately after the * last row. * - * A #ClutterModelIter can only be created by a #ClutterModel and it is - * valid as long as the model does not change. + * A #ClutterModelIter can only be created by a #ClutterModel implementation + * and it is valid as long as the model does not change. * * #ClutterModelIter is available since Clutter 0.6 */ -G_DEFINE_TYPE (ClutterModelIter, clutter_model_iter, G_TYPE_OBJECT); +G_DEFINE_ABSTRACT_TYPE (ClutterModelIter, clutter_model_iter, G_TYPE_OBJECT); #define CLUTTER_MODEL_ITER_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \ @@ -1420,9 +1381,10 @@ G_DEFINE_TYPE (ClutterModelIter, clutter_model_iter, G_TYPE_OBJECT); struct _ClutterModelIterPrivate { ClutterModel *model; - GSequenceIter *seq_iter; - gboolean ignore_sort; + gint row; + + guint ignore_sort : 1; }; enum @@ -1430,27 +1392,83 @@ enum ITER_PROP_0, ITER_PROP_MODEL, - ITER_PROP_ROW, - ITER_PROP_ITER, + ITER_PROP_ROW }; -/* Forwards */ -static void _model_iter_get_value (ClutterModelIter *iter, - guint column, - GValue *value); -static void _model_iter_set_value (ClutterModelIter *iter, - guint column, - const GValue *value); -static gboolean _model_iter_is_first (ClutterModelIter *iter); -static gboolean _model_iter_is_last (ClutterModelIter *iter); -static ClutterModelIter * _model_iter_next (ClutterModelIter *iter); -static ClutterModelIter * _model_iter_prev (ClutterModelIter *iter); -static ClutterModel * _model_iter_get_model (ClutterModelIter *iter); -static guint _model_iter_get_row (ClutterModelIter *iter); -static void _model_iter_set_row (ClutterModelIter *iter, - guint row); +static ClutterModel * +clutter_model_iter_real_get_model (ClutterModelIter *iter) +{ + return iter->priv->model; +} + +static guint +clutter_model_iter_real_get_row (ClutterModelIter *iter) +{ + return iter->priv->row; +} + +static void +clutter_model_iter_get_value_unimplemented (ClutterModelIter *iter, + guint column, + GValue *value) +{ + g_warning ("%s: Iterator of type `%s' does not implement the " + "ClutterModelIter::get_value() virtual function", + G_STRLOC, + g_type_name (G_OBJECT_TYPE (iter))); +} + +static void +clutter_model_iter_set_value_unimplemented (ClutterModelIter *iter, + guint column, + const GValue *value) +{ + g_warning ("%s: Iterator of type `%s' does not implement the " + "ClutterModelIter::set_value() virtual function", + G_STRLOC, + g_type_name (G_OBJECT_TYPE (iter))); +} + +static gboolean +clutter_model_iter_is_first_unimplemented (ClutterModelIter *iter) +{ + g_warning ("%s: Iterator of type `%s' does not implement the " + "ClutterModelIter::is_first() virtual function", + G_STRLOC, + g_type_name (G_OBJECT_TYPE (iter))); + return FALSE; +} + +static gboolean +clutter_model_iter_is_last_unimplemented (ClutterModelIter *iter) +{ + g_warning ("%s: Iterator of type `%s' does not implement the " + "ClutterModelIter::is_last() virtual function", + G_STRLOC, + g_type_name (G_OBJECT_TYPE (iter))); + return FALSE; +} + +static ClutterModelIter * +clutter_model_iter_next_unimplemented (ClutterModelIter *iter) +{ + g_warning ("%s: Iterator of type `%s' does not implement the " + "ClutterModelIter::next() virtual function", + G_STRLOC, + g_type_name (G_OBJECT_TYPE (iter))); + return NULL; +} + +static ClutterModelIter * +clutter_model_iter_prev_unimplemented (ClutterModelIter *iter) +{ + g_warning ("%s: Iterator of type `%s' does not implement the " + "ClutterModelIter::prev() virtual function", + G_STRLOC, + g_type_name (G_OBJECT_TYPE (iter))); + return NULL; +} -/* GObject stuff */ static void clutter_model_iter_get_property (GObject *object, guint prop_id, @@ -1458,24 +1476,19 @@ clutter_model_iter_get_property (GObject *object, GParamSpec *pspec) { ClutterModelIter *iter = CLUTTER_MODEL_ITER (object); - ClutterModelIterPrivate *priv; - - g_return_if_fail (CLUTTER_IS_MODEL_ITER (object)); - priv = iter->priv; + ClutterModelIterPrivate *priv = iter->priv; switch (prop_id) { - case ITER_PROP_MODEL: - g_value_set_object (value, priv->model); - break; - case ITER_PROP_ROW: - g_value_set_uint (value, clutter_model_iter_get_row (iter)); - break; - case ITER_PROP_ITER: - g_value_set_pointer (value, priv->seq_iter); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + case ITER_PROP_MODEL: + g_value_set_object (value, priv->model); + break; + case ITER_PROP_ROW: + g_value_set_uint (value, priv->row); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } } @@ -1486,24 +1499,19 @@ clutter_model_iter_set_property (GObject *object, GParamSpec *pspec) { ClutterModelIter *iter = CLUTTER_MODEL_ITER (object); - ClutterModelIterPrivate *priv; - - g_return_if_fail (CLUTTER_IS_MODEL_ITER (object)); - priv = iter->priv; + ClutterModelIterPrivate *priv = iter->priv; switch (prop_id) { - case ITER_PROP_MODEL: - priv->model = g_value_get_object (value); - break; - case ITER_PROP_ROW: - _model_iter_set_row (iter, g_value_get_uint (value)); - break; - case ITER_PROP_ITER: - priv->seq_iter = g_value_get_pointer (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + case ITER_PROP_MODEL: + priv->model = g_value_get_object (value); + break; + case ITER_PROP_ROW: + priv->row = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; } } @@ -1515,14 +1523,14 @@ clutter_model_iter_class_init (ClutterModelIterClass *klass) gobject_class->get_property = clutter_model_iter_get_property; gobject_class->set_property = clutter_model_iter_set_property; - klass->get_value = _model_iter_get_value; - klass->set_value = _model_iter_set_value; - klass->is_first = _model_iter_is_first; - klass->is_last = _model_iter_is_last; - klass->next = _model_iter_next; - klass->prev = _model_iter_prev; - klass->get_model = _model_iter_get_model; - klass->get_row = _model_iter_get_row; + klass->get_model = clutter_model_iter_real_get_model; + klass->get_row = clutter_model_iter_real_get_row; + klass->is_first = clutter_model_iter_is_first_unimplemented; + klass->is_last = clutter_model_iter_is_last_unimplemented; + klass->next = clutter_model_iter_next_unimplemented; + klass->prev = clutter_model_iter_prev_unimplemented; + klass->get_value = clutter_model_iter_get_value_unimplemented; + klass->set_value = clutter_model_iter_set_value_unimplemented; /* Properties */ @@ -1534,42 +1542,27 @@ clutter_model_iter_class_init (ClutterModelIterClass *klass) * Since: 0.6 */ g_object_class_install_property (gobject_class, - ITER_PROP_MODEL, - g_param_spec_object ("model", - "Model", - "A ClutterModel", - CLUTTER_TYPE_MODEL, - G_PARAM_READWRITE)); + ITER_PROP_MODEL, + g_param_spec_object ("model", + "Model", + "The model to which the iterator belongs to", + CLUTTER_TYPE_MODEL, + CLUTTER_PARAM_READWRITE)); /** * ClutterModelIter:row: * - * A reference to the row number that this iter represents. + * The row number to which this iter points to. * * Since: 0.6 */ g_object_class_install_property (gobject_class, - ITER_PROP_ROW, - g_param_spec_uint ("row", - "Row", - "The row number", - 0, 65535, 0, - G_PARAM_READWRITE)); - - /** - * ClutterModelIter:iter: - * - * An internal iter reference. This property should only be used when - * sub-classing #ClutterModelIter. - * - * Since: 0.6 - */ - g_object_class_install_property (gobject_class, - ITER_PROP_ITER, - g_param_spec_pointer ("iter", - "Iter", - "The internal iter reference", - G_PARAM_READWRITE)); + ITER_PROP_ROW, + g_param_spec_uint ("row", + "Row", + "The row to which the iterator points to", + 0, G_MAXUINT, 0, + CLUTTER_PARAM_READWRITE)); g_type_class_add_private (gobject_class, sizeof (ClutterModelIterPrivate)); } @@ -1581,386 +1574,12 @@ clutter_model_iter_init (ClutterModelIter *self) self->priv = priv = CLUTTER_MODEL_ITER_GET_PRIVATE (self); - priv->seq_iter = NULL; priv->model = NULL; + priv->row = 0; + priv->ignore_sort = FALSE; } -static void -_model_iter_get_value (ClutterModelIter *iter, - guint column, - GValue *value) -{ - ClutterModelIterPrivate *priv; - GValueArray *value_array; - GValue *iter_value; - GValue real_value = { 0, }; - gboolean converted = FALSE; - - g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter)); - priv = iter->priv; - g_return_if_fail (CLUTTER_IS_MODEL (priv->model)); - g_return_if_fail (priv->seq_iter); - - value_array = g_sequence_get (priv->seq_iter); - iter_value = g_value_array_get_nth (value_array, column); - - if (!g_type_is_a (G_VALUE_TYPE (value), G_VALUE_TYPE (iter_value))) - { - if (!g_value_type_compatible (G_VALUE_TYPE (value), - G_VALUE_TYPE (iter_value)) && - !g_value_type_compatible (G_VALUE_TYPE (iter_value), - G_VALUE_TYPE (value))) - { - g_warning ("%s: Unable to convert from %s to %s\n", - G_STRLOC, - g_type_name (G_VALUE_TYPE (value)), - g_type_name (G_VALUE_TYPE (iter_value))); - return; - } - if (!g_value_transform (value, &real_value)) - { - g_warning ("%s: Unable to make conversion from %s to %s\n", - G_STRLOC, - g_type_name (G_VALUE_TYPE (value)), - g_type_name (G_VALUE_TYPE (iter_value))); - g_value_unset (&real_value); - } - converted = TRUE; - } - - if (converted) - g_value_copy (&real_value, value); - else - g_value_copy (iter_value, value); -} - -static void -_model_iter_set_value (ClutterModelIter *iter, - guint column, - const GValue *value) -{ - ClutterModelPrivate *model_priv; - ClutterModelIterPrivate *priv; - GValueArray *value_array; - GValue *iter_value; - GValue real_value = { 0, }; - gboolean converted = FALSE; - - g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter)); - priv = iter->priv; - g_return_if_fail (CLUTTER_IS_MODEL (priv->model)); - g_return_if_fail (priv->seq_iter); - - model_priv = priv->model->priv; - - value_array = g_sequence_get (priv->seq_iter); - iter_value = g_value_array_get_nth (value_array, column); - - if (!g_type_is_a (G_VALUE_TYPE (value), G_VALUE_TYPE (iter_value))) - { - if (!g_value_type_compatible (G_VALUE_TYPE (value), - G_VALUE_TYPE (iter_value)) && - !g_value_type_compatible (G_VALUE_TYPE (iter_value), - G_VALUE_TYPE (value))) - { - g_warning ("%s: Unable to convert from %s to %s\n", - G_STRLOC, - g_type_name (G_VALUE_TYPE (value)), - g_type_name (G_VALUE_TYPE (iter_value))); - return; - } - if (!g_value_transform (value, &real_value)) - { - g_warning ("%s: Unable to make conversion from %s to %s\n", - G_STRLOC, - g_type_name (G_VALUE_TYPE (value)), - g_type_name (G_VALUE_TYPE (iter_value))); - g_value_unset (&real_value); - } - converted = TRUE; - } - - if (converted) - { - g_value_copy (&real_value, iter_value); - g_value_unset (&real_value); - } - else - g_value_copy (value, iter_value); - - /* Check if we need to sort */ - if (!priv->ignore_sort) - { - if (model_priv->sort_column == column && model_priv->sort) - _model_sort (priv->model); - - g_signal_emit (priv->model, model_signals[ROW_CHANGED], 0, iter); - } -} - -static gboolean -_model_iter_is_first (ClutterModelIter *iter) -{ - ClutterModel *model = NULL; - ClutterModelPrivate *model_priv; - ClutterModelIterPrivate *iter_priv; - GSequenceIter *begin, *end; - ClutterModelIter *temp_iter; - - g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), TRUE); - iter_priv = iter->priv; - model = iter_priv->model; - - g_return_val_if_fail (CLUTTER_IS_MODEL (model), TRUE); - model_priv = model->priv; - - begin = g_sequence_get_begin_iter (model_priv->sequence); - end = iter_priv->seq_iter; - - temp_iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, "model", model, NULL); - - while (!g_sequence_iter_is_begin (begin)) - { - temp_iter->priv->seq_iter = begin; - if (_model_filter (model, temp_iter)) - { - end = begin; - break; - } - begin = g_sequence_iter_prev (begin); - } - /* This is because the 'begin_iter' is always *before* the last valid iter. - * Otherwise we'd have endless loops - */ - end = g_sequence_iter_prev (end); - - g_object_unref (temp_iter); - return iter_priv->seq_iter == end; -} - -static gboolean -_model_iter_is_last (ClutterModelIter *iter) -{ - ClutterModel *model = NULL; - ClutterModelPrivate *model_priv; - ClutterModelIterPrivate *iter_priv; - GSequenceIter *begin, *end; - ClutterModelIter *temp_iter; - - g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), TRUE); - iter_priv = iter->priv; - model = iter_priv->model; - - g_return_val_if_fail (CLUTTER_IS_MODEL (model), TRUE); - model_priv = model->priv; - - if (g_sequence_iter_is_end (iter_priv->seq_iter)) - return TRUE; - - begin = g_sequence_get_end_iter (model_priv->sequence); - begin = g_sequence_iter_prev (begin); - end = iter_priv->seq_iter; - - temp_iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, - "model", model, - "iter", begin, - NULL); - - while (!g_sequence_iter_is_begin (begin)) - { - temp_iter->priv->seq_iter = begin; - if (_model_filter (model, temp_iter)) - { - end = begin; - break; - } - - begin = g_sequence_iter_prev (begin); - } - /* This is because the 'end_iter' is always *after* the last valid iter. - * Otherwise we'd have endless loops - */ - end = g_sequence_iter_next (end); - - g_object_unref (temp_iter); - return iter_priv->seq_iter == end; -} - -static ClutterModelIter * -_model_iter_next (ClutterModelIter *iter) -{ - ClutterModel *model = NULL; - ClutterModelPrivate *model_priv; - ClutterModelIterPrivate *iter_priv; - GSequenceIter *filter_next; - ClutterModelIter *temp_iter; - - g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), iter); - iter_priv = iter->priv; - model = iter_priv->model; - - g_return_val_if_fail (CLUTTER_IS_MODEL (model), iter); - model_priv = model->priv; - - filter_next = g_sequence_iter_next (iter_priv->seq_iter); - temp_iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, "model", model, NULL); - - while (!g_sequence_iter_is_end (filter_next)) - { - g_object_set (temp_iter, "iter", filter_next, NULL); - if (_model_filter (model, temp_iter)) - break; - - filter_next = g_sequence_iter_next (filter_next); - } - - g_object_unref (temp_iter); - - /* We do this because the 'end_iter' is always *after* the last valid iter. - * Otherwise loops will go on forever - */ - if (filter_next == iter_priv->seq_iter) - filter_next = g_sequence_iter_next (filter_next); - - g_object_set (iter, "iter", filter_next, NULL); - return iter; -} - -static ClutterModelIter * -_model_iter_prev (ClutterModelIter *iter) -{ - ClutterModel *model = NULL; - ClutterModelPrivate *model_priv; - ClutterModelIterPrivate *iter_priv; - GSequenceIter *filter_prev; - ClutterModelIter *temp_iter; - - g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), iter); - iter_priv = iter->priv; - model = iter_priv->model; - - g_return_val_if_fail (CLUTTER_IS_MODEL (model), iter); - model_priv = model->priv; - - filter_prev = g_sequence_iter_prev (iter_priv->seq_iter); - temp_iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, "model", model, NULL); - - while (!g_sequence_iter_is_begin (filter_prev)) - { - g_object_set (temp_iter, "iter", filter_prev, NULL); - if (_model_filter (model, temp_iter)) - break; - - filter_prev = g_sequence_iter_prev (filter_prev); - } - - /* We do this because the 'end_iter' is always *after* the last valid iter. - * Otherwise loops will go on forever - */ - if (filter_prev == iter_priv->seq_iter) - filter_prev = g_sequence_iter_prev (filter_prev); - - g_object_set (iter, "iter", filter_prev, NULL); - - g_object_unref (temp_iter); - - return iter; -} - -static ClutterModel * -_model_iter_get_model (ClutterModelIter *iter) -{ - ClutterModelIterPrivate *priv; - - g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL); - priv = iter->priv; - g_return_val_if_fail (CLUTTER_IS_MODEL (priv->model), NULL); - - return priv->model; -} - -static guint -_model_iter_get_row (ClutterModelIter *iter) -{ - ClutterModel *model = NULL; - ClutterModelPrivate *model_priv; - ClutterModelIterPrivate *iter_priv; - GSequenceIter *filter_next; - ClutterModelIter *temp_iter; - guint row = 0; - - g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), row); - iter_priv = iter->priv; - model = iter_priv->model; - - g_return_val_if_fail (CLUTTER_IS_MODEL (model), row); - model_priv = model->priv; - - filter_next = g_sequence_iter_next (iter_priv->seq_iter); - temp_iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, - "model", model, NULL); - - while (!g_sequence_iter_is_end (filter_next)) - { - g_object_set (temp_iter, "iter", filter_next, NULL); - if (_model_filter (model, temp_iter)) - { - if (iter_priv->seq_iter == temp_iter->priv->seq_iter) - break; - - row++; - } - filter_next = g_sequence_iter_next (filter_next); - } - - g_object_unref (temp_iter); - - return row; -} - -static void -_model_iter_set_row (ClutterModelIter *iter, guint row) -{ - ClutterModel *model = NULL; - ClutterModelPrivate *model_priv; - ClutterModelIterPrivate *iter_priv; - GSequenceIter *filter_next; - ClutterModelIter *temp_iter; - guint i = 0; - - g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter)); - iter_priv = iter->priv; - model = iter_priv->model; - - g_return_if_fail (CLUTTER_IS_MODEL (model)); - model_priv = model->priv; - - temp_iter = g_object_new (CLUTTER_TYPE_MODEL_ITER, - "model", model, - NULL); - - filter_next = g_sequence_get_begin_iter (model_priv->sequence); - while (!g_sequence_iter_is_end (filter_next)) - { - g_object_set (temp_iter, "iter", filter_next, NULL); - if (_model_filter (model, temp_iter)) - { - if (i == row) - { - iter_priv->seq_iter = filter_next; - break; - } - - i++; - } - - filter_next = g_sequence_iter_next (filter_next); - } - - g_object_unref (temp_iter); -} - /* * Public functions */ @@ -2033,7 +1652,7 @@ clutter_model_iter_set_valist (ClutterModelIter *iter, priv->ignore_sort = FALSE; if (sort) - _model_sort (model); + clutter_model_resort (model); g_signal_emit (model, model_signals[ROW_CHANGED], 0, iter); } @@ -2088,12 +1707,13 @@ clutter_model_iter_get_value (ClutterModelIter *iter, g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter)); - klass = CLUTTER_MODEL_ITER_GET_CLASS (iter); - g_return_if_fail (klass->get_value != NULL); - model = iter->priv->model; + g_value_init (value, clutter_model_get_column_type (model, column)); - klass->get_value (iter, column, value); + + klass = CLUTTER_MODEL_ITER_GET_CLASS (iter); + if (klass && klass->get_value) + klass->get_value (iter, column, value); } /** @@ -2206,9 +1826,8 @@ clutter_model_iter_set_value (ClutterModelIter *iter, g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter)); klass = CLUTTER_MODEL_ITER_GET_CLASS (iter); - g_return_if_fail (klass->set_value != NULL); - - klass->set_value (iter, column, value); + if (klass && klass->set_value) + klass->set_value (iter, column, value); } /** @@ -2230,9 +1849,10 @@ clutter_model_iter_is_first (ClutterModelIter *iter) g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), FALSE); klass = CLUTTER_MODEL_ITER_GET_CLASS (iter); - g_return_val_if_fail (klass->is_first != NULL, FALSE); - - return klass->is_first (iter); + if (klass && klass->is_first) + return klass->is_first (iter); + + return FALSE; } /** @@ -2254,9 +1874,10 @@ clutter_model_iter_is_last (ClutterModelIter *iter) g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), FALSE); klass = CLUTTER_MODEL_ITER_GET_CLASS (iter); - g_return_val_if_fail (klass->is_last != NULL, FALSE); - - return klass->is_last (iter); + if (klass && klass->is_last) + return klass->is_last (iter); + + return FALSE; } /** @@ -2277,9 +1898,10 @@ clutter_model_iter_next (ClutterModelIter *iter) g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL); klass = CLUTTER_MODEL_ITER_GET_CLASS (iter); - g_return_val_if_fail (klass->next != NULL, NULL); - - return klass->next (iter); + if (klass && klass->next) + return klass->next (iter); + + return NULL; } /** @@ -2300,9 +1922,10 @@ clutter_model_iter_prev (ClutterModelIter *iter) g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL); klass = CLUTTER_MODEL_ITER_GET_CLASS (iter); - g_return_val_if_fail (klass->prev != NULL, NULL); - - return klass->prev (iter); + if (klass && klass->prev) + return klass->prev (iter); + + return NULL; } /** @@ -2323,9 +1946,10 @@ clutter_model_iter_get_model (ClutterModelIter *iter) g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL); klass = CLUTTER_MODEL_ITER_GET_CLASS (iter); - g_return_val_if_fail (klass->get_model != NULL, NULL); - - return klass->get_model (iter); + if (klass && klass->get_model) + return klass->get_model (iter); + + return NULL; } /** @@ -2343,10 +1967,11 @@ clutter_model_iter_get_row (ClutterModelIter *iter) { ClutterModelIterClass *klass; - g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), -1); + g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), 0); klass = CLUTTER_MODEL_ITER_GET_CLASS (iter); - g_return_val_if_fail (klass->get_row != NULL, -1); - - return klass->get_row (iter); + if (klass && klass->get_row) + return klass->get_row (iter); + + return 0; } diff --git a/clutter/clutter-model.h b/clutter/clutter-model.h index 18b262c1d..7fe685885 100644 --- a/clutter/clutter-model.h +++ b/clutter/clutter-model.h @@ -78,10 +78,10 @@ typedef gboolean (*ClutterModelFilterFunc) (ClutterModel *model, * * Since: 0.6 */ -typedef gboolean (*ClutterModelSortFunc) (ClutterModel *model, - const GValue *a, - const GValue *b, - gpointer user_data); +typedef gint (*ClutterModelSortFunc) (ClutterModel *model, + const GValue *a, + const GValue *b, + gpointer user_data); /** * ClutterModelForeachFunc: @@ -127,6 +127,16 @@ struct _ClutterModel * @get_column_type: virtual function for returning the type of a column * @get_iter_at_row: virtual function for returning an iterator for the * given row + * @get_n_rows: virtual function for returning the number of rows + * of the model, not considering any filter function if present + * @get_n_columns: virtual function for retuning the number of columns + * of the model + * @resort: virtual function for sorting the model using the passed + * sorting function + * @insert_row: virtual function for inserting a row at the given index + * and returning an iterator pointing to it; if the index is a negative + * integer, the row should be appended to the model + * @remove_row: virtual function for removing a row at the given index * * Class for #ClutterModel instances. * @@ -139,12 +149,21 @@ struct _ClutterModelClass /*< public >*/ /* vtable */ - const gchar * (* get_column_name) (ClutterModel *model, - guint column); - GType (* get_column_type) (ClutterModel *model, - guint column); - ClutterModelIter *(* get_iter_at_row) (ClutterModel *model, - guint row); + guint (* get_n_rows) (ClutterModel *model); + guint (* get_n_columns) (ClutterModel *model); + const gchar * (* get_column_name) (ClutterModel *model, + guint column); + GType (* get_column_type) (ClutterModel *model, + guint column); + ClutterModelIter *(* insert_row) (ClutterModel *model, + gint index_); + void (* remove_row) (ClutterModel *model, + guint row); + ClutterModelIter *(* get_iter_at_row) (ClutterModel *model, + guint row); + void (* resort) (ClutterModel *model, + ClutterModelSortFunc func, + gpointer data); /* signals */ void (* row_added) (ClutterModel *model, @@ -153,7 +172,6 @@ struct _ClutterModelClass ClutterModelIter *iter); void (* row_changed) (ClutterModel *model, ClutterModelIter *iter); - void (* sort_changed) (ClutterModel *model); void (* filter_changed) (ClutterModel *model); @@ -165,90 +183,87 @@ struct _ClutterModelClass void (*_clutter_model_4) (void); }; +GType clutter_model_get_type (void) G_GNUC_CONST; - -GType clutter_model_get_type (void) G_GNUC_CONST; - -ClutterModel * clutter_model_new (guint n_columns, - ...); -ClutterModel * clutter_model_newv (guint n_columns, - GType *types, - const gchar * const names[]); -void clutter_model_set_types (ClutterModel *model, - guint n_columns, - GType *types); -void clutter_model_set_names (ClutterModel *model, - guint n_columns, +void clutter_model_set_types (ClutterModel *model, + guint n_columns, + GType *types); +void clutter_model_set_names (ClutterModel *model, + guint n_columns, const gchar * const names[]); -void clutter_model_append (ClutterModel *model, +void clutter_model_append (ClutterModel *model, ...); -void clutter_model_append_value (ClutterModel *model, - guint column, - const GValue *value); -void clutter_model_prepend (ClutterModel *model, +void clutter_model_append_value (ClutterModel *model, + guint column, + const GValue *value); +void clutter_model_prepend (ClutterModel *model, ...); -void clutter_model_prepend_value (ClutterModel *model, - guint column, - const GValue *value); -void clutter_model_insert (ClutterModel *model, - guint row, +void clutter_model_prepend_value (ClutterModel *model, + guint column, + const GValue *value); +void clutter_model_insert (ClutterModel *model, + guint row, ...); -void clutter_model_insert_value (ClutterModel *model, - guint row, - guint column, - const GValue *value); -void clutter_model_remove (ClutterModel *model, - guint row); +void clutter_model_insert_value (ClutterModel *model, + guint row, + guint column, + const GValue *value); +void clutter_model_remove (ClutterModel *model, + guint row); -guint clutter_model_get_n_rows (ClutterModel *model); +guint clutter_model_get_n_rows (ClutterModel *model); +guint clutter_model_get_n_columns (ClutterModel *model); +G_CONST_RETURN gchar *clutter_model_get_column_name (ClutterModel *model, + guint column); +GType clutter_model_get_column_type (ClutterModel *model, + guint column); -G_CONST_RETURN gchar *clutter_model_get_column_name (ClutterModel *model, - guint column); -GType clutter_model_get_column_type (ClutterModel *model, - guint column); -guint clutter_model_get_n_columns (ClutterModel *model); +ClutterModelIter * clutter_model_get_first_iter (ClutterModel *model); +ClutterModelIter * clutter_model_get_last_iter (ClutterModel *model); +ClutterModelIter * clutter_model_get_iter_at_row (ClutterModel *model, + guint row); -ClutterModelIter * clutter_model_get_first_iter (ClutterModel *model); -ClutterModelIter * clutter_model_get_last_iter (ClutterModel *model); -ClutterModelIter * clutter_model_get_iter_at_row (ClutterModel *model, - guint row); +void clutter_model_set_sorting_column (ClutterModel *model, + gint column); +gint clutter_model_get_sorting_column (ClutterModel *model); -void clutter_model_set_sorting_column (ClutterModel *model, - gint column); -gint clutter_model_get_sorting_column (ClutterModel *model); - -void clutter_model_foreach (ClutterModel *model, +void clutter_model_foreach (ClutterModel *model, ClutterModelForeachFunc func, - gpointer user_data); -void clutter_model_set_sort (ClutterModel *model, - guint column, + gpointer user_data); +void clutter_model_set_sort (ClutterModel *model, + guint column, ClutterModelSortFunc func, - gpointer user_data, - GDestroyNotify notify); -void clutter_model_set_filter (ClutterModel *model, + gpointer user_data, + GDestroyNotify notify); +void clutter_model_set_filter (ClutterModel *model, ClutterModelFilterFunc func, - gpointer user_data, - GDestroyNotify notify); + gpointer user_data, + GDestroyNotify notify); +void clutter_model_resort (ClutterModel *model); +gboolean clutter_model_filter_row (ClutterModel *model, + guint row); +gboolean clutter_model_filter_iter (ClutterModel *model, + ClutterModelIter *iter); /* * ClutterModelIter */ -#define CLUTTER_TYPE_MODEL_ITER (clutter_model_iter_get_type ()) -#define CLUTTER_MODEL_ITER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MODEL_ITER, ClutterModelIter)) -#define CLUTTER_MODEL_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_MODEL_ITER, ClutterModelIterClass)) -#define CLUTTER_IS_MODEL_ITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MODEL_ITER)) -#define CLUTTER_IS_MODEL_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_MODEL_ITER)) -#define CLUTTER_MODEL_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_MODEL_ITER, ClutterModelIterClass)) +#define CLUTTER_TYPE_MODEL_ITER (clutter_model_iter_get_type ()) +#define CLUTTER_MODEL_ITER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MODEL_ITER, ClutterModelIter)) +#define CLUTTER_MODEL_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_MODEL_ITER, ClutterModelIterClass)) +#define CLUTTER_IS_MODEL_ITER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MODEL_ITER)) +#define CLUTTER_IS_MODEL_ITER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_MODEL_ITER)) +#define CLUTTER_MODEL_ITER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_MODEL_ITER, ClutterModelIterClass)) /** * ClutterModelIter: * - * Base class for list models iters. The #ClutterModelIter structure contains - * only private data and should be manipulated using the provided - * API. + * Base class for list models iters. The #ClutterModelIter structure + * contains only private data and should be manipulated using the + * provided API. * * Since: 0.6 */ @@ -262,6 +277,18 @@ struct _ClutterModelIter /** * ClutterModelIterClass: + * @get_value: Virtual function for retrieving the value at the given + * column of the row pointed by the iterator + * @set_value: Virtual function for setting the value at the given + * column of the row pointer by the iterator + * @is_last: Virtual function for knowing whether the iterator points + * at the last row in the model + * @is_first: Virtual function for knowing whether the iterator points + * at the first row in the model + * @get_model: Virtual function for getting the model to which the + * iterator belongs to + * @get_row: Virtual function for getting the row to which the iterator + * points * * Class for #ClutterModelIter instances. * @@ -273,7 +300,6 @@ struct _ClutterModelIterClass GObjectClass parent_class; /*< public >*/ - /* vtable not signals */ void (* get_value) (ClutterModelIter *iter, guint column, @@ -287,7 +313,7 @@ struct _ClutterModelIterClass ClutterModelIter *(* next) (ClutterModelIter *iter); ClutterModelIter *(* prev) (ClutterModelIter *iter); - + ClutterModel* (* get_model) (ClutterModelIter *iter); guint (* get_row) (ClutterModelIter *iter); @@ -299,8 +325,7 @@ struct _ClutterModelIterClass void (*_clutter_model_iter_4) (void); }; -GType clutter_model_iter_get_type (void) G_GNUC_CONST; - +GType clutter_model_iter_get_type (void) G_GNUC_CONST; void clutter_model_iter_get (ClutterModelIter *iter, ...); @@ -316,10 +341,15 @@ void clutter_model_iter_set_valist (ClutterModelIter *iter, void clutter_model_iter_set_value (ClutterModelIter *iter, guint column, const GValue *value); + gboolean clutter_model_iter_is_first (ClutterModelIter *iter); gboolean clutter_model_iter_is_last (ClutterModelIter *iter); +gboolean clutter_model_iter_has_next (ClutterModelIter *iter); +gboolean clutter_model_iter_has_prev (ClutterModelIter *iter); + ClutterModelIter *clutter_model_iter_next (ClutterModelIter *iter); ClutterModelIter *clutter_model_iter_prev (ClutterModelIter *iter); + ClutterModel * clutter_model_iter_get_model (ClutterModelIter *iter); guint clutter_model_iter_get_row (ClutterModelIter *iter); diff --git a/clutter/clutter.h b/clutter/clutter.h index 06c8a063e..7009e7b73 100644 --- a/clutter/clutter.h +++ b/clutter/clutter.h @@ -52,6 +52,7 @@ #include "clutter-main.h" #include "clutter-media.h" #include "clutter-model.h" +#include "clutter-model-default.h" #include "clutter-stage.h" #include "clutter-texture.h" #include "clutter-timeout-pool.h" diff --git a/doc/reference/ChangeLog b/doc/reference/ChangeLog index 2e5f12265..bcf798856 100644 --- a/doc/reference/ChangeLog +++ b/doc/reference/ChangeLog @@ -1,3 +1,10 @@ +2007-12-14 Emmanuele Bassi + + * Makefile.am: + * clutter-docs.sgml: + * clutter-sections.txt: + * clutter.types: Update for ClutterModel changes. + 2007-12-10 Emmanuele Bassi * clutter-sections.txt: Add the new ClutterModel API. diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am index 94def3249..beda4492f 100644 --- a/doc/reference/Makefile.am +++ b/doc/reference/Makefile.am @@ -51,14 +51,14 @@ CFILE_GLOB=$(top_srcdir)/clutter/*.c IGNORE_HFILES=\ clutter.h \ clutter-debug.h \ - clutter-private.h \ - clutter-marshal.h \ + clutter-deprecated.h \ + clutter-enum-types.h \ + clutter-json.h \ clutter-keysyms.h \ clutter-keysyms-table.h \ - clutter-enum-types.h \ + clutter-marshal.h \ + clutter-private.h \ clutter-script-private.h \ - clutter-json.h \ - clutter-deprecated.h \ stamp-clutter-enum-types.h \ stamp-clutter-marshal.h \ cogl \ diff --git a/doc/reference/clutter-docs.sgml b/doc/reference/clutter-docs.sgml index e8e11a598..77f8afbbb 100644 --- a/doc/reference/clutter-docs.sgml +++ b/doc/reference/clutter-docs.sgml @@ -159,6 +159,7 @@ + diff --git a/doc/reference/clutter-sections.txt b/doc/reference/clutter-sections.txt index 8f674429f..ed43aa8ee 100644 --- a/doc/reference/clutter-sections.txt +++ b/doc/reference/clutter-sections.txt @@ -1143,8 +1143,6 @@ ClutterModelClass ClutterModelFilterFunc ClutterModelSortFunc ClutterModelForeachFunc -clutter_model_new -clutter_model_newv clutter_model_set_names clutter_model_set_types clutter_model_append @@ -1208,6 +1206,25 @@ ClutterModelIterPrivate clutter_model_iter_get_type +
+clutter-model-default +ClutterModelDefault +ClutterModelDefault +ClutterModelDefaultIter +clutter_model_default_new +clutter_model_default_newv + +CLUTTER_TYPE_MODEL_DEFAULT +CLUTTER_TYPE_MODEL_DEFAULT_ITER +CLUTTER_MODEL_DEFAULT +CLUTTER_MODEL_DEFAULT_ITER +CLUTTER_IS_MODEL_DEFAULT +CLUTTER_IS_MODEL_DEFAULT_ITER + +clutter_model_default_get_type +clutter_model_default_iter_get_type +
+
clutter-score ClutterScore diff --git a/doc/reference/clutter.types b/doc/reference/clutter.types index f6a51df91..026997292 100644 --- a/doc/reference/clutter.types +++ b/doc/reference/clutter.types @@ -24,5 +24,7 @@ clutter_script_get_type clutter_scriptable_get_type clutter_model_get_type clutter_model_iter_get_type +clutter_model_default_get_type +clutter_model_default_iter_get_type clutter_score_get_type clutter_shader_get_type diff --git a/tests/test-model.c b/tests/test-model.c index 4f685812c..ffd1c9db1 100644 --- a/tests/test-model.c +++ b/tests/test-model.c @@ -10,16 +10,19 @@ enum }; static void -print_iter (ClutterModelIter *iter, const gchar *text) +print_iter (ClutterModelIter *iter, + const gchar *text) { ClutterModel *model; gint i; gchar *string; model = clutter_model_iter_get_model (iter); + clutter_model_iter_get (iter, COLUMN_FOO, &i, COLUMN_BAR, &string, -1); - g_print ("%s: (%s: %d), (%s: %s)\n", + g_print ("[row:%02d]: %s: (%s: %d), (%s: %s)\n", + clutter_model_iter_get_row (iter), text, clutter_model_get_column_name (model, COLUMN_FOO), i, clutter_model_get_column_name (model, COLUMN_BAR), string); @@ -28,20 +31,28 @@ print_iter (ClutterModelIter *iter, const gchar *text) } static gboolean -foreach_func (ClutterModel *model, ClutterModelIter *iter, gpointer null) +foreach_func (ClutterModel *model, + ClutterModelIter *iter, + gpointer dummy) { gint i; gchar *string; clutter_model_iter_get (iter, COLUMN_FOO, &i, COLUMN_BAR, &string, -1); - g_print ("Foreach: %d: %s\n", i, string); + + g_print ("[row:%02d]: Foreach: %d, %s\n", + clutter_model_iter_get_row (iter), + i, string); g_free (string); + return TRUE; } static gboolean -filter_func (ClutterModel *model, ClutterModelIter *iter, gpointer null) +filter_func (ClutterModel *model, + ClutterModelIter *iter, + gpointer dummy) { gint i = 0; @@ -54,13 +65,14 @@ static gint sort_func (ClutterModel *model, const GValue *a, const GValue *b, - gpointer null) + gpointer dummy) { return -1 * strcmp (g_value_get_string (a), g_value_get_string (b)); } static void -on_row_changed (ClutterModel *model, ClutterModelIter *iter) +on_row_changed (ClutterModel *model, + ClutterModelIter *iter) { print_iter (iter, "Changed"); } @@ -70,21 +82,22 @@ filter_model (ClutterModel *model) { ClutterModelIter *iter; + g_print ("* Filter function: even rows\n"); clutter_model_set_filter (model, filter_func, NULL, NULL); iter = clutter_model_get_first_iter (model); - while (!clutter_model_iter_is_last (iter)) - { - print_iter (iter, "Filtered Forward Iteration"); - iter = clutter_model_iter_next (iter); - } + { + print_iter (iter, "Filtered Forward Iteration"); + + iter = clutter_model_iter_next (iter); + } g_object_unref (iter); + g_print ("* Sorting function: reverse alpha\n"); clutter_model_set_sort (model, COLUMN_BAR, sort_func, NULL, NULL); - g_signal_connect (model, "row-changed", - G_CALLBACK (on_row_changed), NULL); + g_signal_connect (model, "row-changed", G_CALLBACK (on_row_changed), NULL); iter = clutter_model_get_iter_at_row (model, 0); clutter_model_iter_set (iter, COLUMN_BAR, "Changed string of 0th row, " @@ -94,11 +107,11 @@ filter_model (ClutterModel *model) clutter_model_foreach (model, foreach_func, NULL); + g_print ("* Unset filter\n"); clutter_model_set_filter (model, NULL, NULL, NULL); + while (clutter_model_get_n_rows (model)) - { clutter_model_remove (model, 0); - } clutter_main_quit (); } @@ -111,18 +124,18 @@ iterate (ClutterModel *model) iter = clutter_model_get_first_iter (model); while (!clutter_model_iter_is_last (iter)) - { - print_iter (iter, "Forward Iteration"); - iter = clutter_model_iter_next (iter); - } + { + print_iter (iter, "Forward Iteration"); + iter = clutter_model_iter_next (iter); + } g_object_unref (iter); iter = clutter_model_get_last_iter (model); do - { - print_iter (iter, "Reverse Iteration"); - iter = clutter_model_iter_prev (iter); - } + { + print_iter (iter, "Reverse Iteration"); + iter = clutter_model_iter_prev (iter); + } while (!clutter_model_iter_is_first (iter)); print_iter (iter, "Reverse Iteration"); @@ -155,20 +168,26 @@ populate_model (ClutterModel *model) } static void -on_row_added (ClutterModel *model, ClutterModelIter *iter, gpointer null) +on_row_added (ClutterModel *model, + ClutterModelIter *iter, + gpointer dummy) { gint i; gchar *string; clutter_model_iter_get (iter, COLUMN_FOO, &i, COLUMN_BAR, &string, -1); - g_print ("Added: %d, %s\n", i, string); + g_print ("[row:%02d]: Added: %d, %s\n", + clutter_model_iter_get_row (iter), + i, string); g_free (string); } static void -on_row_removed (ClutterModel *model, ClutterModelIter *iter, gpointer null) +on_row_removed (ClutterModel *model, + ClutterModelIter *iter, + gpointer dummy) { print_iter (iter, "Removed"); } @@ -176,14 +195,14 @@ on_row_removed (ClutterModel *model, ClutterModelIter *iter, gpointer null) static void on_sort_changed (ClutterModel *model) { - g_print ("\nSort Changed\n\n"); + g_print ("\n*** Sort Changed ***\n\n"); clutter_model_foreach (model, foreach_func, NULL); } static void on_filter_changed (ClutterModel *model) { - g_print ("\nFilter Changed\n\n"); + g_print ("\n*** Filter Changed ***\n\n"); } int @@ -193,11 +212,11 @@ main (int argc, char *argv[]) clutter_init (&argc, &argv); - model = clutter_model_new (N_COLUMNS, - G_TYPE_INT, "Foo", - G_TYPE_STRING, "Bar"); + model = clutter_model_default_new (N_COLUMNS, + G_TYPE_INT, "Foo", + G_TYPE_STRING, "Bar"); - g_timeout_add (1000, (GSourceFunc)populate_model, model); + g_timeout_add (1000, (GSourceFunc) populate_model, model); g_signal_connect (model, "row-added", G_CALLBACK (on_row_added), NULL); diff --git a/tests/test-shader.c b/tests/test-shader.c index de278b1a4..45259a948 100644 --- a/tests/test-shader.c +++ b/tests/test-shader.c @@ -210,7 +210,7 @@ main (gint argc, shader = clutter_shader_new (); error = NULL; - clutter_shader_set_fragment_source (shader, shaders[shader_no].source, NULL); + clutter_shader_set_fragment_source (shader, shaders[shader_no].source, -1); clutter_shader_bind (shader, &error); if (error) {