summaryrefslogtreecommitdiff
path: root/gcr/gcr-collection-model.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcr/gcr-collection-model.c')
-rw-r--r--gcr/gcr-collection-model.c1575
1 files changed, 0 insertions, 1575 deletions
diff --git a/gcr/gcr-collection-model.c b/gcr/gcr-collection-model.c
deleted file mode 100644
index 79493e08..00000000
--- a/gcr/gcr-collection-model.c
+++ /dev/null
@@ -1,1575 +0,0 @@
-/*
- * gnome-keyring
- *
- * Copyright (C) 2010 Stefan Walter
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the
- * Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "config.h"
-
-#include "gcr-collection-model.h"
-
-#include <gtk/gtk.h>
-
-#include <string.h>
-#include <unistd.h>
-
-/**
- * SECTION:gcr-collection-model
- * @title: GcrCollectionModel
- * @short_description: A GtkTreeModel that represents a collection
- *
- * This is an implementation of #GtkTreeModel which represents the objects in
- * the a #GcrCollection. As objects are added or removed from the collection,
- * rows are added and removed from this model.
- *
- * The row values come from the properties of the objects in the collection. Use
- * gcr_collection_model_new() to create a new collection model. To have more
- * control over the values use a set of #GcrColumn structures to define the
- * columns. This can be done with gcr_collection_model_new_full() or
- * gcr_collection_model_set_columns().
- *
- * Each row can have a selected state, which is represented by a boolean column.
- * The selected state can be toggled with gcr_collection_model_toggle_selected()
- * or set with gcr_collection_model_set_selected_objects() and retrieved with
- * gcr_collection_model_get_selected_objects().
- *
- * To determine which object a row represents and vice versa, use the
- * gcr_collection_model_iter_for_object() or gcr_collection_model_object_for_iter()
- * functions.
- */
-
-/**
- * GcrCollectionModel:
- *
- * A #GtkTreeModel which contains a row for each object in a #GcrCollection.
- */
-
-/**
- * GcrCollectionModelClass:
- * @parent_class: The parent class
- *
- * The class for #GcrCollectionModel.
- */
-
-#define COLLECTION_MODEL_STAMP 0xAABBCCDD
-
-enum {
- PROP_0,
- PROP_COLLECTION,
- PROP_COLUMNS
-};
-
-typedef struct {
- GObject *object;
- GSequenceIter *parent;
- GSequence *children;
-} GcrCollectionRow;
-
-typedef struct {
- GtkTreeIterCompareFunc sort_func;
- gpointer user_data;
- GDestroyNotify destroy_func;
-} GcrCollectionSortClosure;
-
-typedef struct _GcrCollectionColumn {
- gchar *property;
- GType *type;
- GtkTreeIterCompareFunc sort_func;
- gpointer sort_data;
- GDestroyNotify sort_destroy;
-} GcrCollectionColumn;
-
-struct _GcrCollectionModelPrivate {
- GcrCollection *collection;
- GHashTable *selected;
- GSequence *root_sequence;
- GHashTable *object_to_seq;
-
- const GcrColumn *columns;
- guint n_columns;
-
- /* Sort information */
- gint sort_column_id;
- GtkSortType sort_order_type;
- GcrCollectionSortClosure *column_sort_closures;
- GcrCollectionSortClosure default_sort_closure;
-
- /* Sequence ordering information */
- GCompareDataFunc order_current;
- gpointer order_argument;
-};
-
-/* Forward declarations */
-static void gcr_collection_model_tree_model_init (GtkTreeModelIface *iface);
-static void gcr_collection_model_tree_sortable_init (GtkTreeSortableIface *iface);
-
-G_DEFINE_TYPE_EXTENDED (GcrCollectionModel, gcr_collection_model, G_TYPE_OBJECT, 0,
- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, gcr_collection_model_tree_model_init)
- G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE, gcr_collection_model_tree_sortable_init)
-);
-
-typedef gint (*CompareValueFunc) (const GValue *va,
- const GValue *vb);
-
-static gint
-compare_int_value (const GValue *va,
- const GValue *vb)
-{
- gint a = g_value_get_int (va);
- gint b = g_value_get_int (vb);
- if (a > b) return 1;
- else if (a < b) return -1;
- return 0;
-}
-
-static gint
-compare_uint_value (const GValue *va,
- const GValue *vb)
-{
- guint a = g_value_get_uint (va);
- guint b = g_value_get_uint (vb);
- if (a > b) return 1;
- else if (a < b) return -1;
- return 0;
-}
-
-static gint
-compare_long_value (const GValue *va,
- const GValue *vb)
-{
- glong a = g_value_get_long (va);
- glong b = g_value_get_long (vb);
- if (a > b) return 1;
- else if (a < b) return -1;
- return 0;
-}
-
-static gint
-compare_ulong_value (const GValue *va,
- const GValue *vb)
-{
- gulong a = g_value_get_ulong (va);
- gulong b = g_value_get_ulong (vb);
- if (a > b) return 1;
- else if (a < b) return -1;
- return 0;
-}
-
-static gint
-compare_string_value (const GValue *va,
- const GValue *vb)
-{
- const gchar *a = g_value_get_string (va);
- const gchar *b = g_value_get_string (vb);
- gchar *case_a;
- gchar *case_b;
- gboolean ret;
-
- if (a == b)
- return 0;
- else if (!a)
- return -1;
- else if (!b)
- return 1;
-
- case_a = g_utf8_casefold (a, -1);
- case_b = g_utf8_casefold (b, -1);
- ret = g_utf8_collate (case_a, case_b);
- g_free (case_a);
- g_free (case_b);
-
- return ret;
-}
-
-static gint
-compare_date_value (const GValue *va,
- const GValue *vb)
-{
- GDate *a = g_value_get_boxed (va);
- GDate *b = g_value_get_boxed (vb);
-
- if (a == b)
- return 0;
- else if (!a)
- return -1;
- else if (!b)
- return 1;
- else
- return g_date_compare (a, b);
-}
-
-static CompareValueFunc
-lookup_compare_func (GType type)
-{
- switch (type) {
- case G_TYPE_INT:
- return compare_int_value;
- case G_TYPE_UINT:
- return compare_uint_value;
- case G_TYPE_LONG:
- return compare_long_value;
- case G_TYPE_ULONG:
- return compare_ulong_value;
- case G_TYPE_STRING:
- return compare_string_value;
- }
-
- if (type == G_TYPE_DATE)
- return compare_date_value;
-
- return NULL;
-}
-
-static gint
-order_sequence_by_closure (gconstpointer a,
- gconstpointer b,
- gpointer user_data)
-{
- 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, row_a->object, &iter_a))
- g_return_val_if_reached (0);
- 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),
- &iter_a, &iter_b, closure->user_data);
-}
-
-static gint
-order_sequence_by_closure_reverse (gconstpointer a,
- gconstpointer b,
- gpointer user_data)
-{
- return 0 - order_sequence_by_closure (a, b, user_data);
-}
-
-static gint
-order_sequence_as_unsorted (gconstpointer a,
- gconstpointer b,
- gpointer user_data)
-{
- 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
-order_sequence_as_unsorted_reverse (gconstpointer a,
- gconstpointer b,
- gpointer user_data)
-{
- 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
-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, };
- GValue value_b = { 0, };
- CompareValueFunc compare;
- gint ret;
-
- g_assert (column);
-
- /* Sort according to property values */
- column = &self->pv->columns[self->pv->sort_column_id];
- g_value_init (&value_a, column->property_type);
- lookup_object_property (row_a->object, column->property_name, &value_a);
- g_value_init (&value_b, column->property_type);
- lookup_object_property (row_b->object, column->property_name, &value_b);
-
- compare = lookup_compare_func (column->property_type);
- g_assert (compare != NULL);
-
- ret = (compare) (&value_a, &value_b);
-
- g_value_unset (&value_a);
- g_value_unset (&value_b);
-
- return ret;
-}
-
-static gint
-order_sequence_by_property_reverse (gconstpointer a,
- gconstpointer b,
- gpointer user_data)
-{
- return 0 - order_sequence_by_property (a, b, user_data);
-}
-
-static GHashTable*
-selected_hash_table_new (void)
-{
- return g_hash_table_new (g_direct_hash, g_direct_equal);
-}
-
-static gboolean
-sequence_iter_to_tree (GcrCollectionModel *self,
- GSequenceIter *seq,
- GtkTreeIter *iter)
-{
- GcrCollectionRow *row;
-
- g_return_val_if_fail (seq != NULL, FALSE);
-
- if (g_sequence_iter_is_end (seq))
- return 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 = row->object;
- iter->user_data2 = seq;
- return TRUE;
-}
-
-static GSequenceIter *
-sequence_iter_for_tree (GcrCollectionModel *self,
- GtkTreeIter *iter)
-{
- g_return_val_if_fail (iter != NULL, NULL);
- g_return_val_if_fail (iter->stamp == COLLECTION_MODEL_STAMP, NULL);
- return iter->user_data2;
-}
-
-static GtkTreePath *
-sequence_iter_to_path (GcrCollectionModel *self,
- GSequenceIter *seq)
-{
- GcrCollectionRow *row;
- GtkTreePath *path;
-
- 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 GSequence *
-child_sequence_for_tree (GcrCollectionModel *self,
- GtkTreeIter *iter)
-{
- GcrCollectionRow *row;
- GSequenceIter *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
-on_object_notify (GObject *object, GParamSpec *spec, GcrCollectionModel *self)
-{
- GtkTreeIter iter;
- GtkTreePath *path;
- gboolean found = FALSE;
- guint i;
-
- g_return_if_fail (spec->name);
-
- for (i = 0; i < self->pv->n_columns - 1; ++i) {
- g_assert (self->pv->columns[i].property_name);
- if (g_str_equal (self->pv->columns[i].property_name, spec->name)) {
- found = TRUE;
- break;
- }
- }
-
- /* Tell the tree view that this row changed */
- if (found) {
- if (!gcr_collection_model_iter_for_object (self, object, &iter))
- g_return_if_reached ();
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (self), &iter);
- g_return_if_fail (path);
- gtk_tree_model_row_changed (GTK_TREE_MODEL (self), path, &iter);
- gtk_tree_path_free (path);
- }
-}
-
-static void
-on_object_gone (gpointer unused, GObject *was_object)
-{
- g_warning ("object contained in GcrCollection and included in GcrCollectionModel "
- "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
-add_object_to_sequence (GcrCollectionModel *self,
- GSequence *sequence,
- GSequenceIter *parent,
- GObject *object,
- gboolean emit)
-{
- GcrCollectionRow *row;
- GSequenceIter *seq;
- GtkTreeIter iter;
- GtkTreePath *path;
-
- g_assert (GCR_IS_COLLECTION_MODEL (self));
- g_assert (G_IS_OBJECT (object));
- g_assert (self->pv->order_current);
-
- 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);
-
- 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);
- }
-
- 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
-on_collection_added (GcrCollection *collection,
- GObject *object,
- gpointer user_data)
-{
- 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
-remove_children_from_sequence (GcrCollectionModel *self,
- GSequence *sequence,
- GcrCollection *collection,
- gboolean emit)
-{
- GSequenceIter *seq, *next;
- GcrCollectionRow *row;
-
- g_signal_handlers_disconnect_by_func (collection, on_collection_added, self);
- g_signal_handlers_disconnect_by_func (collection, on_collection_removed, self);
-
- 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);
- }
-}
-
-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);
- }
-
- 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;
- }
-
- if (self->pv->selected)
- g_hash_table_remove (self->pv->selected, 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 */
- if (path != NULL) {
- gtk_tree_model_row_deleted (GTK_TREE_MODEL (self), path);
- gtk_tree_path_free (path);
- }
-
-}
-
-static void
-on_collection_removed (GcrCollection *collection,
- GObject *object,
- gpointer user_data)
-{
- 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
-free_owned_columns (gpointer data)
-{
- GcrColumn *columns;
- g_assert (data);
-
- /* Only the property column is in use */
- for (columns = data; columns->property_name; ++columns)
- g_free ((gchar*)columns->property_name);
- g_free (data);
-}
-
-static GtkTreeModelFlags
-gcr_collection_model_real_get_flags (GtkTreeModel *model)
-{
- return GTK_TREE_MODEL_ITERS_PERSIST;
-}
-
-static gint
-gcr_collection_model_real_get_n_columns (GtkTreeModel *model)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
- return self->pv->n_columns;
-}
-
-static GType
-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);
-
- /* The last is the selected column */
- if (column_id == self->pv->n_columns)
- return G_TYPE_BOOLEAN;
-
- return self->pv->columns[column_id].column_type;
-}
-
-static gboolean
-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;
-
- sequence = self->pv->root_sequence;
- seq = NULL;
-
- indices = gtk_tree_path_get_indices_with_depth (path, &count);
- if (count == 0)
- return FALSE;
-
- 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)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
- GSequenceIter *seq;
-
- if (iter == NULL)
- return gtk_tree_path_new ();
-
- 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)
-{
- 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));
- g_return_if_fail (column_id >= 0 && column_id < self->pv->n_columns);
-
- /* The selected column? Last one */
- if (column_id == self->pv->n_columns - 1) {
- g_value_init (value, G_TYPE_BOOLEAN);
- g_value_set_boolean (value, gcr_collection_model_is_selected (self, iter));
- return;
- }
-
- /* Figure out which property */
- column = &self->pv->columns[column_id];
- g_assert (column->property_name);
- g_value_init (value, column->column_type);
-
- /* 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;
- }
-
- /* 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)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
- 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)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
- 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)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
- 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)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
- 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)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (model);
- GSequence *sequence;
- GSequenceIter *seq;
-
- sequence = child_sequence_for_tree (self, parent);
- if (sequence == NULL)
- return FALSE;
- 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 *model,
- GtkTreeIter *iter,
- GtkTreeIter *child)
-{
- 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)
-{
- /* Nothing to do */
-}
-
-static void
-gcr_collection_model_real_unref_node (GtkTreeModel *model,
- GtkTreeIter *iter)
-{
- /* Nothing to do */
-}
-
-static void
-gcr_collection_model_tree_model_init (GtkTreeModelIface *iface)
-{
- iface->get_flags = gcr_collection_model_real_get_flags;
- iface->get_n_columns = gcr_collection_model_real_get_n_columns;
- iface->get_column_type = gcr_collection_model_real_get_column_type;
- iface->get_iter = gcr_collection_model_real_get_iter;
- iface->get_path = gcr_collection_model_real_get_path;
- iface->get_value = gcr_collection_model_real_get_value;
- iface->iter_next = gcr_collection_model_real_iter_next;
- iface->iter_children = gcr_collection_model_real_iter_children;
- iface->iter_has_child = gcr_collection_model_real_iter_has_child;
- iface->iter_n_children = gcr_collection_model_real_iter_n_children;
- iface->iter_nth_child = gcr_collection_model_real_iter_nth_child;
- iface->iter_parent = gcr_collection_model_real_iter_parent;
- iface->ref_node = gcr_collection_model_real_ref_node;
- iface->unref_node = gcr_collection_model_real_unref_node;
-}
-
-static void
-collection_resort_sequence (GcrCollectionModel *self,
- GSequenceIter *parent,
- GSequence *sequence)
-{
- GPtrArray *previous;
- GSequenceIter *seq, *next;
- gint *new_order;
- GtkTreePath *path;
- GtkTreeIter iter;
- GcrCollectionRow *row;
- gint index;
- gint i;
-
- /* 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 (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);
- }
-
- if (previous->len == 0) {
- g_ptr_array_free (previous, TRUE);
- return;
- }
-
- /* Actually perform the sort */
- 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_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;
- }
-
- g_ptr_array_free (previous, TRUE);
-
- 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);
-}
-
-static gboolean
-gcr_collection_model_get_sort_column_id (GtkTreeSortable *sortable,
- gint *sort_column_id,
- GtkSortType *order)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (sortable);
-
- if (order)
- *order = self->pv->sort_order_type;
- if (sort_column_id)
- *sort_column_id = self->pv->sort_column_id;
- return (self->pv->sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID &&
- self->pv->sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID);
-}
-
-static void
-gcr_collection_model_set_sort_column_id (GtkTreeSortable *sortable,
- gint sort_column_id,
- GtkSortType order)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (sortable);
- GCompareDataFunc func;
- gpointer argument;
- const GcrColumn *column;
- gboolean reverse;
-
- reverse = (order == GTK_SORT_DESCENDING);
-
- if (sort_column_id == GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID) {
- func = reverse ? order_sequence_as_unsorted_reverse : order_sequence_as_unsorted;
- argument = NULL;
-
- } else if (sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) {
- func = reverse ? order_sequence_by_closure_reverse : order_sequence_by_closure;
- argument = &self->pv->default_sort_closure;
-
- } else if (sort_column_id >= 0 && sort_column_id < self->pv->n_columns) {
- if (self->pv->column_sort_closures[sort_column_id].sort_func) {
- func = reverse ? order_sequence_by_closure_reverse : order_sequence_by_closure;
- argument = &self->pv->column_sort_closures[sort_column_id];
- } else {
- column = &self->pv->columns[sort_column_id];
- if (!(column->flags & GCR_COLUMN_SORTABLE))
- return;
- if (!lookup_compare_func (column->property_type)) {
- g_warning ("no sort implementation defined for type '%s' on column '%s'",
- g_type_name (column->property_type), column->property_name);
- return;
- }
-
- func = reverse ? order_sequence_by_property_reverse : order_sequence_by_property;
- argument = (gpointer)column;
- }
- } else {
- g_warning ("invalid sort_column_id passed to gtk_tree_sortable_set_sort_column_id(): %d",
- sort_column_id);
- return;
- }
-
- if (sort_column_id != self->pv->sort_column_id ||
- order != self->pv->sort_order_type) {
- self->pv->sort_column_id = sort_column_id;
- self->pv->sort_order_type = order;
- gtk_tree_sortable_sort_column_changed (sortable);
- }
-
- if (func != self->pv->order_current ||
- argument != self->pv->order_argument) {
- self->pv->order_current = func;
- self->pv->order_argument = (gpointer)argument;
- collection_resort_sequence (self, NULL, self->pv->root_sequence);
- }
-}
-
-static void
-clear_sort_closure (GcrCollectionSortClosure *closure)
-{
- if (closure->destroy_func)
- (closure->destroy_func) (closure->user_data);
- closure->sort_func = NULL;
- closure->destroy_func = NULL;
- closure->user_data = NULL;
-}
-
-static void
-set_sort_closure (GcrCollectionSortClosure *closure,
- GtkTreeIterCompareFunc func,
- gpointer data,
- GDestroyNotify destroy)
-{
- clear_sort_closure (closure);
- closure->sort_func = func;
- closure->user_data = data;
- closure->destroy_func = destroy;
-}
-
-static void
-gcr_collection_model_set_sort_func (GtkTreeSortable *sortable,
- gint sort_column_id,
- GtkTreeIterCompareFunc func,
- gpointer data,
- GDestroyNotify destroy)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (sortable);
-
- g_return_if_fail (sort_column_id >= 0 && sort_column_id < self->pv->n_columns);
-
- set_sort_closure (&self->pv->column_sort_closures[sort_column_id],
- func, data, destroy);
-
- /* Resorts if necessary */
- if (self->pv->sort_column_id == sort_column_id) {
- gcr_collection_model_set_sort_column_id (sortable,
- self->pv->sort_column_id,
- self->pv->sort_order_type);
- }
-}
-
-static void
-gcr_collection_model_set_default_sort_func (GtkTreeSortable *sortable,
- GtkTreeIterCompareFunc func,
- gpointer data, GDestroyNotify destroy)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (sortable);
-
- set_sort_closure (&self->pv->default_sort_closure,
- func, data, destroy);
-
- /* Resorts if necessary */
- if (self->pv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) {
- gcr_collection_model_set_sort_column_id (sortable,
- self->pv->sort_column_id,
- self->pv->sort_order_type);
- }
-}
-
-static gboolean
-gcr_collection_model_has_default_sort_func (GtkTreeSortable *sortable)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (sortable);
-
- return (self->pv->default_sort_closure.sort_func != NULL);
-}
-
-static void
-gcr_collection_model_tree_sortable_init (GtkTreeSortableIface *iface)
-{
- iface->get_sort_column_id = gcr_collection_model_get_sort_column_id;
- iface->set_sort_column_id = gcr_collection_model_set_sort_column_id;
- iface->set_sort_func = gcr_collection_model_set_sort_func;
- iface->set_default_sort_func = gcr_collection_model_set_default_sort_func;
- iface->has_default_sort_func = gcr_collection_model_has_default_sort_func;
-}
-
-static void
-gcr_collection_model_init (GcrCollectionModel *self)
-{
- self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_COLLECTION_MODEL, GcrCollectionModelPrivate);
-
- 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;
-}
-
-static void
-gcr_collection_model_set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *pspec)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (object);
- GcrColumn *columns;
-
- switch (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) {
- add_children_to_sequence (self, self->pv->root_sequence,
- NULL, self->pv->collection, FALSE);
- }
- break;
-
- case PROP_COLUMNS:
- columns = g_value_get_pointer (value);
- if (columns)
- gcr_collection_model_set_columns (self, columns);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gcr_collection_model_get_property (GObject *object, guint prop_id,
- GValue *value, GParamSpec *pspec)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (object);
-
- switch (prop_id) {
- case PROP_COLLECTION:
- g_value_set_object (value, self->pv->collection);
- break;
-
- case PROP_COLUMNS:
- g_value_set_pointer (value, (gpointer)self->pv->columns);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gcr_collection_model_dispose (GObject *object)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (object);
-
- /* Disconnect from all rows */
- if (self->pv->collection) {
- remove_children_from_sequence (self, self->pv->root_sequence,
- self->pv->collection, FALSE);
- g_object_unref (self->pv->collection);
- self->pv->collection = NULL;
- }
-
- G_OBJECT_CLASS (gcr_collection_model_parent_class)->dispose (object);
-}
-
-static void
-gcr_collection_model_finalize (GObject *object)
-{
- GcrCollectionModel *self = GCR_COLLECTION_MODEL (object);
- guint i;
-
- g_assert (!self->pv->collection);
-
- 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);
-
- if (self->pv->selected) {
- g_assert (g_hash_table_size (self->pv->selected) == 0);
- g_hash_table_destroy (self->pv->selected);
- self->pv->selected = NULL;
- }
-
- self->pv->columns = NULL;
- for (i = 0; i < self->pv->n_columns; i++)
- clear_sort_closure (&self->pv->column_sort_closures[i]);
- g_free (self->pv->column_sort_closures);
- clear_sort_closure (&self->pv->default_sort_closure);
-
- G_OBJECT_CLASS (gcr_collection_model_parent_class)->finalize (object);
-}
-
-static void
-gcr_collection_model_class_init (GcrCollectionModelClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- gcr_collection_model_parent_class = g_type_class_peek_parent (klass);
-
- gobject_class->dispose = gcr_collection_model_dispose;
- gobject_class->finalize = gcr_collection_model_finalize;
- gobject_class->set_property = gcr_collection_model_set_property;
- gobject_class->get_property = gcr_collection_model_get_property;
-
- g_object_class_install_property (gobject_class, PROP_COLLECTION,
- g_param_spec_object ("collection", "Object Collection", "Collection to get objects from",
- GCR_TYPE_COLLECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
- g_object_class_install_property (gobject_class, PROP_COLUMNS,
- g_param_spec_pointer ("columns", "Columns", "Columns for the model",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
- g_type_class_add_private (klass, sizeof (GcrCollectionModelPrivate));
-}
-
-/* -----------------------------------------------------------------------------
- * PUBLIC
- */
-
-/**
- * gcr_collection_model_new: (skip)
- * @collection: The collection to represent
- * @...: The column names and types.
- *
- * Create a new #GcrCollectionModel. The variable argument list should contain
- * pairs of property names, and #GType values. The variable argument list should
- * be terminated with %NULL.
- *
- * Returns: (transfer full): a newly allocated model, which should be released
- * with g_object_unref().
- */
-GcrCollectionModel*
-gcr_collection_model_new (GcrCollection *collection, ...)
-{
- GcrColumn column;
- GcrCollectionModel *self;
- const gchar *arg;
- GArray *array;
- va_list va;
-
- /* With a null terminator */
- array = g_array_new (TRUE, TRUE, sizeof (GcrColumn));
-
- va_start (va, collection);
- while ((arg = va_arg (va, const gchar*)) != NULL) {
- memset (&column, 0, sizeof (column));
- column.property_name = g_strdup (arg);
- column.property_type = va_arg (va, GType);
- column.column_type = column.property_type;
- g_array_append_val (array, column);
- }
- va_end (va);
-
- self = gcr_collection_model_new_full (collection, (GcrColumn*)array->data);
- g_object_set_data_full (G_OBJECT (self), "gcr_collection_model_new",
- g_array_free (array, FALSE), free_owned_columns);
- return self;
-}
-
-/**
- * gcr_collection_model_new_full: (skip)
- * @collection: The collection to represent
- * @columns: The columns the model should contain
- *
- * Create a new #GcrCollectionModel.
- *
- * Returns: (transfer full): a newly allocated model, which should be released
- * with g_object_unref()
- */
-GcrCollectionModel*
-gcr_collection_model_new_full (GcrCollection *collection, const GcrColumn *columns)
-{
- GcrCollectionModel *self = g_object_new (GCR_TYPE_COLLECTION_MODEL, "collection", collection, NULL);
- gcr_collection_model_set_columns (self, columns);
- return self;
-}
-
-/**
- * gcr_collection_model_set_columns: (skip)
- * @self: The model
- * @columns: The columns the model should contain
- *
- * Set the columns that the model should contain. @columns is an array of
- * #GcrColumn structures, with the last one containing %NULL for all values.
- *
- * This function can only be called once, and only if the model was not created
- * without a set of columns. This function cannot be called after the model
- * has been added to a view.
- *
- * The columns are accessed as static data. They should continue to remain
- * in memory for longer than the GcrCollectionModel object.
- *
- * Returns: The number of columns
- */
-guint
-gcr_collection_model_set_columns (GcrCollectionModel *self,
- const GcrColumn *columns)
-{
- const GcrColumn *col;
- guint n_columns;
-
- g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), 0);
- g_return_val_if_fail (columns, 0);
- g_return_val_if_fail (self->pv->n_columns == 0, 0);
-
- /* Count the number of columns, extra column for selected */
- for (col = columns, n_columns = 1; col->property_name; ++col)
- ++n_columns;
-
- /* We expect the columns to stay around */
- self->pv->columns = columns;
- self->pv->n_columns = n_columns;
- self->pv->column_sort_closures = g_new0 (GcrCollectionSortClosure, self->pv->n_columns);
-
- return n_columns - 1;
-}
-
-/**
- * gcr_collection_model_get_collection:
- * @self: a collection model
- *
- * Get the collection which this model represents
- *
- * Returns: (transfer none): the collection, owned by the model
- */
-GcrCollection *
-gcr_collection_model_get_collection (GcrCollectionModel *self)
-{
- g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), NULL);
- return self->pv->collection;
-}
-
-/**
- * gcr_collection_model_object_for_iter:
- * @self: The model
- * @iter: The row
- *
- * Get the object that is represented by the given row in the model.
- *
- * Returns: (transfer none): The object, owned by the model.
- */
-GObject *
-gcr_collection_model_object_for_iter (GcrCollectionModel *self, const GtkTreeIter *iter)
-{
- g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), NULL);
- g_return_val_if_fail (iter != NULL, NULL);
- g_return_val_if_fail (iter->stamp == COLLECTION_MODEL_STAMP, NULL);
- g_return_val_if_fail (G_IS_OBJECT (iter->user_data), NULL);
-
- return G_OBJECT (iter->user_data);
-}
-
-/**
- * gcr_collection_model_iter_for_object:
- * @self: The model
- * @object: The object
- * @iter: The row for the object
- *
- * Set @iter to the row for the given object. If the object is not in this
- * model, then %FALSE will be returned.
- *
- * Returns: %TRUE if the object was present.
- */
-gboolean
-gcr_collection_model_iter_for_object (GcrCollectionModel *self, GObject *object,
- GtkTreeIter *iter)
-{
- 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 != NULL, FALSE);
-
- seq = g_hash_table_lookup (self->pv->object_to_seq, object);
- if (seq == NULL)
- return FALSE;
-
- return sequence_iter_to_tree (self, seq, iter);
-}
-
-/**
- * gcr_collection_model_column_for_selected:
- * @self: The model
- *
- * Get the column identifier for the column that contains the values
- * of the selected state.
- *
- * Returns: The column identifier.
- */
-gint
-gcr_collection_model_column_for_selected (GcrCollectionModel *self)
-{
- g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), 0);
- g_assert (self->pv->n_columns > 0);
- return self->pv->n_columns - 1;
-}
-
-/**
- * gcr_collection_model_toggle_selected:
- * @self: The model
- * @iter: The row
- *
- * Toggle the selected state of a given row.
- */
-void
-gcr_collection_model_toggle_selected (GcrCollectionModel *self, GtkTreeIter *iter)
-{
- GObject *object;
-
- g_return_if_fail (GCR_IS_COLLECTION_MODEL (self));
-
- object = gcr_collection_model_object_for_iter (self, iter);
- g_return_if_fail (G_IS_OBJECT (object));
-
- if (!self->pv->selected)
- self->pv->selected = selected_hash_table_new ();
-
- if (g_hash_table_lookup (self->pv->selected, object))
- g_hash_table_remove (self->pv->selected, object);
- else
- g_hash_table_insert (self->pv->selected, object, object);
-}
-
-/**
- * gcr_collection_model_change_selected:
- * @self: The model
- * @iter: The row
- * @selected: Whether the row should be selected or not.
- *
- * Set whether a given row is toggled selected or not.
- */
-void
-gcr_collection_model_change_selected (GcrCollectionModel *self, GtkTreeIter *iter, gboolean selected)
-{
- GtkTreePath *path;
- GObject *object;
-
- g_return_if_fail (GCR_IS_COLLECTION_MODEL (self));
-
- object = gcr_collection_model_object_for_iter (self, iter);
- g_return_if_fail (G_IS_OBJECT (object));
-
- if (!self->pv->selected)
- self->pv->selected = g_hash_table_new (g_direct_hash, g_direct_equal);
-
- if (selected)
- g_hash_table_insert (self->pv->selected, object, object);
- else
- g_hash_table_remove (self->pv->selected, object);
-
- /* Tell the view that this row changed */
- path = gtk_tree_model_get_path (GTK_TREE_MODEL (self), iter);
- g_return_if_fail (path);
- gtk_tree_model_row_changed (GTK_TREE_MODEL (self), path, iter);
- gtk_tree_path_free (path);
-}
-
-/**
- * gcr_collection_model_is_selected:
- * @self: The model
- * @iter: The row
- *
- * Check whether a given row has been toggled as selected.
- *
- * Returns: Whether the row has been selected.
- */
-gboolean
-gcr_collection_model_is_selected (GcrCollectionModel *self, GtkTreeIter *iter)
-{
- GObject *object;
-
- g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), FALSE);
-
- object = gcr_collection_model_object_for_iter (self, iter);
- g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
-
- if (!self->pv->selected)
- return FALSE;
-
- return g_hash_table_lookup (self->pv->selected, object) ? TRUE : FALSE;
-}
-
-/**
- * gcr_collection_model_get_selected_objects:
- * @self: the collection model
- *
- * Get a list of checked/selected objects.
- *
- * Returns: (transfer container) (element-type GLib.Object): a list of selected
- * objects, which should be freed with g_list_free()
- */
-GList *
-gcr_collection_model_get_selected_objects (GcrCollectionModel *self)
-{
- GHashTableIter iter;
- GList *result = NULL;
- gpointer key;
-
- g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), NULL);
-
- if (!self->pv->selected)
- return NULL;
-
- g_hash_table_iter_init (&iter, self->pv->selected);
- while (g_hash_table_iter_next (&iter, &key, NULL))
- result = g_list_prepend (result, key);
- return result;
-}
-
-/**
- * gcr_collection_model_set_selected_objects:
- * @self: the collection model
- * @selected: (element-type GLib.Object): a list of objects to select
- *
- * Set the checked/selected objects.
- */
-void
-gcr_collection_model_set_selected_objects (GcrCollectionModel *self,
- GList *selected)
-{
- GHashTable *newly_selected;
- GList *old_selection;
- GtkTreeIter iter;
- GList *l;
-
- old_selection = gcr_collection_model_get_selected_objects (self);
- newly_selected = selected_hash_table_new ();
-
- /* Select all the objects in selected which aren't already selected */
- for (l = selected; l; l = g_list_next (l)) {
- if (!self->pv->selected || !g_hash_table_lookup (self->pv->selected, l->data)) {
- if (!gcr_collection_model_iter_for_object (self, l->data, &iter))
- g_return_if_reached ();
- gcr_collection_model_change_selected (self, &iter, TRUE);
- }
-
- /* Note that we've seen this one */
- g_hash_table_insert (newly_selected, l->data, l->data);
- }
-
- /* Unselect all the objects which aren't supposed to be selected */
- for (l = old_selection; l; l = g_list_next (l)) {
- if (!g_hash_table_lookup (newly_selected, l->data)) {
- if (!gcr_collection_model_iter_for_object (self, l->data, &iter))
- g_return_if_reached ();
- gcr_collection_model_change_selected (self, &iter, FALSE);
- }
- }
-
- g_list_free (old_selection);
- g_hash_table_destroy (newly_selected);
-}