[list-model] Make ClutterListModel subclassable

ClutterListModel has been added as a terminal class in case we
decided to change API or implementation.

Apparently, it's a lot more resilient than we expected -- or far
too few are using it and reporting bugs. Once common issue, though,
is that it cannot be subclassed, hence it's fairly limited in its
usage.

In the hope that more developers will start using it, here's a
patch that makes ListModel a fully subclassable object.

May whatever god you believe in have mercy on your eventual soul.
This commit is contained in:
Emmanuele Bassi 2009-02-14 11:31:00 +00:00
parent f17437124e
commit 0ac6d6637e
2 changed files with 67 additions and 37 deletions

View File

@ -34,9 +34,6 @@
* values for each row, so it's optimized for insertion and look up * values for each row, so it's optimized for insertion and look up
* in sorted lists. * in sorted lists.
* *
* #ClutterListModel is a terminal class: it cannot be subclassed,
* only instantiated.
*
* #ClutterListModel is available since Clutter 0.6 * #ClutterListModel is available since Clutter 0.6
*/ */
@ -76,27 +73,13 @@
CLUTTER_TYPE_LIST_MODEL_ITER, \ CLUTTER_TYPE_LIST_MODEL_ITER, \
ClutterListModelIterClass)) 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 _ClutterListModelIter ClutterListModelIter;
typedef struct _ClutterModelIterClass ClutterListModelIterClass; typedef struct _ClutterModelIterClass ClutterListModelIterClass;
typedef struct _ClutterModelClass ClutterListModelClass; #define CLUTTER_LIST_MODEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_LIST_MODEL, ClutterListModelPrivate))
struct _ClutterListModel struct _ClutterListModelPrivate
{ {
ClutterModel parent_instance;
GSequence *sequence; GSequence *sequence;
}; };
@ -229,6 +212,7 @@ clutter_list_model_iter_is_first (ClutterModelIter *iter)
ClutterListModelIter *iter_default; ClutterListModelIter *iter_default;
ClutterModel *model; ClutterModel *model;
ClutterModelIter *temp_iter; ClutterModelIter *temp_iter;
GSequence *sequence;
GSequenceIter *begin, *end; GSequenceIter *begin, *end;
guint row; guint row;
@ -238,7 +222,9 @@ clutter_list_model_iter_is_first (ClutterModelIter *iter)
model = clutter_model_iter_get_model (iter); model = clutter_model_iter_get_model (iter);
row = clutter_model_iter_get_row (iter); row = clutter_model_iter_get_row (iter);
begin = g_sequence_get_begin_iter (CLUTTER_LIST_MODEL (model)->sequence); sequence = CLUTTER_LIST_MODEL (model)->priv->sequence;
begin = g_sequence_get_begin_iter (sequence);
end = iter_default->seq_iter; end = iter_default->seq_iter;
temp_iter = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER, temp_iter = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
@ -276,6 +262,7 @@ clutter_list_model_iter_is_last (ClutterModelIter *iter)
ClutterListModelIter *iter_default; ClutterListModelIter *iter_default;
ClutterModelIter *temp_iter; ClutterModelIter *temp_iter;
ClutterModel *model; ClutterModel *model;
GSequence *sequence;
GSequenceIter *begin, *end; GSequenceIter *begin, *end;
guint row; guint row;
@ -288,7 +275,9 @@ clutter_list_model_iter_is_last (ClutterModelIter *iter)
model = clutter_model_iter_get_model (iter); model = clutter_model_iter_get_model (iter);
row = clutter_model_iter_get_row (iter); row = clutter_model_iter_get_row (iter);
begin = g_sequence_get_end_iter (CLUTTER_LIST_MODEL (model)->sequence); sequence = CLUTTER_LIST_MODEL (model)->priv->sequence;
begin = g_sequence_get_end_iter (sequence);
begin = g_sequence_iter_prev (begin); begin = g_sequence_iter_prev (begin);
end = iter_default->seq_iter; end = iter_default->seq_iter;
@ -476,16 +465,17 @@ clutter_list_model_get_iter_at_row (ClutterModel *model,
guint row) guint row)
{ {
ClutterListModel *model_default = CLUTTER_LIST_MODEL (model); ClutterListModel *model_default = CLUTTER_LIST_MODEL (model);
GSequence *sequence = model_default->priv->sequence;
ClutterListModelIter *retval; ClutterListModelIter *retval;
if (row >= g_sequence_get_length (model_default->sequence)) if (row >= g_sequence_get_length (sequence))
return NULL; return NULL;
retval = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER, retval = g_object_new (CLUTTER_TYPE_LIST_MODEL_ITER,
"model", model, "model", model,
"row", row, "row", row,
NULL); NULL);
retval->seq_iter = g_sequence_get_iter_at_pos (model_default->sequence, row); retval->seq_iter = g_sequence_get_iter_at_pos (sequence, row);
return CLUTTER_MODEL_ITER (retval); return CLUTTER_MODEL_ITER (retval);
} }
@ -495,6 +485,7 @@ clutter_list_model_insert_row (ClutterModel *model,
gint index_) gint index_)
{ {
ClutterListModel *model_default = CLUTTER_LIST_MODEL (model); ClutterListModel *model_default = CLUTTER_LIST_MODEL (model);
GSequence *sequence = model_default->priv->sequence;
ClutterListModelIter *retval; ClutterListModelIter *retval;
guint n_columns, i, pos; guint n_columns, i, pos;
GValueArray *array; GValueArray *array;
@ -515,17 +506,17 @@ clutter_list_model_insert_row (ClutterModel *model,
if (index_ < 0) if (index_ < 0)
{ {
seq_iter = g_sequence_append (model_default->sequence, array); seq_iter = g_sequence_append (sequence, array);
pos = g_sequence_get_length (model_default->sequence); pos = g_sequence_get_length (sequence);
} }
else if (index_ == 0) else if (index_ == 0)
{ {
seq_iter = g_sequence_prepend (model_default->sequence, array); seq_iter = g_sequence_prepend (sequence, array);
pos = 0; pos = 0;
} }
else else
{ {
seq_iter = g_sequence_get_iter_at_pos (model_default->sequence, index_); seq_iter = g_sequence_get_iter_at_pos (sequence, index_);
seq_iter = g_sequence_insert_before (seq_iter, array); seq_iter = g_sequence_insert_before (seq_iter, array);
pos = index_; pos = index_;
} }
@ -544,10 +535,11 @@ clutter_list_model_remove_row (ClutterModel *model,
guint row) guint row)
{ {
ClutterListModel *model_default = CLUTTER_LIST_MODEL (model); ClutterListModel *model_default = CLUTTER_LIST_MODEL (model);
GSequence *sequence = model_default->priv->sequence;
GSequenceIter *seq_iter; GSequenceIter *seq_iter;
guint pos = 0; guint pos = 0;
seq_iter = g_sequence_get_begin_iter (model_default->sequence); seq_iter = g_sequence_get_begin_iter (sequence);
while (!g_sequence_iter_is_end (seq_iter)) while (!g_sequence_iter_is_end (seq_iter))
{ {
if (clutter_model_filter_row (model, pos)) if (clutter_model_filter_row (model, pos))
@ -587,7 +579,7 @@ clutter_list_model_get_n_rows (ClutterModel *model)
{ {
ClutterListModel *model_default = CLUTTER_LIST_MODEL (model); ClutterListModel *model_default = CLUTTER_LIST_MODEL (model);
return g_sequence_get_length (model_default->sequence); return g_sequence_get_length (model_default->priv->sequence);
} }
typedef struct typedef struct
@ -625,7 +617,7 @@ clutter_list_model_resort (ClutterModel *model,
sort_closure.func = func; sort_closure.func = func;
sort_closure.data = data; sort_closure.data = data;
g_sequence_sort (CLUTTER_LIST_MODEL (model)->sequence, g_sequence_sort (CLUTTER_LIST_MODEL (model)->priv->sequence,
sort_model_default, sort_model_default,
&sort_closure); &sort_closure);
} }
@ -650,9 +642,10 @@ static void
clutter_list_model_finalize (GObject *gobject) clutter_list_model_finalize (GObject *gobject)
{ {
ClutterListModel *model = CLUTTER_LIST_MODEL (gobject); ClutterListModel *model = CLUTTER_LIST_MODEL (gobject);
GSequence *sequence = model->priv->sequence;
GSequenceIter *iter; GSequenceIter *iter;
iter = g_sequence_get_begin_iter (model->sequence); iter = g_sequence_get_begin_iter (sequence);
while (!g_sequence_iter_is_end (iter)) while (!g_sequence_iter_is_end (iter))
{ {
GValueArray *value_array = g_sequence_get (iter); GValueArray *value_array = g_sequence_get (iter);
@ -660,7 +653,7 @@ clutter_list_model_finalize (GObject *gobject)
g_value_array_free (value_array); g_value_array_free (value_array);
iter = g_sequence_iter_next (iter); iter = g_sequence_iter_next (iter);
} }
g_sequence_free (model->sequence); g_sequence_free (sequence);
G_OBJECT_CLASS (clutter_list_model_parent_class)->finalize (gobject); G_OBJECT_CLASS (clutter_list_model_parent_class)->finalize (gobject);
} }
@ -671,6 +664,8 @@ clutter_list_model_class_init (ClutterListModelClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterModelClass *model_class = CLUTTER_MODEL_CLASS (klass); ClutterModelClass *model_class = CLUTTER_MODEL_CLASS (klass);
g_type_class_add_private (klass, sizeof (ClutterListModelPrivate));
gobject_class->finalize = clutter_list_model_finalize; gobject_class->finalize = clutter_list_model_finalize;
model_class->get_n_rows = clutter_list_model_get_n_rows; model_class->get_n_rows = clutter_list_model_get_n_rows;
@ -685,7 +680,9 @@ clutter_list_model_class_init (ClutterListModelClass *klass)
static void static void
clutter_list_model_init (ClutterListModel *model) clutter_list_model_init (ClutterListModel *model)
{ {
model->sequence = g_sequence_new (NULL); model->priv = CLUTTER_LIST_MODEL_GET_PRIVATE (model);
model->priv->sequence = g_sequence_new (NULL);
} }
/** /**

View File

@ -36,11 +36,44 @@
G_BEGIN_DECLS G_BEGIN_DECLS
#define CLUTTER_TYPE_LIST_MODEL (clutter_list_model_get_type ()) #define CLUTTER_TYPE_LIST_MODEL (clutter_list_model_get_type ())
#define CLUTTER_LIST_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_LIST_MODEL, ClutterListModel)) #define CLUTTER_LIST_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_LIST_MODEL, ClutterListModel))
#define CLUTTER_IS_LIST_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_LIST_MODEL)) #define CLUTTER_IS_LIST_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_LIST_MODEL))
#define CLUTTER_LIST_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_LIST_MODEL, ClutterListModeClass))
#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, ClutterListModeClass))
typedef struct _ClutterListModel ClutterListModel; typedef struct _ClutterListModel ClutterListModel;
typedef struct _ClutterListModelPrivate ClutterListModelPrivate;
typedef struct _ClutterListModelClass ClutterListModelClass;
/**
* ClutterListModel:
*
* The #ClutterListModel struct contains only private data.
*
* Since: 0.6
*/
struct _ClutterListModel
{
/*< private >*/
ClutterModel parent_instance;
ClutterListModelPrivate *priv;
};
/**
* ClutterListModelClass:
*
* The #ClutterListModelClass struct contains only private data.
*
* Since: 0.6
*/
struct _ClutterListModelClass
{
/*< private >*/
ClutterModelClass parent_class;
};
GType clutter_list_model_get_type (void) G_GNUC_CONST; GType clutter_list_model_get_type (void) G_GNUC_CONST;