[gnome-keyring: 2/12] gcr: Add support for GcrCollectionModel to have child rows
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-keyring: 2/12] gcr: Add support for GcrCollectionModel to have child rows
- Date: Mon, 19 Sep 2011 07:38:46 +0000 (UTC)
commit 77bec21769670365a25004087e2eb56955b20249
Author: Stef Walter <stefw collabora co uk>
Date: Fri Sep 2 21:10:06 2011 +0200
gcr: Add support for GcrCollectionModel to have child rows
* A child row is represented by an object that implements the
GcrCollection
gcr/gcr-collection-model.c | 569 +++++++++++++++++++++++++++-------------
gcr/gcr-collection-model.h | 7 -
gcr/tests/frob-tree-selector.c | 114 ++++++++-
3 files changed, 498 insertions(+), 192 deletions(-)
---
diff --git a/gcr/gcr-collection-model.c b/gcr/gcr-collection-model.c
index 2ffb89d..16d15d0 100644
--- a/gcr/gcr-collection-model.c
+++ b/gcr/gcr-collection-model.c
@@ -76,6 +76,12 @@ enum {
};
typedef struct {
+ GObject *object;
+ GSequenceIter *parent;
+ GSequence *children;
+} GcrCollectionRow;
+
+typedef struct {
GtkTreeIterCompareFunc sort_func;
gpointer user_data;
GDestroyNotify destroy_func;
@@ -92,8 +98,8 @@ typedef struct _GcrCollectionColumn {
struct _GcrCollectionModelPrivate {
GcrCollection *collection;
GHashTable *selected;
- GSequence *object_sequence;
- GHashTable *object_to_sequence;
+ GSequence *root_sequence;
+ GHashTable *object_to_seq;
const GcrColumn *columns;
guint n_columns;
@@ -237,15 +243,17 @@ order_sequence_by_closure (gconstpointer a,
{
GcrCollectionModel *self = GCR_COLLECTION_MODEL (user_data);
GcrCollectionSortClosure *closure = self->pv->order_argument;
+ const GcrCollectionRow *row_a = a;
+ const GcrCollectionRow *row_b = b;
GtkTreeIter iter_a;
GtkTreeIter iter_b;
g_assert (closure);
g_assert (closure->sort_func);
- if (!gcr_collection_model_iter_for_object (self, (GObject *)a, &iter_a))
+ if (!gcr_collection_model_iter_for_object (self, row_a->object, &iter_a))
g_return_val_if_reached (0);
- if (!gcr_collection_model_iter_for_object (self, (GObject *)b, &iter_b))
+ if (!gcr_collection_model_iter_for_object (self, row_b->object, &iter_b))
g_return_val_if_reached (0);
return (closure->sort_func) (GTK_TREE_MODEL (self),
@@ -265,7 +273,9 @@ order_sequence_as_unsorted (gconstpointer a,
gconstpointer b,
gpointer user_data)
{
- return GPOINTER_TO_INT (a) - GPOINTER_TO_INT (b);
+ const GcrCollectionRow *row_a = a;
+ const GcrCollectionRow *row_b = b;
+ return GPOINTER_TO_INT (row_a->object) - GPOINTER_TO_INT (row_b->object);
}
static gint
@@ -273,7 +283,22 @@ order_sequence_as_unsorted_reverse (gconstpointer a,
gconstpointer b,
gpointer user_data)
{
- return GPOINTER_TO_INT (b) - GPOINTER_TO_INT (a);
+ const GcrCollectionRow *row_a = a;
+ const GcrCollectionRow *row_b = b;
+ return GPOINTER_TO_INT (row_b->object) - GPOINTER_TO_INT (row_a->object);
+}
+
+static void
+lookup_object_property (GObject *object,
+ const gchar *property_name,
+ GValue *value)
+{
+ if (g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name))
+ g_object_get_property (object, property_name, value);
+
+ /* Other types have sane defaults */
+ else if (G_VALUE_TYPE (value) == G_TYPE_STRING)
+ g_value_set_string (value, "");
}
static gint
@@ -281,6 +306,8 @@ order_sequence_by_property (gconstpointer a,
gconstpointer b,
gpointer user_data)
{
+ const GcrCollectionRow *row_a = a;
+ const GcrCollectionRow *row_b = b;
GcrCollectionModel *self = GCR_COLLECTION_MODEL (user_data);
const GcrColumn *column = self->pv->order_argument;
GValue value_a = { 0, };
@@ -293,9 +320,9 @@ order_sequence_by_property (gconstpointer a,
/* Sort according to property values */
column = &self->pv->columns[self->pv->sort_column_id];
g_value_init (&value_a, column->property_type);
- g_object_get_property ((GObject *)a, column->property_name, &value_a);
+ lookup_object_property (row_a->object, column->property_name, &value_a);
g_value_init (&value_b, column->property_type);
- g_object_get_property ((GObject *)b, column->property_name, &value_b);
+ lookup_object_property (row_b->object, column->property_name, &value_b);
compare = lookup_compare_func (column->property_type);
g_assert (compare != NULL);
@@ -322,61 +349,68 @@ selected_hash_table_new (void)
return g_hash_table_new (g_direct_hash, g_direct_equal);
}
-static gint
-index_for_iter (GcrCollectionModel *self, const GtkTreeIter *iter)
+static gboolean
+sequence_iter_to_tree (GcrCollectionModel *self,
+ GSequenceIter *seq,
+ GtkTreeIter *iter)
{
- GSequenceIter *seq;
- gint index;
+ GcrCollectionRow *row;
- g_return_val_if_fail (iter, -1);
- g_return_val_if_fail (iter->stamp == COLLECTION_MODEL_STAMP, -1);
+ g_return_val_if_fail (seq != NULL, FALSE);
- seq = iter->user_data2;
- g_return_val_if_fail (g_sequence_iter_get_sequence (seq) ==
- self->pv->object_sequence, -1);
-
- index = g_sequence_iter_get_position (seq);
- g_assert (index >= 0 && index < g_sequence_get_length (self->pv->object_sequence));
- return index;
-}
-
-static gboolean
-iter_for_seq (GcrCollectionModel *self, GSequenceIter *seq, GtkTreeIter *iter)
-{
- GObject *object;
+ if (g_sequence_iter_is_end (seq))
+ return FALSE;
- object = g_sequence_get (seq);
- g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
+ row = g_sequence_get (seq);
+ g_return_val_if_fail (row != NULL && G_IS_OBJECT (row->object), FALSE);
memset (iter, 0, sizeof (*iter));
iter->stamp = COLLECTION_MODEL_STAMP;
- iter->user_data = object;
+ iter->user_data = row->object;
iter->user_data2 = seq;
return TRUE;
}
-static gboolean
-iter_for_index (GcrCollectionModel *self, gint index, GtkTreeIter *iter)
+static GSequenceIter *
+sequence_iter_for_tree (GcrCollectionModel *self,
+ GtkTreeIter *iter)
{
- GSequenceIter *seq;
+ g_return_val_if_fail (iter != NULL, NULL);
+ g_return_val_if_fail (iter->stamp == COLLECTION_MODEL_STAMP, NULL);
+ return iter->user_data2;
+}
- if (index < 0 || index >= g_sequence_get_length (self->pv->object_sequence))
- return FALSE;
+static GtkTreePath *
+sequence_iter_to_path (GcrCollectionModel *self,
+ GSequenceIter *seq)
+{
+ GcrCollectionRow *row;
+ GtkTreePath *path;
- seq = g_sequence_get_iter_at_pos (self->pv->object_sequence, index);
- return iter_for_seq (self, seq, iter);
+ path = gtk_tree_path_new ();
+ while (seq) {
+ gtk_tree_path_prepend_index (path, g_sequence_iter_get_position (seq));
+ row = g_sequence_get (seq);
+ seq = row->parent;
+ }
+ return path;
}
-static gint
-index_for_object (GcrCollectionModel *self, GObject *object)
+static GSequence *
+child_sequence_for_tree (GcrCollectionModel *self,
+ GtkTreeIter *iter)
{
+ GcrCollectionRow *row;
GSequenceIter *seq;
- seq = g_hash_table_lookup (self->pv->object_to_sequence, object);
- if (seq == NULL)
- return -1;
-
- return g_sequence_iter_get_position (seq);
+ if (iter == NULL) {
+ return self->pv->root_sequence;
+ } else {
+ seq = sequence_iter_for_tree (self, iter);
+ g_return_val_if_fail (seq != NULL, NULL);
+ row = g_sequence_get (seq);
+ return row->children;
+ }
}
static void
@@ -415,77 +449,196 @@ on_object_gone (gpointer unused, GObject *was_object)
"was destroyed before it was removed from the collection");
}
+static void on_collection_added (GcrCollection *collection,
+ GObject *object,
+ gpointer user_data);
+
+static void on_collection_removed (GcrCollection *collection,
+ GObject *object,
+ gpointer user_data);
+
+static void add_object_to_sequence (GcrCollectionModel *self,
+ GSequence *sequence,
+ GSequenceIter *parent,
+ GObject *object,
+ gboolean emit);
+
+static void remove_object_from_sequence (GcrCollectionModel *self,
+ GSequence *sequence,
+ GSequenceIter *seq,
+ GObject *object,
+ gboolean emit);
+
+static void
+add_children_to_sequence (GcrCollectionModel *self,
+ GSequence *sequence,
+ GSequenceIter *parent,
+ GcrCollection *collection,
+ gboolean emit)
+{
+ GList *children, *l;
+
+ children = gcr_collection_get_objects (collection);
+ for (l = children; l; l = g_list_next (l))
+ add_object_to_sequence (self, sequence, parent, l->data, emit);
+ g_list_free (children);
+
+ /* Now listen in for any changes */
+ g_signal_connect_after (collection, "added", G_CALLBACK (on_collection_added), self);
+ g_signal_connect_after (collection, "removed", G_CALLBACK (on_collection_removed), self);
+}
+
static void
-on_collection_added (GcrCollection *collection, GObject *object, GcrCollectionModel *self)
+add_object_to_sequence (GcrCollectionModel *self,
+ GSequence *sequence,
+ GSequenceIter *parent,
+ GObject *object,
+ gboolean emit)
{
+ GcrCollectionRow *row;
GSequenceIter *seq;
GtkTreeIter iter;
GtkTreePath *path;
- g_return_if_fail (GCR_COLLECTION_MODEL (self));
- g_return_if_fail (G_IS_OBJECT (object));
-
g_assert (GCR_IS_COLLECTION_MODEL (self));
g_assert (G_IS_OBJECT (object));
g_assert (self->pv->order_current);
- seq = g_sequence_insert_sorted (self->pv->object_sequence, object,
- self->pv->order_current, self);
- g_hash_table_insert (self->pv->object_to_sequence, object, seq);
+ if (g_hash_table_lookup (self->pv->object_to_seq, object)) {
+ g_warning ("object was already added to the GcrCollectionModel. Perhaps "
+ "a loop exists in a tree structure?");
+ return;
+ }
+
+ row = g_slice_new0 (GcrCollectionRow);
+ row->object = object;
+ row->parent = parent;
+ row->children = NULL;
+
+ seq = g_sequence_insert_sorted (sequence, row, self->pv->order_current, self);
+ g_hash_table_insert (self->pv->object_to_seq, object, seq);
g_object_weak_ref (G_OBJECT (object), (GWeakNotify)on_object_gone, self);
g_signal_connect (object, "notify", G_CALLBACK (on_object_notify), self);
- /* Fire signal for this added row */
- if (!iter_for_seq (self, seq, &iter))
- g_assert_not_reached ();
-
- path = gtk_tree_path_new_from_indices (g_sequence_iter_get_position (seq), -1);
+ if (emit) {
+ if (!sequence_iter_to_tree (self, seq, &iter))
+ g_assert_not_reached ();
+ path = sequence_iter_to_path (self, seq);
+ g_assert (path != NULL);
+ gtk_tree_model_row_inserted (GTK_TREE_MODEL (self), path, &iter);
+ gtk_tree_path_free (path);
+ }
- gtk_tree_model_row_inserted (GTK_TREE_MODEL (self), path, &iter);
- gtk_tree_path_free (path);
+ if (GCR_IS_COLLECTION (object)) {
+ row->children = g_sequence_new (NULL);
+ add_children_to_sequence (self, row->children, seq,
+ GCR_COLLECTION (object), emit);
+ }
}
static void
-disconnect_object (GcrCollectionModel *self, GObject *object)
+on_collection_added (GcrCollection *collection,
+ GObject *object,
+ gpointer user_data)
{
- g_object_weak_unref (G_OBJECT (object), on_object_gone, self);
- g_signal_handlers_disconnect_by_func (object, on_object_notify, self);
+ GcrCollectionModel *self = GCR_COLLECTION_MODEL (user_data);
+ GSequence *sequence;
+ GSequenceIter *parent;
+ GcrCollectionRow *row;
+
+ if (collection == self->pv->collection) {
+ sequence = self->pv->root_sequence;
+ parent = NULL;
+ } else {
+ parent = g_hash_table_lookup (self->pv->object_to_seq, G_OBJECT (collection));
+ row = g_sequence_get (parent);
+ g_assert (row->children);
+ sequence = row->children;
+ }
+
+ add_object_to_sequence (self, sequence, parent, object, TRUE);
}
static void
-on_collection_removed (GcrCollection *collection, GObject *object,
- GcrCollectionModel *self)
+remove_children_from_sequence (GcrCollectionModel *self,
+ GSequence *sequence,
+ GcrCollection *collection,
+ gboolean emit)
{
- GtkTreePath *path;
- GSequenceIter *seq;
+ GSequenceIter *seq, *next;
+ GcrCollectionRow *row;
- g_return_if_fail (GCR_COLLECTION_MODEL (self));
- g_return_if_fail (G_IS_OBJECT (object));
+ g_signal_handlers_disconnect_by_func (collection, on_collection_added, self);
+ g_signal_handlers_disconnect_by_func (collection, on_collection_removed, self);
- seq = g_hash_table_lookup (self->pv->object_to_sequence, object);
- g_return_if_fail (seq != NULL);
+ for (seq = g_sequence_get_begin_iter (sequence);
+ !g_sequence_iter_is_end (seq); seq = next) {
+ next = g_sequence_iter_next (seq);
+ row = g_sequence_get (seq);
+ remove_object_from_sequence (self, sequence, seq, row->object, emit);
+ }
+}
- path = gtk_tree_path_new_from_indices (g_sequence_iter_get_position (seq), -1);
+static void
+remove_object_from_sequence (GcrCollectionModel *self,
+ GSequence *sequence,
+ GSequenceIter *seq,
+ GObject *object,
+ gboolean emit)
+{
+ GcrCollectionRow *row;
+ GtkTreePath *path = NULL;
+
+ if (emit) {
+ path = sequence_iter_to_path (self, seq);
+ g_assert (path != NULL);
+ }
- disconnect_object (self, object);
+ row = g_sequence_get (seq);
+ g_assert (row->object == object);
+
+ g_object_weak_unref (object, on_object_gone, self);
+ g_signal_handlers_disconnect_by_func (object, on_object_notify, self);
+
+ if (row->children) {
+ g_assert (GCR_IS_COLLECTION (object));
+ remove_children_from_sequence (self, row->children, GCR_COLLECTION (object), emit);
+ g_assert (g_sequence_get_length (row->children) == 0);
+ g_sequence_free (row->children);
+ row->children = NULL;
+ }
g_hash_table_remove (self->pv->selected, object);
- g_hash_table_remove (self->pv->object_to_sequence, object);
+ if (!g_hash_table_remove (self->pv->object_to_seq, object))
+ g_assert_not_reached ();
+
g_sequence_remove (seq);
+ g_slice_free (GcrCollectionRow, row);
/* Fire signal for this removed row */
- gtk_tree_model_row_deleted (GTK_TREE_MODEL (self), path);
- gtk_tree_path_free (path);
+ if (path != NULL) {
+ gtk_tree_model_row_deleted (GTK_TREE_MODEL (self), path);
+ gtk_tree_path_free (path);
+ }
+
}
static void
-populate_model (GcrCollectionModel *self)
+on_collection_removed (GcrCollection *collection,
+ GObject *object,
+ gpointer user_data)
{
- GList *objects, *l;
- objects = gcr_collection_get_objects (self->pv->collection);
- for (l = objects; l; l = g_list_next (l))
- on_collection_added (self->pv->collection, G_OBJECT (l->data), self);
- g_list_free (objects);
+ GcrCollectionModel *self = GCR_COLLECTION_MODEL (user_data);
+ GSequenceIter *seq;
+ GSequence *sequence;
+
+ seq = g_hash_table_lookup (self->pv->object_to_seq, object);
+ g_return_if_fail (seq != NULL);
+
+ sequence = g_sequence_iter_get_sequence (seq);
+ g_assert (sequence != NULL);
+
+ remove_object_from_sequence (self, sequence, seq, object, TRUE);
}
static void
@@ -514,7 +667,8 @@ gcr_collection_model_real_get_n_columns (GtkTreeModel *model)
}
static GType
-gcr_collection_model_real_get_column_type (GtkTreeModel *model, gint column_id)
+gcr_collection_model_real_get_column_type (GtkTreeModel *model,
+ gint column_id)
{
GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
g_return_val_if_fail (column_id >= 0 && column_id <= self->pv->n_columns, 0);
@@ -527,43 +681,64 @@ gcr_collection_model_real_get_column_type (GtkTreeModel *model, gint column_id)
}
static gboolean
-gcr_collection_model_real_get_iter (GtkTreeModel *model, GtkTreeIter *iter, GtkTreePath *path)
+gcr_collection_model_real_get_iter (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
{
GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
const gint *indices;
+ GSequence *sequence;
+ GSequenceIter *seq;
+ GcrCollectionRow *row;
gint count;
+ gint i;
- count = gtk_tree_path_get_depth (path);
- if (count != 1)
+ sequence = self->pv->root_sequence;
+ seq = NULL;
+
+ indices = gtk_tree_path_get_indices_with_depth (path, &count);
+ if (count == 0)
return FALSE;
- indices = gtk_tree_path_get_indices (path);
- return iter_for_index (self, indices[0], iter);
+ for (i = 0; i < count; i++) {
+ if (!sequence)
+ return FALSE;
+ seq = g_sequence_get_iter_at_pos (sequence, indices[i]);
+ if (g_sequence_iter_is_end (seq))
+ return FALSE;
+ row = g_sequence_get (seq);
+ sequence = row->children;
+ }
+
+ return sequence_iter_to_tree (self, seq, iter);
}
static GtkTreePath*
-gcr_collection_model_real_get_path (GtkTreeModel *model, GtkTreeIter *iter)
+gcr_collection_model_real_get_path (GtkTreeModel *model,
+ GtkTreeIter *iter)
{
GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
- GtkTreePath *path;
- gint index;
+ GSequenceIter *seq;
- index = index_for_iter (self, iter);
- g_return_val_if_fail (index >= 0, NULL);
+ if (iter == NULL)
+ return gtk_tree_path_new ();
- path = gtk_tree_path_new ();
- gtk_tree_path_prepend_index (path, index);
- return path;
+ seq = sequence_iter_for_tree (self, iter);
+ g_return_val_if_fail (seq != NULL, NULL);
+ return sequence_iter_to_path (self, seq);
}
static void
-gcr_collection_model_real_get_value (GtkTreeModel *model, GtkTreeIter *iter,
- gint column_id, GValue *value)
+gcr_collection_model_real_get_value (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gint column_id,
+ GValue *value)
{
GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
GObject *object;
GValue original;
const GcrColumn *column;
+ GParamSpec *spec;
object = gcr_collection_model_object_for_iter (self, iter);
g_return_if_fail (G_IS_OBJECT (object));
@@ -581,93 +756,122 @@ gcr_collection_model_real_get_value (GtkTreeModel *model, GtkTreeIter *iter,
g_assert (column->property_name);
g_value_init (value, column->column_type);
- /* A transformer is specified, or mismatched types */
- if (column->transformer || column->column_type != column->property_type) {
- memset (&original, 0, sizeof (original));
- g_value_init (&original, column->property_type);
- g_object_get_property (object, column->property_name, &original);
+ /* Lookup the property on the object */
+ spec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), column->property_name);
+ if (spec != NULL) {
+ /* A transformer is specified, or mismatched types */
+ if (column->transformer || column->column_type != column->property_type) {
+ memset (&original, 0, sizeof (original));
+ g_value_init (&original, column->property_type);
+ g_object_get_property (object, column->property_name, &original);
+
+ if (column->transformer) {
+ (column->transformer) (&original, value);
+ } else {
+ g_warning ("%s property of %s class was of type %s instead of type %s"
+ " and cannot be converted due to lack of transformer",
+ column->property_name, G_OBJECT_TYPE_NAME (object),
+ g_type_name (column->property_type),
+ g_type_name (column->column_type));
+ spec = NULL;
+ }
- if (column->transformer) {
- (column->transformer) (&original, value);
+ /* Simple, no transformation necessary */
} else {
- g_warning ("%s property of %s class was of type %s instead of type %s"
- " and cannot be converted due to lack of transformer",
- column->property_name, G_OBJECT_TYPE_NAME (object),
- g_type_name (column->property_type),
- g_type_name (column->column_type));
+ g_object_get_property (object, column->property_name, value);
}
+ }
- /* Simple, no transformation necessary */
- } else {
- g_object_get_property (object, column->property_name, value);
+ if (spec == NULL) {
+
+ /* All the number types have sane defaults */
+ if (column->column_type == G_TYPE_STRING)
+ g_value_set_string (value, "");
}
}
static gboolean
-gcr_collection_model_real_iter_next (GtkTreeModel *model, GtkTreeIter *iter)
+gcr_collection_model_real_iter_next (GtkTreeModel *model,
+ GtkTreeIter *iter)
{
GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
- gint index;
-
- index = index_for_iter (self, iter);
- g_return_val_if_fail (index >= 0, FALSE);
-
- return iter_for_index (self, index + 1, iter);
+ GSequenceIter *seq = sequence_iter_for_tree (self, iter);
+ g_return_val_if_fail (seq != NULL, FALSE);
+ return sequence_iter_to_tree (self, g_sequence_iter_next (seq), iter);
}
static gboolean
-gcr_collection_model_real_iter_children (GtkTreeModel *model, GtkTreeIter *iter, GtkTreeIter *parent)
+gcr_collection_model_real_iter_children (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
{
GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
-
- if (parent != NULL)
- return FALSE;
-
- return iter_for_index (self, 0, iter);
+ GSequence *sequence = child_sequence_for_tree (self, parent);
+ return sequence && sequence_iter_to_tree (self, g_sequence_get_begin_iter (sequence), iter);
}
static gboolean
-gcr_collection_model_real_iter_has_child (GtkTreeModel *model, GtkTreeIter *iter)
+gcr_collection_model_real_iter_has_child (GtkTreeModel *model,
+ GtkTreeIter *iter)
{
GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
- if (iter == NULL)
- return !g_sequence_iter_is_end (g_sequence_get_begin_iter (self->pv->object_sequence));
- return FALSE;
+ GSequence *sequence = child_sequence_for_tree (self, iter);
+ return sequence && !g_sequence_iter_is_end (g_sequence_get_begin_iter (sequence));
}
static gint
-gcr_collection_model_real_iter_n_children (GtkTreeModel *model, GtkTreeIter *iter)
+gcr_collection_model_real_iter_n_children (GtkTreeModel *model,
+ GtkTreeIter *iter)
{
GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
- if (iter == NULL)
- return g_sequence_get_length (self->pv->object_sequence);
- return 0;
+ GSequence *sequence = child_sequence_for_tree (self, iter);
+ return sequence ? g_sequence_get_length (sequence) : 0;
}
static gboolean
-gcr_collection_model_real_iter_nth_child (GtkTreeModel *model, GtkTreeIter *iter,
- GtkTreeIter *parent, gint n)
+gcr_collection_model_real_iter_nth_child (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent,
+ gint n)
{
GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
- if (parent != NULL)
+ GSequence *sequence;
+ GSequenceIter *seq;
+
+ sequence = child_sequence_for_tree (self, parent);
+ if (sequence == NULL)
return FALSE;
- return iter_for_index (self, n, iter);
+ seq = g_sequence_get_iter_at_pos (sequence, n);
+ return sequence_iter_to_tree (self, seq, iter);
}
static gboolean
-gcr_collection_model_real_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child)
+gcr_collection_model_real_iter_parent (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreeIter *child)
{
- return FALSE;
+ GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
+ GSequenceIter *seq;
+ GcrCollectionRow *row;
+
+ seq = sequence_iter_for_tree (self, child);
+ g_return_val_if_fail (seq != NULL, FALSE);
+ row = g_sequence_get (seq);
+ if (row->parent == NULL)
+ return FALSE;
+ return sequence_iter_to_tree (self, row->parent, iter);
}
static void
-gcr_collection_model_real_ref_node (GtkTreeModel *model, GtkTreeIter *iter)
+gcr_collection_model_real_ref_node (GtkTreeModel *model,
+ GtkTreeIter *iter)
{
/* Nothing to do */
}
static void
-gcr_collection_model_real_unref_node (GtkTreeModel *model, GtkTreeIter *iter)
+gcr_collection_model_real_unref_node (GtkTreeModel *model,
+ GtkTreeIter *iter)
{
/* Nothing to do */
}
@@ -692,29 +896,38 @@ gcr_collection_model_tree_model_init (GtkTreeModelIface *iface)
}
static void
-collection_resort (GcrCollectionModel *self)
+collection_resort_sequence (GcrCollectionModel *self,
+ GSequenceIter *parent,
+ GSequence *sequence)
{
GPtrArray *previous;
- GSequenceIter *seq;
+ GSequenceIter *seq, *next;
gint *new_order;
GtkTreePath *path;
+ GtkTreeIter iter;
+ GcrCollectionRow *row;
gint index;
gint i;
- /* Make note of how things stand */
+ /* Make note of how things stand, and at same time resort all kids */
previous = g_ptr_array_new ();
- for (seq = g_sequence_get_begin_iter (self->pv->object_sequence);
- !g_sequence_iter_is_end (seq); seq = g_sequence_iter_next (seq))
- g_ptr_array_add (previous, g_sequence_get (seq));
+ for (seq = g_sequence_get_begin_iter (sequence);
+ !g_sequence_iter_is_end (seq); seq = next) {
+ next = g_sequence_iter_next (seq);
+ row = g_sequence_get (seq);
+ if (row->children)
+ collection_resort_sequence (self, seq, row->children);
+ g_ptr_array_add (previous, row->object);
+ }
/* Actually perform the sort */
- g_sequence_sort (self->pv->object_sequence, self->pv->order_current, self);
+ g_sequence_sort (sequence, self->pv->order_current, self);
/* Now go through and map out how things changed */
new_order = g_new0 (gint, previous->len);
for (i = 0; i < previous->len; i++) {
- seq = g_hash_table_lookup (self->pv->object_to_sequence,
- previous->pdata[i]);
+ seq = g_hash_table_lookup (self->pv->object_to_seq, previous->pdata[i]);
+ g_assert (seq != NULL);
index = g_sequence_iter_get_position (seq);
g_assert (index >= 0 && index < previous->len);
new_order[index] = i;
@@ -722,8 +935,15 @@ collection_resort (GcrCollectionModel *self)
g_ptr_array_free (previous, TRUE);
- path = gtk_tree_path_new ();
- gtk_tree_model_rows_reordered (GTK_TREE_MODEL (self), path, NULL, new_order);
+ path = sequence_iter_to_path (self, parent);
+ if (parent == NULL) {
+ gtk_tree_model_rows_reordered (GTK_TREE_MODEL (self), path, NULL, new_order);
+ } else {
+ if (!sequence_iter_to_tree (self, parent, &iter))
+ g_assert_not_reached ();
+ gtk_tree_model_rows_reordered (GTK_TREE_MODEL (self), path, &iter, new_order);
+ }
+ gtk_tree_path_free (path);
g_free (new_order);
}
@@ -797,7 +1017,7 @@ gcr_collection_model_set_sort_column_id (GtkTreeSortable *sortable,
argument != self->pv->order_argument) {
self->pv->order_current = func;
self->pv->order_argument = (gpointer)argument;
- collection_resort (self);
+ collection_resort_sequence (self, NULL, self->pv->root_sequence);
}
}
@@ -886,8 +1106,8 @@ gcr_collection_model_init (GcrCollectionModel *self)
{
self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_COLLECTION_MODEL, GcrCollectionModelPrivate);
- self->pv->object_sequence = g_sequence_new (NULL);
- self->pv->object_to_sequence = g_hash_table_new (g_direct_hash, g_direct_equal);
+ self->pv->root_sequence = g_sequence_new (NULL);
+ self->pv->object_to_seq = g_hash_table_new (g_direct_hash, g_direct_equal);
self->pv->sort_column_id = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID;
self->pv->sort_order_type = GTK_SORT_ASCENDING;
self->pv->order_current = order_sequence_as_unsorted;
@@ -904,10 +1124,11 @@ gcr_collection_model_set_property (GObject *object, guint prop_id,
case PROP_COLLECTION:
g_return_if_fail (self->pv->collection == NULL);
self->pv->collection = g_value_dup_object (value);
+
+ /* During construction, so we don't emit anything */
if (self->pv->collection) {
- g_signal_connect_after (self->pv->collection, "added", G_CALLBACK (on_collection_added), self);
- g_signal_connect_after (self->pv->collection, "removed", G_CALLBACK (on_collection_removed), self);
- populate_model (self);
+ add_children_to_sequence (self, self->pv->root_sequence,
+ NULL, self->pv->collection, FALSE);
}
break;
@@ -948,30 +1169,15 @@ static void
gcr_collection_model_dispose (GObject *object)
{
GcrCollectionModel *self = GCR_COLLECTION_MODEL (object);
- GSequenceIter *seq;
- GSequenceIter *next;
/* Disconnect from all rows */
- for (seq = g_sequence_get_begin_iter (self->pv->object_sequence);
- !g_sequence_iter_is_end (seq); seq = next) {
- next = g_sequence_iter_next (seq);
- disconnect_object (self, g_sequence_get (seq));
- g_sequence_remove (seq);
- }
-
- g_hash_table_remove_all (self->pv->object_to_sequence);
-
- /* Disconnect from the collection */
if (self->pv->collection) {
- g_signal_handlers_disconnect_by_func (self->pv->collection, on_collection_added, self);
- g_signal_handlers_disconnect_by_func (self->pv->collection, on_collection_removed, self);
+ remove_children_from_sequence (self, self->pv->root_sequence,
+ self->pv->collection, FALSE);
g_object_unref (self->pv->collection);
self->pv->collection = NULL;
}
- if (self->pv->selected)
- g_hash_table_remove_all (self->pv->selected);
-
G_OBJECT_CLASS (gcr_collection_model_parent_class)->dispose (object);
}
@@ -983,11 +1189,12 @@ gcr_collection_model_finalize (GObject *object)
g_assert (!self->pv->collection);
- g_assert (g_sequence_get_length (self->pv->object_sequence) == 0);
- g_sequence_free (self->pv->object_sequence);
- g_assert (g_hash_table_size (self->pv->object_to_sequence) == 0);
- g_hash_table_destroy (self->pv->object_to_sequence);
+ g_assert (g_sequence_get_length (self->pv->root_sequence) == 0);
+ g_sequence_free (self->pv->root_sequence);
+ g_assert (g_hash_table_size (self->pv->object_to_seq) == 0);
+ g_hash_table_destroy (self->pv->object_to_seq);
+ g_assert (g_hash_table_size (self->pv->selected) == 0);
if (self->pv->selected)
g_hash_table_destroy (self->pv->selected);
self->pv->selected = NULL;
@@ -1153,17 +1360,17 @@ gboolean
gcr_collection_model_iter_for_object (GcrCollectionModel *self, GObject *object,
GtkTreeIter *iter)
{
- gint index;
+ GSequenceIter *seq;
g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), FALSE);
g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
g_return_val_if_fail (iter, FALSE);
- index = index_for_object (self, object);
- if (index < 0)
+ seq = g_hash_table_lookup (self->pv->object_to_seq, object);
+ if (seq == NULL)
return FALSE;
- return iter_for_index (self, index, iter);
+ return sequence_iter_to_tree (self, seq, iter);
}
/**
diff --git a/gcr/gcr-collection-model.h b/gcr/gcr-collection-model.h
index 4cfc293..c8a1775 100644
--- a/gcr/gcr-collection-model.h
+++ b/gcr/gcr-collection-model.h
@@ -60,13 +60,6 @@ GcrCollectionModel* gcr_collection_model_new_full (GcrCollection *c
void gcr_collection_model_set_columns (GcrCollectionModel *self,
const GcrColumn *columns);
-void gcr_collection_model_get_child_property (GcrCollectionModel *self,
- const gchar *property_name);
-
-void gcr_collection_model_set_child_property (GcrCollectionModel *self,
- const gchar *property_name,
- GValueTransform transformer);
-
GObject* gcr_collection_model_object_for_iter (GcrCollectionModel *self,
const GtkTreeIter *iter);
diff --git a/gcr/tests/frob-tree-selector.c b/gcr/tests/frob-tree-selector.c
index d756f3d..313781e 100644
--- a/gcr/tests/frob-tree-selector.c
+++ b/gcr/tests/frob-tree-selector.c
@@ -9,19 +9,125 @@
#include <string.h>
#include <errno.h>
+#define TEST_TYPE_COLLECTION (test_collection_get_type ())
+#define TEST_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_COLLECTION, TestCollection))
+#define TEST_IS_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_COLLECTION))
+
+typedef struct _TestCollection TestCollection;
+typedef struct _TestCollectionClass TestCollectionClass;
+typedef struct _TestCollectionPrivate TestCollectionPrivate;
+
+struct _TestCollection {
+ GcrSimpleCollection parent;
+ gchar *label;
+};
+
+struct _TestCollectionClass {
+ GcrSimpleCollectionClass parent_class;
+};
+
+GType test_collection_get_type (void) G_GNUC_CONST;
+
+enum {
+ PROP_0,
+ PROP_LABEL,
+};
+
+G_DEFINE_TYPE (TestCollection, test_collection, GCR_TYPE_SIMPLE_COLLECTION);
+
+static GHashTable *all_collections = NULL;
+
+static void
+test_collection_init (TestCollection *self)
+{
+
+}
+
+static void
+test_collection_finalize (GObject *obj)
+{
+ TestCollection *self = TEST_COLLECTION (obj);
+ g_free (self->label);
+ g_hash_table_remove (all_collections, self);
+ G_OBJECT_CLASS (test_collection_parent_class)->finalize (obj);
+}
+
+static void
+test_collection_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TestCollection *self = TEST_COLLECTION (obj);
+ switch (prop_id) {
+ case PROP_LABEL:
+ g_value_set_string (value, self->label);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+test_collection_class_init (TestCollectionClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->get_property = test_collection_get_property;
+ gobject_class->finalize = test_collection_finalize;
+
+ g_object_class_install_property (gobject_class, PROP_LABEL,
+ g_param_spec_string ("label", "label", "label", NULL, G_PARAM_READABLE));
+}
+
+static GcrSimpleCollection *
+test_collection_instance (const gchar *label)
+{
+ TestCollection *collection = NULL;
+
+ g_assert (label);
+
+ if (!all_collections) {
+ all_collections = g_hash_table_new (g_str_hash, g_str_equal);
+ } else {
+ collection = g_hash_table_lookup (all_collections, label);
+ if (collection != NULL)
+ return g_object_ref (collection);
+ }
+
+ collection = g_object_new (TEST_TYPE_COLLECTION, NULL);
+ collection->label = g_strdup (label);
+ g_hash_table_insert (all_collections, collection->label, collection);
+ return GCR_SIMPLE_COLLECTION (collection);
+}
+
static void
on_parser_parsed (GcrParser *parser, gpointer user_data)
{
GcrSimpleCollection *collection = user_data;
+ GcrSimpleCollection *testcol;
GcrRenderer *renderer;
+ gchar *group;
renderer = gcr_renderer_create (gcr_parser_get_parsed_label (parser),
gcr_parser_get_parsed_attributes (parser));
+ if (renderer == NULL)
+ return;
- if (renderer) {
- gcr_simple_collection_add (collection, G_OBJECT (renderer));
- g_object_unref (renderer);
- }
+ if (GCR_IS_CERTIFICATE (renderer))
+ group = gcr_certificate_get_subject_part (GCR_CERTIFICATE (renderer), "O");
+ else
+ group = g_strdup (G_OBJECT_TYPE_NAME (renderer));
+
+
+ testcol = test_collection_instance (group);
+ if (!gcr_simple_collection_contains (collection, G_OBJECT (testcol)))
+ gcr_simple_collection_add (collection, G_OBJECT (testcol));
+
+ gcr_simple_collection_add (GCR_SIMPLE_COLLECTION (testcol), G_OBJECT (renderer));
+ g_object_unref (renderer);
+ g_object_unref (testcol);
+ g_free (group);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]