2007-12-14 17:25:55 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
2008-01-09 14:34:24 +00:00
|
|
|
|
* SECTION:clutter-list-model
|
|
|
|
|
* @short_description: List model implementation
|
2007-12-14 17:25:55 +00:00
|
|
|
|
*
|
2008-01-09 14:34:24 +00:00
|
|
|
|
* #ClutterListModel is a #ClutterModel implementation provided by
|
|
|
|
|
* Clutter. #ClutterListModel uses a #GSequence for storing the
|
2007-12-14 17:25:55 +00:00
|
|
|
|
* values for each row, so it's optimized for insertion and look up
|
|
|
|
|
* in sorted lists.
|
|
|
|
|
*
|
2008-01-09 14:34:24 +00:00
|
|
|
|
* #ClutterListModel is a terminal class: it cannot be subclassed,
|
2007-12-14 17:25:55 +00:00
|
|
|
|
* only instantiated.
|
|
|
|
|
*
|
2008-01-09 14:34:24 +00:00
|
|
|
|
* #ClutterListModel is available since Clutter 0.6
|
2007-12-14 17:25:55 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include <glib-object.h>
|
|
|
|
|
|
|
|
|
|
#include "clutter-model.h"
|
2008-01-09 14:18:53 +00:00
|
|
|
|
#include "clutter-model-private.h"
|
2008-01-09 14:40:31 +00:00
|
|
|
|
#include "clutter-list-model.h"
|
2007-12-14 17:25:55 +00:00
|
|
|
|
#include "clutter-private.h"
|
|
|
|
|
#include "clutter-debug.h"
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
#define CLUTTER_TYPE_LIST_MODEL_ITER \
|
|
|
|
|
(clutter_list_model_iter_get_type())
|
|
|
|
|
#define CLUTTER_LIST_MODEL_ITER(obj) \
|
|
|
|
|
(G_TYPE_CHECK_INSTANCE_CAST((obj), \
|
|
|
|
|
CLUTTER_TYPE_LIST_MODEL_ITER, \
|
|
|
|
|
ClutterListModelIter))
|
|
|
|
|
#define CLUTTER_IS_LIST_MODEL_ITER(obj) \
|
|
|
|
|
(G_TYPE_CHECK_INSTANCE_TYPE((obj), \
|
|
|
|
|
CLUTTER_TYPE_LIST_MODEL_ITER))
|
|
|
|
|
#define CLUTTER_LIST_MODEL_ITER_CLASS(klass) \
|
|
|
|
|
(G_TYPE_CHECK_CLASS_CAST ((klass), \
|
|
|
|
|
CLUTTER_TYPE_LIST_MODEL_ITER, \
|
|
|
|
|
ClutterListModelIterClass))
|
|
|
|
|
#define CLUTTER_IS_LIST_MODEL_ITER_CLASS(klass) \
|
|
|
|
|
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
|
|
|
|
CLUTTER_TYPE_LIST_MODEL_ITER))
|
|
|
|
|
#define CLUTTER_LIST_MODEL_ITER_GET_CLASS(obj) \
|
|
|
|
|
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
|
|
|
|
|
CLUTTER_TYPE_LIST_MODEL_ITER, \
|
|
|
|
|
ClutterListModelIterClass))
|
|
|
|
|
|
|
|
|
|
#define CLUTTER_LIST_MODEL_CLASS(klass) \
|
|
|
|
|
(G_TYPE_CHECK_CLASS_CAST ((klass), \
|
|
|
|
|
CLUTTER_TYPE_LIST_MODEL, \
|
|
|
|
|
ClutterListModelClass))
|
|
|
|
|
#define CLUTTER_IS_LIST_MODEL_CLASS(klass) \
|
|
|
|
|
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
|
|
|
|
|
CLUTTER_TYPE_LIST_MODEL))
|
|
|
|
|
#define CLUTTER_LIST_MODEL_GET_CLASS(obj) \
|
|
|
|
|
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
|
|
|
|
|
CLUTTER_TYPE_LIST_MODEL, \
|
|
|
|
|
ClutterListModelClass))
|
|
|
|
|
|
|
|
|
|
typedef struct _ClutterListModelIter ClutterListModelIter;
|
|
|
|
|
typedef struct _ClutterModelIterClass ClutterListModelIterClass;
|
|
|
|
|
|
|
|
|
|
typedef struct _ClutterModelClass ClutterListModelClass;
|
|
|
|
|
|
|
|
|
|
struct _ClutterListModel
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
|
|
|
|
ClutterModel parent_instance;
|
|
|
|
|
|
|
|
|
|
GSequence *sequence;
|
|
|
|
|
};
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
struct _ClutterListModelIter
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
|
|
|
|
ClutterModelIter parent_instance;
|
|
|
|
|
|
|
|
|
|
GSequenceIter *seq_iter;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2008-01-09 14:34:24 +00:00
|
|
|
|
* ClutterListModel
|
2007-12-14 17:25:55 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
G_DEFINE_TYPE (ClutterListModelIter,
|
|
|
|
|
clutter_list_model_iter,
|
2007-12-14 17:25:55 +00:00
|
|
|
|
CLUTTER_TYPE_MODEL_ITER);
|
|
|
|
|
|
|
|
|
|
static void
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_iter_get_value (ClutterModelIter *iter,
|
|
|
|
|
guint column,
|
|
|
|
|
GValue *value)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
ClutterListModelIter *iter_default;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
GValueArray *value_array;
|
|
|
|
|
GValue *iter_value;
|
|
|
|
|
GValue real_value = { 0, };
|
|
|
|
|
gboolean converted = FALSE;
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
iter_default = CLUTTER_LIST_MODEL_ITER (iter);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-18 14:32:57 +00:00
|
|
|
|
if (!g_value_transform (iter_value, &real_value))
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
|
|
|
|
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
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_iter_set_value (ClutterModelIter *iter,
|
|
|
|
|
guint column,
|
|
|
|
|
const GValue *value)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
ClutterListModelIter *iter_default;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
GValueArray *value_array;
|
|
|
|
|
GValue *iter_value;
|
|
|
|
|
GValue real_value = { 0, };
|
|
|
|
|
gboolean converted = FALSE;
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
iter_default = CLUTTER_LIST_MODEL_ITER (iter);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
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
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_iter_is_first (ClutterModelIter *iter)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
ClutterListModelIter *iter_default;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
ClutterModel *model;
|
|
|
|
|
ClutterModelIter *temp_iter;
|
|
|
|
|
GSequenceIter *begin, *end;
|
|
|
|
|
guint row;
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
iter_default = CLUTTER_LIST_MODEL_ITER (iter);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
g_assert (iter_default->seq_iter != NULL);
|
|
|
|
|
|
|
|
|
|
model = clutter_model_iter_get_model (iter);
|
|
|
|
|
row = clutter_model_iter_get_row (iter);
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
begin = g_sequence_get_begin_iter (CLUTTER_LIST_MODEL (model)->sequence);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
end = iter_default->seq_iter;
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
temp_iter = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
|
2007-12-14 17:25:55 +00:00
|
|
|
|
"model", model,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
while (!g_sequence_iter_is_begin (begin))
|
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
CLUTTER_LIST_MODEL_ITER (temp_iter)->seq_iter = begin;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
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
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_iter_is_last (ClutterModelIter *iter)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
ClutterListModelIter *iter_default;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
ClutterModelIter *temp_iter;
|
|
|
|
|
ClutterModel *model;
|
|
|
|
|
GSequenceIter *begin, *end;
|
|
|
|
|
guint row;
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
iter_default = CLUTTER_LIST_MODEL_ITER (iter);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
begin = g_sequence_get_end_iter (CLUTTER_LIST_MODEL (model)->sequence);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
begin = g_sequence_iter_prev (begin);
|
|
|
|
|
end = iter_default->seq_iter;
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
temp_iter = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
|
2007-12-14 17:25:55 +00:00
|
|
|
|
"model", model,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
while (!g_sequence_iter_is_begin (begin))
|
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
CLUTTER_LIST_MODEL_ITER (temp_iter)->seq_iter = begin;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
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 *
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_iter_next (ClutterModelIter *iter)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
ClutterListModelIter *iter_default;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
ClutterModelIter *temp_iter;
|
|
|
|
|
ClutterModel *model = NULL;
|
|
|
|
|
GSequenceIter *filter_next;
|
|
|
|
|
guint row;
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
iter_default = CLUTTER_LIST_MODEL_ITER (iter);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
temp_iter = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
|
2007-12-14 17:25:55 +00:00
|
|
|
|
"model", model,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
while (!g_sequence_iter_is_end (filter_next))
|
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
CLUTTER_LIST_MODEL_ITER (temp_iter)->seq_iter = filter_next;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2007-12-15 13:02:06 +00:00
|
|
|
|
/* update the iterator and return it */
|
|
|
|
|
g_object_set (G_OBJECT (iter_default), "model", model, "row", row, NULL);
|
|
|
|
|
iter_default->seq_iter = filter_next;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
|
2007-12-15 13:02:06 +00:00
|
|
|
|
return CLUTTER_MODEL_ITER (iter_default);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ClutterModelIter *
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_iter_prev (ClutterModelIter *iter)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
ClutterListModelIter *iter_default;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
ClutterModelIter *temp_iter;
|
|
|
|
|
ClutterModel *model;
|
|
|
|
|
GSequenceIter *filter_prev;
|
|
|
|
|
guint row;
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
iter_default = CLUTTER_LIST_MODEL_ITER (iter);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
temp_iter = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
|
2007-12-14 17:25:55 +00:00
|
|
|
|
"model", model,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
while (!g_sequence_iter_is_begin (filter_prev))
|
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
CLUTTER_LIST_MODEL_ITER (temp_iter)->seq_iter = filter_prev;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2007-12-15 13:02:06 +00:00
|
|
|
|
/* update the iterator and return it */
|
|
|
|
|
g_object_set (G_OBJECT (iter_default), "model", model, "row", row, NULL);
|
|
|
|
|
iter_default->seq_iter = filter_prev;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
|
2007-12-15 13:02:06 +00:00
|
|
|
|
return CLUTTER_MODEL_ITER (iter_default);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
}
|
|
|
|
|
static void
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_iter_class_init (ClutterListModelIterClass *klass)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
|
|
|
|
ClutterModelIterClass *iter_class = CLUTTER_MODEL_ITER_CLASS (klass);
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
iter_class->get_value = clutter_list_model_iter_get_value;
|
|
|
|
|
iter_class->set_value = clutter_list_model_iter_set_value;
|
|
|
|
|
iter_class->is_first = clutter_list_model_iter_is_first;
|
|
|
|
|
iter_class->is_last = clutter_list_model_iter_is_last;
|
|
|
|
|
iter_class->next = clutter_list_model_iter_next;
|
|
|
|
|
iter_class->prev = clutter_list_model_iter_prev;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_iter_init (ClutterListModelIter *iter)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
|
|
|
|
iter->seq_iter = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2008-01-09 14:34:24 +00:00
|
|
|
|
* ClutterListModel
|
2007-12-14 17:25:55 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
G_DEFINE_TYPE (ClutterListModel, clutter_list_model, CLUTTER_TYPE_MODEL);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
|
|
|
|
|
static ClutterModelIter *
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_get_iter_at_row (ClutterModel *model,
|
|
|
|
|
guint row)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
ClutterListModel *model_default = CLUTTER_LIST_MODEL (model);
|
|
|
|
|
ClutterListModelIter *retval;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
|
2008-01-02 12:15:10 +00:00
|
|
|
|
if (row >= g_sequence_get_length (model_default->sequence))
|
2007-12-14 17:25:55 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
retval = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
|
2007-12-14 17:25:55 +00:00
|
|
|
|
"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 *
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_insert_row (ClutterModel *model,
|
|
|
|
|
gint index_)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
ClutterListModel *model_default = CLUTTER_LIST_MODEL (model);
|
|
|
|
|
ClutterListModelIter *retval;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
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);
|
2008-01-02 12:15:10 +00:00
|
|
|
|
pos = g_sequence_get_length (model_default->sequence);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
}
|
|
|
|
|
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_;
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
retval = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
|
2007-12-14 17:25:55 +00:00
|
|
|
|
"model", model,
|
|
|
|
|
"row", pos,
|
|
|
|
|
NULL);
|
|
|
|
|
retval->seq_iter = seq_iter;
|
|
|
|
|
|
|
|
|
|
return CLUTTER_MODEL_ITER (retval);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_remove_row (ClutterModel *model,
|
|
|
|
|
guint row)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
ClutterListModel *model_default = CLUTTER_LIST_MODEL (model);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
iter = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
|
2007-12-14 17:25:55 +00:00
|
|
|
|
"model", model,
|
|
|
|
|
"row", pos,
|
|
|
|
|
NULL);
|
2008-01-09 14:34:24 +00:00
|
|
|
|
CLUTTER_LIST_MODEL_ITER (iter)->seq_iter = seq_iter;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
|
2008-01-02 12:15:10 +00:00
|
|
|
|
/* the actual row is removed from the sequence inside
|
|
|
|
|
* the ::row-removed signal class handler, so that every
|
|
|
|
|
* handler connected to ::row-removed will still get
|
|
|
|
|
* a valid iterator, and every signal connected to
|
|
|
|
|
* ::row-removed with the AFTER flag will get an updated
|
|
|
|
|
* model
|
|
|
|
|
*/
|
2007-12-14 17:25:55 +00:00
|
|
|
|
g_signal_emit_by_name (model, "row-removed", iter);
|
|
|
|
|
|
|
|
|
|
g_object_unref (iter);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pos += 1;
|
|
|
|
|
seq_iter = g_sequence_iter_next (seq_iter);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static guint
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_get_n_rows (ClutterModel *model)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
ClutterListModel *model_default = CLUTTER_LIST_MODEL (model);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
|
|
|
|
|
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
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_resort (ClutterModel *model,
|
|
|
|
|
ClutterModelSortFunc func,
|
|
|
|
|
gpointer data)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
g_sequence_sort (CLUTTER_LIST_MODEL (model)->sequence,
|
2007-12-14 17:25:55 +00:00
|
|
|
|
sort_model_default,
|
|
|
|
|
&sort_closure);
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-02 12:15:10 +00:00
|
|
|
|
static void
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_row_removed (ClutterModel *model,
|
|
|
|
|
ClutterModelIter *iter)
|
2008-01-02 12:15:10 +00:00
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
ClutterListModelIter *iter_default;
|
2008-01-02 12:15:10 +00:00
|
|
|
|
GValueArray *array;
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
iter_default = CLUTTER_LIST_MODEL_ITER (iter);
|
2008-01-02 12:15:10 +00:00
|
|
|
|
|
|
|
|
|
array = g_sequence_get (iter_default->seq_iter);
|
|
|
|
|
g_value_array_free (array);
|
|
|
|
|
|
|
|
|
|
g_sequence_remove (iter_default->seq_iter);
|
|
|
|
|
iter_default->seq_iter = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2007-12-14 17:25:55 +00:00
|
|
|
|
static void
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_finalize (GObject *gobject)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
2008-01-09 14:34:24 +00:00
|
|
|
|
ClutterListModel *model = CLUTTER_LIST_MODEL (gobject);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
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);
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
G_OBJECT_CLASS (clutter_list_model_parent_class)->finalize (gobject);
|
2007-12-14 17:25:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_class_init (ClutterListModelClass *klass)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
ClutterModelClass *model_class = CLUTTER_MODEL_CLASS (klass);
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
gobject_class->finalize = clutter_list_model_finalize;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
model_class->get_n_rows = clutter_list_model_get_n_rows;
|
|
|
|
|
model_class->get_iter_at_row = clutter_list_model_get_iter_at_row;
|
|
|
|
|
model_class->insert_row = clutter_list_model_insert_row;
|
|
|
|
|
model_class->remove_row = clutter_list_model_remove_row;
|
|
|
|
|
model_class->resort = clutter_list_model_resort;
|
2008-01-02 12:15:10 +00:00
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
model_class->row_removed = clutter_list_model_row_removed;
|
2007-12-14 17:25:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_init (ClutterListModel *model)
|
2007-12-14 17:25:55 +00:00
|
|
|
|
{
|
|
|
|
|
model->sequence = g_sequence_new (NULL);
|
|
|
|
|
}
|
2008-01-09 14:18:53 +00:00
|
|
|
|
|
|
|
|
|
/**
|
2008-01-09 14:34:24 +00:00
|
|
|
|
* clutter_list_model_new:
|
2008-01-09 14:18:53 +00:00
|
|
|
|
* @n_columns: number of columns in the model
|
|
|
|
|
* @Varargs: @n_columns number of #GType and string pairs
|
|
|
|
|
*
|
|
|
|
|
* Creates a new default model with @n_columns columns with the types
|
|
|
|
|
* and names passed in.
|
|
|
|
|
*
|
|
|
|
|
* For example:
|
|
|
|
|
*
|
|
|
|
|
* <informalexample><programlisting>
|
2008-01-09 14:34:24 +00:00
|
|
|
|
* model = clutter_list_model_new (3,
|
|
|
|
|
* G_TYPE_INT, "Score",
|
|
|
|
|
* G_TYPE_STRING, "Team",
|
|
|
|
|
* GDK_TYPE_PIXBUF, "Logo");
|
2008-01-09 14:18:53 +00:00
|
|
|
|
* </programlisting></informalexample>
|
|
|
|
|
*
|
|
|
|
|
* will create a new #ClutterModel with three columns of type int,
|
|
|
|
|
* string and #GdkPixbuf respectively.
|
|
|
|
|
*
|
|
|
|
|
* Note that the name of the column can be set to %NULL, in which case
|
|
|
|
|
* the canonical name of the type held by the column will be used as
|
|
|
|
|
* the title.
|
|
|
|
|
*
|
2008-01-09 14:34:24 +00:00
|
|
|
|
* Return value: a new #ClutterListModel
|
2008-01-09 14:18:53 +00:00
|
|
|
|
*
|
|
|
|
|
* Since: 0.6
|
|
|
|
|
*/
|
|
|
|
|
ClutterModel *
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_new (guint n_columns,
|
|
|
|
|
...)
|
2008-01-09 14:18:53 +00:00
|
|
|
|
{
|
|
|
|
|
ClutterModel *model;
|
|
|
|
|
va_list args;
|
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (n_columns > 0, NULL);
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
model = g_object_new (CLUTTER_TYPE_LIST_MODEL, NULL);
|
2008-01-09 14:18:53 +00:00
|
|
|
|
clutter_model_set_n_columns (model, n_columns, TRUE, TRUE);
|
|
|
|
|
|
|
|
|
|
va_start (args, n_columns);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < n_columns; i++)
|
|
|
|
|
{
|
|
|
|
|
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));
|
|
|
|
|
g_object_unref (model);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clutter_model_set_column_type (model, i, type);
|
|
|
|
|
clutter_model_set_column_name (model, i, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
va_end (args);
|
|
|
|
|
|
|
|
|
|
return model;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-01-09 14:34:24 +00:00
|
|
|
|
* clutter_list_model_newv:
|
2008-01-09 14:18:53 +00:00
|
|
|
|
* @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
|
|
|
|
|
*
|
2008-01-09 14:34:24 +00:00
|
|
|
|
* Non-vararg version of clutter_list_model_new(). This function is
|
2008-01-09 14:18:53 +00:00
|
|
|
|
* useful for language bindings.
|
|
|
|
|
*
|
|
|
|
|
* Return value: a new default #ClutterModel
|
|
|
|
|
*
|
|
|
|
|
* Since: 0.6
|
|
|
|
|
*/
|
|
|
|
|
ClutterModel *
|
2008-01-09 14:34:24 +00:00
|
|
|
|
clutter_list_model_newv (guint n_columns,
|
|
|
|
|
GType *types,
|
|
|
|
|
const gchar * const names[])
|
2008-01-09 14:18:53 +00:00
|
|
|
|
{
|
|
|
|
|
ClutterModel *model;
|
|
|
|
|
gint i;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (n_columns > 0, NULL);
|
|
|
|
|
|
2008-01-09 14:34:24 +00:00
|
|
|
|
model = g_object_new (CLUTTER_TYPE_LIST_MODEL, NULL);
|
2008-01-09 14:18:53 +00:00
|
|
|
|
clutter_model_set_n_columns (model, n_columns, TRUE, TRUE);
|
|
|
|
|
|
|
|
|
|
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]));
|
|
|
|
|
g_object_unref (model);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clutter_model_set_column_type (model, i, types[i]);
|
|
|
|
|
clutter_model_set_column_name (model, i, names[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return model;
|
|
|
|
|
}
|