gcr: Add GcrUnionCollection class
authorStef Walter <stefw@collabora.co.uk>
Tue, 6 Sep 2011 13:21:07 +0000 (15:21 +0200)
committerStef Walter <stefw@collabora.co.uk>
Tue, 6 Sep 2011 13:21:07 +0000 (15:21 +0200)
 * A GcrCollection which combines the contents of other collections
   into a single collection.

docs/reference/gcr/gcr-sections.txt
gcr/Makefile.am
gcr/gcr-collection.c
gcr/gcr-union-collection.c [new file with mode: 0644]
gcr/gcr-union-collection.h [new file with mode: 0644]
gcr/gcr.h

index ee7bd91..7019ad3 100644 (file)
@@ -246,10 +246,10 @@ GcrCollectionIface
 <FILE>gcr-simple-collection</FILE>
 GcrSimpleCollection
 GcrSimpleCollectionClass
-gcr_simple_collection_add
-gcr_simple_collection_contains
 gcr_simple_collection_new
+gcr_simple_collection_add
 gcr_simple_collection_remove
+gcr_simple_collection_contains
 <SUBSECTION Standard>
 gcr_simple_collection_get_type
 GCR_IS_SIMPLE_COLLECTION
@@ -262,6 +262,25 @@ GcrSimpleCollectionPrivate
 </SECTION>
 
 <SECTION>
+<FILE>gcr-union-collection</FILE>
+GcrUnionCollection
+GcrUnionCollectionClass
+gcr_union_collection_new
+gcr_union_collection_add
+gcr_union_collection_take
+gcr_union_collection_remove
+<SUBSECTION Standard>
+GCR_IS_UNION_COLLECTION
+GCR_IS_UNION_COLLECTION_CLASS
+GCR_TYPE_UNION_COLLECTION
+GCR_UNION_COLLECTION
+GCR_UNION_COLLECTION_CLASS
+GCR_UNION_COLLECTION_GET_CLASS
+GcrUnionCollectionPrivate
+gcr_union_collection_get_type
+</SECTION>
+
+<SECTION>
 <FILE>gcr-collection-model</FILE>
 GcrCollectionModel
 GcrCollectionModelClass
index 03ad178..3402c85 100644 (file)
@@ -49,6 +49,7 @@ HEADER_FILES = \
        gcr-tree-selector.h \
        gcr-trust.h \
        gcr-types.h \
+       gcr-union-collection.h \
        gcr-unlock-options.h \
        gcr-unlock-options-widget.h \
        gcr-viewer.h \
@@ -122,6 +123,7 @@ libgcr_@GCR_MAJOR@_la_SOURCES = \
        gcr-tree-selector.c gcr-tree-selector.h \
        gcr-trust.c gcr-trust.h \
        gcr-types.h \
+       gcr-union-collection.c \
        gcr-unlock-options.h \
        gcr-unlock-options-widget.c gcr-unlock-options-widget.h \
        gcr-unlock-renderer.c gcr-unlock-renderer.h \
index aa7a60f..61b75cc 100644 (file)
@@ -144,6 +144,7 @@ gcr_collection_get_objects (GcrCollection *self)
 /**
  * gcr_collection_contains:
  * @self: the collection
+ * @object: object to check
  *
  * Check whether the collection contains an object or not.
  *
diff --git a/gcr/gcr-union-collection.c b/gcr/gcr-union-collection.c
new file mode 100644 (file)
index 0000000..d331c67
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include "gcr-collection.h"
+#include "gcr-internal.h"
+#include "gcr-union-collection.h"
+
+#include <string.h>
+
+/**
+ * SECTION:gcr-union-collection
+ * @title: GcrUnionCollection
+ * @short_description: A GcrCollection which combines other collections
+ *
+ * An implementation of #GcrCollection, which combines the objects in
+ * other #GcrCollections. Use gcr_union_collection_add() to add and
+ * gcr_union_collection_remove() to remove them.
+ */
+
+/**
+ * GcrUnionCollection:
+ * @parent: The parent object
+ *
+ * A union implementation of #GcrCollection.
+ */
+
+/**
+ * GcrUnionCollectionClass:
+ * @parent_class: The parent class
+ *
+ * The class for #GcrUnionCollection.
+ */
+
+struct _GcrUnionCollectionPrivate {
+       GHashTable *items;
+       GHashTable *collections;
+};
+
+static void      gcr_collection_iface       (GcrCollectionIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GcrUnionCollection, gcr_union_collection, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GCR_TYPE_COLLECTION, gcr_collection_iface));
+
+static void
+on_collection_added (GcrCollection *collection,
+                     GObject *object,
+                     gpointer user_data)
+{
+       GcrUnionCollection *self = GCR_UNION_COLLECTION (user_data);
+       gint *count;
+
+       g_object_ref (object);
+
+       count = g_hash_table_lookup (self->pv->items, object);
+       if (count == NULL) {
+               count = g_new0 (gint, 1);
+               *count = 1;
+               g_hash_table_insert (self->pv->items, object, count);
+               gcr_collection_emit_added (GCR_COLLECTION (self), object);
+       } else {
+               g_assert (*count > 0);
+               (*count)++;
+       }
+
+       g_object_unref (object);
+}
+
+static void
+on_collection_removed (GcrCollection *collection,
+                       GObject *object,
+                       gpointer user_data)
+{
+       GcrUnionCollection *self = GCR_UNION_COLLECTION (user_data);
+       gint *count;
+
+       g_object_ref (object);
+
+       count = g_hash_table_lookup (self->pv->items, object);
+       if (count != NULL) {
+               g_assert (*count > 0);
+               (*count)--;
+
+               if (*count == 0) {
+                       g_hash_table_remove (self->pv->items, object);
+                       gcr_collection_emit_removed (GCR_COLLECTION (self), object);
+               }
+       } else {
+               g_warning ("Object of type %s that exists in an underlying "
+                          "collection of a GcrUnionCollection appeared without "
+                          "emitting 'added' signal.", G_OBJECT_TYPE_NAME (object));
+       }
+
+       g_object_unref (object);
+
+}
+
+static void
+connect_to_collection (GcrUnionCollection *self,
+                       GcrCollection *collection)
+{
+       g_signal_connect (collection, "added", G_CALLBACK (on_collection_added), self);
+       g_signal_connect (collection, "removed", G_CALLBACK (on_collection_removed), self);
+}
+
+static void
+disconnect_from_collection (GcrUnionCollection *self,
+                            GcrCollection *collection)
+{
+       g_signal_handlers_disconnect_by_func (collection, on_collection_added, self);
+       g_signal_handlers_disconnect_by_func (collection, on_collection_removed, self);
+}
+
+static void
+gcr_union_collection_init (GcrUnionCollection *self)
+{
+       self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_UNION_COLLECTION, GcrUnionCollectionPrivate);
+       self->pv->items = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+                                                NULL, g_free);
+       self->pv->collections = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+                                                      g_object_unref, NULL);
+}
+
+static void
+gcr_union_collection_dispose (GObject *obj)
+{
+       GcrUnionCollection *self = GCR_UNION_COLLECTION (obj);
+       GHashTableIter iter;
+       GcrCollection *collection;
+
+       g_hash_table_iter_init (&iter, self->pv->collections);
+       while (g_hash_table_iter_next (&iter, (gpointer *)&collection, NULL))
+               disconnect_from_collection (self, collection);
+       g_hash_table_remove_all (self->pv->collections);
+       g_hash_table_remove_all (self->pv->items);
+
+       G_OBJECT_CLASS (gcr_union_collection_parent_class)->dispose (obj);
+}
+
+static void
+gcr_union_collection_finalize (GObject *obj)
+{
+       GcrUnionCollection *self = GCR_UNION_COLLECTION (obj);
+
+       g_assert (g_hash_table_size (self->pv->items) == 0);
+       g_hash_table_destroy (self->pv->items);
+
+       g_assert (g_hash_table_size (self->pv->collections) == 0);
+       g_hash_table_destroy (self->pv->collections);
+
+       G_OBJECT_CLASS (gcr_union_collection_parent_class)->finalize (obj);
+}
+
+static void
+gcr_union_collection_class_init (GcrUnionCollectionClass *klass)
+{
+       GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+       gobject_class->dispose = gcr_union_collection_dispose;
+       gobject_class->finalize = gcr_union_collection_finalize;
+       g_type_class_add_private (gobject_class, sizeof (GcrUnionCollectionPrivate));
+}
+
+static guint
+gcr_union_collection_real_get_length (GcrCollection *coll)
+{
+       GcrUnionCollection *self = GCR_UNION_COLLECTION (coll);
+       return g_hash_table_size (self->pv->items);
+}
+
+static GList*
+gcr_union_collection_real_get_objects (GcrCollection *coll)
+{
+       GcrUnionCollection *self = GCR_UNION_COLLECTION (coll);
+       return g_hash_table_get_keys (self->pv->items);
+}
+
+static gboolean
+gcr_union_collection_real_contains (GcrCollection *collection,
+                                    GObject *object)
+{
+       GcrUnionCollection *self = GCR_UNION_COLLECTION (collection);
+       return g_hash_table_lookup (self->pv->items, object) ? TRUE : FALSE;
+}
+
+static void
+gcr_collection_iface (GcrCollectionIface *iface)
+{
+       iface->get_length = gcr_union_collection_real_get_length;
+       iface->get_objects = gcr_union_collection_real_get_objects;
+       iface->contains = gcr_union_collection_real_contains;
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+/**
+ * gcr_union_collection_new:
+ *
+ * Create a new #GcrUnionCollection.
+ *
+ * Returns: A newly allocated collection, which should be freed with
+ *     g_object_unref().
+ */
+GcrCollection*
+gcr_union_collection_new (void)
+{
+       return g_object_new (GCR_TYPE_UNION_COLLECTION, NULL);
+}
+
+/**
+ * gcr_union_collection_add:
+ * @self: The union collection
+ * @collection: The collection whose objects to add
+ *
+ * Add objects from this collection to the union
+ */
+void
+gcr_union_collection_add (GcrUnionCollection *self,
+                          GcrCollection *collection)
+{
+       g_return_if_fail (GCR_IS_UNION_COLLECTION (self));
+       g_return_if_fail (GCR_IS_COLLECTION (collection));
+       gcr_union_collection_take (self, g_object_ref (collection));
+}
+
+/**
+ * gcr_union_collection_take:
+ * @self: The union collection
+ * @collection: The collection whose objects to add
+ *
+ * Add objects from this collection to the union. Do not add an additional
+ * reference to the collection.
+ */
+void
+gcr_union_collection_take (GcrUnionCollection *self,
+                           GcrCollection *collection)
+{
+       GList *objects, *l;
+
+       g_return_if_fail (GCR_IS_UNION_COLLECTION (self));
+       g_return_if_fail (GCR_IS_COLLECTION (collection));
+       g_return_if_fail (!g_hash_table_lookup (self->pv->collections, collection));
+
+       g_object_ref (collection);
+
+       g_hash_table_insert (self->pv->collections, g_object_ref (collection), collection);
+       connect_to_collection (self, collection);
+
+       objects = gcr_collection_get_objects (collection);
+       for (l = objects; l != NULL; l = g_list_next (l))
+               on_collection_added (collection, l->data, self);
+       g_list_free (objects);
+
+       g_object_unref (collection);
+}
+
+/**
+ * gcr_union_collection_remove:
+ * @self: The collection
+ * @collection: The collection whose objects to remove
+ *
+ * Remove an object from the collection.
+ */
+void
+gcr_union_collection_remove (GcrUnionCollection *self,
+                             GcrCollection *collection)
+{
+       GList *objects, *l;
+
+       g_return_if_fail (GCR_IS_UNION_COLLECTION (self));
+       g_return_if_fail (GCR_IS_COLLECTION (collection));
+       g_return_if_fail (g_hash_table_lookup (self->pv->collections, collection));
+
+       g_object_ref (collection);
+
+       g_hash_table_remove (self->pv->collections, collection);
+       disconnect_from_collection (self, collection);
+
+       objects = gcr_collection_get_objects (collection);
+       for (l = objects; l != NULL; l = g_list_next (l))
+               on_collection_removed (collection, l->data, self);
+       g_list_free (objects);
+
+       g_object_unref (collection);
+}
diff --git a/gcr/gcr-union-collection.h b/gcr/gcr-union-collection.h
new file mode 100644 (file)
index 0000000..ac9a59d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#ifndef __GCR_UNION_COLLECTION_H__
+#define __GCR_UNION_COLLECTION_H__
+
+#include "gcr.h"
+#include "gcr-collection.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GCR_TYPE_UNION_COLLECTION               (gcr_union_collection_get_type ())
+#define GCR_UNION_COLLECTION(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_COLLECTION, GcrUnionCollection))
+#define GCR_UNION_COLLECTION_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_COLLECTION, GcrUnionCollectionClass))
+#define GCR_IS_UNION_COLLECTION(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_COLLECTION))
+#define GCR_IS_UNION_COLLECTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_COLLECTION))
+#define GCR_UNION_COLLECTION_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_COLLECTION, GcrUnionCollectionClass))
+
+typedef struct _GcrUnionCollection GcrUnionCollection;
+typedef struct _GcrUnionCollectionClass GcrUnionCollectionClass;
+typedef struct _GcrUnionCollectionPrivate GcrUnionCollectionPrivate;
+
+struct _GcrUnionCollection {
+       GObject parent;
+
+       /*< private >*/
+       GcrUnionCollectionPrivate *pv;
+};
+
+struct _GcrUnionCollectionClass {
+       GObjectClass parent_class;
+};
+
+GType               gcr_union_collection_get_type                (void);
+
+GcrCollection*      gcr_union_collection_new                     (void);
+
+void                gcr_union_collection_add                     (GcrUnionCollection *self,
+                                                                  GcrCollection *collection);
+
+void                gcr_union_collection_take                    (GcrUnionCollection *self,
+                                                                  GcrCollection *collection);
+
+void                gcr_union_collection_remove                  (GcrUnionCollection *self,
+                                                                  GcrCollection *collection);
+
+G_END_DECLS
+
+#endif /* __GCR_UNION_COLLECTION_H__ */
index e6a1238..cdb53ec 100644 (file)
--- a/gcr/gcr.h
+++ b/gcr/gcr.h
@@ -55,6 +55,7 @@
 #include "gcr-simple-collection.h"
 #include "gcr-tree-selector.h"
 #include "gcr-trust.h"
+#include "gcr-union-collection.h"
 #include "gcr-unlock-options.h"
 #include "gcr-unlock-options-widget.h"
 #include "gcr-viewer.h"