mirror of
https://github.com/brl/mutter.git
synced 2024-12-29 14:22:13 +00:00
3ab2ff9846
Merge from clutter-0-6: * clutter/clutter-model.c: (clutter_model_iter_set_internal_valist): Add an internal function wrapping ClutterModelIter::set_value that does not emit the ::row-changed signal. Emitting this signal before the ::row-added one is wrong: a row cannot change before being inserted. (clutter_model_append), (clutter_model_prepend), (clutter_model_insert): Use the non-signal emitting variant of clutter_model_iter_set_valist(). (clutter_model_iter_set_valist): Use the internal version and emit the ::row-changed signal at the end.
2046 lines
52 KiB
C
2046 lines
52 KiB
C
/*
|
|
* Clutter.
|
|
*
|
|
* An OpenGL based 'interactive canvas' library.
|
|
*
|
|
* Authored By Matthew Allum <mallum@openedhand.com>
|
|
* Neil Jagdish Patel <njp@o-hand.com>
|
|
* Emmanuele Bassi <ebassi@openedhand.com>
|
|
*
|
|
* 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
|
|
*/
|
|
|
|
/**
|
|
* SECTION:clutter-model
|
|
* @short_description: A generic model implementation
|
|
*
|
|
* #ClutterModel is a generic list model API which can be used to implement
|
|
* the model-view-controller architectural pattern in Clutter.
|
|
*
|
|
* The #ClutterModel class is a list model which can accept most GObject
|
|
* types as a column type.
|
|
*
|
|
* Creating a simple clutter model:
|
|
* <informalexample><programlisting>
|
|
* enum
|
|
* {
|
|
* COLUMN_INT,
|
|
* COLUMN_STRING,
|
|
*
|
|
* N_COLUMNS
|
|
* };
|
|
*
|
|
* {
|
|
* ClutterModel *model;
|
|
* gint i;
|
|
*
|
|
* 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);
|
|
* clutter_model_append (model,
|
|
* COLUMN_INT, i,
|
|
* COLUMN_STRING, string,
|
|
* -1);
|
|
* g_free (string);
|
|
* }
|
|
*
|
|
*
|
|
* }
|
|
* </programlisting></informalexample>
|
|
*
|
|
* 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.
|
|
*
|
|
* A valid #ClutterModelIter represents the position between two rows in the
|
|
* 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:
|
|
* <informalexample><programlisting>
|
|
* enum
|
|
* {
|
|
* COLUMN_INT,
|
|
* COLUMN_STRING.
|
|
*
|
|
* N_COLUMNS
|
|
* };
|
|
*
|
|
* {
|
|
* ClutterModel *model;
|
|
* ClutterModelIter *iter = NULL;
|
|
*
|
|
* /<!-- -->* Fill the model *<!-- -->/
|
|
* model = populate_model ();
|
|
*
|
|
* /<!-- -->* Get the first iter *<!-- -->/
|
|
* iter = clutter_model_get_first_iter (model);
|
|
* while (!clutter_model_iter_is_last (iter))
|
|
* {
|
|
* print_row (iter);
|
|
*
|
|
* iter = clutter_model_iter_next (iter);
|
|
* }
|
|
*
|
|
* /<!-- -->* Make sure to unref the iter *<!-- -->/
|
|
* g_object_unref (iter);
|
|
* }
|
|
* </programlisting></informalexample>
|
|
*
|
|
* #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 <string.h>
|
|
#include <glib-object.h>
|
|
#include <gobject/gvaluecollector.h>
|
|
|
|
#include "clutter-model.h"
|
|
#include "clutter-model-private.h"
|
|
|
|
#include "clutter-marshal.h"
|
|
#include "clutter-private.h"
|
|
#include "clutter-debug.h"
|
|
|
|
|
|
G_DEFINE_ABSTRACT_TYPE (ClutterModel, clutter_model, G_TYPE_OBJECT);
|
|
|
|
enum
|
|
{
|
|
ROW_ADDED,
|
|
ROW_REMOVED,
|
|
ROW_CHANGED,
|
|
|
|
SORT_CHANGED,
|
|
FILTER_CHANGED,
|
|
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static guint model_signals[LAST_SIGNAL] = { 0, };
|
|
|
|
#define CLUTTER_MODEL_GET_PRIVATE(obj) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_MODEL, ClutterModelPrivate))
|
|
|
|
struct _ClutterModelPrivate
|
|
{
|
|
GType *column_types;
|
|
gchar **column_names;
|
|
gint n_columns;
|
|
|
|
ClutterModelFilterFunc filter_func;
|
|
gpointer filter_data;
|
|
GDestroyNotify filter_notify;
|
|
|
|
gint sort_column;
|
|
ClutterModelSortFunc sort_func;
|
|
gpointer sort_data;
|
|
GDestroyNotify sort_notify;
|
|
};
|
|
|
|
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 guint
|
|
clutter_model_real_get_n_rows (ClutterModel *model)
|
|
{
|
|
ClutterModelIter *iter;
|
|
guint n_rows = 0;
|
|
|
|
iter = clutter_model_get_first_iter (model);
|
|
if (!iter)
|
|
return 0;
|
|
|
|
while (!clutter_model_iter_is_last (iter))
|
|
{
|
|
n_rows += 1;
|
|
|
|
clutter_model_iter_next (iter);
|
|
}
|
|
|
|
g_object_unref (iter);
|
|
|
|
return n_rows;
|
|
}
|
|
|
|
static void
|
|
clutter_model_finalize (GObject *object)
|
|
{
|
|
ClutterModelPrivate *priv = CLUTTER_MODEL (object)->priv;
|
|
gint i;
|
|
|
|
if (priv->sort_notify)
|
|
priv->sort_notify (priv->sort_data);
|
|
|
|
if (priv->filter_notify)
|
|
priv->filter_notify (priv->filter_data);
|
|
|
|
g_free (priv->column_types);
|
|
|
|
/* 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);
|
|
}
|
|
|
|
static void
|
|
clutter_model_class_init (ClutterModelClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->finalize = clutter_model_finalize;
|
|
|
|
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;
|
|
klass->get_n_rows = clutter_model_real_get_n_rows;
|
|
|
|
/**
|
|
* ClutterModel::row-added:
|
|
* @model: the #ClutterModel on which the signal is emitted
|
|
* @iter: a #ClutterModelIter pointing to the new row
|
|
*
|
|
* The ::row-added signal is emitted when a new row has been added.
|
|
* The data on the row has already been set when the ::row-added signal
|
|
* has been emitted.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
model_signals[ROW_ADDED] =
|
|
g_signal_new ("row-added",
|
|
G_TYPE_FROM_CLASS (gobject_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterModelClass, row_added),
|
|
NULL, NULL,
|
|
clutter_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE, 1,
|
|
CLUTTER_TYPE_MODEL_ITER);
|
|
/**
|
|
* ClutterModel::row-removed:
|
|
* @model: the #ClutterModel on which the signal is emitted
|
|
* @iter: a #ClutterModelIter pointing to the removed row
|
|
*
|
|
* The ::row-removed signal is emitted when a row has been removed.
|
|
* The data on the row pointed by the passed iterator is still valid
|
|
* when the ::row-removed signal has been emitted.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
model_signals[ROW_REMOVED] =
|
|
g_signal_new ("row-removed",
|
|
G_TYPE_FROM_CLASS (gobject_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterModelClass, row_removed),
|
|
NULL, NULL,
|
|
clutter_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE, 1,
|
|
CLUTTER_TYPE_MODEL_ITER);
|
|
/**
|
|
* ClutterModel::row-changed:
|
|
* @model: the #ClutterModel on which the signal is emitted
|
|
* @iter: a #ClutterModelIter pointing to the changed row
|
|
*
|
|
* The ::row-removed signal is emitted when a row has been changed.
|
|
* The data on the row has already been updated when the ::row-changed
|
|
* signal has been emitted.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
model_signals[ROW_CHANGED] =
|
|
g_signal_new ("row-changed",
|
|
G_TYPE_FROM_CLASS (gobject_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterModelClass, row_changed),
|
|
NULL, NULL,
|
|
clutter_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE, 1,
|
|
CLUTTER_TYPE_MODEL_ITER);
|
|
/**
|
|
* ClutterModel::sort-changed:
|
|
* @model: the #ClutterModel on which the signal is emitted
|
|
*
|
|
* The ::sort-changed signal is emitted after the model has been sorted
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
model_signals[SORT_CHANGED] =
|
|
g_signal_new ("sort-changed",
|
|
G_TYPE_FROM_CLASS (gobject_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterModelClass, sort_changed),
|
|
NULL, NULL,
|
|
clutter_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
/**
|
|
* ClutterModel::filter-changed:
|
|
* @model: the #ClutterModel on which the signal is emitted
|
|
*
|
|
* The ::filter-changed signal is emitted when a new filter has been applied
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
model_signals[FILTER_CHANGED] =
|
|
g_signal_new ("filter-changed",
|
|
G_TYPE_FROM_CLASS (gobject_class),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (ClutterModelClass, filter_changed),
|
|
NULL, NULL,
|
|
clutter_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
}
|
|
|
|
static void
|
|
clutter_model_init (ClutterModel *self)
|
|
{
|
|
ClutterModelPrivate *priv;
|
|
|
|
self->priv = priv = CLUTTER_MODEL_GET_PRIVATE (self);
|
|
|
|
priv->n_columns = -1;
|
|
priv->column_types = NULL;
|
|
priv->column_names = NULL;
|
|
|
|
priv->filter_func = NULL;
|
|
priv->filter_data = NULL;
|
|
priv->filter_notify = 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.
|
|
*/
|
|
gboolean
|
|
clutter_model_check_type (GType gtype)
|
|
{
|
|
gint i = 0;
|
|
static const GType type_list[] =
|
|
{
|
|
G_TYPE_BOOLEAN,
|
|
G_TYPE_CHAR,
|
|
G_TYPE_UCHAR,
|
|
G_TYPE_INT,
|
|
G_TYPE_UINT,
|
|
G_TYPE_LONG,
|
|
G_TYPE_ULONG,
|
|
G_TYPE_INT64,
|
|
G_TYPE_UINT64,
|
|
G_TYPE_ENUM,
|
|
G_TYPE_FLAGS,
|
|
G_TYPE_FLOAT,
|
|
G_TYPE_DOUBLE,
|
|
G_TYPE_STRING,
|
|
G_TYPE_POINTER,
|
|
G_TYPE_BOXED,
|
|
G_TYPE_OBJECT,
|
|
G_TYPE_INVALID
|
|
};
|
|
|
|
if (! G_TYPE_IS_VALUE_TYPE (gtype))
|
|
return FALSE;
|
|
|
|
while (type_list[i] != G_TYPE_INVALID)
|
|
{
|
|
if (g_type_is_a (gtype, type_list[i]))
|
|
return TRUE;
|
|
i++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
|
|
klass = CLUTTER_MODEL_GET_CLASS (model);
|
|
|
|
if (klass->resort)
|
|
klass->resort (model, priv->sort_func, priv->sort_data);
|
|
}
|
|
|
|
/**
|
|
* 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_func)
|
|
return TRUE;
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* clutter_model_set_n_columns:
|
|
* @model: a #ClutterModel
|
|
* @n_columns: number of columns
|
|
* @set_types: set the columns type
|
|
* @set_names: set the columns name
|
|
*
|
|
* Sets the number of columns in @model to @n_columns. If @set_types
|
|
* or @set_names are %TRUE, initialises the columns type and name
|
|
* arrays as well.
|
|
*
|
|
* This function can only be called once.
|
|
*/
|
|
void
|
|
clutter_model_set_n_columns (ClutterModel *model,
|
|
gint n_columns,
|
|
gboolean set_types,
|
|
gboolean set_names)
|
|
{
|
|
ClutterModelPrivate *priv = model->priv;
|
|
gboolean types_set, names_set;
|
|
|
|
types_set = (priv->column_types != NULL);
|
|
names_set = (priv->column_names != NULL);
|
|
|
|
if (priv->n_columns > 0 && priv->n_columns != n_columns)
|
|
return;
|
|
|
|
priv->n_columns = n_columns;
|
|
|
|
if (set_types && !priv->column_types)
|
|
priv->column_types = g_new0 (GType, n_columns);
|
|
|
|
if (set_names && !priv->column_names)
|
|
priv->column_names = g_new0 (gchar*, n_columns);
|
|
}
|
|
|
|
/*
|
|
* clutter_model_set_column_type:
|
|
* @model: a #ClutterModel
|
|
* @column: column index
|
|
* @gtype: type of the column
|
|
*
|
|
* Sets the type of @column inside @model
|
|
*/
|
|
void
|
|
clutter_model_set_column_type (ClutterModel *model,
|
|
gint column,
|
|
GType gtype)
|
|
{
|
|
ClutterModelPrivate *priv = model->priv;
|
|
|
|
priv->column_types[column] = gtype;
|
|
}
|
|
|
|
/*
|
|
* clutter_model_set_column_name:
|
|
* @model: a #ClutterModel
|
|
* @column: column index
|
|
* @name: name of the column, or %NULL
|
|
*
|
|
* Sets the name of @column inside @model
|
|
*/
|
|
void
|
|
clutter_model_set_column_name (ClutterModel *model,
|
|
gint column,
|
|
const gchar *name)
|
|
{
|
|
ClutterModelPrivate *priv = model->priv;
|
|
|
|
priv->column_names[column] = g_strdup (name);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_set_types:
|
|
* @model: a #ClutterModel
|
|
* @n_columns: number of columns for the model
|
|
* @types: an array of #GType types
|
|
*
|
|
* Sets the types of the columns inside a #ClutterModel.
|
|
*
|
|
* This function is meant primarily for #GObjects that inherit from
|
|
* #ClutterModel, and should only be used when contructing a #ClutterModel.
|
|
* It will not work after the initial creation of the #ClutterModel.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_set_types (ClutterModel *model,
|
|
guint n_columns,
|
|
GType *types)
|
|
{
|
|
ClutterModelPrivate *priv;
|
|
gint i;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
g_return_if_fail (n_columns > 0);
|
|
|
|
priv = model->priv;
|
|
|
|
g_return_if_fail (priv->n_columns < 0 || priv->n_columns == n_columns);
|
|
g_return_if_fail (priv->column_types == NULL);
|
|
|
|
clutter_model_set_n_columns (model, n_columns, TRUE, FALSE);
|
|
|
|
for (i = 0; i < n_columns; i++)
|
|
{
|
|
if (!clutter_model_check_type (types[i]))
|
|
{
|
|
g_warning ("%s: Invalid type %s\n", G_STRLOC, g_type_name (types[i]));
|
|
return;
|
|
}
|
|
|
|
clutter_model_set_column_type (model, i, types[i]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clutter_model_set_names:
|
|
* @model: a #ClutterModel
|
|
* @n_columns: the number of column names
|
|
* @names: an array of strings
|
|
*
|
|
* Assigns a name to the columns of a #ClutterModel.
|
|
*
|
|
* This function is meant primarily for #GObjects that inherit from
|
|
* #ClutterModel, and should only be used when contructing a #ClutterModel.
|
|
* It will not work after the initial creation of the #ClutterModel.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_set_names (ClutterModel *model,
|
|
guint n_columns,
|
|
const gchar * const names[])
|
|
{
|
|
ClutterModelPrivate *priv;
|
|
gint i;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
g_return_if_fail (n_columns > 0);
|
|
|
|
priv = model->priv;
|
|
|
|
g_return_if_fail (priv->n_columns < 0 || priv->n_columns == n_columns);
|
|
g_return_if_fail (priv->column_names == NULL);
|
|
|
|
clutter_model_set_n_columns (model, n_columns, FALSE, TRUE);
|
|
|
|
for (i = 0; i < n_columns; i++)
|
|
clutter_model_set_column_name (model, i, names[i]);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_get_n_columns:
|
|
* @model: a #ClutterModel
|
|
*
|
|
* Retrieves the number of columns inside @model.
|
|
*
|
|
* Return value: the number of columns
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
guint
|
|
clutter_model_get_n_columns (ClutterModel *model)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL (model), 0);
|
|
|
|
return CLUTTER_MODEL_GET_CLASS (model)->get_n_columns (model);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_appendv:
|
|
* @model: a #ClutterModel
|
|
* @n_columns: the number of columns and values
|
|
* @columns: a vector with the columns to set
|
|
* @values: a vector with the values
|
|
*
|
|
* Creates and appends a new row to the #ClutterModel, setting the row
|
|
* values for the given @columns upon creation.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_appendv (ClutterModel *model,
|
|
guint n_columns,
|
|
guint *columns,
|
|
GValue *values)
|
|
{
|
|
ClutterModelPrivate *priv;
|
|
ClutterModelIter *iter;
|
|
gint i;
|
|
gboolean resort = FALSE;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
g_return_if_fail (n_columns <= clutter_model_get_n_columns (model));
|
|
g_return_if_fail (columns != NULL);
|
|
g_return_if_fail (values != NULL);
|
|
|
|
priv = model->priv;
|
|
|
|
iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, -1);
|
|
g_assert (CLUTTER_IS_MODEL_ITER (iter));
|
|
|
|
for (i = 0; i < n_columns; i++)
|
|
{
|
|
if (priv->sort_column == columns[i])
|
|
resort = TRUE;
|
|
|
|
clutter_model_iter_set_value (iter, columns[i], &values[i]);
|
|
}
|
|
|
|
g_signal_emit (model, model_signals[ROW_ADDED], 0, iter);
|
|
|
|
if (resort)
|
|
clutter_model_resort (model);
|
|
|
|
g_object_unref (iter);
|
|
}
|
|
|
|
/* forward declaration */
|
|
static void clutter_model_iter_set_internal_valist (ClutterModelIter *iter,
|
|
va_list args);
|
|
|
|
/**
|
|
* clutter_model_append:
|
|
* @model: a #ClutterModel
|
|
* @Varargs: pairs of column number and value, terminated with -1
|
|
*
|
|
* Creates and appends a new row to the #ClutterModel, setting the
|
|
* row values upon creation. For example, to append a new row where
|
|
* column 0 is type %G_TYPE_INT and column 1 is of type %G_TYPE_STRING:
|
|
*
|
|
* <informalexample><programlisting>
|
|
* ClutterModel *model;
|
|
* model = clutter_model_default_new (2,
|
|
* G_TYPE_INT, "Score",
|
|
* G_TYPE_STRING, "Team");
|
|
* clutter_model_append (model, 0, 42, 1, "Team #1", -1);
|
|
* </programlisting></informalexample>
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_append (ClutterModel *model,
|
|
...)
|
|
{
|
|
ClutterModelPrivate *priv;
|
|
ClutterModelIter *iter;
|
|
va_list args;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
priv = model->priv;
|
|
|
|
iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, -1);
|
|
g_assert (CLUTTER_IS_MODEL_ITER (iter));
|
|
|
|
/* do not emit the ::row-changed signal */
|
|
va_start (args, model);
|
|
clutter_model_iter_set_internal_valist (iter, args);
|
|
va_end (args);
|
|
|
|
g_signal_emit (model, model_signals[ROW_ADDED], 0, iter);
|
|
|
|
g_object_unref (iter);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_prependv:
|
|
* @model: a #ClutterModel
|
|
* @n_columns: the number of columns and values to set
|
|
* @columns: a vector containing the columns to set
|
|
* @values: a vector containing the values for the cells
|
|
*
|
|
* Creates and prepends a new row to the #ClutterModel, setting the row
|
|
* values for the given @columns upon creation.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_prependv (ClutterModel *model,
|
|
guint n_columns,
|
|
guint *columns,
|
|
GValue *values)
|
|
{
|
|
ClutterModelPrivate *priv;
|
|
ClutterModelIter *iter;
|
|
gint i;
|
|
gboolean resort = FALSE;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
g_return_if_fail (n_columns <= clutter_model_get_n_columns (model));
|
|
g_return_if_fail (columns != NULL);
|
|
g_return_if_fail (values != NULL);
|
|
|
|
priv = model->priv;
|
|
|
|
iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, 0);
|
|
g_assert (CLUTTER_IS_MODEL_ITER (iter));
|
|
|
|
for (i = 0; i < n_columns; i++)
|
|
{
|
|
if (priv->sort_column == columns[i])
|
|
resort = TRUE;
|
|
|
|
clutter_model_iter_set_value (iter, columns[i], &values[i]);
|
|
}
|
|
|
|
g_signal_emit (model, model_signals[ROW_ADDED], 0, iter);
|
|
|
|
if (resort)
|
|
clutter_model_resort (model);
|
|
|
|
g_object_unref (iter);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_prepend:
|
|
* @model: a #ClutterModel
|
|
* @Varargs: pairs of column number and value, terminated with -1
|
|
*
|
|
* Creates and prepends a new row to the #ClutterModel, setting the row
|
|
* values upon creation. For example, to prepend a new row where column 0
|
|
* is type %G_TYPE_INT and column 1 is of type %G_TYPE_STRING:
|
|
*
|
|
* <informalexample><programlisting>
|
|
* ClutterModel *model;
|
|
* model = clutter_model_default_new (2,
|
|
* G_TYPE_INT, "Score",
|
|
* G_TYPE_STRING, "Team");
|
|
* clutter_model_prepend (model, 0, 42, 1, "Team #1", -1);
|
|
* </programlisting></informalexample>
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_prepend (ClutterModel *model,
|
|
...)
|
|
{
|
|
ClutterModelIter *iter;
|
|
va_list args;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
|
|
iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, 0);
|
|
g_assert (CLUTTER_IS_MODEL_ITER (iter));
|
|
|
|
va_start (args, model);
|
|
clutter_model_iter_set_internal_valist (iter, args);
|
|
va_end (args);
|
|
|
|
g_signal_emit (model, model_signals[ROW_ADDED], 0, iter);
|
|
|
|
g_object_unref (iter);
|
|
}
|
|
|
|
|
|
/**
|
|
* clutter_model_insert:
|
|
* @model: a #ClutterModel
|
|
* @row: the position to insert the new row
|
|
* @Varargs: pairs of column number and value, terminated with -1
|
|
*
|
|
* Inserts a new row to the #ClutterModel at @row, setting the row
|
|
* values upon creation. For example, to insert a new row at index 100,
|
|
* where column 0 is type %G_TYPE_INT and column 1 is of type
|
|
* %G_TYPE_STRING:
|
|
*
|
|
* <informalexample><programlisting>
|
|
* ClutterModel *model;
|
|
* model = clutter_model_default_new (2,
|
|
* G_TYPE_INT, "Score",
|
|
* G_TYPE_STRING, "Team");
|
|
* clutter_model_insert (model, 3, 0, 42, 1, "Team #1", -1);
|
|
* </programlisting></informalexample>
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_insert (ClutterModel *model,
|
|
guint row,
|
|
...)
|
|
{
|
|
ClutterModelIter *iter;
|
|
va_list args;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
|
|
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_internal_valist (iter, args);
|
|
va_end (args);
|
|
|
|
g_signal_emit (model, model_signals[ROW_ADDED], 0, iter);
|
|
|
|
g_object_unref (iter);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_insertv:
|
|
* @model: a #ClutterModel
|
|
* @row: row index
|
|
* @n_columns: the number of columns and values to set
|
|
* @columns: a vector containing the columns to set
|
|
* @values: a vector containing the values for the cells
|
|
*
|
|
* Inserts data at @row into the #ClutterModel, setting the row
|
|
* values for the given @columns upon creation.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_insertv (ClutterModel *model,
|
|
guint row,
|
|
guint n_columns,
|
|
guint *columns,
|
|
GValue *values)
|
|
{
|
|
ClutterModelPrivate *priv;
|
|
ClutterModelIter *iter;
|
|
gint i;
|
|
gboolean resort = FALSE;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
g_return_if_fail (n_columns <= clutter_model_get_n_columns (model));
|
|
g_return_if_fail (columns != NULL);
|
|
g_return_if_fail (values != NULL);
|
|
|
|
priv = model->priv;
|
|
|
|
iter = CLUTTER_MODEL_GET_CLASS (model)->insert_row (model, row);
|
|
g_assert (CLUTTER_IS_MODEL_ITER (iter));
|
|
|
|
for (i = 0; i < n_columns; i++)
|
|
{
|
|
if (priv->sort_column == columns[i])
|
|
resort = TRUE;
|
|
|
|
clutter_model_iter_set_value (iter, columns[i], &values[i]);
|
|
}
|
|
|
|
g_signal_emit (model, model_signals[ROW_ADDED], 0, iter);
|
|
|
|
if (resort)
|
|
clutter_model_resort (model);
|
|
|
|
g_object_unref (iter);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_insert_value:
|
|
* @model: a #ClutterModel
|
|
* @row: position of the row to modify
|
|
* @column: column to modify
|
|
* @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. If the row does
|
|
* not exist then it is created.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_insert_value (ClutterModel *model,
|
|
guint row,
|
|
guint column,
|
|
const GValue *value)
|
|
{
|
|
ClutterModelPrivate *priv;
|
|
ClutterModelClass *klass;
|
|
ClutterModelIter *iter;
|
|
gboolean added = FALSE;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
|
|
priv = model->priv;
|
|
klass = CLUTTER_MODEL_GET_CLASS (model);
|
|
|
|
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)
|
|
clutter_model_resort (model);
|
|
|
|
g_object_unref (iter);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_remove:
|
|
* @model: a #ClutterModel
|
|
* @row: position of row to remove
|
|
*
|
|
* Removes the row at the given position from the model.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_remove (ClutterModel *model,
|
|
guint row)
|
|
{
|
|
ClutterModelClass *klass;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
|
|
klass = CLUTTER_MODEL_GET_CLASS (model);
|
|
if (klass->remove_row)
|
|
klass->remove_row (model, row);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_get_column_name:
|
|
* @model: #ClutterModel
|
|
* @column: the column number
|
|
*
|
|
* Retrieves the name of the @column
|
|
*
|
|
* Return value: the name of the column. The model holds the returned
|
|
* string, and it should not be modified or freed
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
G_CONST_RETURN gchar *
|
|
clutter_model_get_column_name (ClutterModel *model,
|
|
guint column)
|
|
{
|
|
ClutterModelPrivate *priv;
|
|
ClutterModelClass *klass;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL);
|
|
|
|
priv = model->priv;
|
|
if (column < 0 || column >= clutter_model_get_n_columns (model))
|
|
{
|
|
g_warning ("%s: Invalid column id value %d\n", G_STRLOC, column);
|
|
return NULL;
|
|
}
|
|
|
|
klass = CLUTTER_MODEL_GET_CLASS (model);
|
|
if (klass->get_column_name)
|
|
return klass->get_column_name (model, column);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* clutter_model_get_column_type:
|
|
* @model: #ClutterModel
|
|
* @column: the column number
|
|
*
|
|
* Retrieves the type of the @column.
|
|
*
|
|
* Return value: the type of the column.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
GType
|
|
clutter_model_get_column_type (ClutterModel *model,
|
|
guint column)
|
|
{
|
|
ClutterModelPrivate *priv;
|
|
ClutterModelClass *klass;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL (model), G_TYPE_INVALID);
|
|
|
|
priv = model->priv;
|
|
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;
|
|
}
|
|
|
|
klass = CLUTTER_MODEL_GET_CLASS (model);
|
|
if (klass->get_column_type)
|
|
return klass->get_column_type (model, column);
|
|
|
|
return G_TYPE_INVALID;
|
|
}
|
|
|
|
/**
|
|
* clutter_model_get_iter_at_row:
|
|
* @model: a #ClutterModel
|
|
* @row: position of the row to retrieve
|
|
*
|
|
* Retrieves a #ClutterModelIter representing the row at the given index.
|
|
*
|
|
* Return value: A new #ClutterModelIter, or %NULL if @row was out of bounds.
|
|
* When done using the iterator object, call g_object_unref() to deallocate
|
|
* its resources
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
ClutterModelIter *
|
|
clutter_model_get_iter_at_row (ClutterModel *model,
|
|
guint row)
|
|
{
|
|
ClutterModelClass *klass;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL);
|
|
|
|
klass = CLUTTER_MODEL_GET_CLASS (model);
|
|
if (klass->get_iter_at_row)
|
|
return klass->get_iter_at_row (model, row);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
* clutter_model_get_first_iter:
|
|
* @model: a #ClutterModel
|
|
*
|
|
* Retrieves a #ClutterModelIter representing the first row in @model.
|
|
*
|
|
* Return value: A new #ClutterModelIter. Call g_object_unref() when
|
|
* done using it
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
ClutterModelIter *
|
|
clutter_model_get_first_iter (ClutterModel *model)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL);
|
|
|
|
return clutter_model_get_iter_at_row (model, 0);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_get_last_iter:
|
|
* @model: a #ClutterModel
|
|
*
|
|
* Retrieves a #ClutterModelIter representing the last row in @model.
|
|
*
|
|
* Return value: A new #ClutterModelIter. Call g_object_unref() when
|
|
* done using it
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
ClutterModelIter *
|
|
clutter_model_get_last_iter (ClutterModel *model)
|
|
{
|
|
guint length;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL (model), NULL);
|
|
|
|
length = clutter_model_get_n_rows (model);
|
|
|
|
return clutter_model_get_iter_at_row (model, length - 1);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_get_n_rows:
|
|
* @model: a #ClutterModel
|
|
*
|
|
* Retrieves the number of rows inside @model.
|
|
*
|
|
* Return value: The length of the @model. If there is a filter set, then
|
|
* the length of the filtered @model is returned.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
guint
|
|
clutter_model_get_n_rows (ClutterModel *model)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL (model), 0);
|
|
|
|
return CLUTTER_MODEL_GET_CLASS (model)->get_n_rows (model);
|
|
}
|
|
|
|
|
|
/**
|
|
* clutter_model_set_sorting_column:
|
|
* @model: a #ClutterModel
|
|
* @column: the column of the @model to sort, or -1
|
|
*
|
|
* Sets the model to sort by @column. If @column is a negative value
|
|
* the sorting column will be unset.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_set_sorting_column (ClutterModel *model,
|
|
gint column)
|
|
{
|
|
ClutterModelPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
priv = model->priv;
|
|
|
|
if (column >= clutter_model_get_n_columns (model))
|
|
{
|
|
g_warning ("%s: Invalid column id value %d\n", G_STRLOC, column);
|
|
return;
|
|
}
|
|
|
|
priv->sort_column = column;
|
|
|
|
if (priv->sort_column >= 0)
|
|
clutter_model_resort (model);
|
|
|
|
g_signal_emit (model, model_signals[SORT_CHANGED], 0);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_get_sorting_column:
|
|
* @model: a #ClutterModel
|
|
*
|
|
* Retrieves the number of column used for sorting the @model.
|
|
*
|
|
* Return value: a column number, or -1 if the model is not sorted
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
gint
|
|
clutter_model_get_sorting_column (ClutterModel *model)
|
|
{
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL (model), -1);
|
|
|
|
return model->priv->sort_column;
|
|
}
|
|
|
|
/**
|
|
* clutter_model_foreach:
|
|
* @model: a #ClutterModel
|
|
* @func: a #ClutterModelForeachFunc
|
|
* @user_data: user data to pass to @func
|
|
*
|
|
* Calls @func for each row in the model.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_foreach (ClutterModel *model,
|
|
ClutterModelForeachFunc func,
|
|
gpointer user_data)
|
|
{
|
|
ClutterModelIter *iter;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
|
|
iter = clutter_model_get_first_iter (model);
|
|
if (!iter)
|
|
return;
|
|
|
|
while (!clutter_model_iter_is_last (iter))
|
|
{
|
|
if (clutter_model_filter_iter (model, iter))
|
|
{
|
|
if (!func (model, iter, user_data))
|
|
break;
|
|
}
|
|
|
|
iter = clutter_model_iter_next (iter);
|
|
}
|
|
|
|
g_object_unref (iter);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_set_sort:
|
|
* @model: a #ClutterModel
|
|
* @column: the column to sort on
|
|
* @func: a #ClutterModelSortFunc, or #NULL
|
|
* @user_data: user data to pass to @func, or #NULL
|
|
* @notify: destroy notifier of @user_data, or #NULL
|
|
*
|
|
* Sorts @model using the given sorting function.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_set_sort (ClutterModel *model,
|
|
guint column,
|
|
ClutterModelSortFunc func,
|
|
gpointer user_data,
|
|
GDestroyNotify notify)
|
|
{
|
|
ClutterModelPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
priv = model->priv;
|
|
|
|
if (priv->sort_notify)
|
|
priv->sort_notify (priv->sort_data);
|
|
|
|
priv->sort_func = func;
|
|
priv->sort_data = user_data;
|
|
priv->sort_notify = notify;
|
|
|
|
/* This takes care of calling _model_sort & emitting the signal*/
|
|
clutter_model_set_sorting_column (model, column);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_set_filter:
|
|
* @model: a #ClutterModel
|
|
* @func: a #ClutterModelFilterFunc, or #NULL
|
|
* @user_data: user data to pass to @func, or #NULL
|
|
* @notify: destroy notifier of @user_data, or #NULL
|
|
*
|
|
* Filters the @model using the given filtering function.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_set_filter (ClutterModel *model,
|
|
ClutterModelFilterFunc func,
|
|
gpointer user_data,
|
|
GDestroyNotify notify)
|
|
{
|
|
ClutterModelPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL (model));
|
|
priv = model->priv;
|
|
|
|
if (priv->filter_notify)
|
|
priv->filter_notify (priv->filter_data);
|
|
|
|
priv->filter_func = func;
|
|
priv->filter_data = user_data;
|
|
priv->filter_notify = notify;
|
|
|
|
g_signal_emit (model, model_signals[FILTER_CHANGED], 0);
|
|
}
|
|
|
|
/*
|
|
* ClutterModelIter Object
|
|
*/
|
|
|
|
/**
|
|
* SECTION:clutter-model-iter
|
|
* @short_description: Iterates through a model
|
|
*
|
|
* #ClutterModelIter is an object used for iterating through all the rows
|
|
* of a #ClutterModel. It allows setting and getting values on the row
|
|
* which is currently pointing at.
|
|
*
|
|
* A #ClutterModelIter represents a position between two elements
|
|
* of the sequence. For example, the iterator returned by
|
|
* clutter_model_get_first_iter() represents the gap immediately before
|
|
* the first row of the #ClutterModel, and the iterator returned by
|
|
* clutter_model_get_last_iter() represents the gap immediately after the
|
|
* last row.
|
|
*
|
|
* 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_ABSTRACT_TYPE (ClutterModelIter, clutter_model_iter, G_TYPE_OBJECT);
|
|
|
|
#define CLUTTER_MODEL_ITER_GET_PRIVATE(obj) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
|
|
CLUTTER_TYPE_MODEL_ITER, ClutterModelIterPrivate))
|
|
|
|
struct _ClutterModelIterPrivate
|
|
{
|
|
ClutterModel *model;
|
|
|
|
gint row;
|
|
|
|
guint ignore_sort : 1;
|
|
};
|
|
|
|
enum
|
|
{
|
|
ITER_PROP_0,
|
|
|
|
ITER_PROP_MODEL,
|
|
ITER_PROP_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;
|
|
}
|
|
|
|
static ClutterModelIter *
|
|
clutter_model_iter_copy_unimplemented (ClutterModelIter *iter)
|
|
{
|
|
g_warning ("%s: Iterator of type `%s' does not implement the "
|
|
"ClutterModelIter::copy() virtual function",
|
|
G_STRLOC,
|
|
g_type_name (G_OBJECT_TYPE (iter)));
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
clutter_model_iter_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
ClutterModelIter *iter = CLUTTER_MODEL_ITER (object);
|
|
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, priv->row);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
clutter_model_iter_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
ClutterModelIter *iter = CLUTTER_MODEL_ITER (object);
|
|
ClutterModelIterPrivate *priv = iter->priv;
|
|
|
|
switch (prop_id)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
static void
|
|
clutter_model_iter_class_init (ClutterModelIterClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->get_property = clutter_model_iter_get_property;
|
|
gobject_class->set_property = clutter_model_iter_set_property;
|
|
|
|
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;
|
|
klass->copy = clutter_model_iter_copy_unimplemented;
|
|
|
|
/* Properties */
|
|
|
|
/**
|
|
* ClutterModelIter:model:
|
|
*
|
|
* A reference to the #ClutterModel that this iter belongs to.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
g_object_class_install_property (gobject_class,
|
|
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:
|
|
*
|
|
* 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 to which the iterator points to",
|
|
0, G_MAXUINT, 0,
|
|
CLUTTER_PARAM_READWRITE));
|
|
|
|
g_type_class_add_private (gobject_class, sizeof (ClutterModelIterPrivate));
|
|
}
|
|
|
|
static void
|
|
clutter_model_iter_init (ClutterModelIter *self)
|
|
{
|
|
ClutterModelIterPrivate *priv;
|
|
|
|
self->priv = priv = CLUTTER_MODEL_ITER_GET_PRIVATE (self);
|
|
|
|
priv->model = NULL;
|
|
priv->row = 0;
|
|
|
|
priv->ignore_sort = FALSE;
|
|
}
|
|
|
|
/*
|
|
* Public functions
|
|
*/
|
|
|
|
static void
|
|
clutter_model_iter_set_internal_valist (ClutterModelIter *iter,
|
|
va_list args)
|
|
{
|
|
ClutterModel *model;
|
|
ClutterModelIterPrivate *priv;
|
|
guint column = 0;
|
|
gboolean sort = FALSE;
|
|
|
|
priv = iter->priv;
|
|
model = priv->model;
|
|
g_assert (CLUTTER_IS_MODEL (model));
|
|
|
|
column = va_arg (args, gint);
|
|
|
|
/* Don't want to sort while setting lots of fields, leave that till the end
|
|
*/
|
|
priv->ignore_sort = TRUE;
|
|
while (column != -1)
|
|
{
|
|
GValue value = { 0, };
|
|
gchar *error = NULL;
|
|
|
|
if (column < 0 || column >= clutter_model_get_n_columns (model))
|
|
{
|
|
g_warning ("%s: Invalid column number %d added to iter "
|
|
"(remember to end you list of columns with a -1)",
|
|
G_STRLOC, column);
|
|
break;
|
|
}
|
|
g_value_init (&value, clutter_model_get_column_type (model, column));
|
|
|
|
G_VALUE_COLLECT (&value, args, 0, &error);
|
|
if (error)
|
|
{
|
|
g_warning ("%s: %s", G_STRLOC, error);
|
|
g_free (error);
|
|
|
|
/* Leak value as it might not be in a sane state */
|
|
break;
|
|
}
|
|
|
|
clutter_model_iter_set_value (iter, column, &value);
|
|
|
|
g_value_unset (&value);
|
|
|
|
if (column == clutter_model_get_sorting_column (model))
|
|
sort = TRUE;
|
|
|
|
column = va_arg (args, gint);
|
|
}
|
|
|
|
priv->ignore_sort = FALSE;
|
|
if (sort)
|
|
clutter_model_resort (model);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_iter_set_valist:
|
|
* @iter: a #ClutterModelIter
|
|
* @args: va_list of column/value pairs, terminiated by -1
|
|
*
|
|
* See clutter_model_iter_set(); this version takes a va_list for language
|
|
* bindings.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_iter_set_valist (ClutterModelIter *iter,
|
|
va_list args)
|
|
{
|
|
ClutterModelIterPrivate *priv;
|
|
ClutterModel *model;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter));
|
|
|
|
clutter_model_iter_set_internal_valist (iter, args);
|
|
|
|
priv = iter->priv;
|
|
model = priv->model;
|
|
g_assert (CLUTTER_IS_MODEL (model));
|
|
|
|
g_signal_emit (model, model_signals[ROW_CHANGED], 0, iter);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_iter_get:
|
|
* @iter: a #ClutterModelIter
|
|
* @Varargs: a list of column/return location pairs, terminated by -1
|
|
*
|
|
* Gets the value of one or more cells in the row referenced by @iter. The
|
|
* variable argument list should contain integer column numbers, each column
|
|
* column number followed by a place to store the value being retrieved. The
|
|
* list is terminated by a -1.
|
|
*
|
|
* For example, to get a value from column 0 with type %G_TYPE_STRING use:
|
|
* <informalexample><programlisting>
|
|
* clutter_model_iter_get (iter, 0, &place_string_here, -1);
|
|
* </programlisting></informalexample>
|
|
*
|
|
* where place_string_here is a gchar* to be filled with the string. If
|
|
* appropriate, the returned values have to be freed or unreferenced.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_iter_get (ClutterModelIter *iter,
|
|
...)
|
|
{
|
|
va_list args;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter));
|
|
|
|
va_start (args, iter);
|
|
clutter_model_iter_get_valist (iter, args);
|
|
va_end (args);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_iter_get_value:
|
|
* @iter: a #ClutterModelIter
|
|
* @column: column number to retrieve the value from
|
|
* @value: an empty #GValue to set
|
|
*
|
|
* Sets an initializes @value to that at @column. When done with @value,
|
|
* g_value_unset() needs to be called to free any allocated memory.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_iter_get_value (ClutterModelIter *iter,
|
|
guint column,
|
|
GValue *value)
|
|
{
|
|
ClutterModelIterClass *klass;
|
|
ClutterModel *model;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter));
|
|
|
|
model = iter->priv->model;
|
|
|
|
g_value_init (value, clutter_model_get_column_type (model, column));
|
|
|
|
klass = CLUTTER_MODEL_ITER_GET_CLASS (iter);
|
|
if (klass && klass->get_value)
|
|
klass->get_value (iter, column, value);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_iter_get_valist:
|
|
* @iter: a #ClutterModelIter
|
|
* @args: a list of column/return location pairs, terminated by -1
|
|
*
|
|
* See clutter_model_iter_get(). This version takes a va_list for language
|
|
* bindings.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_iter_get_valist (ClutterModelIter *iter,
|
|
va_list args)
|
|
{
|
|
ClutterModelIterPrivate *priv;
|
|
ClutterModel *model;
|
|
guint column = 0;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter));
|
|
|
|
priv = iter->priv;
|
|
model = priv->model;
|
|
g_assert (CLUTTER_IS_MODEL (model));
|
|
|
|
column = va_arg (args, gint);
|
|
|
|
while (column != -1)
|
|
{
|
|
GValue value = { 0, };
|
|
gchar *error = NULL;
|
|
|
|
if (column < 0 || column >= clutter_model_get_n_columns (model))
|
|
{
|
|
g_warning ("%s: Invalid column number %d added to iter "
|
|
"(remember to end you list of columns with a -1)",
|
|
G_STRLOC, column);
|
|
break;
|
|
}
|
|
|
|
/* this one will take care of initialising value to the
|
|
* correct type
|
|
*/
|
|
clutter_model_iter_get_value (iter, column, &value);
|
|
|
|
G_VALUE_LCOPY (&value, args, 0, &error);
|
|
if (error)
|
|
{
|
|
g_warning ("%s: %s", G_STRLOC, error);
|
|
g_free (error);
|
|
|
|
/* Leak value as it might not be in a sane state */
|
|
break;
|
|
}
|
|
|
|
g_value_unset (&value);
|
|
|
|
column = va_arg (args, gint);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* clutter_model_iter_set:
|
|
* @iter: a #ClutterModelIter
|
|
* @Varargs: a list of column/return location pairs, terminated by -1
|
|
*
|
|
* Sets the value of one or more cells in the row referenced by @iter. The
|
|
* variable argument list should contain integer column numbers, each column
|
|
* column number followed by the value to be set. The list is terminated by a
|
|
* -1.
|
|
*
|
|
* For example, to set column 0 with type %G_TYPE_STRING, use:
|
|
* <informalexample><programlisting>
|
|
* clutter_model_iter_set (iter, 0, "foo", -1);
|
|
* </programlisting></informalexample>
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_iter_set (ClutterModelIter *iter,
|
|
...)
|
|
{
|
|
va_list args;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter));
|
|
|
|
va_start (args, iter);
|
|
clutter_model_iter_set_valist (iter, args);
|
|
va_end (args);
|
|
}
|
|
|
|
|
|
/**
|
|
* clutter_model_iter_set_value:
|
|
* @iter: a #ClutterModelIter
|
|
* @column: column number to retrieve the value from
|
|
* @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.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
void
|
|
clutter_model_iter_set_value (ClutterModelIter *iter,
|
|
guint column,
|
|
const GValue *value)
|
|
{
|
|
ClutterModelIterClass *klass;
|
|
|
|
g_return_if_fail (CLUTTER_IS_MODEL_ITER (iter));
|
|
|
|
klass = CLUTTER_MODEL_ITER_GET_CLASS (iter);
|
|
if (klass && klass->set_value)
|
|
klass->set_value (iter, column, value);
|
|
}
|
|
|
|
/**
|
|
* clutter_model_iter_is_first:
|
|
* @iter: a #ClutterModelIter
|
|
*
|
|
* Gets whether the current iterator is at the beginning of the model
|
|
* to which it belongs.
|
|
*
|
|
* Return value: #TRUE if @iter is the first iter in the filtered model
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
gboolean
|
|
clutter_model_iter_is_first (ClutterModelIter *iter)
|
|
{
|
|
ClutterModelIterClass *klass;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), FALSE);
|
|
|
|
klass = CLUTTER_MODEL_ITER_GET_CLASS (iter);
|
|
if (klass && klass->is_first)
|
|
return klass->is_first (iter);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* clutter_model_iter_is_last:
|
|
* @iter: a #ClutterModelIter
|
|
*
|
|
* Gets whether the iterator is at the end of the model to which it
|
|
* belongs.
|
|
*
|
|
* Return value: #TRUE if @iter is the last iter in the filtered model.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
gboolean
|
|
clutter_model_iter_is_last (ClutterModelIter *iter)
|
|
{
|
|
ClutterModelIterClass *klass;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), FALSE);
|
|
|
|
klass = CLUTTER_MODEL_ITER_GET_CLASS (iter);
|
|
if (klass && klass->is_last)
|
|
return klass->is_last (iter);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* clutter_model_iter_next:
|
|
* @iter: a #ClutterModelIter
|
|
*
|
|
* Updates the @iter to point at the next position in the model.
|
|
* The model implementation should take into account the presence of
|
|
* a filter function.
|
|
*
|
|
* Return value: The passed iterator, updated to point at the next
|
|
* row in the model.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
ClutterModelIter *
|
|
clutter_model_iter_next (ClutterModelIter *iter)
|
|
{
|
|
ClutterModelIterClass *klass;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL);
|
|
|
|
klass = CLUTTER_MODEL_ITER_GET_CLASS (iter);
|
|
if (klass && klass->next)
|
|
return klass->next (iter);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* clutter_model_iter_prev:
|
|
* @iter: a #ClutterModelIter
|
|
*
|
|
* Sets the @iter to point at the previous position in the model.
|
|
* The model implementation should take into account the presence of
|
|
* a filter function.
|
|
*
|
|
* Return value: The passed iterator, updated to point at the previous
|
|
* row in the model.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
ClutterModelIter *
|
|
clutter_model_iter_prev (ClutterModelIter *iter)
|
|
{
|
|
ClutterModelIterClass *klass;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL);
|
|
|
|
klass = CLUTTER_MODEL_ITER_GET_CLASS (iter);
|
|
if (klass && klass->prev)
|
|
return klass->prev (iter);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* clutter_model_iter_get_model:
|
|
* @iter: a #ClutterModelIter
|
|
*
|
|
* Retrieves a pointer to the #ClutterModel that this iter is part of.
|
|
*
|
|
* Return value: a pointer to a #ClutterModel.
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
ClutterModel *
|
|
clutter_model_iter_get_model (ClutterModelIter *iter)
|
|
{
|
|
ClutterModelIterClass *klass;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL);
|
|
|
|
klass = CLUTTER_MODEL_ITER_GET_CLASS (iter);
|
|
if (klass && klass->get_model)
|
|
return klass->get_model (iter);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* clutter_model_iter_get_row:
|
|
* @iter: a #ClutterModelIter
|
|
*
|
|
* Retrieves the position of the row that the @iter points to.
|
|
*
|
|
* Return value: the position of the @iter in the model
|
|
*
|
|
* Since: 0.6
|
|
*/
|
|
guint
|
|
clutter_model_iter_get_row (ClutterModelIter *iter)
|
|
{
|
|
ClutterModelIterClass *klass;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), 0);
|
|
|
|
klass = CLUTTER_MODEL_ITER_GET_CLASS (iter);
|
|
if (klass && klass->get_row)
|
|
return klass->get_row (iter);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* clutter_model_iter_copy:
|
|
* @iter: a #ClutterModelIter
|
|
*
|
|
* Copies the passed iterator.
|
|
*
|
|
* Return value: a copy of the iterator, or %NULL
|
|
*
|
|
* Since: 0.8
|
|
*/
|
|
ClutterModelIter *
|
|
clutter_model_iter_copy (ClutterModelIter *iter)
|
|
{
|
|
ClutterModelIterClass *klass;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_MODEL_ITER (iter), NULL);
|
|
|
|
klass = CLUTTER_MODEL_ITER_GET_CLASS (iter);
|
|
if (klass->copy)
|
|
return klass->copy (iter);
|
|
|
|
return NULL;
|
|
}
|