Blame gcr/gcr-filter-collection.c

Packit Service f02b19
/*
Packit Service f02b19
 * gnome-keyring
Packit Service f02b19
 *
Packit Service f02b19
 * Copyright (C) 2010 Stefan Walter
Packit Service f02b19
 *
Packit Service f02b19
 * This program is free software; you can redistribute it and/or modify
Packit Service f02b19
 * it under the terms of the GNU Lesser General Public License as
Packit Service f02b19
 * published by the Free Software Foundation; either version 2.1 of
Packit Service f02b19
 * the License, or (at your option) any later version.
Packit Service f02b19
 *
Packit Service f02b19
 * This program is distributed in the hope that it will be useful, but
Packit Service f02b19
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service f02b19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service f02b19
 * Lesser General Public License for more details.
Packit Service f02b19
 *
Packit Service f02b19
 * You should have received a copy of the GNU Lesser General Public
Packit Service f02b19
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
Packit Service f02b19
 */
Packit Service f02b19
Packit Service f02b19
#include "config.h"
Packit Service f02b19
Packit Service f02b19
#include "gcr-collection.h"
Packit Service f02b19
#include "gcr-filter-collection.h"
Packit Service f02b19
Packit Service f02b19
#include <string.h>
Packit Service f02b19
Packit Service f02b19
/**
Packit Service f02b19
 * SECTION:gcr-filter-collection
Packit Service f02b19
 * @title: GcrFilterCollection
Packit Service f02b19
 * @short_description: A collection which filters a GcrCollection
Packit Service f02b19
 *
Packit Service f02b19
 * An implementation of #GcrCollection which filters objects from another
Packit Service f02b19
 * underlying collection. Use gcr_filter_collection_new_with_callback()
Packit Service f02b19
 * to create a new filter collection.
Packit Service f02b19
 *
Packit Service f02b19
 * The callback will determine the criteria for whether an object shows through
Packit Service f02b19
 * the filter or not.
Packit Service f02b19
 */
Packit Service f02b19
Packit Service f02b19
/**
Packit Service f02b19
 * GcrFilterCollection:
Packit Service f02b19
 *
Packit Service f02b19
 * A filter implementation of #GcrCollection.
Packit Service f02b19
 */
Packit Service f02b19
Packit Service f02b19
/**
Packit Service f02b19
 * GcrFilterCollectionClass:
Packit Service f02b19
 * @parent_class: the parent class
Packit Service f02b19
 *
Packit Service f02b19
 * The class for #GcrFilterCollection.
Packit Service f02b19
 */
Packit Service f02b19
Packit Service f02b19
/**
Packit Service f02b19
 * GcrFilterCollectionFunc:
Packit Service f02b19
 * @object: object to filter
Packit Service f02b19
 * @user_data: user data passed to the callback
Packit Service f02b19
 *
Packit Service f02b19
 * A function which is called by #GcrFilterCollection in order to determine
Packit Service f02b19
 * whether an object should show through the filter or not.
Packit Service f02b19
 *
Packit Service f02b19
 * Returns: %TRUE if an object should be included in the filtered collection
Packit Service f02b19
 */
Packit Service f02b19
Packit Service f02b19
enum {
Packit Service f02b19
	PROP_0,
Packit Service f02b19
	PROP_UNDERLYING
Packit Service f02b19
};
Packit Service f02b19
Packit Service f02b19
struct _GcrFilterCollectionPrivate {
Packit Service f02b19
	GHashTable *items;
Packit Service f02b19
	GcrCollection *underlying;
Packit Service f02b19
	GcrFilterCollectionFunc filter_func;
Packit Service f02b19
	gpointer user_data;
Packit Service f02b19
	GDestroyNotify destroy_func;
Packit Service f02b19
};
Packit Service f02b19
Packit Service f02b19
static void       gcr_filter_collection_iface       (GcrCollectionIface *iface);
Packit Service f02b19
Packit Service f02b19
G_DEFINE_TYPE_WITH_CODE (GcrFilterCollection, gcr_filter_collection, G_TYPE_OBJECT,
Packit Service f02b19
                         G_IMPLEMENT_INTERFACE (GCR_TYPE_COLLECTION, gcr_filter_collection_iface));
Packit Service f02b19
Packit Service f02b19
static void
Packit Service f02b19
add_object (GcrFilterCollection *self,
Packit Service f02b19
            GObject *object)
Packit Service f02b19
{
Packit Service f02b19
	g_assert (g_hash_table_lookup (self->pv->items, object) == NULL);
Packit Service f02b19
	g_hash_table_insert (self->pv->items, g_object_ref (object), object);
Packit Service f02b19
	gcr_collection_emit_added (GCR_COLLECTION (self), object);
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static void
Packit Service f02b19
remove_object (GcrFilterCollection *self,
Packit Service f02b19
               GObject *object)
Packit Service f02b19
{
Packit Service f02b19
	g_object_ref (object);
Packit Service f02b19
	if (!g_hash_table_remove (self->pv->items, object))
Packit Service f02b19
		g_assert_not_reached ();
Packit Service f02b19
	gcr_collection_emit_removed (GCR_COLLECTION (self), object);
Packit Service f02b19
	g_object_unref (object);
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static gboolean
Packit Service f02b19
filter_object (GcrFilterCollection *self,
Packit Service f02b19
               GObject *object)
Packit Service f02b19
{
Packit Service f02b19
	gboolean match = TRUE;
Packit Service f02b19
Packit Service f02b19
	if (self->pv->filter_func)
Packit Service f02b19
		match = (self->pv->filter_func) (object, self->pv->user_data);
Packit Service f02b19
Packit Service f02b19
	return match;
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static void
Packit Service f02b19
on_collection_added (GcrCollection *collection,
Packit Service f02b19
                     GObject *object,
Packit Service f02b19
                     gpointer user_data)
Packit Service f02b19
{
Packit Service f02b19
	GcrFilterCollection *self = GCR_FILTER_COLLECTION (user_data);
Packit Service f02b19
	if (filter_object (self, object))
Packit Service f02b19
		add_object (self, object);
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static void
Packit Service f02b19
on_collection_removed (GcrCollection *collection,
Packit Service f02b19
                       GObject *object,
Packit Service f02b19
                       gpointer user_data)
Packit Service f02b19
{
Packit Service f02b19
	GcrFilterCollection *self = GCR_FILTER_COLLECTION (user_data);
Packit Service f02b19
	if (g_hash_table_lookup (self->pv->items, object))
Packit Service f02b19
		remove_object (self, object);
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static void
Packit Service f02b19
gcr_filter_collection_init (GcrFilterCollection *self)
Packit Service f02b19
{
Packit Service f02b19
	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_FILTER_COLLECTION, GcrFilterCollectionPrivate);
Packit Service f02b19
	self->pv->items = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static void
Packit Service f02b19
gcr_filter_collection_set_property (GObject *obj,
Packit Service f02b19
                                    guint property_id,
Packit Service f02b19
                                    const GValue *value,
Packit Service f02b19
                                    GParamSpec *pspec)
Packit Service f02b19
{
Packit Service f02b19
	GcrFilterCollection *self = GCR_FILTER_COLLECTION (obj);
Packit Service f02b19
Packit Service f02b19
	switch (property_id) {
Packit Service f02b19
	case PROP_UNDERLYING:
Packit Service f02b19
		g_return_if_fail (self->pv->underlying == NULL);
Packit Service f02b19
		self->pv->underlying = g_value_dup_object (value);
Packit Service f02b19
		g_return_if_fail (self->pv->underlying != NULL);
Packit Service f02b19
		g_signal_connect (self->pv->underlying, "added",
Packit Service f02b19
		                  G_CALLBACK (on_collection_added), self);
Packit Service f02b19
		g_signal_connect (self->pv->underlying, "removed",
Packit Service f02b19
		                  G_CALLBACK (on_collection_removed), self);
Packit Service f02b19
		break;
Packit Service f02b19
	default:
Packit Service f02b19
		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
Packit Service f02b19
		break;
Packit Service f02b19
	}
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static void
Packit Service f02b19
gcr_filter_collection_get_property (GObject *obj,
Packit Service f02b19
                                    guint property_id,
Packit Service f02b19
                                    GValue *value,
Packit Service f02b19
                                    GParamSpec *pspec)
Packit Service f02b19
{
Packit Service f02b19
	GcrFilterCollection *self = GCR_FILTER_COLLECTION (obj);
Packit Service f02b19
Packit Service f02b19
	switch (property_id) {
Packit Service f02b19
	case PROP_UNDERLYING:
Packit Service f02b19
		g_value_set_object (value, gcr_filter_collection_get_underlying (self));
Packit Service f02b19
		break;
Packit Service f02b19
	default:
Packit Service f02b19
		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
Packit Service f02b19
		break;
Packit Service f02b19
	}
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static void
Packit Service f02b19
gcr_filter_collection_finalize (GObject *obj)
Packit Service f02b19
{
Packit Service f02b19
	GcrFilterCollection *self = GCR_FILTER_COLLECTION (obj);
Packit Service f02b19
Packit Service f02b19
	if (self->pv->underlying) {
Packit Service f02b19
		g_signal_handlers_disconnect_by_func (self->pv->underlying,
Packit Service f02b19
		                                      on_collection_added, self);
Packit Service f02b19
		g_signal_handlers_disconnect_by_func (self->pv->underlying,
Packit Service f02b19
		                                      on_collection_removed, self);
Packit Service f02b19
		g_object_unref (self->pv->underlying);
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	if (self->pv->destroy_func)
Packit Service f02b19
		(self->pv->destroy_func) (self->pv->user_data);
Packit Service f02b19
Packit Service f02b19
	g_assert (self->pv->items);
Packit Service f02b19
	g_hash_table_destroy (self->pv->items);
Packit Service f02b19
	self->pv->items = NULL;
Packit Service f02b19
Packit Service f02b19
	G_OBJECT_CLASS (gcr_filter_collection_parent_class)->finalize (obj);
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static void
Packit Service f02b19
gcr_filter_collection_class_init (GcrFilterCollectionClass *klass)
Packit Service f02b19
{
Packit Service f02b19
	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit Service f02b19
Packit Service f02b19
	gobject_class->get_property = gcr_filter_collection_get_property;
Packit Service f02b19
	gobject_class->set_property = gcr_filter_collection_set_property;
Packit Service f02b19
	gobject_class->finalize = gcr_filter_collection_finalize;
Packit Service f02b19
Packit Service f02b19
	g_type_class_add_private (gobject_class, sizeof (GcrFilterCollectionPrivate));
Packit Service f02b19
Packit Service f02b19
	g_object_class_install_property (gobject_class, PROP_UNDERLYING,
Packit Service f02b19
	            g_param_spec_object ("underlying", "Underlying", "Underlying collection",
Packit Service f02b19
	                                 GCR_TYPE_COLLECTION, G_PARAM_STATIC_STRINGS |
Packit Service f02b19
	                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static guint
Packit Service f02b19
gcr_filter_collection_get_length (GcrCollection *coll)
Packit Service f02b19
{
Packit Service f02b19
	GcrFilterCollection *self = GCR_FILTER_COLLECTION (coll);
Packit Service f02b19
	return g_hash_table_size (self->pv->items);
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static GList*
Packit Service f02b19
gcr_filter_collection_get_objects (GcrCollection *coll)
Packit Service f02b19
{
Packit Service f02b19
	GcrFilterCollection *self = GCR_FILTER_COLLECTION (coll);
Packit Service f02b19
	return g_hash_table_get_keys (self->pv->items);
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static gboolean
Packit Service f02b19
gcr_filter_collection_contains (GcrCollection *collection,
Packit Service f02b19
                                GObject *object)
Packit Service f02b19
{
Packit Service f02b19
	GcrFilterCollection *self = GCR_FILTER_COLLECTION (collection);
Packit Service f02b19
	return g_hash_table_lookup (self->pv->items, object) ? TRUE : FALSE;
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static void
Packit Service f02b19
gcr_filter_collection_iface (GcrCollectionIface *iface)
Packit Service f02b19
{
Packit Service f02b19
	iface->get_length = gcr_filter_collection_get_length;
Packit Service f02b19
	iface->get_objects = gcr_filter_collection_get_objects;
Packit Service f02b19
	iface->contains = gcr_filter_collection_contains;
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
/**
Packit Service f02b19
 * gcr_filter_collection_new_with_callback:
Packit Service f02b19
 * @underlying: the underlying collection
Packit Service f02b19
 * @callback: (allow-none): function to call for each object
Packit Service f02b19
 * @user_data: data to pass to the callback
Packit Service f02b19
 * @destroy_func: called for user_data when it is no longer needed
Packit Service f02b19
 *
Packit Service f02b19
 * Create a new #GcrFilterCollection.
Packit Service f02b19
 *
Packit Service f02b19
 * The callback should return %TRUE if an object should appear in the
Packit Service f02b19
 * filtered collection.
Packit Service f02b19
 *
Packit Service f02b19
 * If a %NULL callback is set, then all underlynig objects will appear in the
Packit Service f02b19
 * filtered collection.
Packit Service f02b19
 *
Packit Service f02b19
 * Returns: (transfer full) (type Gcr.FilterCollection): a newly allocated
Packit Service f02b19
 *          filtered collection, which should be freed with g_object_unref()
Packit Service f02b19
 */
Packit Service f02b19
GcrCollection *
Packit Service f02b19
gcr_filter_collection_new_with_callback (GcrCollection *underlying,
Packit Service f02b19
                                         GcrFilterCollectionFunc callback,
Packit Service f02b19
                                         gpointer user_data,
Packit Service f02b19
                                         GDestroyNotify destroy_func)
Packit Service f02b19
{
Packit Service f02b19
	GcrCollection *collection;
Packit Service f02b19
Packit Service f02b19
	collection = g_object_new (GCR_TYPE_FILTER_COLLECTION,
Packit Service f02b19
	                           "underlying", underlying,
Packit Service f02b19
	                           NULL);
Packit Service f02b19
	gcr_filter_collection_set_callback (GCR_FILTER_COLLECTION (collection),
Packit Service f02b19
	                                    callback, user_data, destroy_func);
Packit Service f02b19
Packit Service f02b19
	return collection;
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
/**
Packit Service f02b19
 * gcr_filter_collection_set_callback:
Packit Service f02b19
 * @self: a filter collection
Packit Service f02b19
 * @callback: (allow-none): function to call for each object
Packit Service f02b19
 * @user_data: data to pass to the callback
Packit Service f02b19
 * @destroy_func: called for user_data when it is no longer needed
Packit Service f02b19
 *
Packit Service f02b19
 * Set the callback used to filter the objects in the underlying collection.
Packit Service f02b19
 * The callback should return %TRUE if an object should appear in the
Packit Service f02b19
 * filtered collection.
Packit Service f02b19
 *
Packit Service f02b19
 * If a %NULL callback is set, then all underlynig objects will appear in the
Packit Service f02b19
 * filtered collection.
Packit Service f02b19
 *
Packit Service f02b19
 * This will refilter the collection.
Packit Service f02b19
 */
Packit Service f02b19
void
Packit Service f02b19
gcr_filter_collection_set_callback (GcrFilterCollection *self,
Packit Service f02b19
                                    GcrFilterCollectionFunc callback,
Packit Service f02b19
                                    gpointer user_data,
Packit Service f02b19
                                    GDestroyNotify destroy_func)
Packit Service f02b19
{
Packit Service f02b19
	g_return_if_fail (GCR_IS_FILTER_COLLECTION (self));
Packit Service f02b19
Packit Service f02b19
	if (self->pv->destroy_func)
Packit Service f02b19
		(self->pv->destroy_func) (self->pv->user_data);
Packit Service f02b19
	self->pv->filter_func = callback;
Packit Service f02b19
	self->pv->user_data = user_data;
Packit Service f02b19
	self->pv->destroy_func = destroy_func;
Packit Service f02b19
Packit Service f02b19
	gcr_filter_collection_refilter (self);
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
/**
Packit Service f02b19
 * gcr_filter_collection_refilter:
Packit Service f02b19
 * @self: a filter collection
Packit Service f02b19
 *
Packit Service f02b19
 * Refilter all objects in the underlying collection. Call this function if
Packit Service f02b19
 * the filter callback function changes its filtering criteria.
Packit Service f02b19
 */
Packit Service f02b19
void
Packit Service f02b19
gcr_filter_collection_refilter (GcrFilterCollection *self)
Packit Service f02b19
{
Packit Service f02b19
	GList *objects = NULL;
Packit Service f02b19
	GHashTable *snapshot;
Packit Service f02b19
	GHashTableIter iter;
Packit Service f02b19
	GObject *object;
Packit Service f02b19
	gboolean have;
Packit Service f02b19
	gboolean should;
Packit Service f02b19
	GList *l;
Packit Service f02b19
Packit Service f02b19
	g_return_if_fail (GCR_IS_FILTER_COLLECTION (self));
Packit Service f02b19
Packit Service f02b19
	snapshot = g_hash_table_new (g_direct_hash, g_direct_equal);
Packit Service f02b19
	g_hash_table_iter_init (&iter, self->pv->items);
Packit Service f02b19
	while (g_hash_table_iter_next (&iter, (gpointer *)&object, NULL))
Packit Service f02b19
		g_hash_table_insert (snapshot, object, object);
Packit Service f02b19
Packit Service f02b19
	if (self->pv->underlying)
Packit Service f02b19
		objects = gcr_collection_get_objects (self->pv->underlying);
Packit Service f02b19
Packit Service f02b19
	for (l = objects; l != NULL; l = g_list_next (l)) {
Packit Service f02b19
		have = g_hash_table_remove (snapshot, l->data);
Packit Service f02b19
		should = filter_object (self, l->data);
Packit Service f02b19
		if (have && !should)
Packit Service f02b19
			remove_object (self, l->data);
Packit Service f02b19
		else if (!have && should)
Packit Service f02b19
			add_object (self, l->data);
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	g_hash_table_iter_init (&iter, snapshot);
Packit Service f02b19
	while (g_hash_table_iter_next (&iter, (gpointer *)&object, NULL))
Packit Service f02b19
		remove_object (self, object);
Packit Service f02b19
	g_hash_table_destroy (snapshot);
Packit Service f02b19
Packit Service f02b19
	g_list_free (objects);
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
/**
Packit Service f02b19
 * gcr_filter_collection_get_underlying:
Packit Service f02b19
 * @self: a filter collection
Packit Service f02b19
 *
Packit Service f02b19
 * Get the collection that is being filtered by this filter collection.
Packit Service f02b19
 *
Packit Service f02b19
 * Returns: (transfer none): the underlying collection
Packit Service f02b19
 */
Packit Service f02b19
GcrCollection *
Packit Service f02b19
gcr_filter_collection_get_underlying (GcrFilterCollection *self)
Packit Service f02b19
{
Packit Service f02b19
	g_return_val_if_fail (GCR_IS_FILTER_COLLECTION (self), NULL);
Packit Service f02b19
	return self->pv->underlying;
Packit Service f02b19
}